@masterteam/form-builder 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,19 +1,20 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, Injectable, computed, input, signal, viewChild, Component, effect, output } from '@angular/core';
3
- import * as i4 from '@angular/common';
2
+ import { inject, Injectable, computed, input, signal, viewChild, Component, effect, output, DestroyRef } from '@angular/core';
3
+ import * as i5 from '@angular/common';
4
4
  import { CommonModule } from '@angular/common';
5
5
  import * as i1 from '@angular/forms';
6
6
  import { FormControl, ReactiveFormsModule, FormGroup, FormsModule } from '@angular/forms';
7
- import * as i1$1 from 'primeng/tabs';
7
+ import * as i2 from 'primeng/tabs';
8
8
  import { TabsModule } from 'primeng/tabs';
9
- import * as i2 from 'primeng/skeleton';
9
+ import * as i3 from 'primeng/skeleton';
10
10
  import { SkeletonModule } from 'primeng/skeleton';
11
11
  import { Button } from '@masterteam/components/button';
12
12
  import { Card } from '@masterteam/components/card';
13
+ import { TextField } from '@masterteam/components/text-field';
13
14
  import { ModalService } from '@masterteam/components/modal';
14
15
  import { ConfirmationService } from '@masterteam/components/confirmation';
15
16
  import { TranslocoDirective, TranslocoService } from '@jsverse/transloco';
16
- import * as i3 from '@angular/cdk/drag-drop';
17
+ import * as i4 from '@angular/cdk/drag-drop';
17
18
  import { CdkDrag, CdkDropList, CdkDragPlaceholder, DragDropModule } from '@angular/cdk/drag-drop';
18
19
  import { DynamicField } from '@masterteam/forms/dynamic-field';
19
20
  import { Icon } from '@masterteam/icons';
@@ -23,9 +24,12 @@ import { CrudStateBase, handleApiRequest, RadioCardsFieldConfig } from '@mastert
23
24
  import { DynamicForm } from '@masterteam/forms/dynamic-form';
24
25
  import { ToggleField } from '@masterteam/components/toggle-field';
25
26
  import { ModalRef } from '@masterteam/components/dialog';
26
- import { FormulaToolbar, FormulaEditor } from '@masterteam/components/formula';
27
+ import { FormulaToolbar, FormulaEditor, serializeTokens } from '@masterteam/components/formula';
27
28
  import { Tooltip } from '@masterteam/components/tooltip';
28
29
  import { Tabs } from '@masterteam/components/tabs';
30
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
31
+ import { Table } from '@masterteam/components/table';
32
+ import { RadioCards } from '@masterteam/components/radio-cards';
29
33
 
30
34
  // ============================================================================
31
35
  // Module Configuration Actions
@@ -142,6 +146,41 @@ class MoveField {
142
146
  this.payload = payload;
143
147
  }
144
148
  }
149
+ // ============================================================================
150
+ // Validation Actions
151
+ // ============================================================================
152
+ class AddValidation {
153
+ payload;
154
+ static type = '[FormBuilder] Add Validation';
155
+ constructor(payload) {
156
+ this.payload = payload;
157
+ }
158
+ }
159
+ class UpdateValidation {
160
+ validationId;
161
+ payload;
162
+ static type = '[FormBuilder] Update Validation';
163
+ constructor(validationId, payload) {
164
+ this.validationId = validationId;
165
+ this.payload = payload;
166
+ }
167
+ }
168
+ class DeleteValidation {
169
+ validationId;
170
+ static type = '[FormBuilder] Delete Validation';
171
+ constructor(validationId) {
172
+ this.validationId = validationId;
173
+ }
174
+ }
175
+ class ToggleValidationActive {
176
+ validationId;
177
+ payload;
178
+ static type = '[FormBuilder] Toggle Validation Active';
179
+ constructor(validationId, payload) {
180
+ this.validationId = validationId;
181
+ this.payload = payload;
182
+ }
183
+ }
145
184
 
146
185
  // ============================================================================
147
186
  // Action Keys Enum
@@ -161,6 +200,11 @@ var FormBuilderActionKey;
161
200
  FormBuilderActionKey["DeleteField"] = "deleteField";
162
201
  FormBuilderActionKey["MoveField"] = "moveField";
163
202
  FormBuilderActionKey["ReorderFields"] = "reorderFields";
203
+ // Validation Rules
204
+ FormBuilderActionKey["AddValidation"] = "addValidation";
205
+ FormBuilderActionKey["UpdateValidation"] = "updateValidation";
206
+ FormBuilderActionKey["DeleteValidation"] = "deleteValidation";
207
+ FormBuilderActionKey["ToggleValidationActive"] = "toggleValidationActive";
164
208
  })(FormBuilderActionKey || (FormBuilderActionKey = {}));
165
209
 
166
210
  var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
@@ -216,6 +260,9 @@ let FormBuilderState = class FormBuilderState extends CrudStateBase {
216
260
  static getProperties(state) {
217
261
  return state?.properties ?? [];
218
262
  }
263
+ static getValidations(state) {
264
+ return state?.formConfiguration?.validations ?? [];
265
+ }
219
266
  // ============================================================================
220
267
  // Module Configuration Actions
221
268
  // ============================================================================
@@ -254,7 +301,9 @@ let FormBuilderState = class FormBuilderState extends CrudStateBase {
254
301
  key: FormBuilderActionKey.GetFormConfiguration,
255
302
  request$: req$,
256
303
  updateState: (_state, data) => ({
257
- formConfiguration: data ?? null,
304
+ formConfiguration: data
305
+ ? { ...data, validations: data.validations ?? [] }
306
+ : null,
258
307
  }),
259
308
  });
260
309
  }
@@ -267,7 +316,9 @@ let FormBuilderState = class FormBuilderState extends CrudStateBase {
267
316
  key: FormBuilderActionKey.ResetFormConfiguration,
268
317
  request$: req$,
269
318
  onSuccess: (res, _currentState) => ({
270
- formConfiguration: res.data ?? null,
319
+ formConfiguration: res.data
320
+ ? { ...res.data, validations: res.data.validations ?? [] }
321
+ : null,
271
322
  }),
272
323
  });
273
324
  }
@@ -660,6 +711,88 @@ let FormBuilderState = class FormBuilderState extends CrudStateBase {
660
711
  },
661
712
  });
662
713
  }
714
+ // ============================================================================
715
+ // Validation Actions
716
+ // ============================================================================
717
+ addValidation(ctx, action) {
718
+ const state = ctx.getState();
719
+ const apiPath = `${this.getApiPath(state)}/validations`;
720
+ const req$ = this.http.post(apiPath, action.payload);
721
+ return handleApiRequest({
722
+ ctx,
723
+ key: FormBuilderActionKey.AddValidation,
724
+ request$: req$,
725
+ onSuccess: (res, currentState) => {
726
+ const validations = [
727
+ ...(currentState.formConfiguration?.validations ?? []),
728
+ res.data,
729
+ ];
730
+ return {
731
+ formConfiguration: {
732
+ ...currentState.formConfiguration,
733
+ validations,
734
+ },
735
+ };
736
+ },
737
+ });
738
+ }
739
+ updateValidation(ctx, action) {
740
+ const state = ctx.getState();
741
+ const apiPath = `${this.getApiPath(state)}/validations/${action.validationId}`;
742
+ const req$ = this.http.put(apiPath, action.payload);
743
+ return handleApiRequest({
744
+ ctx,
745
+ key: FormBuilderActionKey.UpdateValidation,
746
+ request$: req$,
747
+ onSuccess: (res, currentState) => {
748
+ const validations = (currentState.formConfiguration?.validations ?? []).map((rule) => (rule.id === res.data.id ? res.data : rule));
749
+ return {
750
+ formConfiguration: {
751
+ ...currentState.formConfiguration,
752
+ validations,
753
+ },
754
+ };
755
+ },
756
+ });
757
+ }
758
+ deleteValidation(ctx, action) {
759
+ const state = ctx.getState();
760
+ const apiPath = `${this.getApiPath(state)}/validations/${action.validationId}`;
761
+ const req$ = this.http.delete(apiPath);
762
+ return handleApiRequest({
763
+ ctx,
764
+ key: FormBuilderActionKey.DeleteValidation,
765
+ request$: req$,
766
+ onSuccess: (res, currentState) => {
767
+ const validations = (currentState.formConfiguration?.validations ?? []).filter((rule) => rule.id !== res.data.id);
768
+ return {
769
+ formConfiguration: {
770
+ ...currentState.formConfiguration,
771
+ validations,
772
+ },
773
+ };
774
+ },
775
+ });
776
+ }
777
+ toggleValidationActive(ctx, action) {
778
+ const state = ctx.getState();
779
+ const apiPath = `${this.getApiPath(state)}/validations/${action.validationId}/active`;
780
+ const req$ = this.http.patch(apiPath, action.payload);
781
+ return handleApiRequest({
782
+ ctx,
783
+ key: FormBuilderActionKey.ToggleValidationActive,
784
+ request$: req$,
785
+ onSuccess: (res, currentState) => {
786
+ const validations = (currentState.formConfiguration?.validations ?? []).map((rule) => (rule.id === res.data.id ? res.data : rule));
787
+ return {
788
+ formConfiguration: {
789
+ ...currentState.formConfiguration,
790
+ validations,
791
+ },
792
+ };
793
+ },
794
+ });
795
+ }
663
796
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormBuilderState, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
664
797
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormBuilderState });
665
798
  };
