@masterteam/form-builder 0.0.6 → 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,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, Injectable, computed, input, signal, viewChild, Component, effect, output } from '@angular/core';
|
|
2
|
+
import { inject, Injectable, computed, input, signal, viewChild, Component, effect, output, DestroyRef } from '@angular/core';
|
|
3
3
|
import * as i5 from '@angular/common';
|
|
4
4
|
import { CommonModule } from '@angular/common';
|
|
5
5
|
import * as i1 from '@angular/forms';
|
|
@@ -24,9 +24,12 @@ import { CrudStateBase, handleApiRequest, RadioCardsFieldConfig } from '@mastert
|
|
|
24
24
|
import { DynamicForm } from '@masterteam/forms/dynamic-form';
|
|
25
25
|
import { ToggleField } from '@masterteam/components/toggle-field';
|
|
26
26
|
import { ModalRef } from '@masterteam/components/dialog';
|
|
27
|
-
import { FormulaToolbar, FormulaEditor } from '@masterteam/components/formula';
|
|
27
|
+
import { FormulaToolbar, FormulaEditor, serializeTokens } from '@masterteam/components/formula';
|
|
28
28
|
import { Tooltip } from '@masterteam/components/tooltip';
|
|
29
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';
|
|
30
33
|
|
|
31
34
|
// ============================================================================
|
|
32
35
|
// Module Configuration Actions
|
|
@@ -143,6 +146,41 @@ class MoveField {
|
|
|
143
146
|
this.payload = payload;
|
|
144
147
|
}
|
|
145
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
|
+
}
|
|
146
184
|
|
|
147
185
|
// ============================================================================
|
|
148
186
|
// Action Keys Enum
|
|
@@ -162,6 +200,11 @@ var FormBuilderActionKey;
|
|
|
162
200
|
FormBuilderActionKey["DeleteField"] = "deleteField";
|
|
163
201
|
FormBuilderActionKey["MoveField"] = "moveField";
|
|
164
202
|
FormBuilderActionKey["ReorderFields"] = "reorderFields";
|
|
203
|
+
// Validation Rules
|
|
204
|
+
FormBuilderActionKey["AddValidation"] = "addValidation";
|
|
205
|
+
FormBuilderActionKey["UpdateValidation"] = "updateValidation";
|
|
206
|
+
FormBuilderActionKey["DeleteValidation"] = "deleteValidation";
|
|
207
|
+
FormBuilderActionKey["ToggleValidationActive"] = "toggleValidationActive";
|
|
165
208
|
})(FormBuilderActionKey || (FormBuilderActionKey = {}));
|
|
166
209
|
|
|
167
210
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
@@ -217,6 +260,9 @@ let FormBuilderState = class FormBuilderState extends CrudStateBase {
|
|
|
217
260
|
static getProperties(state) {
|
|
218
261
|
return state?.properties ?? [];
|
|
219
262
|
}
|
|
263
|
+
static getValidations(state) {
|
|
264
|
+
return state?.formConfiguration?.validations ?? [];
|
|
265
|
+
}
|
|
220
266
|
// ============================================================================
|
|
221
267
|
// Module Configuration Actions
|
|
222
268
|
// ============================================================================
|
|
@@ -255,7 +301,9 @@ let FormBuilderState = class FormBuilderState extends CrudStateBase {
|
|
|
255
301
|
key: FormBuilderActionKey.GetFormConfiguration,
|
|
256
302
|
request$: req$,
|
|
257
303
|
updateState: (_state, data) => ({
|
|
258
|
-
formConfiguration: data
|
|
304
|
+
formConfiguration: data
|
|
305
|
+
? { ...data, validations: data.validations ?? [] }
|
|
306
|
+
: null,
|
|
259
307
|
}),
|
|
260
308
|
});
|
|
261
309
|
}
|
|
@@ -268,7 +316,9 @@ let FormBuilderState = class FormBuilderState extends CrudStateBase {
|
|
|
268
316
|
key: FormBuilderActionKey.ResetFormConfiguration,
|
|
269
317
|
request$: req$,
|
|
270
318
|
onSuccess: (res, _currentState) => ({
|
|
271
|
-
formConfiguration: res.data
|
|
319
|
+
formConfiguration: res.data
|
|
320
|
+
? { ...res.data, validations: res.data.validations ?? [] }
|
|
321
|
+
: null,
|
|
272
322
|
}),
|
|
273
323
|
});
|
|
274
324
|
}
|
|
@@ -661,6 +711,88 @@ let FormBuilderState = class FormBuilderState extends CrudStateBase {
|
|
|
661
711
|
},
|
|
662
712
|
});
|
|
663
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
|
+
}
|
|
664
796
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormBuilderState, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
|
|
665
797
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormBuilderState });
|
|
666
798
|
};
|
|
@@ -703,6 +835,18 @@ __decorate([
|
|
|
703
835
|
__decorate([
|
|
704
836
|
Action(MoveField)
|
|
705
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);
|
|
706
850
|
__decorate([
|
|
707
851
|
Selector()
|
|
708
852
|
], FormBuilderState, "getState", null);
|
|
@@ -721,6 +865,9 @@ __decorate([
|
|
|
721
865
|
__decorate([
|
|
722
866
|
Selector()
|
|
723
867
|
], FormBuilderState, "getProperties", null);
|
|
868
|
+
__decorate([
|
|
869
|
+
Selector()
|
|
870
|
+
], FormBuilderState, "getValidations", null);
|
|
724
871
|
FormBuilderState = __decorate([
|
|
725
872
|
State({
|
|
726
873
|
name: 'formBuilder',
|
|
@@ -729,7 +876,7 @@ FormBuilderState = __decorate([
|
|
|
729
876
|
], FormBuilderState);
|
|
730
877
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormBuilderState, decorators: [{
|
|
731
878
|
type: Injectable
|
|
732
|
-
}], 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: [] } });
|
|
733
880
|
|
|
734
881
|
class FormBuilderFacade {
|
|
735
882
|
store = inject(Store);
|
|
@@ -740,6 +887,7 @@ class FormBuilderFacade {
|
|
|
740
887
|
formConfiguration = select(FormBuilderState.getFormConfiguration);
|
|
741
888
|
sections = select(FormBuilderState.getSections);
|
|
742
889
|
properties = select(FormBuilderState.getProperties);
|
|
890
|
+
validations = select(FormBuilderState.getValidations);
|
|
743
891
|
moduleType = select(FormBuilderState.getModuleType);
|
|
744
892
|
moduleId = select(FormBuilderState.getModuleId);
|
|
745
893
|
// ============================================================================
|
|
@@ -754,6 +902,10 @@ class FormBuilderFacade {
|
|
|
754
902
|
isUpdatingField = computed(() => this.stateSignal().loadingActive.includes(FormBuilderActionKey.UpdateField), ...(ngDevMode ? [{ debugName: "isUpdatingField" }] : []));
|
|
755
903
|
isDeletingField = computed(() => this.stateSignal().loadingActive.includes(FormBuilderActionKey.DeleteField), ...(ngDevMode ? [{ debugName: "isDeletingField" }] : []));
|
|
756
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" }] : []));
|
|
757
909
|
// ============================================================================
|
|
758
910
|
// Error Signals
|
|
759
911
|
// ============================================================================
|
|
@@ -774,6 +926,14 @@ class FormBuilderFacade {
|
|
|
774
926
|
errors[FormBuilderActionKey.MoveField] ??
|
|
775
927
|
null);
|
|
776
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" }] : []));
|
|
777
937
|
// ============================================================================
|
|
778
938
|
// Module Configuration Dispatchers
|
|
779
939
|
// ============================================================================
|
|
@@ -825,6 +985,21 @@ class FormBuilderFacade {
|
|
|
825
985
|
moveField(sectionId, fieldId, payload) {
|
|
826
986
|
return this.store.dispatch(new MoveField(sectionId, fieldId, payload));
|
|
827
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
|
+
}
|
|
828
1003
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormBuilderFacade, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
829
1004
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormBuilderFacade, providedIn: 'root' });
|
|
830
1005
|
}
|
|
@@ -1150,7 +1325,7 @@ class FBFieldConditions {
|
|
|
1150
1325
|
this.ref.close({ saved: false });
|
|
1151
1326
|
}
|
|
1152
1327
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FBFieldConditions, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1153
|
-
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"] }] });
|
|
1154
1329
|
}
|
|
1155
1330
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FBFieldConditions, decorators: [{
|
|
1156
1331
|
type: Component,
|
|
@@ -1741,6 +1916,573 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
|
|
|
1741
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" }]
|
|
1742
1917
|
}], ctorParameters: () => [], propDecorators: { sections: [{ type: i0.Input, args: [{ isSignal: true, alias: "sections", required: false }] }] } });
|
|
1743
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
|
+
|
|
1744
2486
|
class FormBuilder {
|
|
1745
2487
|
modalService = inject(ModalService);
|
|
1746
2488
|
confirmationService = inject(ConfirmationService);
|
|
@@ -1886,6 +2628,15 @@ class FormBuilder {
|
|
|
1886
2628
|
},
|
|
1887
2629
|
});
|
|
1888
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
|
+
}
|
|
1889
2640
|
resetFormConfiguration() {
|
|
1890
2641
|
this.confirmationService.confirm({
|
|
1891
2642
|
type: 'dialog',
|
|
@@ -1897,7 +2648,7 @@ class FormBuilder {
|
|
|
1897
2648
|
}
|
|
1898
2649
|
noReturnPredicate = () => false;
|
|
1899
2650
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormBuilder, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1900
|
-
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 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" }] });
|
|
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" }] });
|
|
1901
2652
|
}
|
|
1902
2653
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormBuilder, decorators: [{
|
|
1903
2654
|
type: Component,
|
|
@@ -1913,7 +2664,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
|
|
|
1913
2664
|
FBSection,
|
|
1914
2665
|
DragDropModule,
|
|
1915
2666
|
Icon,
|
|
1916
|
-
], 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 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"] }]
|
|
1917
2668
|
}], ctorParameters: () => [] });
|
|
1918
2669
|
|
|
1919
2670
|
/*
|
|
@@ -1924,5 +2675,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
|
|
|
1924
2675
|
* Generated bundle index. Do not edit.
|
|
1925
2676
|
*/
|
|
1926
2677
|
|
|
1927
|
-
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 };
|
|
1928
2679
|
//# sourceMappingURL=masterteam-form-builder.mjs.map
|