@masterteam/forms 0.0.45 → 0.0.47

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.
@@ -6,6 +6,7 @@ import { CommonModule } from '@angular/common';
6
6
  import { Skeleton } from 'primeng/skeleton';
7
7
  import * as i2 from 'primeng/stepper';
8
8
  import { StepperModule } from 'primeng/stepper';
9
+ import { EntitiesPreview } from '@masterteam/components/entities';
9
10
  import { Tabs } from '@masterteam/components/tabs';
10
11
  import { DynamicForm } from '@masterteam/forms/dynamic-form';
11
12
  import { HttpClient, HttpContext } from '@angular/common/http';
@@ -136,6 +137,11 @@ const WIDTH_TO_COLSPAN = {
136
137
  '50': 6,
137
138
  '100': 12,
138
139
  };
140
+ const WIDTH_TO_ENTITY_SIZE = {
141
+ '25': 6,
142
+ '50': 12,
143
+ '100': 24,
144
+ };
139
145
  // ============================================================================
140
146
  // Public Mapper Functions
141
147
  // ============================================================================
@@ -159,7 +165,7 @@ function mapToDynamicFormConfig(config, lang = 'en', mode = 'create', lookups =
159
165
  const visibleFields = section.fields
160
166
  .filter((field) => {
161
167
  // isRead=false → completely hidden
162
- if (field.isRead === false)
168
+ if (field.isWrite !== true && field.isRead === false)
163
169
  return false;
164
170
  if (mode === 'create')
165
171
  return !field.hiddenInCreation;
@@ -234,18 +240,51 @@ function mapFormValueToSubmitValues(formValue, loadResponse) {
234
240
  })
235
241
  .filter((value) => !!value);
236
242
  }
243
+ function getPreviewOnlyFieldKeys(config, mode = 'create') {
244
+ return config.sections.flatMap((section) => (section.fields ?? [])
245
+ .filter((field) => isFieldVisible(field, mode) && isPreviewOnlyField(field))
246
+ .map((field) => field.propertyKey));
247
+ }
248
+ function mapPreviewFieldsToEntities(config, values, mode = 'create') {
249
+ const resolvedValues = mapValuesToFormValue(values, config);
250
+ return config.sections
251
+ .slice()
252
+ .sort((a, b) => a.order - b.order)
253
+ .flatMap((section) => (section.fields ?? [])
254
+ .filter((field) => isFieldVisible(field, mode) && isPreviewOnlyField(field))
255
+ .sort((a, b) => a.order - b.order)
256
+ .flatMap((field) => {
257
+ const property = field.propertyMetadata;
258
+ return [
259
+ {
260
+ ...property,
261
+ name: property.name?.display,
262
+ key: property.key ?? field.propertyKey,
263
+ value: resolvedValues[field.propertyKey],
264
+ order: section.order * 1000 + field.order,
265
+ configuration: {
266
+ ...property.configuration,
267
+ size: WIDTH_TO_ENTITY_SIZE[field.width] ?? 24,
268
+ },
269
+ },
270
+ ];
271
+ }));
272
+ }
237
273
  // ============================================================================
238
274
  // Internal Helpers
239
275
  // ============================================================================
240
- /**
241
- * Resolve the property item from either `property` or `propertyMetadata`.
242
- * The API may return the data under either key.
243
- */
244
- function resolveProperty(field) {
245
- return field.property ?? field.propertyMetadata;
276
+ function isFieldVisible(field, mode) {
277
+ if (field.isWrite !== true && field.isRead === false)
278
+ return false;
279
+ if (mode === 'create')
280
+ return !field.hiddenInCreation;
281
+ return !field.hiddenInEditForm;
282
+ }
283
+ function isPreviewOnlyField(field) {
284
+ return field.isWrite === false && field.isRead !== false;
246
285
  }
247
286
  function resolveFieldMeta(field) {
248
- const property = resolveProperty(field);
287
+ const property = field.propertyMetadata;
249
288
  return {
250
289
  property,
251
290
  propertyId: property?.propertyId,
@@ -254,7 +293,8 @@ function resolveFieldMeta(field) {
254
293
  }
255
294
  function mapFieldToConfig(field, lang, lookups) {
256
295
  const { property: prop, viewType } = resolveFieldMeta(field);
257
- const label = resolvePropertyName(prop, lang) || field.propertyKey;
296
+ const label = prop?.name?.display ??
297
+ field.propertyKey;
258
298
  const colSpan = WIDTH_TO_COLSPAN[field.width] ?? 12;
259
299
  const base = {
260
300
  key: field.propertyKey,
@@ -382,14 +422,6 @@ function mapValidationRules(config, lang) {
382
422
  enabled: rule.enabled,
383
423
  }));
384
424
  }
385
- function resolvePropertyName(property, lang) {
386
- if (!property?.name)
387
- return '';
388
- if (typeof property.name === 'string')
389
- return property.name;
390
- // Prefer display name, then lang-specific, then English fallback
391
- return (property.name['display'] ?? property.name[lang] ?? property.name['en'] ?? '');
392
- }
393
425
  /**
394
426
  * Resolve lookup items for Lookup / LookupMultiSelect viewTypes.
395
427
  *
@@ -465,7 +497,7 @@ function buildFieldValueMap(config) {
465
497
  field.propertyKey,
466
498
  stripTemplatePrefix(field.propertyKey),
467
499
  ]);
468
- const property = resolveProperty(field);
500
+ const property = field.propertyMetadata;
469
501
  if (property?.key) {
470
502
  aliases.add(property.key);
471
503
  aliases.add(stripTemplatePrefix(property.key));
@@ -591,7 +623,7 @@ class ClientForm {
591
623
  readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : []));
592
624
  autoLoad = input(true, ...(ngDevMode ? [{ debugName: "autoLoad" }] : []));
593
625
  formMode = input('create', ...(ngDevMode ? [{ debugName: "formMode" }] : []));
594
- renderMode = input('form', ...(ngDevMode ? [{ debugName: "renderMode" }] : []));
626
+ renderMode = input(...(ngDevMode ? [undefined, { debugName: "renderMode" }] : []));
595
627
  showInternalStepActions = input(true, ...(ngDevMode ? [{ debugName: "showInternalStepActions" }] : []));
596
628
  lang = input('en', ...(ngDevMode ? [{ debugName: "lang" }] : []));
597
629
  lookups = input([], ...(ngDevMode ? [{ debugName: "lookups" }] : []));
@@ -621,9 +653,47 @@ class ClientForm {
621
653
  }, ...(ngDevMode ? [{ debugName: "initialValues" }] : []));
622
654
  virtualFields = computed(() => this.state.virtualFields(), ...(ngDevMode ? [{ debugName: "virtualFields" }] : []));
623
655
  hasVirtualFields = computed(() => this.virtualFields().length > 0, ...(ngDevMode ? [{ debugName: "hasVirtualFields" }] : []));
624
- stepSections = computed(() => this.formConfig()?.sections ?? [], ...(ngDevMode ? [{ debugName: "stepSections" }] : []));
625
- stepsEnabled = computed(() => this.renderMode() === 'steps' && this.stepSections().length > 1, ...(ngDevMode ? [{ debugName: "stepsEnabled" }] : []));
626
- tabsEnabled = computed(() => this.renderMode() === 'tabs' && this.stepSections().length > 1, ...(ngDevMode ? [{ debugName: "tabsEnabled" }] : []));
656
+ previewFieldKeys = computed(() => {
657
+ const config = this.state.formConfiguration();
658
+ if (!config)
659
+ return [];
660
+ return getPreviewOnlyFieldKeys(config, this.formMode());
661
+ }, ...(ngDevMode ? [{ debugName: "previewFieldKeys" }] : []));
662
+ previewEntities = computed(() => {
663
+ const config = this.state.formConfiguration();
664
+ if (!config)
665
+ return [];
666
+ return mapPreviewFieldsToEntities(config, this.state.formValues(), this.formMode());
667
+ }, ...(ngDevMode ? [{ debugName: "previewEntities" }] : []));
668
+ editableFormConfig = computed(() => {
669
+ const config = this.formConfig();
670
+ if (!config)
671
+ return null;
672
+ const previewFieldKeys = new Set(this.previewFieldKeys());
673
+ return {
674
+ ...config,
675
+ sections: config.sections
676
+ .map((section) => ({
677
+ ...section,
678
+ fields: section.fields.filter((field) => !field.key || !previewFieldKeys.has(field.key)),
679
+ }))
680
+ .filter((section) => section.fields.some((field) => field.type !== 'spacer')),
681
+ };
682
+ }, ...(ngDevMode ? [{ debugName: "editableFormConfig" }] : []));
683
+ stepSections = computed(() => this.editableFormConfig()?.sections ?? [], ...(ngDevMode ? [{ debugName: "stepSections" }] : []));
684
+ hasEditableFormSections = computed(() => this.stepSections().length > 0, ...(ngDevMode ? [{ debugName: "hasEditableFormSections" }] : []));
685
+ effectiveRenderMode = computed(() => {
686
+ const explicitRenderMode = this.renderMode();
687
+ if (explicitRenderMode)
688
+ return explicitRenderMode;
689
+ const configRenderMode = this.state.formConfiguration()?.renderMode;
690
+ if (configRenderMode === 'steps' || configRenderMode === 'tabs') {
691
+ return configRenderMode;
692
+ }
693
+ return 'form';
694
+ }, ...(ngDevMode ? [{ debugName: "effectiveRenderMode" }] : []));
695
+ stepsEnabled = computed(() => this.effectiveRenderMode() === 'steps' && this.stepSections().length > 1, ...(ngDevMode ? [{ debugName: "stepsEnabled" }] : []));
696
+ tabsEnabled = computed(() => this.effectiveRenderMode() === 'tabs' && this.stepSections().length > 1, ...(ngDevMode ? [{ debugName: "tabsEnabled" }] : []));
627
697
  sectionNavigationEnabled = computed(() => this.stepsEnabled() || this.tabsEnabled(), ...(ngDevMode ? [{ debugName: "sectionNavigationEnabled" }] : []));
628
698
  tabOptions = computed(() => this.stepSections().map((section, index) => ({
629
699
  label: section.label || `Tab ${index + 1}`,
@@ -643,13 +713,16 @@ class ClientForm {
643
713
  return [];
644
714
  const sections = this.stepSections();
645
715
  const currentIndex = this.currentStep() - 1;
646
- return sections.flatMap((section, index) => {
716
+ const hiddenFieldKeys = new Set();
717
+ sections.forEach((section, index) => {
647
718
  if (index === currentIndex)
648
- return [];
649
- return section.fields
719
+ return;
720
+ section.fields
650
721
  .map((field) => field.key)
651
- .filter((key) => !!key);
722
+ .filter((key) => !!key)
723
+ .forEach((key) => hiddenFieldKeys.add(key));
652
724
  });
725
+ return [...hiddenFieldKeys];
653
726
  }, ...(ngDevMode ? [{ debugName: "forcedHiddenFieldKeys" }] : []));
654
727
  // ============================================================================
655
728
  // Effects
@@ -871,8 +944,8 @@ class ClientForm {
871
944
  const formValue = this.getFormValue();
872
945
  const values = mapFormValueToSubmitValues(formValue, loadResponse);
873
946
  const req = {
874
- moduleKey: context?.moduleKey ?? this.moduleKey(),
875
- operationKey: context?.operationKey ?? this.operationKey(),
947
+ moduleKey: this.moduleKey() ?? context?.moduleKey,
948
+ operationKey: this.operationKey() ?? context?.operationKey,
876
949
  values,
877
950
  };
878
951
  const moduleId = context?.moduleId ?? this.moduleId();
@@ -899,18 +972,19 @@ class ClientForm {
899
972
  return req;
900
973
  }
901
974
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ClientForm, deps: [], target: i0.ɵɵFactoryTarget.Component });
902
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: ClientForm, isStandalone: true, selector: "mt-client-form", inputs: { moduleKey: { classPropertyName: "moduleKey", publicName: "moduleKey", isSignal: true, isRequired: true, transformFunction: null }, operationKey: { classPropertyName: "operationKey", publicName: "operationKey", isSignal: true, isRequired: true, transformFunction: null }, moduleId: { classPropertyName: "moduleId", publicName: "moduleId", isSignal: true, isRequired: false, transformFunction: null }, levelId: { classPropertyName: "levelId", publicName: "levelId", isSignal: true, isRequired: false, transformFunction: null }, levelDataId: { classPropertyName: "levelDataId", publicName: "levelDataId", isSignal: true, isRequired: false, transformFunction: null }, moduleDataId: { classPropertyName: "moduleDataId", publicName: "moduleDataId", isSignal: true, isRequired: false, transformFunction: null }, requestSchemaId: { classPropertyName: "requestSchemaId", publicName: "requestSchemaId", isSignal: true, isRequired: false, transformFunction: null }, draftProcessId: { classPropertyName: "draftProcessId", publicName: "draftProcessId", isSignal: true, isRequired: false, transformFunction: null }, preview: { classPropertyName: "preview", publicName: "preview", isSignal: true, isRequired: false, transformFunction: null }, returnUrl: { classPropertyName: "returnUrl", publicName: "returnUrl", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, autoLoad: { classPropertyName: "autoLoad", publicName: "autoLoad", isSignal: true, isRequired: false, transformFunction: null }, formMode: { classPropertyName: "formMode", publicName: "formMode", isSignal: true, isRequired: false, transformFunction: null }, renderMode: { classPropertyName: "renderMode", publicName: "renderMode", isSignal: true, isRequired: false, transformFunction: null }, showInternalStepActions: { classPropertyName: "showInternalStepActions", publicName: "showInternalStepActions", isSignal: true, isRequired: false, transformFunction: null }, lang: { classPropertyName: "lang", publicName: "lang", isSignal: true, isRequired: false, transformFunction: null }, lookups: { classPropertyName: "lookups", publicName: "lookups", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { loaded: "loaded", submitted: "submitted", errored: "errored", modeDetected: "modeDetected", formSourceDetected: "formSourceDetected" }, providers: [ClientFormStateService], ngImport: i0, template: "<!-- Client Form Template \u2014 Render only, NO action buttons -->\n\n<!-- Loading State -->\n@if (state.loading()) {\n <div class=\"flex flex-col gap-6\">\n <!-- Section header skeleton -->\n <div class=\"flex flex-col gap-4\">\n <p-skeleton width=\"30%\" height=\"1.5rem\" />\n <div class=\"grid grid-cols-12 gap-4\">\n <div class=\"col-span-6 flex flex-col gap-2\">\n <p-skeleton width=\"40%\" height=\"0.875rem\" />\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\n </div>\n <div class=\"col-span-6 flex flex-col gap-2\">\n <p-skeleton width=\"40%\" height=\"0.875rem\" />\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\n </div>\n <div class=\"col-span-12 flex flex-col gap-2\">\n <p-skeleton width=\"25%\" height=\"0.875rem\" />\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\n </div>\n <div class=\"col-span-6 flex flex-col gap-2\">\n <p-skeleton width=\"35%\" height=\"0.875rem\" />\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\n </div>\n <div class=\"col-span-6 flex flex-col gap-2\">\n <p-skeleton width=\"45%\" height=\"0.875rem\" />\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\n </div>\n </div>\n </div>\n\n <!-- Second section skeleton -->\n <div class=\"flex flex-col gap-4\">\n <p-skeleton width=\"25%\" height=\"1.5rem\" />\n <div class=\"grid grid-cols-12 gap-4\">\n <div class=\"col-span-6 flex flex-col gap-2\">\n <p-skeleton width=\"35%\" height=\"0.875rem\" />\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\n </div>\n <div class=\"col-span-6 flex flex-col gap-2\">\n <p-skeleton width=\"50%\" height=\"0.875rem\" />\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\n </div>\n <div class=\"col-span-12 flex flex-col gap-2\">\n <p-skeleton width=\"30%\" height=\"0.875rem\" />\n <p-skeleton width=\"100%\" height=\"5rem\" />\n </div>\n </div>\n </div>\n </div>\n}\n\n<!-- Loaded State -->\n@if (state.isLoaded() && !state.loading()) {\n <!-- Dynamic Form -->\n @if (state.requiresForm() && formConfig(); as config) {\n <div class=\"flex flex-col gap-4\">\n @if (runtimeErrors().length > 0 || runtimeWarnings().length > 0) {\n <div class=\"rounded-lg border border-surface-200 p-4 bg-surface-50\">\n @if (runtimeErrors().length > 0) {\n <div class=\"mb-3\">\n <h4 class=\"text-sm font-semibold text-red-600 mb-2\">\n Validation Errors\n </h4>\n <ul class=\"list-disc ps-5 text-sm text-red-600 space-y-1\">\n @for (\n msg of runtimeErrors();\n track msg.ruleId || msg.fieldKey || msg.message\n ) {\n <li>{{ msg.message }}</li>\n }\n </ul>\n </div>\n }\n\n @if (runtimeWarnings().length > 0) {\n <div>\n <h4 class=\"text-sm font-semibold text-amber-600 mb-2\">\n Validation Warnings\n </h4>\n <ul class=\"list-disc ps-5 text-sm text-amber-700 space-y-1\">\n @for (\n msg of runtimeWarnings();\n track msg.ruleId || msg.fieldKey || msg.message\n ) {\n <li>{{ msg.message }}</li>\n }\n </ul>\n </div>\n }\n </div>\n }\n @if (stepsEnabled()) {\n <div class=\"flex flex-col gap-4\">\n <p-stepper\n [value]=\"currentStep()\"\n (valueChange)=\"onStepChange($event)\"\n >\n <p-step-list>\n @for (section of stepSections(); track section.key || $index) {\n <p-step [value]=\"$index + 1\">\n {{ section.label || \"Step \" + ($index + 1) }}\n </p-step>\n }\n </p-step-list>\n </p-stepper>\n\n @if (showInternalStepActions()) {\n <div class=\"flex justify-between gap-2\">\n <button\n type=\"button\"\n class=\"px-3 py-2 rounded border border-surface-300 text-sm\"\n [disabled]=\"currentStep() === 1\"\n (click)=\"goToPreviousStep()\"\n >\n Previous\n </button>\n <button\n type=\"button\"\n class=\"px-3 py-2 rounded border border-surface-300 text-sm\"\n [disabled]=\"currentStep() === stepSections().length\"\n (click)=\"goToNextStep()\"\n >\n Next\n </button>\n </div>\n }\n </div>\n }\n\n @if (tabsEnabled()) {\n <mt-tabs\n [active]=\"currentStep()\"\n (activeChange)=\"onStepChange($event)\"\n [options]=\"tabOptions()\"\n size=\"small\"\n fluid\n />\n }\n\n <mt-dynamic-form\n [formConfig]=\"config\"\n [formControl]=\"formControl\"\n [visibleSectionKeys]=\"visibleSectionKeys()\"\n [forcedHiddenFieldKeys]=\"forcedHiddenFieldKeys()\"\n [preserveForcedHiddenValues]=\"true\"\n (runtimeMessagesChange)=\"onRuntimeMessagesChange($event)\"\n />\n </div>\n } @else if (!state.requiresForm()) {\n <div\n class=\"flex items-center justify-center p-6 rounded-lg bg-surface-50 border border-surface-200 border-dashed\"\n >\n <p class=\"text-sm text-muted-color\">\n No form required for this operation.\n </p>\n </div>\n }\n}\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: DynamicForm, selector: "mt-dynamic-form", inputs: ["formConfig", "forcedHiddenFieldKeys", "preserveForcedHiddenValues", "visibleSectionKeys"], outputs: ["runtimeMessagesChange"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "size", "fluid", "disabled"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "ngmodule", type: StepperModule }, { kind: "component", type: i2.Stepper, selector: "p-stepper", inputs: ["value", "linear", "transitionOptions", "motionOptions"], outputs: ["valueChange"] }, { kind: "component", type: i2.StepList, selector: "p-step-list" }, { kind: "component", type: i2.Step, selector: "p-step", inputs: ["value", "disabled"], outputs: ["valueChange"] }] });
975
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: ClientForm, isStandalone: true, selector: "mt-client-form", inputs: { moduleKey: { classPropertyName: "moduleKey", publicName: "moduleKey", isSignal: true, isRequired: true, transformFunction: null }, operationKey: { classPropertyName: "operationKey", publicName: "operationKey", isSignal: true, isRequired: true, transformFunction: null }, moduleId: { classPropertyName: "moduleId", publicName: "moduleId", isSignal: true, isRequired: false, transformFunction: null }, levelId: { classPropertyName: "levelId", publicName: "levelId", isSignal: true, isRequired: false, transformFunction: null }, levelDataId: { classPropertyName: "levelDataId", publicName: "levelDataId", isSignal: true, isRequired: false, transformFunction: null }, moduleDataId: { classPropertyName: "moduleDataId", publicName: "moduleDataId", isSignal: true, isRequired: false, transformFunction: null }, requestSchemaId: { classPropertyName: "requestSchemaId", publicName: "requestSchemaId", isSignal: true, isRequired: false, transformFunction: null }, draftProcessId: { classPropertyName: "draftProcessId", publicName: "draftProcessId", isSignal: true, isRequired: false, transformFunction: null }, preview: { classPropertyName: "preview", publicName: "preview", isSignal: true, isRequired: false, transformFunction: null }, returnUrl: { classPropertyName: "returnUrl", publicName: "returnUrl", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, autoLoad: { classPropertyName: "autoLoad", publicName: "autoLoad", isSignal: true, isRequired: false, transformFunction: null }, formMode: { classPropertyName: "formMode", publicName: "formMode", isSignal: true, isRequired: false, transformFunction: null }, renderMode: { classPropertyName: "renderMode", publicName: "renderMode", isSignal: true, isRequired: false, transformFunction: null }, showInternalStepActions: { classPropertyName: "showInternalStepActions", publicName: "showInternalStepActions", isSignal: true, isRequired: false, transformFunction: null }, lang: { classPropertyName: "lang", publicName: "lang", isSignal: true, isRequired: false, transformFunction: null }, lookups: { classPropertyName: "lookups", publicName: "lookups", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { loaded: "loaded", submitted: "submitted", errored: "errored", modeDetected: "modeDetected", formSourceDetected: "formSourceDetected" }, providers: [ClientFormStateService], ngImport: i0, template: "<!-- Client Form Template \u2014 Render only, NO action buttons -->\r\n\r\n<!-- Loading State -->\r\n@if (state.loading()) {\r\n <div class=\"flex flex-col gap-6\">\r\n <!-- Section header skeleton -->\r\n <div class=\"flex flex-col gap-4\">\r\n <p-skeleton width=\"30%\" height=\"1.5rem\" />\r\n <div class=\"grid grid-cols-12 gap-4\">\r\n <div class=\"col-span-6 flex flex-col gap-2\">\r\n <p-skeleton width=\"40%\" height=\"0.875rem\" />\r\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\r\n </div>\r\n <div class=\"col-span-6 flex flex-col gap-2\">\r\n <p-skeleton width=\"40%\" height=\"0.875rem\" />\r\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\r\n </div>\r\n <div class=\"col-span-12 flex flex-col gap-2\">\r\n <p-skeleton width=\"25%\" height=\"0.875rem\" />\r\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\r\n </div>\r\n <div class=\"col-span-6 flex flex-col gap-2\">\r\n <p-skeleton width=\"35%\" height=\"0.875rem\" />\r\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\r\n </div>\r\n <div class=\"col-span-6 flex flex-col gap-2\">\r\n <p-skeleton width=\"45%\" height=\"0.875rem\" />\r\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Second section skeleton -->\r\n <div class=\"flex flex-col gap-4\">\r\n <p-skeleton width=\"25%\" height=\"1.5rem\" />\r\n <div class=\"grid grid-cols-12 gap-4\">\r\n <div class=\"col-span-6 flex flex-col gap-2\">\r\n <p-skeleton width=\"35%\" height=\"0.875rem\" />\r\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\r\n </div>\r\n <div class=\"col-span-6 flex flex-col gap-2\">\r\n <p-skeleton width=\"50%\" height=\"0.875rem\" />\r\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\r\n </div>\r\n <div class=\"col-span-12 flex flex-col gap-2\">\r\n <p-skeleton width=\"30%\" height=\"0.875rem\" />\r\n <p-skeleton width=\"100%\" height=\"5rem\" />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n}\r\n\r\n<!-- Loaded State -->\r\n@if (state.isLoaded() && !state.loading()) {\r\n <div class=\"flex flex-col gap-4\">\r\n @if (previewEntities().length > 0) {\r\n <mt-entities-preview [entities]=\"previewEntities()\" />\r\n }\r\n\r\n <!-- Dynamic Form -->\r\n @if (state.requiresForm() && editableFormConfig(); as config) {\r\n @if (hasEditableFormSections()) {\r\n <div class=\"flex flex-col gap-4\">\r\n @if (runtimeErrors().length > 0 || runtimeWarnings().length > 0) {\r\n <div class=\"rounded-lg border border-surface-200 p-4 bg-surface-50\">\r\n @if (runtimeErrors().length > 0) {\r\n <div class=\"mb-3\">\r\n <h4 class=\"text-sm font-semibold text-red-600 mb-2\">\r\n Validation Errors\r\n </h4>\r\n <ul class=\"list-disc ps-5 text-sm text-red-600 space-y-1\">\r\n @for (\r\n msg of runtimeErrors();\r\n track msg.ruleId || msg.fieldKey || msg.message\r\n ) {\r\n <li>{{ msg.message }}</li>\r\n }\r\n </ul>\r\n </div>\r\n }\r\n\r\n @if (runtimeWarnings().length > 0) {\r\n <div>\r\n <h4 class=\"text-sm font-semibold text-amber-600 mb-2\">\r\n Validation Warnings\r\n </h4>\r\n <ul class=\"list-disc ps-5 text-sm text-amber-700 space-y-1\">\r\n @for (\r\n msg of runtimeWarnings();\r\n track msg.ruleId || msg.fieldKey || msg.message\r\n ) {\r\n <li>{{ msg.message }}</li>\r\n }\r\n </ul>\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n @if (stepsEnabled()) {\r\n <div class=\"flex flex-col gap-4\">\r\n <p-stepper\r\n [value]=\"currentStep()\"\r\n (valueChange)=\"onStepChange($event)\"\r\n >\r\n <p-step-list>\r\n @for (\r\n section of stepSections();\r\n track section.key || $index\r\n ) {\r\n <p-step [value]=\"$index + 1\">\r\n {{ section.label || \"Step \" + ($index + 1) }}\r\n </p-step>\r\n }\r\n </p-step-list>\r\n </p-stepper>\r\n\r\n @if (showInternalStepActions()) {\r\n <div class=\"flex justify-between gap-2\">\r\n <button\r\n type=\"button\"\r\n class=\"px-3 py-2 rounded border border-surface-300 text-sm\"\r\n [disabled]=\"currentStep() === 1\"\r\n (click)=\"goToPreviousStep()\"\r\n >\r\n Previous\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"px-3 py-2 rounded border border-surface-300 text-sm\"\r\n [disabled]=\"currentStep() === stepSections().length\"\r\n (click)=\"goToNextStep()\"\r\n >\r\n Next\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n @if (tabsEnabled()) {\r\n <mt-tabs\r\n [active]=\"currentStep()\"\r\n (activeChange)=\"onStepChange($event)\"\r\n [options]=\"tabOptions()\"\r\n size=\"small\"\r\n fluid\r\n />\r\n }\r\n <mt-dynamic-form\r\n [formConfig]=\"config\"\r\n [formControl]=\"formControl\"\r\n [visibleSectionKeys]=\"visibleSectionKeys()\"\r\n [forcedHiddenFieldKeys]=\"forcedHiddenFieldKeys()\"\r\n [preserveForcedHiddenValues]=\"true\"\r\n (runtimeMessagesChange)=\"onRuntimeMessagesChange($event)\"\r\n />\r\n </div>\r\n }\r\n } @else if (previewEntities().length === 0) {\r\n <div\r\n class=\"flex items-center justify-center p-6 rounded-lg bg-surface-50 border border-surface-200 border-dashed\"\r\n >\r\n <p class=\"text-sm text-muted-color\">\r\n No form required for this operation.\r\n </p>\r\n </div>\r\n }\r\n </div>\r\n}\r\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: EntitiesPreview, selector: "mt-entities-preview", inputs: ["entities"] }, { kind: "component", type: DynamicForm, selector: "mt-dynamic-form", inputs: ["formConfig", "forcedHiddenFieldKeys", "preserveForcedHiddenValues", "visibleSectionKeys"], outputs: ["runtimeMessagesChange"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "size", "fluid", "disabled"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "ngmodule", type: StepperModule }, { kind: "component", type: i2.Stepper, selector: "p-stepper", inputs: ["value", "linear", "transitionOptions", "motionOptions"], outputs: ["valueChange"] }, { kind: "component", type: i2.StepList, selector: "p-step-list" }, { kind: "component", type: i2.Step, selector: "p-step", inputs: ["value", "disabled"], outputs: ["valueChange"] }] });
903
976
  }
904
977
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ClientForm, decorators: [{
905
978
  type: Component,
906
979
  args: [{ selector: 'mt-client-form', standalone: true, imports: [
907
980
  CommonModule,
908
981
  ReactiveFormsModule,
982
+ EntitiesPreview,
909
983
  DynamicForm,
910
984
  Tabs,
911
985
  Skeleton,
912
986
  StepperModule,
913
- ], providers: [ClientFormStateService], template: "<!-- Client Form Template \u2014 Render only, NO action buttons -->\n\n<!-- Loading State -->\n@if (state.loading()) {\n <div class=\"flex flex-col gap-6\">\n <!-- Section header skeleton -->\n <div class=\"flex flex-col gap-4\">\n <p-skeleton width=\"30%\" height=\"1.5rem\" />\n <div class=\"grid grid-cols-12 gap-4\">\n <div class=\"col-span-6 flex flex-col gap-2\">\n <p-skeleton width=\"40%\" height=\"0.875rem\" />\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\n </div>\n <div class=\"col-span-6 flex flex-col gap-2\">\n <p-skeleton width=\"40%\" height=\"0.875rem\" />\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\n </div>\n <div class=\"col-span-12 flex flex-col gap-2\">\n <p-skeleton width=\"25%\" height=\"0.875rem\" />\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\n </div>\n <div class=\"col-span-6 flex flex-col gap-2\">\n <p-skeleton width=\"35%\" height=\"0.875rem\" />\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\n </div>\n <div class=\"col-span-6 flex flex-col gap-2\">\n <p-skeleton width=\"45%\" height=\"0.875rem\" />\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\n </div>\n </div>\n </div>\n\n <!-- Second section skeleton -->\n <div class=\"flex flex-col gap-4\">\n <p-skeleton width=\"25%\" height=\"1.5rem\" />\n <div class=\"grid grid-cols-12 gap-4\">\n <div class=\"col-span-6 flex flex-col gap-2\">\n <p-skeleton width=\"35%\" height=\"0.875rem\" />\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\n </div>\n <div class=\"col-span-6 flex flex-col gap-2\">\n <p-skeleton width=\"50%\" height=\"0.875rem\" />\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\n </div>\n <div class=\"col-span-12 flex flex-col gap-2\">\n <p-skeleton width=\"30%\" height=\"0.875rem\" />\n <p-skeleton width=\"100%\" height=\"5rem\" />\n </div>\n </div>\n </div>\n </div>\n}\n\n<!-- Loaded State -->\n@if (state.isLoaded() && !state.loading()) {\n <!-- Dynamic Form -->\n @if (state.requiresForm() && formConfig(); as config) {\n <div class=\"flex flex-col gap-4\">\n @if (runtimeErrors().length > 0 || runtimeWarnings().length > 0) {\n <div class=\"rounded-lg border border-surface-200 p-4 bg-surface-50\">\n @if (runtimeErrors().length > 0) {\n <div class=\"mb-3\">\n <h4 class=\"text-sm font-semibold text-red-600 mb-2\">\n Validation Errors\n </h4>\n <ul class=\"list-disc ps-5 text-sm text-red-600 space-y-1\">\n @for (\n msg of runtimeErrors();\n track msg.ruleId || msg.fieldKey || msg.message\n ) {\n <li>{{ msg.message }}</li>\n }\n </ul>\n </div>\n }\n\n @if (runtimeWarnings().length > 0) {\n <div>\n <h4 class=\"text-sm font-semibold text-amber-600 mb-2\">\n Validation Warnings\n </h4>\n <ul class=\"list-disc ps-5 text-sm text-amber-700 space-y-1\">\n @for (\n msg of runtimeWarnings();\n track msg.ruleId || msg.fieldKey || msg.message\n ) {\n <li>{{ msg.message }}</li>\n }\n </ul>\n </div>\n }\n </div>\n }\n @if (stepsEnabled()) {\n <div class=\"flex flex-col gap-4\">\n <p-stepper\n [value]=\"currentStep()\"\n (valueChange)=\"onStepChange($event)\"\n >\n <p-step-list>\n @for (section of stepSections(); track section.key || $index) {\n <p-step [value]=\"$index + 1\">\n {{ section.label || \"Step \" + ($index + 1) }}\n </p-step>\n }\n </p-step-list>\n </p-stepper>\n\n @if (showInternalStepActions()) {\n <div class=\"flex justify-between gap-2\">\n <button\n type=\"button\"\n class=\"px-3 py-2 rounded border border-surface-300 text-sm\"\n [disabled]=\"currentStep() === 1\"\n (click)=\"goToPreviousStep()\"\n >\n Previous\n </button>\n <button\n type=\"button\"\n class=\"px-3 py-2 rounded border border-surface-300 text-sm\"\n [disabled]=\"currentStep() === stepSections().length\"\n (click)=\"goToNextStep()\"\n >\n Next\n </button>\n </div>\n }\n </div>\n }\n\n @if (tabsEnabled()) {\n <mt-tabs\n [active]=\"currentStep()\"\n (activeChange)=\"onStepChange($event)\"\n [options]=\"tabOptions()\"\n size=\"small\"\n fluid\n />\n }\n\n <mt-dynamic-form\n [formConfig]=\"config\"\n [formControl]=\"formControl\"\n [visibleSectionKeys]=\"visibleSectionKeys()\"\n [forcedHiddenFieldKeys]=\"forcedHiddenFieldKeys()\"\n [preserveForcedHiddenValues]=\"true\"\n (runtimeMessagesChange)=\"onRuntimeMessagesChange($event)\"\n />\n </div>\n } @else if (!state.requiresForm()) {\n <div\n class=\"flex items-center justify-center p-6 rounded-lg bg-surface-50 border border-surface-200 border-dashed\"\n >\n <p class=\"text-sm text-muted-color\">\n No form required for this operation.\n </p>\n </div>\n }\n}\n", styles: [":host{display:block}\n"] }]
987
+ ], providers: [ClientFormStateService], template: "<!-- Client Form Template \u2014 Render only, NO action buttons -->\r\n\r\n<!-- Loading State -->\r\n@if (state.loading()) {\r\n <div class=\"flex flex-col gap-6\">\r\n <!-- Section header skeleton -->\r\n <div class=\"flex flex-col gap-4\">\r\n <p-skeleton width=\"30%\" height=\"1.5rem\" />\r\n <div class=\"grid grid-cols-12 gap-4\">\r\n <div class=\"col-span-6 flex flex-col gap-2\">\r\n <p-skeleton width=\"40%\" height=\"0.875rem\" />\r\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\r\n </div>\r\n <div class=\"col-span-6 flex flex-col gap-2\">\r\n <p-skeleton width=\"40%\" height=\"0.875rem\" />\r\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\r\n </div>\r\n <div class=\"col-span-12 flex flex-col gap-2\">\r\n <p-skeleton width=\"25%\" height=\"0.875rem\" />\r\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\r\n </div>\r\n <div class=\"col-span-6 flex flex-col gap-2\">\r\n <p-skeleton width=\"35%\" height=\"0.875rem\" />\r\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\r\n </div>\r\n <div class=\"col-span-6 flex flex-col gap-2\">\r\n <p-skeleton width=\"45%\" height=\"0.875rem\" />\r\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Second section skeleton -->\r\n <div class=\"flex flex-col gap-4\">\r\n <p-skeleton width=\"25%\" height=\"1.5rem\" />\r\n <div class=\"grid grid-cols-12 gap-4\">\r\n <div class=\"col-span-6 flex flex-col gap-2\">\r\n <p-skeleton width=\"35%\" height=\"0.875rem\" />\r\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\r\n </div>\r\n <div class=\"col-span-6 flex flex-col gap-2\">\r\n <p-skeleton width=\"50%\" height=\"0.875rem\" />\r\n <p-skeleton width=\"100%\" height=\"2.5rem\" />\r\n </div>\r\n <div class=\"col-span-12 flex flex-col gap-2\">\r\n <p-skeleton width=\"30%\" height=\"0.875rem\" />\r\n <p-skeleton width=\"100%\" height=\"5rem\" />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n}\r\n\r\n<!-- Loaded State -->\r\n@if (state.isLoaded() && !state.loading()) {\r\n <div class=\"flex flex-col gap-4\">\r\n @if (previewEntities().length > 0) {\r\n <mt-entities-preview [entities]=\"previewEntities()\" />\r\n }\r\n\r\n <!-- Dynamic Form -->\r\n @if (state.requiresForm() && editableFormConfig(); as config) {\r\n @if (hasEditableFormSections()) {\r\n <div class=\"flex flex-col gap-4\">\r\n @if (runtimeErrors().length > 0 || runtimeWarnings().length > 0) {\r\n <div class=\"rounded-lg border border-surface-200 p-4 bg-surface-50\">\r\n @if (runtimeErrors().length > 0) {\r\n <div class=\"mb-3\">\r\n <h4 class=\"text-sm font-semibold text-red-600 mb-2\">\r\n Validation Errors\r\n </h4>\r\n <ul class=\"list-disc ps-5 text-sm text-red-600 space-y-1\">\r\n @for (\r\n msg of runtimeErrors();\r\n track msg.ruleId || msg.fieldKey || msg.message\r\n ) {\r\n <li>{{ msg.message }}</li>\r\n }\r\n </ul>\r\n </div>\r\n }\r\n\r\n @if (runtimeWarnings().length > 0) {\r\n <div>\r\n <h4 class=\"text-sm font-semibold text-amber-600 mb-2\">\r\n Validation Warnings\r\n </h4>\r\n <ul class=\"list-disc ps-5 text-sm text-amber-700 space-y-1\">\r\n @for (\r\n msg of runtimeWarnings();\r\n track msg.ruleId || msg.fieldKey || msg.message\r\n ) {\r\n <li>{{ msg.message }}</li>\r\n }\r\n </ul>\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n @if (stepsEnabled()) {\r\n <div class=\"flex flex-col gap-4\">\r\n <p-stepper\r\n [value]=\"currentStep()\"\r\n (valueChange)=\"onStepChange($event)\"\r\n >\r\n <p-step-list>\r\n @for (\r\n section of stepSections();\r\n track section.key || $index\r\n ) {\r\n <p-step [value]=\"$index + 1\">\r\n {{ section.label || \"Step \" + ($index + 1) }}\r\n </p-step>\r\n }\r\n </p-step-list>\r\n </p-stepper>\r\n\r\n @if (showInternalStepActions()) {\r\n <div class=\"flex justify-between gap-2\">\r\n <button\r\n type=\"button\"\r\n class=\"px-3 py-2 rounded border border-surface-300 text-sm\"\r\n [disabled]=\"currentStep() === 1\"\r\n (click)=\"goToPreviousStep()\"\r\n >\r\n Previous\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"px-3 py-2 rounded border border-surface-300 text-sm\"\r\n [disabled]=\"currentStep() === stepSections().length\"\r\n (click)=\"goToNextStep()\"\r\n >\r\n Next\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n @if (tabsEnabled()) {\r\n <mt-tabs\r\n [active]=\"currentStep()\"\r\n (activeChange)=\"onStepChange($event)\"\r\n [options]=\"tabOptions()\"\r\n size=\"small\"\r\n fluid\r\n />\r\n }\r\n <mt-dynamic-form\r\n [formConfig]=\"config\"\r\n [formControl]=\"formControl\"\r\n [visibleSectionKeys]=\"visibleSectionKeys()\"\r\n [forcedHiddenFieldKeys]=\"forcedHiddenFieldKeys()\"\r\n [preserveForcedHiddenValues]=\"true\"\r\n (runtimeMessagesChange)=\"onRuntimeMessagesChange($event)\"\r\n />\r\n </div>\r\n }\r\n } @else if (previewEntities().length === 0) {\r\n <div\r\n class=\"flex items-center justify-center p-6 rounded-lg bg-surface-50 border border-surface-200 border-dashed\"\r\n >\r\n <p class=\"text-sm text-muted-color\">\r\n No form required for this operation.\r\n </p>\r\n </div>\r\n }\r\n </div>\r\n}\r\n", styles: [":host{display:block}\n"] }]
914
988
  }], ctorParameters: () => [], propDecorators: { moduleKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "moduleKey", required: true }] }], operationKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "operationKey", required: true }] }], moduleId: [{ type: i0.Input, args: [{ isSignal: true, alias: "moduleId", required: false }] }], levelId: [{ type: i0.Input, args: [{ isSignal: true, alias: "levelId", required: false }] }], levelDataId: [{ type: i0.Input, args: [{ isSignal: true, alias: "levelDataId", required: false }] }], moduleDataId: [{ type: i0.Input, args: [{ isSignal: true, alias: "moduleDataId", required: false }] }], requestSchemaId: [{ type: i0.Input, args: [{ isSignal: true, alias: "requestSchemaId", required: false }] }], draftProcessId: [{ type: i0.Input, args: [{ isSignal: true, alias: "draftProcessId", required: false }] }], preview: [{ type: i0.Input, args: [{ isSignal: true, alias: "preview", required: false }] }], returnUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "returnUrl", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], autoLoad: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoLoad", required: false }] }], formMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "formMode", required: false }] }], renderMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "renderMode", required: false }] }], showInternalStepActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "showInternalStepActions", required: false }] }], lang: [{ type: i0.Input, args: [{ isSignal: true, alias: "lang", required: false }] }], lookups: [{ type: i0.Input, args: [{ isSignal: true, alias: "lookups", required: false }] }], loaded: [{ type: i0.Output, args: ["loaded"] }], submitted: [{ type: i0.Output, args: ["submitted"] }], errored: [{ type: i0.Output, args: ["errored"] }], modeDetected: [{ type: i0.Output, args: ["modeDetected"] }], formSourceDetected: [{ type: i0.Output, args: ["formSourceDetected"] }] } });
915
989
 
916
990
  // ============================================================================
@@ -931,5 +1005,5 @@ function isFormRequiredInterception(response) {
931
1005
  * Generated bundle index. Do not edit.
932
1006
  */
933
1007
 
934
- export { ClientForm, ClientFormApiService, ClientFormStateService, isFormRequiredInterception, mapFormValueToSubmitValues, mapToDynamicFormConfig, mapValuesToFormValue };
1008
+ export { ClientForm, ClientFormApiService, ClientFormStateService, getPreviewOnlyFieldKeys, isFormRequiredInterception, mapFormValueToSubmitValues, mapPreviewFieldsToEntities, mapToDynamicFormConfig, mapValuesToFormValue };
935
1009
  //# sourceMappingURL=masterteam-forms-client-form.mjs.map