@@ -702,6 +835,18 @@ __decorate([
702
835
  __decorate([
703
836
  Action(MoveField)
704
837
  ], FormBuilderState.prototype, "moveField", null);
838
+ __decorate([
839
+ Action(AddValidation)
840
+ ], FormBuilderState.prototype, "addValidation", null);
841
+ __decorate([
842
+ Action(UpdateValidation)
843
+ ], FormBuilderState.prototype, "updateValidation", null);
844
+ __decorate([
845
+ Action(DeleteValidation)
846
+ ], FormBuilderState.prototype, "deleteValidation", null);
847
+ __decorate([
848
+ Action(ToggleValidationActive)
849
+ ], FormBuilderState.prototype, "toggleValidationActive", null);
705
850
  __decorate([
706
851
  Selector()
707
852
  ], FormBuilderState, "getState", null);
@@ -720,6 +865,9 @@ __decorate([
720
865
  __decorate([
721
866
  Selector()
722
867
  ], FormBuilderState, "getProperties", null);
868
+ __decorate([
869
+ Selector()
870
+ ], FormBuilderState, "getValidations", null);
723
871
  FormBuilderState = __decorate([
724
872
  State({
725
873
  name: 'formBuilder',
@@ -728,7 +876,7 @@ FormBuilderState = __decorate([
728
876
  ], FormBuilderState);
729
877
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormBuilderState, decorators: [{
730
878
  type: Injectable
731
- }], propDecorators: { setModuleInfo: [], resetState: [], setProperties: [], getFormConfiguration: [], resetFormConfiguration: [], addSection: [], updateSection: [], deleteSection: [], addField: [], updateField: [], deleteField: [], reorderFields: [], moveField: [] } });
879
+ }], propDecorators: { setModuleInfo: [], resetState: [], setProperties: [], getFormConfiguration: [], resetFormConfiguration: [], addSection: [], updateSection: [], deleteSection: [], addField: [], updateField: [], deleteField: [], reorderFields: [], moveField: [], addValidation: [], updateValidation: [], deleteValidation: [], toggleValidationActive: [] } });
732
880
 
733
881
  class FormBuilderFacade {
734
882
  store = inject(Store);
@@ -739,6 +887,7 @@ class FormBuilderFacade {
739
887
  formConfiguration = select(FormBuilderState.getFormConfiguration);
740
888
  sections = select(FormBuilderState.getSections);
741
889
  properties = select(FormBuilderState.getProperties);
890
+ validations = select(FormBuilderState.getValidations);
742
891
  moduleType = select(FormBuilderState.getModuleType);
743
892
  moduleId = select(FormBuilderState.getModuleId);
744
893
  // ============================================================================
@@ -753,6 +902,10 @@ class FormBuilderFacade {
753
902
  isUpdatingField = computed(() => this.stateSignal().loadingActive.includes(FormBuilderActionKey.UpdateField), ...(ngDevMode ? [{ debugName: "isUpdatingField" }] : []));
754
903
  isDeletingField = computed(() => this.stateSignal().loadingActive.includes(FormBuilderActionKey.DeleteField), ...(ngDevMode ? [{ debugName: "isDeletingField" }] : []));
755
904
  isMovingField = computed(() => this.stateSignal().loadingActive.includes(FormBuilderActionKey.MoveField), ...(ngDevMode ? [{ debugName: "isMovingField" }] : []));
905
+ isAddingValidation = computed(() => this.stateSignal().loadingActive.includes(FormBuilderActionKey.AddValidation), ...(ngDevMode ? [{ debugName: "isAddingValidation" }] : []));
906
+ isUpdatingValidation = computed(() => this.stateSignal().loadingActive.includes(FormBuilderActionKey.UpdateValidation), ...(ngDevMode ? [{ debugName: "isUpdatingValidation" }] : []));
907
+ isDeletingValidation = computed(() => this.stateSignal().loadingActive.includes(FormBuilderActionKey.DeleteValidation), ...(ngDevMode ? [{ debugName: "isDeletingValidation" }] : []));
908
+ isTogglingValidation = computed(() => this.stateSignal().loadingActive.includes(FormBuilderActionKey.ToggleValidationActive), ...(ngDevMode ? [{ debugName: "isTogglingValidation" }] : []));
756
909
  // ============================================================================
757
910
  // Error Signals
758
911
  // ============================================================================
@@ -773,6 +926,14 @@ class FormBuilderFacade {
773
926
  errors[FormBuilderActionKey.MoveField] ??
774
927
  null);
775
928
  }, ...(ngDevMode ? [{ debugName: "fieldError" }] : []));
929
+ validationError = computed(() => {
930
+ const errors = this.stateSignal().errors;
931
+ return (errors[FormBuilderActionKey.AddValidation] ??
932
+ errors[FormBuilderActionKey.UpdateValidation] ??
933
+ errors[FormBuilderActionKey.DeleteValidation] ??
934
+ errors[FormBuilderActionKey.ToggleValidationActive] ??
935
+ null);
936
+ }, ...(ngDevMode ? [{ debugName: "validationError" }] : []));
776
937
  // ============================================================================
777
938
  // Module Configuration Dispatchers
778
939
  // ============================================================================
@@ -824,6 +985,21 @@ class FormBuilderFacade {
824
985
  moveField(sectionId, fieldId, payload) {
825
986
  return this.store.dispatch(new MoveField(sectionId, fieldId, payload));
826
987
  }
988
+ // ============================================================================
989
+ // Validation Dispatchers
990
+ // ============================================================================
991
+ addValidation(payload) {
992
+ return this.store.dispatch(new AddValidation(payload));
993
+ }
994
+ updateValidation(validationId, payload) {
995
+ return this.store.dispatch(new UpdateValidation(validationId, payload));
996
+ }
997
+ deleteValidation(validationId) {
998
+ return this.store.dispatch(new DeleteValidation(validationId));
999
+ }
1000
+ toggleValidationActive(validationId, payload) {
1001
+ return this.store.dispatch(new ToggleValidationActive(validationId, payload));
1002
+ }
827
1003
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormBuilderFacade, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
828
1004
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormBuilderFacade, providedIn: 'root' });
829
1005
  }
@@ -1149,7 +1325,7 @@ class FBFieldConditions {
1149
1325
  this.ref.close({ saved: false });
1150
1326
  }
1151
1327
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FBFieldConditions, deps: [], target: i0.ɵɵFactoryTarget.Component });
1152
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.0.3", type: FBFieldConditions, isStandalone: true, selector: "mt-fb-field-conditions", inputs: { initialFormula: { classPropertyName: "initialFormula", publicName: "initialFormula", isSignal: true, isRequired: false, transformFunction: null }, availableFields: { classPropertyName: "availableFields", publicName: "availableFields", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "editorRef", first: true, predicate: ["editor"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'formBuilder'\">\r\n <div [class]=\"[modalService.contentClass, 'p-4', 'overflow-y-hidden!']\">\r\n <div class=\"mt-4 h-full overflow-y-auto pb-10 flex flex-col gap-3\">\r\n <!-- Formula Toolbar -->\r\n <mt-formula-toolbar\r\n [knownProperties]=\"propertyKeys()\"\r\n [functionCategories]=\"functionCategories\"\r\n [operators]=\"operators\"\r\n [labels]=\"toolbarLabels\"\r\n (onBlockInsert)=\"onBlockInsert($event)\"\r\n />\r\n <!-- Formula Editor -->\r\n <mt-formula-editor\r\n #editor\r\n [placeholder]=\"t('build-condition-formula')\"\r\n [formControl]=\"formulaControl\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div [class]=\"modalService.footerClass\">\r\n <mt-button\r\n [label]=\"t('cancel')\"\r\n severity=\"secondary\"\r\n [disabled]=\"submitting()\"\r\n (onClick)=\"onCancel()\"\r\n />\r\n <mt-button\r\n [label]=\"t('save')\"\r\n severity=\"primary\"\r\n [loading]=\"submitting()\"\r\n (onClick)=\"onSave()\"\r\n />\r\n </div>\r\n</ng-container>\r\n", dependencies: [{ kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: FormulaToolbar, selector: "mt-formula-toolbar", inputs: ["knownProperties", "functionCategories", "operators", "initialTab", "searchPlaceholder", "labels"], outputs: ["onBlockInsert", "onTabChange"] }, { kind: "component", type: FormulaEditor, selector: "mt-formula-editor", inputs: ["placeholder", "initialTokens", "disabled"], outputs: ["formulaChange", "tokensChange", "onBlur", "onFocus"] }] });
1328
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.0.3", type: FBFieldConditions, isStandalone: true, selector: "mt-fb-field-conditions", inputs: { initialFormula: { classPropertyName: "initialFormula", publicName: "initialFormula", isSignal: true, isRequired: false, transformFunction: null }, availableFields: { classPropertyName: "availableFields", publicName: "availableFields", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "editorRef", first: true, predicate: ["editor"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'formBuilder'\">\r\n <div [class]=\"[modalService.contentClass, 'p-4', 'overflow-y-hidden!']\">\r\n <div class=\"mt-4 h-full overflow-y-auto pb-10 flex flex-col gap-3\">\r\n <!-- Formula Toolbar -->\r\n <mt-formula-toolbar\r\n [knownProperties]=\"propertyKeys()\"\r\n [functionCategories]=\"functionCategories\"\r\n [operators]=\"operators\"\r\n [labels]=\"toolbarLabels\"\r\n (onBlockInsert)=\"onBlockInsert($event)\"\r\n />\r\n <!-- Formula Editor -->\r\n <mt-formula-editor\r\n #editor\r\n [placeholder]=\"t('build-condition-formula')\"\r\n [formControl]=\"formulaControl\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div [class]=\"modalService.footerClass\">\r\n <mt-button\r\n [label]=\"t('cancel')\"\r\n severity=\"secondary\"\r\n [disabled]=\"submitting()\"\r\n (onClick)=\"onCancel()\"\r\n />\r\n <mt-button\r\n [label]=\"t('save')\"\r\n severity=\"primary\"\r\n [loading]=\"submitting()\"\r\n (onClick)=\"onSave()\"\r\n />\r\n </div>\r\n</ng-container>\r\n", dependencies: [{ kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: FormulaToolbar, selector: "mt-formula-toolbar", inputs: ["knownProperties", "propertiesTemplate", "functionCategories", "operators", "initialTab", "searchPlaceholder", "labels"], outputs: ["onBlockInsert", "onTabChange"] }, { kind: "component", type: FormulaEditor, selector: "mt-formula-editor", inputs: ["placeholder", "initialTokens", "disabled"], outputs: ["formulaChange", "tokensChange", "onBlur", "onFocus"] }] });
1153
1329
  }
1154
1330
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FBFieldConditions, decorators: [{
1155
1331
  type: Component,
@@ -1740,6 +1916,573 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
1740
1916
  args: [{ selector: 'mt-fb-preview-form', standalone: true, imports: [TranslocoDirective, ReactiveFormsModule, DynamicForm, Tabs], template: "<ng-container *transloco=\"let t; prefix: 'formBuilder'\">\r\n <div [class]=\"[modalService.contentClass, 'p-4', 'overflow-y-hidden!']\">\r\n <!-- Tabs for Create/Edit mode -->\r\n <div class=\"flex justify-center mb-4\">\r\n <mt-tabs [options]=\"tabOptions\" [(active)]=\"activeTab\"></mt-tabs>\r\n </div>\r\n\r\n <div class=\"h-full overflow-y-auto px-3 pb-10\">\r\n @if (isLoading()) {\r\n <div class=\"space-y-4 animate-pulse\">\r\n <div class=\"h-6 bg-surface-200 rounded w-1/3\"></div>\r\n <div class=\"h-10 bg-surface-200 rounded\"></div>\r\n <div class=\"h-10 bg-surface-200 rounded\"></div>\r\n <div class=\"h-10 bg-surface-200 rounded w-2/3\"></div>\r\n </div>\r\n } @else if (formConfig().sections.length > 0) {\r\n <mt-dynamic-form\r\n [formConfig]=\"formConfig()\"\r\n [formControl]=\"formControl\"\r\n >\r\n </mt-dynamic-form>\r\n } @else {\r\n <div\r\n class=\"flex justify-center items-center h-64 text-muted-color text-lg\"\r\n >\r\n {{ t(\"no-fields-visible\") }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n</ng-container>\r\n" }]
1741
1917
  }], ctorParameters: () => [], propDecorators: { sections: [{ type: i0.Input, args: [{ isSignal: true, alias: "sections", required: false }] }] } });
1742
1918
 
1919
+ /**
1920
+ * Validation Formula Constants
1921
+ * Functions and operators for validation formulas
1922
+ */
1923
+ const VALIDATION_FUNCTION_CATEGORIES = [
1924
+ {
1925
+ name: 'Validation',
1926
+ displayName: 'Validation',
1927
+ functions: [
1928
+ {
1929
+ name: 'REQUIRED',
1930
+ category: 'Validation',
1931
+ description: 'Returns true when value is not empty',
1932
+ signature: 'REQUIRED(value)',
1933
+ parameters: [
1934
+ {
1935
+ name: 'value',
1936
+ type: 'any',
1937
+ description: 'Value to check',
1938
+ required: true,
1939
+ },
1940
+ ],
1941
+ returnType: 'boolean',
1942
+ examples: ['REQUIRED(@Email)'],
1943
+ },
1944
+ {
1945
+ name: 'ISNULL',
1946
+ category: 'Validation',
1947
+ description: 'Returns true if value is null or empty',
1948
+ signature: 'ISNULL(value)',
1949
+ parameters: [
1950
+ {
1951
+ name: 'value',
1952
+ type: 'any',
1953
+ description: 'Value to check',
1954
+ required: true,
1955
+ },
1956
+ ],
1957
+ returnType: 'boolean',
1958
+ examples: ['ISNULL(@Phone)'],
1959
+ },
1960
+ {
1961
+ name: 'MIN_LENGTH',
1962
+ category: 'Validation',
1963
+ description: 'Returns true if value length is at least min',
1964
+ signature: 'MIN_LENGTH(value, min)',
1965
+ parameters: [
1966
+ {
1967
+ name: 'value',
1968
+ type: 'string',
1969
+ description: 'Value to check',
1970
+ required: true,
1971
+ },
1972
+ {
1973
+ name: 'min',
1974
+ type: 'number',
1975
+ description: 'Minimum length',
1976
+ required: true,
1977
+ },
1978
+ ],
1979
+ returnType: 'boolean',
1980
+ examples: ['MIN_LENGTH(@Password, 8)'],
1981
+ },
1982
+ {
1983
+ name: 'MAX_LENGTH',
1984
+ category: 'Validation',
1985
+ description: 'Returns true if value length is at most max',
1986
+ signature: 'MAX_LENGTH(value, max)',
1987
+ parameters: [
1988
+ {
1989
+ name: 'value',
1990
+ type: 'string',
1991
+ description: 'Value to check',
1992
+ required: true,
1993
+ },
1994
+ {
1995
+ name: 'max',
1996
+ type: 'number',
1997
+ description: 'Maximum length',
1998
+ required: true,
1999
+ },
2000
+ ],
2001
+ returnType: 'boolean',
2002
+ examples: ['MAX_LENGTH(@Title, 120)'],
2003
+ },
2004
+ {
2005
+ name: 'REGEX',
2006
+ category: 'Validation',
2007
+ description: 'Returns true if value matches regex pattern',
2008
+ signature: 'REGEX(value, pattern)',
2009
+ parameters: [
2010
+ {
2011
+ name: 'value',
2012
+ type: 'string',
2013
+ description: 'Value to check',
2014
+ required: true,
2015
+ },
2016
+ {
2017
+ name: 'pattern',
2018
+ type: 'string',
2019
+ description: 'Regex pattern',
2020
+ required: true,
2021
+ },
2022
+ ],
2023
+ returnType: 'boolean',
2024
+ examples: ['REGEX(@Email, "^[^@]+@[^@]+\\.[^@]+$")'],
2025
+ },
2026
+ {
2027
+ name: 'BEFORE',
2028
+ category: 'Validation',
2029
+ description: 'Returns true if date is before reference date',
2030
+ signature: 'BEFORE(date, reference)',
2031
+ parameters: [
2032
+ {
2033
+ name: 'date',
2034
+ type: 'date',
2035
+ description: 'Date to check',
2036
+ required: true,
2037
+ },
2038
+ {
2039
+ name: 'reference',
2040
+ type: 'date',
2041
+ description: 'Reference date',
2042
+ required: true,
2043
+ },
2044
+ ],
2045
+ returnType: 'boolean',
2046
+ examples: ['BEFORE(@EndDate, @StartDate)'],
2047
+ },
2048
+ {
2049
+ name: 'AFTER',
2050
+ category: 'Validation',
2051
+ description: 'Returns true if date is after reference date',
2052
+ signature: 'AFTER(date, reference)',
2053
+ parameters: [
2054
+ {
2055
+ name: 'date',
2056
+ type: 'date',
2057
+ description: 'Date to check',
2058
+ required: true,
2059
+ },
2060
+ {
2061
+ name: 'reference',
2062
+ type: 'date',
2063
+ description: 'Reference date',
2064
+ required: true,
2065
+ },
2066
+ ],
2067
+ returnType: 'boolean',
2068
+ examples: ['AFTER(@StartDate, @EndDate)'],
2069
+ },
2070
+ ],
2071
+ },
2072
+ {
2073
+ name: 'Logic',
2074
+ displayName: 'Logic Helpers',
2075
+ functions: [
2076
+ {
2077
+ name: 'AND',
2078
+ category: 'Logic',
2079
+ description: 'Returns true if all conditions are true',
2080
+ signature: 'AND(condition1, condition2)',
2081
+ parameters: [
2082
+ {
2083
+ name: 'condition1',
2084
+ type: 'boolean',
2085
+ description: 'First condition',
2086
+ required: true,
2087
+ },
2088
+ {
2089
+ name: 'condition2',
2090
+ type: 'boolean',
2091
+ description: 'Second condition',
2092
+ required: true,
2093
+ },
2094
+ ],
2095
+ returnType: 'boolean',
2096
+ examples: ['AND(REQUIRED(@Email), REGEX(@Email, "^.+@.+$"))'],
2097
+ },
2098
+ {
2099
+ name: 'OR',
2100
+ category: 'Logic',
2101
+ description: 'Returns true if any condition is true',
2102
+ signature: 'OR(condition1, condition2)',
2103
+ parameters: [
2104
+ {
2105
+ name: 'condition1',
2106
+ type: 'boolean',
2107
+ description: 'First condition',
2108
+ required: true,
2109
+ },
2110
+ {
2111
+ name: 'condition2',
2112
+ type: 'boolean',
2113
+ description: 'Second condition',
2114
+ required: true,
2115
+ },
2116
+ ],
2117
+ returnType: 'boolean',
2118
+ examples: ['OR(ISNULL(@Phone), REGEX(@Phone, "^\\+?[0-9]+$"))'],
2119
+ },
2120
+ {
2121
+ name: 'NOT',
2122
+ category: 'Logic',
2123
+ description: 'Returns the opposite of a condition',
2124
+ signature: 'NOT(condition)',
2125
+ parameters: [
2126
+ {
2127
+ name: 'condition',
2128
+ type: 'boolean',
2129
+ description: 'Condition to negate',
2130
+ required: true,
2131
+ },
2132
+ ],
2133
+ returnType: 'boolean',
2134
+ examples: ['NOT(ISNULL(@Password))'],
2135
+ },
2136
+ ],
2137
+ },
2138
+ ];
2139
+ const VALIDATION_OPERATORS = [
2140
+ // Arithmetic
2141
+ {
2142
+ symbol: '+',
2143
+ name: 'Add',
2144
+ type: 'arithmetic',
2145
+ description: 'Addition',
2146
+ precedence: 4,
2147
+ },
2148
+ {
2149
+ symbol: '-',
2150
+ name: 'Subtract',
2151
+ type: 'arithmetic',
2152
+ description: 'Subtraction',
2153
+ precedence: 4,
2154
+ },
2155
+ {
2156
+ symbol: '*',
2157
+ name: 'Multiply',
2158
+ type: 'arithmetic',
2159
+ description: 'Multiplication',
2160
+ precedence: 5,
2161
+ },
2162
+ {
2163
+ symbol: '/',
2164
+ name: 'Divide',
2165
+ type: 'arithmetic',
2166
+ description: 'Division',
2167
+ precedence: 5,
2168
+ },
2169
+ // Comparison
2170
+ {
2171
+ symbol: '==',
2172
+ name: 'Equal',
2173
+ type: 'comparison',
2174
+ description: 'Equal to',
2175
+ precedence: 3,
2176
+ },
2177
+ {
2178
+ symbol: '!=',
2179
+ name: 'Not Equal',
2180
+ type: 'comparison',
2181
+ description: 'Not equal to',
2182
+ precedence: 3,
2183
+ },
2184
+ {
2185
+ symbol: '>',
2186
+ name: 'Greater Than',
2187
+ type: 'comparison',
2188
+ description: 'Greater than',
2189
+ precedence: 3,
2190
+ },
2191
+ {
2192
+ symbol: '<',
2193
+ name: 'Less Than',
2194
+ type: 'comparison',
2195
+ description: 'Less than',
2196
+ precedence: 3,
2197
+ },
2198
+ {
2199
+ symbol: '>=',
2200
+ name: 'Greater or Equal',
2201
+ type: 'comparison',
2202
+ description: 'Greater than or equal',
2203
+ precedence: 3,
2204
+ },
2205
+ {
2206
+ symbol: '<=',
2207
+ name: 'Less or Equal',
2208
+ type: 'comparison',
2209
+ description: 'Less than or equal',
2210
+ precedence: 3,
2211
+ },
2212
+ // Logical
2213
+ {
2214
+ symbol: '&&',
2215
+ name: 'And',
2216
+ type: 'logical',
2217
+ description: 'Logical AND',
2218
+ precedence: 2,
2219
+ },
2220
+ {
2221
+ symbol: '||',
2222
+ name: 'Or',
2223
+ type: 'logical',
2224
+ description: 'Logical OR',
2225
+ precedence: 1,
2226
+ },
2227
+ ];
2228
+
2229
+ class FBValidationRuleForm {
2230
+ modalService = inject(ModalService);
2231
+ ref = inject(ModalRef);
2232
+ facade = inject(FormBuilderFacade);
2233
+ transloco = inject(TranslocoService);
2234
+ destroyRef = inject(DestroyRef);
2235
+ initialData = input(null, ...(ngDevMode ? [{ debugName: "initialData" }] : []));
2236
+ availableFields = input([], ...(ngDevMode ? [{ debugName: "availableFields" }] : []));
2237
+ submitting = signal(false, ...(ngDevMode ? [{ debugName: "submitting" }] : []));
2238
+ activeLang = signal(this.transloco.getActiveLang() ?? 'en', ...(ngDevMode ? [{ debugName: "activeLang" }] : []));
2239
+ messageEnControl = new FormControl('');
2240
+ messageArControl = new FormControl('');
2241
+ severityControl = new FormControl('error', {
2242
+ nonNullable: true,
2243
+ });
2244
+ formulaControl = new FormControl([]);
2245
+ editorRef = viewChild('editor', ...(ngDevMode ? [{ debugName: "editorRef" }] : []));
2246
+ functionCategories = VALIDATION_FUNCTION_CATEGORIES;
2247
+ operators = VALIDATION_OPERATORS;
2248
+ propertyKeys = computed(() => this.availableFields().map((field) => field.key), ...(ngDevMode ? [{ debugName: "propertyKeys" }] : []));
2249
+ toolbarLabels = {
2250
+ functions: 'Functions',
2251
+ properties: 'Fields',
2252
+ operators: 'Operators',
2253
+ noPropertiesAvailable: 'No fields available',
2254
+ };
2255
+ severityOptions = computed(() => {
2256
+ const _lang = this.activeLang();
2257
+ return [
2258
+ {
2259
+ id: 'error',
2260
+ name: this.transloco.translate('formBuilder.severity-error'),
2261
+ },
2262
+ {
2263
+ id: 'warning',
2264
+ name: this.transloco.translate('formBuilder.severity-warning'),
2265
+ },
2266
+ ];
2267
+ }, ...(ngDevMode ? [{ debugName: "severityOptions" }] : []));
2268
+ constructor() {
2269
+ this.transloco.langChanges$
2270
+ .pipe(takeUntilDestroyed(this.destroyRef))
2271
+ .subscribe((lang) => {
2272
+ this.activeLang.set(lang ?? 'en');
2273
+ });
2274
+ effect(() => {
2275
+ const data = this.initialData();
2276
+ if (!data) {
2277
+ this.messageEnControl.reset('');
2278
+ this.messageArControl.reset('');
2279
+ this.severityControl.setValue('error');
2280
+ this.formulaControl.reset([]);
2281
+ return;
2282
+ }
2283
+ this.messageEnControl.setValue(data.message?.en ?? '');
2284
+ this.messageArControl.setValue(data.message?.ar ?? '');
2285
+ this.severityControl.setValue(data.severity ?? 'error');
2286
+ if (data.formulaTokens) {
2287
+ try {
2288
+ const tokens = JSON.parse(data.formulaTokens);
2289
+ this.formulaControl.patchValue(tokens);
2290
+ }
2291
+ catch {
2292
+ this.formulaControl.reset([]);
2293
+ }
2294
+ }
2295
+ else {
2296
+ this.formulaControl.reset([]);
2297
+ }
2298
+ });
2299
+ }
2300
+ onBlockInsert(block) {
2301
+ const editor = this.editorRef();
2302
+ if (editor) {
2303
+ editor.addBlock(block);
2304
+ }
2305
+ }
2306
+ onSeverityChange(item) {
2307
+ this.severityControl.setValue(item.id);
2308
+ }
2309
+ onSave() {
2310
+ const tokens = this.formulaControl.value ?? [];
2311
+ const formulaTokens = tokens.length > 0 ? JSON.stringify(tokens) : '';
2312
+ const formulaText = tokens.length > 0 ? serializeTokens(tokens) : '';
2313
+ const payload = {
2314
+ formulaTokens,
2315
+ formulaText,
2316
+ message: {
2317
+ en: this.messageEnControl.value ?? '',
2318
+ ar: this.messageArControl.value ?? '',
2319
+ },
2320
+ severity: this.severityControl.value ?? 'error',
2321
+ };
2322
+ const data = this.initialData();
2323
+ this.submitting.set(true);
2324
+ if (data?.id !== undefined && data?.id !== null) {
2325
+ this.facade.updateValidation(data.id, payload).subscribe({
2326
+ next: () => this.ref.close(true),
2327
+ error: () => this.submitting.set(false),
2328
+ });
2329
+ return;
2330
+ }
2331
+ this.facade.addValidation(payload).subscribe({
2332
+ next: () => this.ref.close(true),
2333
+ error: () => this.submitting.set(false),
2334
+ });
2335
+ }
2336
+ onCancel() {
2337
+ this.ref.close(false);
2338
+ }
2339
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FBValidationRuleForm, deps: [], target: i0.ɵɵFactoryTarget.Component });
2340
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.0.3", type: FBValidationRuleForm, isStandalone: true, selector: "mt-fb-validation-rule-form", inputs: { initialData: { classPropertyName: "initialData", publicName: "initialData", isSignal: true, isRequired: false, transformFunction: null }, availableFields: { classPropertyName: "availableFields", publicName: "availableFields", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "editorRef", first: true, predicate: ["editor"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'formBuilder'\">\r\n <div [class]=\"[modalService.contentClass, 'p-4', 'overflow-y-hidden!']\">\r\n <div class=\"mt-4 h-full overflow-y-auto pb-10 flex flex-col gap-4\">\r\n <mt-formula-toolbar\r\n [knownProperties]=\"propertyKeys()\"\r\n [functionCategories]=\"functionCategories\"\r\n [operators]=\"operators\"\r\n [labels]=\"toolbarLabels\"\r\n (onBlockInsert)=\"onBlockInsert($event)\"\r\n />\r\n <mt-formula-editor\r\n #editor\r\n [placeholder]=\"t('validation-formula-placeholder')\"\r\n [formControl]=\"formulaControl\"\r\n />\r\n <div class=\"grid grid-cols-2 gap-4\">\r\n <mt-text-field\r\n [label]=\"t('message-en')\"\r\n [placeholder]=\"t('message-en')\"\r\n [formControl]=\"messageEnControl\"\r\n />\r\n <mt-text-field\r\n [label]=\"t('message-ar')\"\r\n [placeholder]=\"t('message-ar')\"\r\n [formControl]=\"messageArControl\"\r\n />\r\n </div>\r\n <div class=\"grid gap-2\">\r\n <label class=\"text-sm font-medium text-gray-700 dark:text-gray-100\">\r\n {{ t(\"severity\") }}\r\n </label>\r\n <mt-radio-cards\r\n [options]=\"severityOptions()\"\r\n [activeId]=\"severityControl.value\"\r\n (selectionChange)=\"onSeverityChange($event)\"\r\n ></mt-radio-cards>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div [class]=\"modalService.footerClass\">\r\n <mt-button\r\n [label]=\"t('cancel')\"\r\n severity=\"secondary\"\r\n [disabled]=\"submitting()\"\r\n (onClick)=\"onCancel()\"\r\n />\r\n <mt-button\r\n [label]=\"t('save')\"\r\n severity=\"primary\"\r\n [loading]=\"submitting()\"\r\n (onClick)=\"onSave()\"\r\n />\r\n </div>\r\n</ng-container>\r\n", dependencies: [{ kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "icon", "iconPosition"] }, { kind: "component", type: RadioCards, selector: "mt-radio-cards", inputs: ["circle", "color", "size", "columns", "options", "activeId", "itemTemplate"], outputs: ["optionsChange", "activeIdChange", "selectionChange"] }, { kind: "component", type: FormulaToolbar, selector: "mt-formula-toolbar", inputs: ["knownProperties", "propertiesTemplate", "functionCategories", "operators", "initialTab", "searchPlaceholder", "labels"], outputs: ["onBlockInsert", "onTabChange"] }, { kind: "component", type: FormulaEditor, selector: "mt-formula-editor", inputs: ["placeholder", "initialTokens", "disabled"], outputs: ["formulaChange", "tokensChange", "onBlur", "onFocus"] }] });
2341
+ }
2342
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FBValidationRuleForm, decorators: [{
2343
+ type: Component,
2344
+ args: [{ selector: 'mt-fb-validation-rule-form', standalone: true, imports: [
2345
+ TranslocoDirective,
2346
+ ReactiveFormsModule,
2347
+ Button,
2348
+ TextField,
2349
+ RadioCards,
2350
+ FormulaToolbar,
2351
+ FormulaEditor,
2352
+ ], template: "<ng-container *transloco=\"let t; prefix: 'formBuilder'\">\r\n <div [class]=\"[modalService.contentClass, 'p-4', 'overflow-y-hidden!']\">\r\n <div class=\"mt-4 h-full overflow-y-auto pb-10 flex flex-col gap-4\">\r\n <mt-formula-toolbar\r\n [knownProperties]=\"propertyKeys()\"\r\n [functionCategories]=\"functionCategories\"\r\n [operators]=\"operators\"\r\n [labels]=\"toolbarLabels\"\r\n (onBlockInsert)=\"onBlockInsert($event)\"\r\n />\r\n <mt-formula-editor\r\n #editor\r\n [placeholder]=\"t('validation-formula-placeholder')\"\r\n [formControl]=\"formulaControl\"\r\n />\r\n <div class=\"grid grid-cols-2 gap-4\">\r\n <mt-text-field\r\n [label]=\"t('message-en')\"\r\n [placeholder]=\"t('message-en')\"\r\n [formControl]=\"messageEnControl\"\r\n />\r\n <mt-text-field\r\n [label]=\"t('message-ar')\"\r\n [placeholder]=\"t('message-ar')\"\r\n [formControl]=\"messageArControl\"\r\n />\r\n </div>\r\n <div class=\"grid gap-2\">\r\n <label class=\"text-sm font-medium text-gray-700 dark:text-gray-100\">\r\n {{ t(\"severity\") }}\r\n </label>\r\n <mt-radio-cards\r\n [options]=\"severityOptions()\"\r\n [activeId]=\"severityControl.value\"\r\n (selectionChange)=\"onSeverityChange($event)\"\r\n ></mt-radio-cards>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div [class]=\"modalService.footerClass\">\r\n <mt-button\r\n [label]=\"t('cancel')\"\r\n severity=\"secondary\"\r\n [disabled]=\"submitting()\"\r\n (onClick)=\"onCancel()\"\r\n />\r\n <mt-button\r\n [label]=\"t('save')\"\r\n severity=\"primary\"\r\n [loading]=\"submitting()\"\r\n (onClick)=\"onSave()\"\r\n />\r\n </div>\r\n</ng-container>\r\n" }]
2353
+ }], ctorParameters: () => [], propDecorators: { initialData: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialData", required: false }] }], availableFields: [{ type: i0.Input, args: [{ isSignal: true, alias: "availableFields", required: false }] }], editorRef: [{ type: i0.ViewChild, args: ['editor', { isSignal: true }] }] } });
2354
+
2355
+ class FBValidationRules {
2356
+ modalService = inject(ModalService);
2357
+ facade = inject(FormBuilderFacade);
2358
+ transloco = inject(TranslocoService);
2359
+ destroyRef = inject(DestroyRef);
2360
+ validations = this.facade.validations;
2361
+ sections = this.facade.sections;
2362
+ properties = this.facade.properties;
2363
+ activeLang = signal(this.transloco.getActiveLang() ?? 'en', ...(ngDevMode ? [{ debugName: "activeLang" }] : []));
2364
+ propertiesMap = computed(() => {
2365
+ const map = new Map();
2366
+ for (const prop of this.properties()) {
2367
+ map.set(prop.id, prop);
2368
+ }
2369
+ return map;
2370
+ }, ...(ngDevMode ? [{ debugName: "propertiesMap" }] : []));
2371
+ availableFields = computed(() => {
2372
+ const sections = this.sections();
2373
+ const propsMap = this.propertiesMap();
2374
+ const lang = this.activeLang();
2375
+ const fields = [];
2376
+ for (const section of sections) {
2377
+ for (const field of section.fields) {
2378
+ const prop = propsMap.get(field.propertyId);
2379
+ const propName = prop?.name;
2380
+ const name = typeof propName === 'string'
2381
+ ? propName
2382
+ : (propName?.[lang] ??
2383
+ propName?.['en'] ??
2384
+ `Property ${field.propertyId}`);
2385
+ fields.push({
2386
+ key: name,
2387
+ name,
2388
+ type: prop?.viewType || 'text',
2389
+ });
2390
+ }
2391
+ }
2392
+ return fields;
2393
+ }, ...(ngDevMode ? [{ debugName: "availableFields" }] : []));
2394
+ tableRows = computed(() => {
2395
+ const lang = this.activeLang();
2396
+ return this.validations().map((rule) => ({
2397
+ ...rule,
2398
+ messageText: rule.message?.[lang] ?? rule.message?.en ?? '',
2399
+ }));
2400
+ }, ...(ngDevMode ? [{ debugName: "tableRows" }] : []));
2401
+ tableColumns = computed(() => {
2402
+ const _lang = this.activeLang();
2403
+ return [
2404
+ {
2405
+ key: 'messageText',
2406
+ label: this.transloco.translate('formBuilder.validation-message'),
2407
+ },
2408
+ {
2409
+ key: 'enabled',
2410
+ label: this.transloco.translate('formBuilder.validation-active'),
2411
+ type: 'boolean',
2412
+ },
2413
+ ];
2414
+ }, ...(ngDevMode ? [{ debugName: "tableColumns" }] : []));
2415
+ rowActions = computed(() => {
2416
+ const _lang = this.activeLang();
2417
+ return [
2418
+ {
2419
+ icon: 'custom.pencil',
2420
+ tooltip: this.transloco.translate('formBuilder.edit-validation-rule'),
2421
+ action: (row) => this.openEdit(row),
2422
+ },
2423
+ {
2424
+ icon: 'general.trash-01',
2425
+ tooltip: this.transloco.translate('formBuilder.delete'),
2426
+ action: (row) => this.deleteRule(row),
2427
+ confirmation: {
2428
+ type: 'popup',
2429
+ confirmationType: 'delete',
2430
+ },
2431
+ },
2432
+ ];
2433
+ }, ...(ngDevMode ? [{ debugName: "rowActions" }] : []));
2434
+ constructor() {
2435
+ this.transloco.langChanges$
2436
+ .pipe(takeUntilDestroyed(this.destroyRef))
2437
+ .subscribe((lang) => {
2438
+ this.activeLang.set(lang ?? 'en');
2439
+ });
2440
+ }
2441
+ openCreate() {
2442
+ this.modalService.openModal(FBValidationRuleForm, 'drawer', {
2443
+ header: this.transloco.translate('formBuilder.add-validation-rule'),
2444
+ styleClass: '!w-[65%] !absolute',
2445
+ position: 'start',
2446
+ modal: true,
2447
+ dismissible: true,
2448
+ appendTo: '#page-content',
2449
+ inputValues: {
2450
+ availableFields: this.availableFields(),
2451
+ },
2452
+ });
2453
+ }
2454
+ openEdit(row) {
2455
+ this.modalService.openModal(FBValidationRuleForm, 'drawer', {
2456
+ header: this.transloco.translate('formBuilder.edit-validation-rule'),
2457
+ styleClass: '!w-[65%] !absolute',
2458
+ position: 'start',
2459
+ modal: true,
2460
+ dismissible: true,
2461
+ appendTo: '#page-content',
2462
+ inputValues: {
2463
+ initialData: row,
2464
+ availableFields: this.availableFields(),
2465
+ },
2466
+ });
2467
+ }
2468
+ deleteRule(row) {
2469
+ this.facade.deleteValidation(row.id).subscribe();
2470
+ }
2471
+ onCellChange(event) {
2472
+ if (event.column !== 'enabled')
2473
+ return;
2474
+ this.facade
2475
+ .toggleValidationActive(event.row.id, { enabled: event.value })
2476
+ .subscribe();
2477
+ }
2478
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FBValidationRules, deps: [], target: i0.ɵɵFactoryTarget.Component });
2479
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.3", type: FBValidationRules, isStandalone: true, selector: "mt-fb-validation-rules", ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'formBuilder'\">\r\n <div [class]=\"[modalService.contentClass, 'p-4', 'overflow-y-auto']\">\r\n <div class=\"flex justify-end pb-4\">\r\n <mt-button\r\n [label]=\"t('add-validation-rule')\"\r\n severity=\"primary\"\r\n variant=\"outlined\"\r\n (onClick)=\"openCreate()\"\r\n ></mt-button>\r\n </div>\r\n <mt-table\r\n [data]=\"tableRows()\"\r\n [columns]=\"tableColumns()\"\r\n [rowActions]=\"rowActions()\"\r\n (cellChange)=\"onCellChange($event)\"\r\n ></mt-table>\r\n </div>\r\n</ng-container>\r\n", dependencies: [{ kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Table, selector: "mt-table", inputs: ["filters", "data", "columns", "rowActions", "size", "showGridlines", "stripedRows", "selectableRows", "generalSearch", "showFilters", "loading", "updating", "lazy", "lazyTotalRecords", "reorderableColumns", "reorderableRows", "dataKey", "exportable", "exportFilename", "tabs", "tabsOptionLabel", "tabsOptionValue", "activeTab", "actions", "paginatorPosition", "pageSize", "currentPage", "first", "filterTerm"], outputs: ["selectionChange", "cellChange", "lazyLoad", "columnReorder", "rowReorder", "filtersChange", "activeTabChange", "onTabChange", "pageSizeChange", "currentPageChange", "firstChange", "filterTermChange"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }] });
2480
+ }
2481
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FBValidationRules, decorators: [{
2482
+ type: Component,
2483
+ args: [{ selector: 'mt-fb-validation-rules', standalone: true, imports: [TranslocoDirective, Table, Button], template: "<ng-container *transloco=\"let t; prefix: 'formBuilder'\">\r\n <div [class]=\"[modalService.contentClass, 'p-4', 'overflow-y-auto']\">\r\n <div class=\"flex justify-end pb-4\">\r\n <mt-button\r\n [label]=\"t('add-validation-rule')\"\r\n severity=\"primary\"\r\n variant=\"outlined\"\r\n (onClick)=\"openCreate()\"\r\n ></mt-button>\r\n </div>\r\n <mt-table\r\n [data]=\"tableRows()\"\r\n [columns]=\"tableColumns()\"\r\n [rowActions]=\"rowActions()\"\r\n (cellChange)=\"onCellChange($event)\"\r\n ></mt-table>\r\n </div>\r\n</ng-container>\r\n" }]
2484
+ }], ctorParameters: () => [] });
2485
+
1743
2486
  class FormBuilder {
1744
2487
  modalService = inject(ModalService);
1745
2488
  confirmationService = inject(ConfirmationService);
@@ -1748,6 +2491,7 @@ class FormBuilder {
1748
2491
  dialogRef;
1749
2492
  // Local UI state
1750
2493
  activeTab = signal('system', ...(ngDevMode ? [{ debugName: "activeTab" }] : []));
2494
+ searchQuery = signal('', ...(ngDevMode ? [{ debugName: "searchQuery" }] : []));
1751
2495
  // State from facade
1752
2496
  sections = this.facade.sections;
1753
2497
  properties = this.facade.properties;
@@ -1800,6 +2544,21 @@ class FormBuilder {
1800
2544
  }
1801
2545
  return tabs;
1802
2546
  }, ...(ngDevMode ? [{ debugName: "availableTabs" }] : []));
2547
+ // Filtered properties based on search query
2548
+ filteredPropertiesByTab = computed(() => {
2549
+ const query = this.searchQuery().toLowerCase().trim();
2550
+ const tabs = this.availableTabs();
2551
+ if (!query) {
2552
+ return tabs;
2553
+ }
2554
+ return tabs.map((tab) => ({
2555
+ ...tab,
2556
+ properties: tab.properties.filter((prop) => {
2557
+ const name = prop.name;
2558
+ return name.toLowerCase().includes(query);
2559
+ }),
2560
+ }));
2561
+ }, ...(ngDevMode ? [{ debugName: "filteredPropertiesByTab" }] : []));
1803
2562
  constructor() {
1804
2563
  // Update active tab when tabs change
1805
2564
  effect(() => {
@@ -1869,6 +2628,15 @@ class FormBuilder {
1869
2628
  },
1870
2629
  });
1871
2630
  }
2631
+ openValidationRules() {
2632
+ this.dialogRef = this.modalService.openModal(FBValidationRules, 'drawer', {
2633
+ header: this.translocoService.translate('formBuilder.validation-rules'),
2634
+ styleClass: '!w-[35%] !absolute !shadow-none',
2635
+ position: 'end',
2636
+ appendTo: '#page-content',
2637
+ dismissible: true,
2638
+ });
2639
+ }
1872
2640
  resetFormConfiguration() {
1873
2641
  this.confirmationService.confirm({
1874
2642
  type: 'dialog',
@@ -1880,7 +2648,7 @@ class FormBuilder {
1880
2648
  }
1881
2649
  noReturnPredicate = () => false;
1882
2650
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormBuilder, deps: [], target: i0.ɵɵFactoryTarget.Component });
1883
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: FormBuilder, isStandalone: true, selector: "mt-form-builder", ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'formBuilder'\">\r\n <div class=\"flex gap-7 h-full w-full overflow-hidden\" cdkDropListGroup>\r\n <!-- Properties Sidebar -->\r\n <mt-card class=\"w-1/5 h-full flex flex-col overflow-hidden\">\r\n <ng-template #headless>\r\n <!-- Header -->\r\n <h3 class=\"text-xl font-semibold px-4 pt-5\">\r\n {{ t(\"form-elements\") }}\r\n </h3>\r\n\r\n @if (properties().length === 0) {\r\n @if (isLoading()) {\r\n <!-- Properties Loading Skeleton -->\r\n <div class=\"flex gap-4 py-3 px-5 mt-4\">\r\n <p-skeleton height=\"2rem\" styleClass=\"rounded-lg\" />\r\n <p-skeleton height=\"2rem\" styleClass=\"rounded-lg\" />\r\n </div>\r\n <div class=\"py-4 px-5 space-y-5\">\r\n @for (i of [1, 2, 3, 4, 5, 6]; track i) {\r\n <p-skeleton height=\"3rem\" styleClass=\"rounded-lg\" />\r\n }\r\n </div>\r\n } @else {\r\n <!-- No Properties State -->\r\n <div class=\"flex-1 flex items-center justify-center p-4\">\r\n <p class=\"text-sm font-semibold text-gray-500\">\r\n {{ t(\"no-data-found\") }}\r\n </p>\r\n </div>\r\n }\r\n } @else {\r\n <!-- Tabs using PrimeNG -->\r\n <p-tabs\r\n [(value)]=\"activeTab\"\r\n styleClass=\"structure-tabs\"\r\n class=\"flex flex-1 flex-col min-h-0\"\r\n >\r\n <p-tablist class=\"shrink-0\">\r\n @for (tab of availableTabs(); track tab.id) {\r\n <p-tab [value]=\"tab.id\">{{ tab.title | titlecase }}</p-tab>\r\n }\r\n </p-tablist>\r\n <p-tabpanels\r\n class=\"!bg-transparent !p-0 !pb-3 flex-1 overflow-hidden\"\r\n >\r\n @for (tab of availableTabs(); track tab.id) {\r\n <p-tabpanel [value]=\"tab.id\" class=\"h-full\">\r\n <!-- Node List -->\r\n <div\r\n class=\"space-y-4 p-4 [&_.cdk-drag-placeholder]:hidden h-full overflow-y-auto\"\r\n [id]=\"'toolbox-' + tab.id\"\r\n cdkDropList\r\n cdkDropListSortingDisabled\r\n [cdkDropListData]=\"tab.properties\"\r\n [cdkDropListEnterPredicate]=\"noReturnPredicate\"\r\n >\r\n @for (node of tab.properties; track $index) {\r\n <div\r\n cdkDrag\r\n [cdkDragData]=\"node\"\r\n class=\"group cursor-move select-none flex items-center gap-3 py-3 px-3 rounded-lg border border-dashed border-surface-300 hover:bg-emphasis dark:border-surface-500 transition-colors\"\r\n >\r\n <div\r\n *cdkDragPlaceholder\r\n class=\"col-span-12 min-h-27 w-full rounded-2xl bg-black/10 z-1\"\r\n ></div>\r\n <span class=\"flex-1 text-base font-medium\">{{\r\n node.name\r\n }}</span>\r\n\r\n <mt-icon\r\n class=\"text-lg\"\r\n icon=\"general.menu-05\"\r\n ></mt-icon>\r\n </div>\r\n }\r\n\r\n @if (tab.properties.length === 0) {\r\n <div class=\"py-8 text-center text-muted-color\">\r\n <p class=\"text-sm\">\r\n All {{ tab.title }} items are in use\r\n </p>\r\n </div>\r\n }\r\n </div>\r\n </p-tabpanel>\r\n }\r\n </p-tabpanels>\r\n </p-tabs>\r\n }\r\n </ng-template>\r\n </mt-card>\r\n\r\n <!-- Main Canvas Area -->\r\n <div class=\"flex flex-1 gap-4 h-full overflow-y-auto\">\r\n <div class=\"flex flex-col w-2/3 gap-4 h-full\">\r\n <mt-card>\r\n <ng-template #headless>\r\n <div class=\"p-4 flex items-center gap-3\">\r\n <mt-button\r\n icon=\"layout.layout-top\"\r\n [label]=\"t('add-section')\"\r\n variant=\"outlined\"\r\n severity=\"primary\"\r\n (onClick)=\"addSection()\"\r\n [disabled]=\"isLoading()\"\r\n ></mt-button>\r\n <mt-button\r\n icon=\"general.eye\"\r\n [label]=\"t('preview')\"\r\n variant=\"outlined\"\r\n severity=\"primary\"\r\n (onClick)=\"openPreview()\"\r\n [disabled]=\"isLoading()\"\r\n ></mt-button>\r\n <mt-button\r\n icon=\"finance.credit-card-plus\"\r\n [label]=\"t('reset')\"\r\n variant=\"outlined\"\r\n severity=\"primary\"\r\n (onClick)=\"resetFormConfiguration()\"\r\n [disabled]=\"isLoading()\"\r\n ></mt-button>\r\n </div>\r\n </ng-template>\r\n </mt-card>\r\n\r\n @if (isLoading()) {\r\n <!-- Form Loading Skeleton -->\r\n @for (i of [1, 2]; track i) {\r\n <mt-card>\r\n <ng-template #headless>\r\n <div class=\"p-4 space-y-4\">\r\n <!-- Section header skeleton -->\r\n <div class=\"flex items-center justify-between\">\r\n <p-skeleton width=\"10rem\" height=\"1.5rem\" />\r\n <div class=\"flex gap-2\">\r\n <p-skeleton width=\"2rem\" height=\"2rem\" shape=\"circle\" />\r\n <p-skeleton width=\"2rem\" height=\"2rem\" shape=\"circle\" />\r\n </div>\r\n </div>\r\n <!-- Fields skeleton -->\r\n <div class=\"grid grid-cols-12 gap-4\">\r\n <div class=\"col-span-6\">\r\n <p-skeleton height=\"4rem\" styleClass=\"rounded-lg\" />\r\n </div>\r\n <div class=\"col-span-6\">\r\n <p-skeleton height=\"4rem\" styleClass=\"rounded-lg\" />\r\n </div>\r\n <div class=\"col-span-12\">\r\n <p-skeleton height=\"4rem\" styleClass=\"rounded-lg\" />\r\n </div>\r\n </div>\r\n </div>\r\n </ng-template>\r\n </mt-card>\r\n }\r\n } @else {\r\n @for (section of enrichedSections(); track section.id) {\r\n <mt-fb-section\r\n [section]=\"section\"\r\n [sectionsCount]=\"enrichedSections().length\"\r\n [allSections]=\"enrichedSections()\"\r\n (onFieldDrop)=\"drop($event)\"\r\n >\r\n </mt-fb-section>\r\n } @empty {\r\n <mt-card>\r\n <div class=\"h-27 p-4\">\r\n <div\r\n class=\"flex justify-center items-center gap-4 h-full border-1 border-primary rounded-xl bg-primary-50 text-primary\"\r\n >\r\n <span>{{ t(\"no-section\") }}</span>\r\n </div>\r\n </div>\r\n </mt-card>\r\n }\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n</ng-container>\r\n", styles: [".cdk-drag{cursor:grab}.cdk-drag:active,.cdk-drag-preview{cursor:grabbing}.cdk-drag-placeholder{opacity:.5}.cdk-drop-list-dragging .cdk-drag{cursor:grabbing}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: TabsModule }, { kind: "component", type: i1$1.Tabs, selector: "p-tabs", inputs: ["value", "scrollable", "lazy", "selectOnFocus", "showNavigators", "tabindex"], outputs: ["valueChange"] }, { kind: "component", type: i1$1.TabPanels, selector: "p-tabpanels" }, { kind: "component", type: i1$1.TabPanel, selector: "p-tabpanel", inputs: ["lazy", "value"], outputs: ["valueChange"] }, { kind: "component", type: i1$1.TabList, selector: "p-tablist" }, { kind: "component", type: i1$1.Tab, selector: "p-tab", inputs: ["value", "disabled"], outputs: ["valueChange"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i2.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: FBSection, selector: "mt-fb-section", inputs: ["section", "sectionsCount", "allSections"], outputs: ["onFieldDrop"] }, { 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", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i3.CdkDropListGroup, selector: "[cdkDropListGroup]", inputs: ["cdkDropListGroupDisabled"], exportAs: ["cdkDropListGroup"] }, { 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.CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "pipe", type: i4.TitleCasePipe, name: "titlecase" }] });
2651
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: FormBuilder, isStandalone: true, selector: "mt-form-builder", ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'formBuilder'\">\r\n <div class=\"flex gap-7 h-full w-full overflow-hidden\" cdkDropListGroup>\r\n <!-- Properties Sidebar -->\r\n <mt-card class=\"w-1/5 h-full flex flex-col overflow-hidden\">\r\n <ng-template #headless>\r\n <!-- Header -->\r\n <h3 class=\"text-xl font-semibold px-4 pt-5\">\r\n {{ t(\"form-elements\") }}\r\n </h3>\r\n\r\n @if (properties().length === 0) {\r\n @if (isLoading()) {\r\n <!-- Properties Loading Skeleton -->\r\n <div class=\"flex gap-4 py-3 px-5 mt-4\">\r\n <p-skeleton height=\"2rem\" styleClass=\"rounded-lg\" />\r\n <p-skeleton height=\"2rem\" styleClass=\"rounded-lg\" />\r\n </div>\r\n <div class=\"py-4 px-5 space-y-5\">\r\n @for (i of [1, 2, 3, 4, 5, 6]; track i) {\r\n <p-skeleton height=\"3rem\" styleClass=\"rounded-lg\" />\r\n }\r\n </div>\r\n } @else {\r\n <!-- No Properties State -->\r\n <div class=\"flex-1 flex items-center justify-center p-4\">\r\n <p class=\"text-sm font-semibold text-gray-500\">\r\n {{ t(\"no-data-found\") }}\r\n </p>\r\n </div>\r\n }\r\n } @else {\r\n <!-- Tabs using PrimeNG -->\r\n <p-tabs\r\n [(value)]=\"activeTab\"\r\n styleClass=\"structure-tabs\"\r\n class=\"flex flex-1 flex-col min-h-0\"\r\n >\r\n <p-tablist class=\"shrink-0\">\r\n @for (tab of availableTabs(); track tab.id) {\r\n <p-tab [value]=\"tab.id\">{{ tab.title | titlecase }}</p-tab>\r\n }\r\n </p-tablist>\r\n <p-tabpanels\r\n class=\"!bg-transparent !p-0 !pb-3 flex-1 overflow-hidden\"\r\n >\r\n @for (tab of filteredPropertiesByTab(); track tab.id) {\r\n <p-tabpanel [value]=\"tab.id\" class=\"h-full flex flex-col\">\r\n <!-- Node List -->\r\n <div\r\n class=\"space-y-4 px-4 pb-4 [&_.cdk-drag-placeholder]:hidden flex-1 overflow-y-auto\"\r\n [id]=\"'toolbox-' + tab.id\"\r\n cdkDropList\r\n cdkDropListSortingDisabled\r\n [cdkDropListData]=\"tab.properties\"\r\n [cdkDropListEnterPredicate]=\"noReturnPredicate\"\r\n >\r\n <!-- Search Field (Sticky) -->\r\n <div class=\"sticky top-0 bg-surface-0 mb-0 py-3 pb-2 mb-1\">\r\n <mt-text-field\r\n [placeholder]=\"t('search-properties')\"\r\n [(ngModel)]=\"searchQuery\"\r\n icon=\"general.search-lg\"\r\n />\r\n </div>\r\n @for (node of tab.properties; track $index) {\r\n <div\r\n cdkDrag\r\n [cdkDragData]=\"node\"\r\n class=\"group cursor-move select-none flex items-center gap-3 py-3 px-3 rounded-lg border border-dashed border-surface-300 hover:bg-emphasis dark:border-surface-500 transition-colors\"\r\n >\r\n <div\r\n *cdkDragPlaceholder\r\n class=\"col-span-12 min-h-27 w-full rounded-2xl bg-black/10 z-1\"\r\n ></div>\r\n <span class=\"flex-1 text-base font-medium\">{{\r\n node.name\r\n }}</span>\r\n\r\n <mt-icon\r\n class=\"text-lg\"\r\n icon=\"general.menu-05\"\r\n ></mt-icon>\r\n </div>\r\n }\r\n\r\n @if (tab.properties.length === 0) {\r\n <div class=\"py-8 text-center text-muted-color\">\r\n <p class=\"text-sm\">\r\n @if (searchQuery()) {\r\n {{ t(\"no-data-found\") }}\r\n } @else {\r\n All {{ tab.title }} items are in use\r\n }\r\n </p>\r\n </div>\r\n }\r\n </div>\r\n </p-tabpanel>\r\n }\r\n </p-tabpanels>\r\n </p-tabs>\r\n }\r\n </ng-template>\r\n </mt-card>\r\n\r\n <!-- Main Canvas Area -->\r\n <div class=\"flex flex-1 gap-4 h-full overflow-y-auto\">\r\n <div class=\"flex flex-col w-2/3 gap-4 h-full\">\r\n <mt-card>\r\n <ng-template #headless>\r\n <div class=\"p-4 flex items-center gap-3\">\r\n <mt-button\r\n icon=\"layout.layout-top\"\r\n [label]=\"t('add-section')\"\r\n variant=\"outlined\"\r\n severity=\"primary\"\r\n (onClick)=\"addSection()\"\r\n [disabled]=\"isLoading()\"\r\n ></mt-button>\r\n <mt-button\r\n icon=\"general.eye\"\r\n [label]=\"t('preview')\"\r\n variant=\"outlined\"\r\n severity=\"primary\"\r\n (onClick)=\"openPreview()\"\r\n [disabled]=\"isLoading()\"\r\n ></mt-button>\r\n <mt-button\r\n [label]=\"t('validation-rules')\"\r\n variant=\"outlined\"\r\n severity=\"primary\"\r\n (onClick)=\"openValidationRules()\"\r\n [disabled]=\"isLoading()\"\r\n ></mt-button>\r\n <mt-button\r\n icon=\"finance.credit-card-plus\"\r\n [label]=\"t('reset')\"\r\n variant=\"outlined\"\r\n severity=\"primary\"\r\n (onClick)=\"resetFormConfiguration()\"\r\n [disabled]=\"isLoading()\"\r\n ></mt-button>\r\n </div>\r\n </ng-template>\r\n </mt-card>\r\n\r\n @if (isLoading()) {\r\n <!-- Form Loading Skeleton -->\r\n @for (i of [1, 2]; track i) {\r\n <mt-card>\r\n <ng-template #headless>\r\n <div class=\"p-4 space-y-4\">\r\n <!-- Section header skeleton -->\r\n <div class=\"flex items-center justify-between\">\r\n <p-skeleton width=\"10rem\" height=\"1.5rem\" />\r\n <div class=\"flex gap-2\">\r\n <p-skeleton width=\"2rem\" height=\"2rem\" shape=\"circle\" />\r\n <p-skeleton width=\"2rem\" height=\"2rem\" shape=\"circle\" />\r\n </div>\r\n </div>\r\n <!-- Fields skeleton -->\r\n <div class=\"grid grid-cols-12 gap-4\">\r\n <div class=\"col-span-6\">\r\n <p-skeleton height=\"4rem\" styleClass=\"rounded-lg\" />\r\n </div>\r\n <div class=\"col-span-6\">\r\n <p-skeleton height=\"4rem\" styleClass=\"rounded-lg\" />\r\n </div>\r\n <div class=\"col-span-12\">\r\n <p-skeleton height=\"4rem\" styleClass=\"rounded-lg\" />\r\n </div>\r\n </div>\r\n </div>\r\n </ng-template>\r\n </mt-card>\r\n }\r\n } @else {\r\n @for (section of enrichedSections(); track section.id) {\r\n <mt-fb-section\r\n [section]=\"section\"\r\n [sectionsCount]=\"enrichedSections().length\"\r\n [allSections]=\"enrichedSections()\"\r\n (onFieldDrop)=\"drop($event)\"\r\n >\r\n </mt-fb-section>\r\n } @empty {\r\n <mt-card>\r\n <div class=\"h-27 p-4\">\r\n <div\r\n class=\"flex justify-center items-center gap-4 h-full border-1 border-primary rounded-xl bg-primary-50 text-primary\"\r\n >\r\n <span>{{ t(\"no-section\") }}</span>\r\n </div>\r\n </div>\r\n </mt-card>\r\n }\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n</ng-container>\r\n", styles: [".cdk-drag{cursor:grab}.cdk-drag:active,.cdk-drag-preview{cursor:grabbing}.cdk-drag-placeholder{opacity:.5}.cdk-drop-list-dragging .cdk-drag{cursor:grabbing}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: TabsModule }, { kind: "component", type: i2.Tabs, selector: "p-tabs", inputs: ["value", "scrollable", "lazy", "selectOnFocus", "showNavigators", "tabindex"], outputs: ["valueChange"] }, { kind: "component", type: i2.TabPanels, selector: "p-tabpanels" }, { kind: "component", type: i2.TabPanel, selector: "p-tabpanel", inputs: ["lazy", "value"], outputs: ["valueChange"] }, { kind: "component", type: i2.TabList, selector: "p-tablist" }, { kind: "component", type: i2.Tab, selector: "p-tab", inputs: ["value", "disabled"], outputs: ["valueChange"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i3.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "icon", "iconPosition"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: FBSection, selector: "mt-fb-section", inputs: ["section", "sectionsCount", "allSections"], outputs: ["onFieldDrop"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i4.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i4.CdkDropListGroup, selector: "[cdkDropListGroup]", inputs: ["cdkDropListGroupDisabled"], exportAs: ["cdkDropListGroup"] }, { kind: "directive", type: i4.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: i4.CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "pipe", type: i5.TitleCasePipe, name: "titlecase" }] });
1884
2652
  }
1885
2653
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormBuilder, decorators: [{
1886
2654
  type: Component,
@@ -1891,11 +2659,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
1891
2659
  SkeletonModule,
1892
2660
  Button,
1893
2661
  Card,
2662
+ TextField,
1894
2663
  TranslocoDirective,
1895
2664
  FBSection,
1896
2665
  DragDropModule,
1897
2666
  Icon,
1898
- ], template: "<ng-container *transloco=\"let t; prefix: 'formBuilder'\">\r\n <div class=\"flex gap-7 h-full w-full overflow-hidden\" cdkDropListGroup>\r\n <!-- Properties Sidebar -->\r\n <mt-card class=\"w-1/5 h-full flex flex-col overflow-hidden\">\r\n <ng-template #headless>\r\n <!-- Header -->\r\n <h3 class=\"text-xl font-semibold px-4 pt-5\">\r\n {{ t(\"form-elements\") }}\r\n </h3>\r\n\r\n @if (properties().length === 0) {\r\n @if (isLoading()) {\r\n <!-- Properties Loading Skeleton -->\r\n <div class=\"flex gap-4 py-3 px-5 mt-4\">\r\n <p-skeleton height=\"2rem\" styleClass=\"rounded-lg\" />\r\n <p-skeleton height=\"2rem\" styleClass=\"rounded-lg\" />\r\n </div>\r\n <div class=\"py-4 px-5 space-y-5\">\r\n @for (i of [1, 2, 3, 4, 5, 6]; track i) {\r\n <p-skeleton height=\"3rem\" styleClass=\"rounded-lg\" />\r\n }\r\n </div>\r\n } @else {\r\n <!-- No Properties State -->\r\n <div class=\"flex-1 flex items-center justify-center p-4\">\r\n <p class=\"text-sm font-semibold text-gray-500\">\r\n {{ t(\"no-data-found\") }}\r\n </p>\r\n </div>\r\n }\r\n } @else {\r\n <!-- Tabs using PrimeNG -->\r\n <p-tabs\r\n [(value)]=\"activeTab\"\r\n styleClass=\"structure-tabs\"\r\n class=\"flex flex-1 flex-col min-h-0\"\r\n >\r\n <p-tablist class=\"shrink-0\">\r\n @for (tab of availableTabs(); track tab.id) {\r\n <p-tab [value]=\"tab.id\">{{ tab.title | titlecase }}</p-tab>\r\n }\r\n </p-tablist>\r\n <p-tabpanels\r\n class=\"!bg-transparent !p-0 !pb-3 flex-1 overflow-hidden\"\r\n >\r\n @for (tab of availableTabs(); track tab.id) {\r\n <p-tabpanel [value]=\"tab.id\" class=\"h-full\">\r\n <!-- Node List -->\r\n <div\r\n class=\"space-y-4 p-4 [&_.cdk-drag-placeholder]:hidden h-full overflow-y-auto\"\r\n [id]=\"'toolbox-' + tab.id\"\r\n cdkDropList\r\n cdkDropListSortingDisabled\r\n [cdkDropListData]=\"tab.properties\"\r\n [cdkDropListEnterPredicate]=\"noReturnPredicate\"\r\n >\r\n @for (node of tab.properties; track $index) {\r\n <div\r\n cdkDrag\r\n [cdkDragData]=\"node\"\r\n class=\"group cursor-move select-none flex items-center gap-3 py-3 px-3 rounded-lg border border-dashed border-surface-300 hover:bg-emphasis dark:border-surface-500 transition-colors\"\r\n >\r\n <div\r\n *cdkDragPlaceholder\r\n class=\"col-span-12 min-h-27 w-full rounded-2xl bg-black/10 z-1\"\r\n ></div>\r\n <span class=\"flex-1 text-base font-medium\">{{\r\n node.name\r\n }}</span>\r\n\r\n <mt-icon\r\n class=\"text-lg\"\r\n icon=\"general.menu-05\"\r\n ></mt-icon>\r\n </div>\r\n }\r\n\r\n @if (tab.properties.length === 0) {\r\n <div class=\"py-8 text-center text-muted-color\">\r\n <p class=\"text-sm\">\r\n All {{ tab.title }} items are in use\r\n </p>\r\n </div>\r\n }\r\n </div>\r\n </p-tabpanel>\r\n }\r\n </p-tabpanels>\r\n </p-tabs>\r\n }\r\n </ng-template>\r\n </mt-card>\r\n\r\n <!-- Main Canvas Area -->\r\n <div class=\"flex flex-1 gap-4 h-full overflow-y-auto\">\r\n <div class=\"flex flex-col w-2/3 gap-4 h-full\">\r\n <mt-card>\r\n <ng-template #headless>\r\n <div class=\"p-4 flex items-center gap-3\">\r\n <mt-button\r\n icon=\"layout.layout-top\"\r\n [label]=\"t('add-section')\"\r\n variant=\"outlined\"\r\n severity=\"primary\"\r\n (onClick)=\"addSection()\"\r\n [disabled]=\"isLoading()\"\r\n ></mt-button>\r\n <mt-button\r\n icon=\"general.eye\"\r\n [label]=\"t('preview')\"\r\n variant=\"outlined\"\r\n severity=\"primary\"\r\n (onClick)=\"openPreview()\"\r\n [disabled]=\"isLoading()\"\r\n ></mt-button>\r\n <mt-button\r\n icon=\"finance.credit-card-plus\"\r\n [label]=\"t('reset')\"\r\n variant=\"outlined\"\r\n severity=\"primary\"\r\n (onClick)=\"resetFormConfiguration()\"\r\n [disabled]=\"isLoading()\"\r\n ></mt-button>\r\n </div>\r\n </ng-template>\r\n </mt-card>\r\n\r\n @if (isLoading()) {\r\n <!-- Form Loading Skeleton -->\r\n @for (i of [1, 2]; track i) {\r\n <mt-card>\r\n <ng-template #headless>\r\n <div class=\"p-4 space-y-4\">\r\n <!-- Section header skeleton -->\r\n <div class=\"flex items-center justify-between\">\r\n <p-skeleton width=\"10rem\" height=\"1.5rem\" />\r\n <div class=\"flex gap-2\">\r\n <p-skeleton width=\"2rem\" height=\"2rem\" shape=\"circle\" />\r\n <p-skeleton width=\"2rem\" height=\"2rem\" shape=\"circle\" />\r\n </div>\r\n </div>\r\n <!-- Fields skeleton -->\r\n <div class=\"grid grid-cols-12 gap-4\">\r\n <div class=\"col-span-6\">\r\n <p-skeleton height=\"4rem\" styleClass=\"rounded-lg\" />\r\n </div>\r\n <div class=\"col-span-6\">\r\n <p-skeleton height=\"4rem\" styleClass=\"rounded-lg\" />\r\n </div>\r\n <div class=\"col-span-12\">\r\n <p-skeleton height=\"4rem\" styleClass=\"rounded-lg\" />\r\n </div>\r\n </div>\r\n </div>\r\n </ng-template>\r\n </mt-card>\r\n }\r\n } @else {\r\n @for (section of enrichedSections(); track section.id) {\r\n <mt-fb-section\r\n [section]=\"section\"\r\n [sectionsCount]=\"enrichedSections().length\"\r\n [allSections]=\"enrichedSections()\"\r\n (onFieldDrop)=\"drop($event)\"\r\n >\r\n </mt-fb-section>\r\n } @empty {\r\n <mt-card>\r\n <div class=\"h-27 p-4\">\r\n <div\r\n class=\"flex justify-center items-center gap-4 h-full border-1 border-primary rounded-xl bg-primary-50 text-primary\"\r\n >\r\n <span>{{ t(\"no-section\") }}</span>\r\n </div>\r\n </div>\r\n </mt-card>\r\n }\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n</ng-container>\r\n", styles: [".cdk-drag{cursor:grab}.cdk-drag:active,.cdk-drag-preview{cursor:grabbing}.cdk-drag-placeholder{opacity:.5}.cdk-drop-list-dragging .cdk-drag{cursor:grabbing}\n"] }]
2667
+ ], template: "<ng-container *transloco=\"let t; prefix: 'formBuilder'\">\r\n <div class=\"flex gap-7 h-full w-full overflow-hidden\" cdkDropListGroup>\r\n <!-- Properties Sidebar -->\r\n <mt-card class=\"w-1/5 h-full flex flex-col overflow-hidden\">\r\n <ng-template #headless>\r\n <!-- Header -->\r\n <h3 class=\"text-xl font-semibold px-4 pt-5\">\r\n {{ t(\"form-elements\") }}\r\n </h3>\r\n\r\n @if (properties().length === 0) {\r\n @if (isLoading()) {\r\n <!-- Properties Loading Skeleton -->\r\n <div class=\"flex gap-4 py-3 px-5 mt-4\">\r\n <p-skeleton height=\"2rem\" styleClass=\"rounded-lg\" />\r\n <p-skeleton height=\"2rem\" styleClass=\"rounded-lg\" />\r\n </div>\r\n <div class=\"py-4 px-5 space-y-5\">\r\n @for (i of [1, 2, 3, 4, 5, 6]; track i) {\r\n <p-skeleton height=\"3rem\" styleClass=\"rounded-lg\" />\r\n }\r\n </div>\r\n } @else {\r\n <!-- No Properties State -->\r\n <div class=\"flex-1 flex items-center justify-center p-4\">\r\n <p class=\"text-sm font-semibold text-gray-500\">\r\n {{ t(\"no-data-found\") }}\r\n </p>\r\n </div>\r\n }\r\n } @else {\r\n <!-- Tabs using PrimeNG -->\r\n <p-tabs\r\n [(value)]=\"activeTab\"\r\n styleClass=\"structure-tabs\"\r\n class=\"flex flex-1 flex-col min-h-0\"\r\n >\r\n <p-tablist class=\"shrink-0\">\r\n @for (tab of availableTabs(); track tab.id) {\r\n <p-tab [value]=\"tab.id\">{{ tab.title | titlecase }}</p-tab>\r\n }\r\n </p-tablist>\r\n <p-tabpanels\r\n class=\"!bg-transparent !p-0 !pb-3 flex-1 overflow-hidden\"\r\n >\r\n @for (tab of filteredPropertiesByTab(); track tab.id) {\r\n <p-tabpanel [value]=\"tab.id\" class=\"h-full flex flex-col\">\r\n <!-- Node List -->\r\n <div\r\n class=\"space-y-4 px-4 pb-4 [&_.cdk-drag-placeholder]:hidden flex-1 overflow-y-auto\"\r\n [id]=\"'toolbox-' + tab.id\"\r\n cdkDropList\r\n cdkDropListSortingDisabled\r\n [cdkDropListData]=\"tab.properties\"\r\n [cdkDropListEnterPredicate]=\"noReturnPredicate\"\r\n >\r\n <!-- Search Field (Sticky) -->\r\n <div class=\"sticky top-0 bg-surface-0 mb-0 py-3 pb-2 mb-1\">\r\n <mt-text-field\r\n [placeholder]=\"t('search-properties')\"\r\n [(ngModel)]=\"searchQuery\"\r\n icon=\"general.search-lg\"\r\n />\r\n </div>\r\n @for (node of tab.properties; track $index) {\r\n <div\r\n cdkDrag\r\n [cdkDragData]=\"node\"\r\n class=\"group cursor-move select-none flex items-center gap-3 py-3 px-3 rounded-lg border border-dashed border-surface-300 hover:bg-emphasis dark:border-surface-500 transition-colors\"\r\n >\r\n <div\r\n *cdkDragPlaceholder\r\n class=\"col-span-12 min-h-27 w-full rounded-2xl bg-black/10 z-1\"\r\n ></div>\r\n <span class=\"flex-1 text-base font-medium\">{{\r\n node.name\r\n }}</span>\r\n\r\n <mt-icon\r\n class=\"text-lg\"\r\n icon=\"general.menu-05\"\r\n ></mt-icon>\r\n </div>\r\n }\r\n\r\n @if (tab.properties.length === 0) {\r\n <div class=\"py-8 text-center text-muted-color\">\r\n <p class=\"text-sm\">\r\n @if (searchQuery()) {\r\n {{ t(\"no-data-found\") }}\r\n } @else {\r\n All {{ tab.title }} items are in use\r\n }\r\n </p>\r\n </div>\r\n }\r\n </div>\r\n </p-tabpanel>\r\n }\r\n </p-tabpanels>\r\n </p-tabs>\r\n }\r\n </ng-template>\r\n </mt-card>\r\n\r\n <!-- Main Canvas Area -->\r\n <div class=\"flex flex-1 gap-4 h-full overflow-y-auto\">\r\n <div class=\"flex flex-col w-2/3 gap-4 h-full\">\r\n <mt-card>\r\n <ng-template #headless>\r\n <div class=\"p-4 flex items-center gap-3\">\r\n <mt-button\r\n icon=\"layout.layout-top\"\r\n [label]=\"t('add-section')\"\r\n variant=\"outlined\"\r\n severity=\"primary\"\r\n (onClick)=\"addSection()\"\r\n [disabled]=\"isLoading()\"\r\n ></mt-button>\r\n <mt-button\r\n icon=\"general.eye\"\r\n [label]=\"t('preview')\"\r\n variant=\"outlined\"\r\n severity=\"primary\"\r\n (onClick)=\"openPreview()\"\r\n [disabled]=\"isLoading()\"\r\n ></mt-button>\r\n <mt-button\r\n [label]=\"t('validation-rules')\"\r\n variant=\"outlined\"\r\n severity=\"primary\"\r\n (onClick)=\"openValidationRules()\"\r\n [disabled]=\"isLoading()\"\r\n ></mt-button>\r\n <mt-button\r\n icon=\"finance.credit-card-plus\"\r\n [label]=\"t('reset')\"\r\n variant=\"outlined\"\r\n severity=\"primary\"\r\n (onClick)=\"resetFormConfiguration()\"\r\n [disabled]=\"isLoading()\"\r\n ></mt-button>\r\n </div>\r\n </ng-template>\r\n </mt-card>\r\n\r\n @if (isLoading()) {\r\n <!-- Form Loading Skeleton -->\r\n @for (i of [1, 2]; track i) {\r\n <mt-card>\r\n <ng-template #headless>\r\n <div class=\"p-4 space-y-4\">\r\n <!-- Section header skeleton -->\r\n <div class=\"flex items-center justify-between\">\r\n <p-skeleton width=\"10rem\" height=\"1.5rem\" />\r\n <div class=\"flex gap-2\">\r\n <p-skeleton width=\"2rem\" height=\"2rem\" shape=\"circle\" />\r\n <p-skeleton width=\"2rem\" height=\"2rem\" shape=\"circle\" />\r\n </div>\r\n </div>\r\n <!-- Fields skeleton -->\r\n <div class=\"grid grid-cols-12 gap-4\">\r\n <div class=\"col-span-6\">\r\n <p-skeleton height=\"4rem\" styleClass=\"rounded-lg\" />\r\n </div>\r\n <div class=\"col-span-6\">\r\n <p-skeleton height=\"4rem\" styleClass=\"rounded-lg\" />\r\n </div>\r\n <div class=\"col-span-12\">\r\n <p-skeleton height=\"4rem\" styleClass=\"rounded-lg\" />\r\n </div>\r\n </div>\r\n </div>\r\n </ng-template>\r\n </mt-card>\r\n }\r\n } @else {\r\n @for (section of enrichedSections(); track section.id) {\r\n <mt-fb-section\r\n [section]=\"section\"\r\n [sectionsCount]=\"enrichedSections().length\"\r\n [allSections]=\"enrichedSections()\"\r\n (onFieldDrop)=\"drop($event)\"\r\n >\r\n </mt-fb-section>\r\n } @empty {\r\n <mt-card>\r\n <div class=\"h-27 p-4\">\r\n <div\r\n class=\"flex justify-center items-center gap-4 h-full border-1 border-primary rounded-xl bg-primary-50 text-primary\"\r\n >\r\n <span>{{ t(\"no-section\") }}</span>\r\n </div>\r\n </div>\r\n </mt-card>\r\n }\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n</ng-container>\r\n", styles: [".cdk-drag{cursor:grab}.cdk-drag:active,.cdk-drag-preview{cursor:grabbing}.cdk-drag-placeholder{opacity:.5}.cdk-drop-list-dragging .cdk-drag{cursor:grabbing}\n"] }]
1899
2668
  }], ctorParameters: () => [] });
1900
2669
 
1901
2670
  /*
@@ -1906,5 +2675,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
1906
2675
  * Generated bundle index. Do not edit.
1907
2676
  */
1908
2677
 
1909
- export { AddField, AddSection, DeleteField, DeleteSection, FormBuilder, FormBuilderActionKey, FormBuilderFacade, FormBuilderState, GetFormConfiguration, MoveField, ReorderFields, ResetFormBuilderState, ResetFormConfiguration, SetModuleInfo, SetProperties, UpdateField, UpdateSection };
2678
+ export { AddField, AddSection, AddValidation, DeleteField, DeleteSection, DeleteValidation, FormBuilder, FormBuilderActionKey, FormBuilderFacade, FormBuilderState, GetFormConfiguration, MoveField, ReorderFields, ResetFormBuilderState, ResetFormConfiguration, SetModuleInfo, SetProperties, ToggleValidationActive, UpdateField, UpdateSection, UpdateValidation };
1910
2679
  //# sourceMappingURL=masterteam-form-builder.mjs.map