ui-core-abv 0.6.38 → 0.6.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/ui-core-abv.mjs +254 -83
- package/fesm2022/ui-core-abv.mjs.map +1 -1
- package/lib/components/rule-builder/rule-builder.component.d.ts +28 -9
- package/lib/components/rule-builder/rule-definirion/rule-definirion.component.d.ts +5 -0
- package/lib/translate/dictionary.en.d.ts +10 -10
- package/lib/translate/dictionary.es.d.ts +9 -9
- package/package.json +1 -1
package/fesm2022/ui-core-abv.mjs
CHANGED
|
@@ -307,21 +307,21 @@ const DICTIONARY_EN = {
|
|
|
307
307
|
column_name_must_be_unique: 'Column name must be unique',
|
|
308
308
|
},
|
|
309
309
|
rule_builder: {
|
|
310
|
-
title: '
|
|
311
|
-
add_rule: '
|
|
312
|
-
add_rule_tip: 'Add
|
|
310
|
+
title: 'Rule',
|
|
311
|
+
add_rule: 'Condition',
|
|
312
|
+
add_rule_tip: 'Add condition',
|
|
313
313
|
add_group: 'Group',
|
|
314
314
|
add_group_tip: 'Add group',
|
|
315
315
|
reset: 'Reset',
|
|
316
316
|
reset_tip: 'Discard unsaved changes',
|
|
317
|
-
save: 'Save',
|
|
317
|
+
save: 'Save rule',
|
|
318
318
|
save_tip: 'Save built rule',
|
|
319
|
-
delete_rule_tip: 'Delete
|
|
319
|
+
delete_rule_tip: 'Delete condition',
|
|
320
320
|
delete_group_tip: 'Delete group',
|
|
321
321
|
toggle_operator_tip: 'Click to change operator',
|
|
322
|
-
no_rules: 'No
|
|
323
|
-
rules_management: 'Select
|
|
324
|
-
edit: 'Edit',
|
|
322
|
+
no_rules: 'No conditions added',
|
|
323
|
+
rules_management: 'Select condition',
|
|
324
|
+
edit: 'Edit rule',
|
|
325
325
|
edit_tip: 'Edit rule',
|
|
326
326
|
edit_condition_tip: 'Click to edit condition',
|
|
327
327
|
select_condition: '- select condition -',
|
|
@@ -334,9 +334,9 @@ const DICTIONARY_EN = {
|
|
|
334
334
|
},
|
|
335
335
|
definition: {
|
|
336
336
|
cancel_and_back: 'Cancel and go back',
|
|
337
|
-
create_and_select: 'Create and select',
|
|
337
|
+
create_and_select: 'Create and select condition',
|
|
338
338
|
search_placeholder: 'Search condition',
|
|
339
|
-
new_rule: 'New
|
|
339
|
+
new_rule: 'New condition',
|
|
340
340
|
no_results: 'No conditions found',
|
|
341
341
|
previous: 'Previous',
|
|
342
342
|
next: 'Next',
|
|
@@ -594,20 +594,20 @@ const DICTIONARY_ES = {
|
|
|
594
594
|
column_name_must_be_unique: 'El nombre de la columna debe ser único',
|
|
595
595
|
},
|
|
596
596
|
rule_builder: {
|
|
597
|
-
title: '
|
|
598
|
-
add_rule: '
|
|
599
|
-
add_rule_tip: 'Agregar
|
|
597
|
+
title: 'Regla',
|
|
598
|
+
add_rule: 'Condición',
|
|
599
|
+
add_rule_tip: 'Agregar condición',
|
|
600
600
|
add_group: 'Grupo',
|
|
601
601
|
add_group_tip: 'Agregar grupo',
|
|
602
|
-
reset: '
|
|
602
|
+
reset: 'Descartar',
|
|
603
603
|
reset_tip: 'Descartar cambios no guardados',
|
|
604
604
|
save: 'Guardar regla',
|
|
605
605
|
save_tip: 'Guardar regla construida',
|
|
606
|
-
delete_rule_tip: 'Eliminar
|
|
606
|
+
delete_rule_tip: 'Eliminar condición',
|
|
607
607
|
delete_group_tip: 'Eliminar grupo',
|
|
608
608
|
toggle_operator_tip: 'Click para cambiar de operador',
|
|
609
|
-
no_rules: 'No hay
|
|
610
|
-
rules_management: 'Seleccionar
|
|
609
|
+
no_rules: 'No hay condiciones agregadas',
|
|
610
|
+
rules_management: 'Seleccionar condición',
|
|
611
611
|
edit: 'Editar regla',
|
|
612
612
|
edit_tip: 'Editar regla',
|
|
613
613
|
edit_condition_tip: 'Click para editar la condición',
|
|
@@ -621,9 +621,9 @@ const DICTIONARY_ES = {
|
|
|
621
621
|
},
|
|
622
622
|
definition: {
|
|
623
623
|
cancel_and_back: 'Cancelar y volver',
|
|
624
|
-
create_and_select: 'Crear y seleccionar',
|
|
624
|
+
create_and_select: 'Crear y seleccionar condición',
|
|
625
625
|
search_placeholder: 'Buscar condición',
|
|
626
|
-
new_rule: 'Nueva
|
|
626
|
+
new_rule: 'Nueva condición',
|
|
627
627
|
no_results: 'No se encontraron condiciones',
|
|
628
628
|
previous: 'Anterior',
|
|
629
629
|
next: 'Siguiente',
|
|
@@ -8623,6 +8623,7 @@ class RuleDefinirionComponent {
|
|
|
8623
8623
|
newRule = false;
|
|
8624
8624
|
fields;
|
|
8625
8625
|
conditions = [];
|
|
8626
|
+
selectedConditionReference = null;
|
|
8626
8627
|
searchTerm = '';
|
|
8627
8628
|
currentPage = 1;
|
|
8628
8629
|
pageSize = 5;
|
|
@@ -8632,6 +8633,9 @@ class RuleDefinirionComponent {
|
|
|
8632
8633
|
constructor(data) {
|
|
8633
8634
|
this.data = data;
|
|
8634
8635
|
this.conditions = data.conditions;
|
|
8636
|
+
this.selectedConditionReference = data.selectedConditionReference == null
|
|
8637
|
+
? null
|
|
8638
|
+
: String(data.selectedConditionReference);
|
|
8635
8639
|
this.fields = this.buildFields();
|
|
8636
8640
|
this.languageSubscription = this.translate.language$.subscribe(() => {
|
|
8637
8641
|
this.fields = this.buildFields();
|
|
@@ -8642,15 +8646,19 @@ class RuleDefinirionComponent {
|
|
|
8642
8646
|
}
|
|
8643
8647
|
get filteredConditions() {
|
|
8644
8648
|
const normalizedSearch = this.normalizeText(this.searchTerm);
|
|
8645
|
-
|
|
8646
|
-
|
|
8647
|
-
|
|
8648
|
-
|
|
8649
|
-
|
|
8650
|
-
|
|
8651
|
-
|
|
8652
|
-
|
|
8653
|
-
|
|
8649
|
+
const conditions = !normalizedSearch
|
|
8650
|
+
? this.conditions
|
|
8651
|
+
: this.conditions.filter(condition => this.normalizeText(condition.description).includes(normalizedSearch) ||
|
|
8652
|
+
this.normalizeText(condition.fieldName).includes(normalizedSearch) ||
|
|
8653
|
+
this.normalizeText(condition.fieldCode).includes(normalizedSearch) ||
|
|
8654
|
+
this.normalizeText(condition.operatorName).includes(normalizedSearch) ||
|
|
8655
|
+
this.normalizeText(condition.operatorCode).includes(normalizedSearch) ||
|
|
8656
|
+
this.normalizeText(condition.value).includes(normalizedSearch));
|
|
8657
|
+
return [...conditions].sort((left, right) => {
|
|
8658
|
+
const leftSelected = this.isSelected(left) ? 1 : 0;
|
|
8659
|
+
const rightSelected = this.isSelected(right) ? 1 : 0;
|
|
8660
|
+
return rightSelected - leftSelected;
|
|
8661
|
+
});
|
|
8654
8662
|
}
|
|
8655
8663
|
get paginatedConditions() {
|
|
8656
8664
|
const start = (this.currentPage - 1) * this.pageSize;
|
|
@@ -8699,6 +8707,9 @@ class RuleDefinirionComponent {
|
|
|
8699
8707
|
select(condition) {
|
|
8700
8708
|
this.ref.closeFloating(condition);
|
|
8701
8709
|
}
|
|
8710
|
+
isSelected(condition) {
|
|
8711
|
+
return this.selectedConditionReference === String(this.getConditionReference(condition));
|
|
8712
|
+
}
|
|
8702
8713
|
highlightSearch(value) {
|
|
8703
8714
|
const text = String(value ?? '');
|
|
8704
8715
|
const query = this.searchTerm.trim();
|
|
@@ -8755,8 +8766,11 @@ class RuleDefinirionComponent {
|
|
|
8755
8766
|
.replace(/"/g, '"')
|
|
8756
8767
|
.replace(/'/g, ''');
|
|
8757
8768
|
}
|
|
8769
|
+
getConditionReference(condition) {
|
|
8770
|
+
return condition.id === 0 ? (condition.temporalId ?? '') : condition.id;
|
|
8771
|
+
}
|
|
8758
8772
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RuleDefinirionComponent, deps: [{ token: MODAL_DATA }], target: i0.ɵɵFactoryTarget.Component });
|
|
8759
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: RuleDefinirionComponent, isStandalone: true, selector: "lib-rule-definirion", ngImport: i0, template: "\n@if (newRule) {\n <ui-form-wrapper #formWrapper (formSubmit)=\"createAndSelectRule($event)\" [fields]=\"fields\" [cols]=\"3\"></ui-form-wrapper>\n <div class=\"condition-btns\">\n <ui-button icon=\"ri-arrow-left-line\" (click)=\"newRule = false\" color=\"black\" type=\"bordered\">{{ 'rule_builder.definition.cancel_and_back' | uicTranslate }}</ui-button>\n <ui-button (click)=\"formWrapper.submit()\" icon=\"ri-check-line\" color=\"black\">{{ 'rule_builder.definition.create_and_select' | uicTranslate }}</ui-button>\n </div>\n} @else {\n <div class=\"condition-searcher\">\n <ui-input>\n <input [(ngModel)]=\"searchTerm\" (ngModelChange)=\"onSearchTermChange()\" [placeholder]=\"'rule_builder.definition.search_placeholder' | uicTranslate\" type=\"text\">\n </ui-input>\n <ui-button (click)=\"newRule = true\" color=\"black\">{{ 'rule_builder.definition.new_rule' | uicTranslate }}</ui-button>\n </div>\n\n @if (paginatedConditions.length > 0) {\n @for (condition of paginatedConditions; track $index) {\n <div class=\"condition\">\n <i class=\"ri-align-item-horizontal-center-line\"></i>\n <div style=\"flex: 1 1;\">\n <div class=\"condition-title\"><span [innerHTML]=\"highlightSearch(condition.description)\"></span>:</div>\n <div class=\"condition-body\">\n <span class=\"condition-field\" [innerHTML]=\"highlightSearch(condition.fieldName)\"></span>\n <span class=\"condition-operator\" [innerHTML]=\"highlightSearch(condition.operatorName)\"></span>\n <span class=\"condition-value\" [innerHTML]=\"highlightSearch(condition.value)\"></span>\n </div>\n </div>\n <ui-button (click)=\"select(condition)\" color=\"primary\" size=\"s\" type=\"bordered\">{{ 'common.select' | uicTranslate }}</ui-button>\n </div>\n }\n } @else {\n <div class=\"condition\">\n <div class=\"condition-emptytext\">\n {{ 'rule_builder.definition.no_results' | uicTranslate }}\n </div>\n </div>\n }\n\n <div class=\"condition-pagination\">\n <ui-button [disabled]=\"!canGoToPreviousPage\" (click)=\"goToPreviousPage()\" color=\"black\" size=\"s\" type=\"bordered\">{{ 'rule_builder.definition.previous' | uicTranslate }}</ui-button>\n <div><b>{{ currentPage }}</b> / {{ totalPages }}</div>\n <ui-button [disabled]=\"!canGoToNextPage\" (click)=\"goToNextPage()\" color=\"black\" size=\"s\" type=\"bordered\">{{ 'rule_builder.definition.next' | uicTranslate }}</ui-button>\n </div>\n}\n", styles: [".condition{border:solid 1px var(--grey-300);border-radius:10px;background-color:var(--grey-50);padding:6px;margin-bottom:4px;display:flex;align-items:center;gap:10px}.condition-emptytext{font-size:12px;text-align:center;color:var(--grey-400);padding:10px;width:100%}.condition i{color:var(--blue-600)}.condition-title{font-size:14px;font-weight:500;line-height:16px}.condition-body{color:var(--grey-500);display:flex;gap:5px;font-size:12px}.condition-searcher{display:flex;gap:25px;margin-bottom:10px}.condition-pagination{margin-top:15px;display:flex;font-size:14px;align-items:center;justify-content:space-between}.condition-btns{padding-top:10px;border-top:solid 1px var(--grey-200);display:flex;justify-content:space-between}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: UicFormWrapperComponent, selector: "ui-form-wrapper", inputs: ["schema", "fields", "cols", "externalData", "loading", "disabled", "showButtons", "fillSelects", "initialValues"], outputs: ["formSubmit", "formChange"] }, { kind: "component", type: UicInputComponent, selector: "ui-input", inputs: ["icon", "iconColor", "internalIcon", "internalIconColor", "size", "label", "error", "tip", "disabled", "loading"], outputs: ["clickButton"] }, { kind: "component", type: UicButtonComponent, selector: "ui-button", inputs: ["text", "icon", "rightIcon", "iconOnly", "disabled", "loading", "size", "type", "color"] }, { kind: "pipe", type: UicTranslatePipe, name: "uicTranslate" }] });
|
|
8773
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: RuleDefinirionComponent, isStandalone: true, selector: "lib-rule-definirion", ngImport: i0, template: "\n@if (newRule) {\n <ui-form-wrapper #formWrapper (formSubmit)=\"createAndSelectRule($event)\" [fields]=\"fields\" [cols]=\"3\"></ui-form-wrapper>\n <div class=\"condition-btns\">\n <ui-button icon=\"ri-arrow-left-line\" (click)=\"newRule = false\" color=\"black\" type=\"bordered\">{{ 'rule_builder.definition.cancel_and_back' | uicTranslate }}</ui-button>\n <ui-button (click)=\"formWrapper.submit()\" icon=\"ri-check-line\" color=\"black\">{{ 'rule_builder.definition.create_and_select' | uicTranslate }}</ui-button>\n </div>\n} @else {\n <div class=\"condition-searcher\">\n <ui-input>\n <input [(ngModel)]=\"searchTerm\" (ngModelChange)=\"onSearchTermChange()\" [placeholder]=\"'rule_builder.definition.search_placeholder' | uicTranslate\" type=\"text\">\n </ui-input>\n <ui-button (click)=\"newRule = true\" color=\"black\">{{ 'rule_builder.definition.new_rule' | uicTranslate }}</ui-button>\n </div>\n\n @if (paginatedConditions.length > 0) {\n @for (condition of paginatedConditions; track $index) {\n <div class=\"condition\" [class.condition-selected]=\"isSelected(condition)\">\n <i class=\"ri-align-item-horizontal-center-line\"></i>\n <div style=\"flex: 1 1;\">\n <div class=\"condition-title\"><span [innerHTML]=\"highlightSearch(condition.description)\"></span>:</div>\n <div class=\"condition-body\">\n <span class=\"condition-field\" [innerHTML]=\"highlightSearch(condition.fieldName)\"></span>\n <span class=\"condition-operator\" [innerHTML]=\"highlightSearch(condition.operatorName)\"></span>\n <span class=\"condition-value\" [innerHTML]=\"highlightSearch(condition.value)\"></span>\n </div>\n </div>\n @if (!isSelected(condition)) {\n <ui-button (click)=\"select(condition)\" color=\"primary\" size=\"s\" type=\"bordered\">{{ 'common.select' | uicTranslate }}</ui-button>\n }\n </div>\n }\n } @else {\n <div class=\"condition\">\n <div class=\"condition-emptytext\">\n {{ 'rule_builder.definition.no_results' | uicTranslate }}\n </div>\n </div>\n }\n\n <div class=\"condition-pagination\">\n <ui-button [disabled]=\"!canGoToPreviousPage\" (click)=\"goToPreviousPage()\" color=\"black\" size=\"s\" type=\"bordered\">{{ 'rule_builder.definition.previous' | uicTranslate }}</ui-button>\n <div><b>{{ currentPage }}</b> / {{ totalPages }}</div>\n <ui-button [disabled]=\"!canGoToNextPage\" (click)=\"goToNextPage()\" color=\"black\" size=\"s\" type=\"bordered\">{{ 'rule_builder.definition.next' | uicTranslate }}</ui-button>\n </div>\n}\n", styles: [".condition{border:solid 1px var(--grey-300);border-radius:10px;background-color:var(--grey-50);padding:6px;margin-bottom:4px;display:flex;align-items:center;gap:10px}.condition-emptytext{font-size:12px;text-align:center;color:var(--grey-400);padding:10px;width:100%}.condition i{color:var(--blue-600)}.condition-selected{border-color:var(--blue-500);background:linear-gradient(135deg,var(--blue-50) 0%,#eef6ff 100%);box-shadow:inset 0 0 0 1px #2563eb1f}.condition-selected .condition-title{color:var(--blue-800)}.condition-selected .condition-body,.condition-selected i{color:var(--blue-700)}.condition-title{font-size:14px;font-weight:500;line-height:16px}.condition-body{color:var(--grey-500);display:flex;gap:5px;font-size:12px}.condition-searcher{display:flex;gap:25px;margin-bottom:10px}.condition-pagination{margin-top:15px;display:flex;font-size:14px;align-items:center;justify-content:space-between}.condition-btns{padding-top:10px;border-top:solid 1px var(--grey-200);display:flex;justify-content:space-between}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: UicFormWrapperComponent, selector: "ui-form-wrapper", inputs: ["schema", "fields", "cols", "externalData", "loading", "disabled", "showButtons", "fillSelects", "initialValues"], outputs: ["formSubmit", "formChange"] }, { kind: "component", type: UicInputComponent, selector: "ui-input", inputs: ["icon", "iconColor", "internalIcon", "internalIconColor", "size", "label", "error", "tip", "disabled", "loading"], outputs: ["clickButton"] }, { kind: "component", type: UicButtonComponent, selector: "ui-button", inputs: ["text", "icon", "rightIcon", "iconOnly", "disabled", "loading", "size", "type", "color"] }, { kind: "pipe", type: UicTranslatePipe, name: "uicTranslate" }] });
|
|
8760
8774
|
}
|
|
8761
8775
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RuleDefinirionComponent, decorators: [{
|
|
8762
8776
|
type: Component,
|
|
@@ -8766,14 +8780,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
|
|
|
8766
8780
|
UicInputComponent,
|
|
8767
8781
|
UicButtonComponent,
|
|
8768
8782
|
UicTranslatePipe
|
|
8769
|
-
], template: "\n@if (newRule) {\n <ui-form-wrapper #formWrapper (formSubmit)=\"createAndSelectRule($event)\" [fields]=\"fields\" [cols]=\"3\"></ui-form-wrapper>\n <div class=\"condition-btns\">\n <ui-button icon=\"ri-arrow-left-line\" (click)=\"newRule = false\" color=\"black\" type=\"bordered\">{{ 'rule_builder.definition.cancel_and_back' | uicTranslate }}</ui-button>\n <ui-button (click)=\"formWrapper.submit()\" icon=\"ri-check-line\" color=\"black\">{{ 'rule_builder.definition.create_and_select' | uicTranslate }}</ui-button>\n </div>\n} @else {\n <div class=\"condition-searcher\">\n <ui-input>\n <input [(ngModel)]=\"searchTerm\" (ngModelChange)=\"onSearchTermChange()\" [placeholder]=\"'rule_builder.definition.search_placeholder' | uicTranslate\" type=\"text\">\n </ui-input>\n <ui-button (click)=\"newRule = true\" color=\"black\">{{ 'rule_builder.definition.new_rule' | uicTranslate }}</ui-button>\n </div>\n\n @if (paginatedConditions.length > 0) {\n @for (condition of paginatedConditions; track $index) {\n <div class=\"condition\">\n <i class=\"ri-align-item-horizontal-center-line\"></i>\n <div style=\"flex: 1 1;\">\n <div class=\"condition-title\"><span [innerHTML]=\"highlightSearch(condition.description)\"></span>:</div>\n <div class=\"condition-body\">\n <span class=\"condition-field\" [innerHTML]=\"highlightSearch(condition.fieldName)\"></span>\n <span class=\"condition-operator\" [innerHTML]=\"highlightSearch(condition.operatorName)\"></span>\n <span class=\"condition-value\" [innerHTML]=\"highlightSearch(condition.value)\"></span>\n </div>\n </div>\n <ui-button (click)=\"select(condition)\" color=\"primary\" size=\"s\" type=\"bordered\">{{ 'common.select' | uicTranslate }}</ui-button>\n </div>\n }\n } @else {\n <div class=\"condition\">\n <div class=\"condition-emptytext\">\n {{ 'rule_builder.definition.no_results' | uicTranslate }}\n </div>\n </div>\n }\n\n <div class=\"condition-pagination\">\n <ui-button [disabled]=\"!canGoToPreviousPage\" (click)=\"goToPreviousPage()\" color=\"black\" size=\"s\" type=\"bordered\">{{ 'rule_builder.definition.previous' | uicTranslate }}</ui-button>\n <div><b>{{ currentPage }}</b> / {{ totalPages }}</div>\n <ui-button [disabled]=\"!canGoToNextPage\" (click)=\"goToNextPage()\" color=\"black\" size=\"s\" type=\"bordered\">{{ 'rule_builder.definition.next' | uicTranslate }}</ui-button>\n </div>\n}\n", styles: [".condition{border:solid 1px var(--grey-300);border-radius:10px;background-color:var(--grey-50);padding:6px;margin-bottom:4px;display:flex;align-items:center;gap:10px}.condition-emptytext{font-size:12px;text-align:center;color:var(--grey-400);padding:10px;width:100%}.condition i{color:var(--blue-600)}.condition-title{font-size:14px;font-weight:500;line-height:16px}.condition-body{color:var(--grey-500);display:flex;gap:5px;font-size:12px}.condition-searcher{display:flex;gap:25px;margin-bottom:10px}.condition-pagination{margin-top:15px;display:flex;font-size:14px;align-items:center;justify-content:space-between}.condition-btns{padding-top:10px;border-top:solid 1px var(--grey-200);display:flex;justify-content:space-between}\n"] }]
|
|
8783
|
+
], template: "\n@if (newRule) {\n <ui-form-wrapper #formWrapper (formSubmit)=\"createAndSelectRule($event)\" [fields]=\"fields\" [cols]=\"3\"></ui-form-wrapper>\n <div class=\"condition-btns\">\n <ui-button icon=\"ri-arrow-left-line\" (click)=\"newRule = false\" color=\"black\" type=\"bordered\">{{ 'rule_builder.definition.cancel_and_back' | uicTranslate }}</ui-button>\n <ui-button (click)=\"formWrapper.submit()\" icon=\"ri-check-line\" color=\"black\">{{ 'rule_builder.definition.create_and_select' | uicTranslate }}</ui-button>\n </div>\n} @else {\n <div class=\"condition-searcher\">\n <ui-input>\n <input [(ngModel)]=\"searchTerm\" (ngModelChange)=\"onSearchTermChange()\" [placeholder]=\"'rule_builder.definition.search_placeholder' | uicTranslate\" type=\"text\">\n </ui-input>\n <ui-button (click)=\"newRule = true\" color=\"black\">{{ 'rule_builder.definition.new_rule' | uicTranslate }}</ui-button>\n </div>\n\n @if (paginatedConditions.length > 0) {\n @for (condition of paginatedConditions; track $index) {\n <div class=\"condition\" [class.condition-selected]=\"isSelected(condition)\">\n <i class=\"ri-align-item-horizontal-center-line\"></i>\n <div style=\"flex: 1 1;\">\n <div class=\"condition-title\"><span [innerHTML]=\"highlightSearch(condition.description)\"></span>:</div>\n <div class=\"condition-body\">\n <span class=\"condition-field\" [innerHTML]=\"highlightSearch(condition.fieldName)\"></span>\n <span class=\"condition-operator\" [innerHTML]=\"highlightSearch(condition.operatorName)\"></span>\n <span class=\"condition-value\" [innerHTML]=\"highlightSearch(condition.value)\"></span>\n </div>\n </div>\n @if (!isSelected(condition)) {\n <ui-button (click)=\"select(condition)\" color=\"primary\" size=\"s\" type=\"bordered\">{{ 'common.select' | uicTranslate }}</ui-button>\n }\n </div>\n }\n } @else {\n <div class=\"condition\">\n <div class=\"condition-emptytext\">\n {{ 'rule_builder.definition.no_results' | uicTranslate }}\n </div>\n </div>\n }\n\n <div class=\"condition-pagination\">\n <ui-button [disabled]=\"!canGoToPreviousPage\" (click)=\"goToPreviousPage()\" color=\"black\" size=\"s\" type=\"bordered\">{{ 'rule_builder.definition.previous' | uicTranslate }}</ui-button>\n <div><b>{{ currentPage }}</b> / {{ totalPages }}</div>\n <ui-button [disabled]=\"!canGoToNextPage\" (click)=\"goToNextPage()\" color=\"black\" size=\"s\" type=\"bordered\">{{ 'rule_builder.definition.next' | uicTranslate }}</ui-button>\n </div>\n}\n", styles: [".condition{border:solid 1px var(--grey-300);border-radius:10px;background-color:var(--grey-50);padding:6px;margin-bottom:4px;display:flex;align-items:center;gap:10px}.condition-emptytext{font-size:12px;text-align:center;color:var(--grey-400);padding:10px;width:100%}.condition i{color:var(--blue-600)}.condition-selected{border-color:var(--blue-500);background:linear-gradient(135deg,var(--blue-50) 0%,#eef6ff 100%);box-shadow:inset 0 0 0 1px #2563eb1f}.condition-selected .condition-title{color:var(--blue-800)}.condition-selected .condition-body,.condition-selected i{color:var(--blue-700)}.condition-title{font-size:14px;font-weight:500;line-height:16px}.condition-body{color:var(--grey-500);display:flex;gap:5px;font-size:12px}.condition-searcher{display:flex;gap:25px;margin-bottom:10px}.condition-pagination{margin-top:15px;display:flex;font-size:14px;align-items:center;justify-content:space-between}.condition-btns{padding-top:10px;border-top:solid 1px var(--grey-200);display:flex;justify-content:space-between}\n"] }]
|
|
8770
8784
|
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
8771
8785
|
type: Inject,
|
|
8772
8786
|
args: [MODAL_DATA]
|
|
8773
8787
|
}] }] });
|
|
8774
8788
|
|
|
8775
8789
|
class UicRuleBuilderComponent {
|
|
8776
|
-
|
|
8790
|
+
conditionsInitialized = false;
|
|
8791
|
+
emitConditionsOnInit = false;
|
|
8792
|
+
emitRuleDefinitionOnInit = false;
|
|
8793
|
+
conditionsEmitScheduled = false;
|
|
8794
|
+
ruleDefinitionEmitScheduled = false;
|
|
8795
|
+
_conditions = [
|
|
8777
8796
|
{
|
|
8778
8797
|
id: 1,
|
|
8779
8798
|
description: 'Mayores de edad',
|
|
@@ -8838,25 +8857,63 @@ class UicRuleBuilderComponent {
|
|
|
8838
8857
|
value: '18',
|
|
8839
8858
|
}
|
|
8840
8859
|
];
|
|
8841
|
-
|
|
8842
|
-
|
|
8843
|
-
|
|
8844
|
-
|
|
8845
|
-
|
|
8846
|
-
|
|
8847
|
-
|
|
8848
|
-
|
|
8849
|
-
|
|
8850
|
-
|
|
8851
|
-
|
|
8852
|
-
|
|
8860
|
+
set conditions(value) {
|
|
8861
|
+
this._conditions = Array.isArray(value) ? value.map(condition => ({ ...condition })) : [];
|
|
8862
|
+
const conditionsNormalized = this.refreshAvailableConditions();
|
|
8863
|
+
const syncResult = this.syncConditionsWithPersistedConditions();
|
|
8864
|
+
this.syncNextTemporalConditionId();
|
|
8865
|
+
if (this.conditionsInitialized && (conditionsNormalized || syncResult.conditionsCleaned)) {
|
|
8866
|
+
this.scheduleConditionsStateEmit();
|
|
8867
|
+
}
|
|
8868
|
+
if (!this.conditionsInitialized && (conditionsNormalized || syncResult.conditionsCleaned)) {
|
|
8869
|
+
this.emitConditionsOnInit = true;
|
|
8870
|
+
}
|
|
8871
|
+
if (this.conditionsInitialized && syncResult.referencesUpdated) {
|
|
8872
|
+
this.scheduleRuleDefinitionStateEmit();
|
|
8873
|
+
}
|
|
8874
|
+
if (!this.conditionsInitialized && syncResult.referencesUpdated) {
|
|
8875
|
+
this.emitRuleDefinitionOnInit = true;
|
|
8876
|
+
}
|
|
8877
|
+
this.conditionsInitialized = true;
|
|
8878
|
+
}
|
|
8879
|
+
get conditions() {
|
|
8880
|
+
return this._conditions;
|
|
8881
|
+
}
|
|
8882
|
+
conditionOperators = [];
|
|
8883
|
+
conditionFields = [];
|
|
8853
8884
|
conditionLabels = {};
|
|
8854
8885
|
editing = false;
|
|
8855
8886
|
nextTemporalConditionId = 1;
|
|
8887
|
+
externalRuleDefinition = this.createEmptyRuleBuilderValue();
|
|
8856
8888
|
title = '';
|
|
8857
|
-
|
|
8889
|
+
set ruleDefinition(value) {
|
|
8890
|
+
const normalizedValue = this.normalizeRuleBuilderValue(value);
|
|
8891
|
+
if (this.areRuleBuilderValuesEqual(normalizedValue, this.externalRuleDefinition)) {
|
|
8892
|
+
return;
|
|
8893
|
+
}
|
|
8894
|
+
this.externalRuleDefinition = normalizedValue;
|
|
8895
|
+
this.editorRules = this.getRulesFromDefinition(normalizedValue.definition);
|
|
8896
|
+
const syncResult = this.syncConditionsWithPersistedConditions();
|
|
8897
|
+
this.syncNextTemporalConditionId();
|
|
8898
|
+
if (this.conditionsInitialized && syncResult.conditionsCleaned) {
|
|
8899
|
+
this.scheduleConditionsStateEmit();
|
|
8900
|
+
}
|
|
8901
|
+
if (this.conditionsInitialized && syncResult.referencesUpdated) {
|
|
8902
|
+
this.scheduleRuleDefinitionStateEmit();
|
|
8903
|
+
}
|
|
8904
|
+
if (!this.conditionsInitialized && syncResult.conditionsCleaned) {
|
|
8905
|
+
this.emitConditionsOnInit = true;
|
|
8906
|
+
}
|
|
8907
|
+
if (!this.conditionsInitialized && syncResult.referencesUpdated) {
|
|
8908
|
+
this.emitRuleDefinitionOnInit = true;
|
|
8909
|
+
}
|
|
8910
|
+
}
|
|
8911
|
+
get ruleDefinition() {
|
|
8912
|
+
return this.externalRuleDefinition;
|
|
8913
|
+
}
|
|
8858
8914
|
ruleDefinitionChange = new EventEmitter();
|
|
8859
|
-
|
|
8915
|
+
conditionsChange = new EventEmitter();
|
|
8916
|
+
editorRules = [];
|
|
8860
8917
|
translate = inject(UicTranslateService);
|
|
8861
8918
|
modal = inject(UicModalService);
|
|
8862
8919
|
tinyAlert = inject(UicTinyAlertService);
|
|
@@ -8864,15 +8921,33 @@ class UicRuleBuilderComponent {
|
|
|
8864
8921
|
return this.title || this.translate.translate('rule_builder.title');
|
|
8865
8922
|
}
|
|
8866
8923
|
ngOnInit() {
|
|
8867
|
-
this.
|
|
8868
|
-
|
|
8924
|
+
if (!this.conditionsInitialized) {
|
|
8925
|
+
this.emitConditionsOnInit = this.refreshAvailableConditions();
|
|
8926
|
+
this.conditionsInitialized = true;
|
|
8927
|
+
}
|
|
8928
|
+
this.editorRules = this.getRulesFromDefinition(this.ruleDefinition.definition);
|
|
8929
|
+
const syncResult = this.syncConditionsWithPersistedConditions();
|
|
8869
8930
|
this.syncNextTemporalConditionId();
|
|
8931
|
+
if (syncResult.conditionsCleaned) {
|
|
8932
|
+
this.emitConditionsOnInit = true;
|
|
8933
|
+
}
|
|
8934
|
+
if (syncResult.referencesUpdated) {
|
|
8935
|
+
this.emitRuleDefinitionOnInit = true;
|
|
8936
|
+
}
|
|
8937
|
+
if (this.emitConditionsOnInit) {
|
|
8938
|
+
this.scheduleConditionsStateEmit();
|
|
8939
|
+
this.emitConditionsOnInit = false;
|
|
8940
|
+
}
|
|
8941
|
+
if (this.emitRuleDefinitionOnInit) {
|
|
8942
|
+
this.scheduleRuleDefinitionStateEmit();
|
|
8943
|
+
this.emitRuleDefinitionOnInit = false;
|
|
8944
|
+
}
|
|
8870
8945
|
}
|
|
8871
|
-
addRule(rules = this.
|
|
8946
|
+
addRule(rules = this.editorRules) {
|
|
8872
8947
|
this.appendExpression(rules, this.createConditionRule());
|
|
8873
8948
|
this.syncRuleDefinition();
|
|
8874
8949
|
}
|
|
8875
|
-
addGroup(rules = this.
|
|
8950
|
+
addGroup(rules = this.editorRules) {
|
|
8876
8951
|
this.appendExpression(rules, this.createGroupRule());
|
|
8877
8952
|
this.syncRuleDefinition();
|
|
8878
8953
|
}
|
|
@@ -8902,6 +8977,7 @@ class UicRuleBuilderComponent {
|
|
|
8902
8977
|
conditions: this.conditions,
|
|
8903
8978
|
conditionOperators: this.conditionOperators,
|
|
8904
8979
|
conditionFields: this.conditionFields,
|
|
8980
|
+
selectedConditionReference: targetRule.value ?? null,
|
|
8905
8981
|
},
|
|
8906
8982
|
size: 'medium'
|
|
8907
8983
|
}).afterClosed().subscribe(r => {
|
|
@@ -8914,29 +8990,38 @@ class UicRuleBuilderComponent {
|
|
|
8914
8990
|
});
|
|
8915
8991
|
}
|
|
8916
8992
|
print() {
|
|
8917
|
-
const normalizedRules = this.normalizeRules(this.cloneRules(this.
|
|
8993
|
+
const normalizedRules = this.normalizeRules(this.cloneRules(this.editorRules));
|
|
8918
8994
|
if (!this.hasOperators(normalizedRules)) {
|
|
8919
8995
|
this.tinyAlert.warning('rule_builder.validation.single_condition_not_allowed');
|
|
8920
8996
|
return;
|
|
8921
8997
|
}
|
|
8922
|
-
this.
|
|
8923
|
-
this.markRulesAsSaved(this.
|
|
8924
|
-
|
|
8925
|
-
this.initValue = output.definition;
|
|
8926
|
-
this.ruleDefinitionChange.emit(output);
|
|
8998
|
+
this.editorRules = normalizedRules;
|
|
8999
|
+
this.markRulesAsSaved(this.editorRules);
|
|
9000
|
+
this.emitRuleDefinitionState();
|
|
8927
9001
|
this.editing = false;
|
|
8928
9002
|
}
|
|
8929
9003
|
reset() {
|
|
8930
|
-
this.
|
|
9004
|
+
this.editorRules = this.getRulesFromDefinition(this.ruleDefinition.definition);
|
|
8931
9005
|
this.editing = false;
|
|
8932
9006
|
}
|
|
8933
9007
|
getOutput() {
|
|
8934
|
-
this.
|
|
9008
|
+
this.editorRules = this.normalizeRules(this.cloneRules(this.editorRules));
|
|
8935
9009
|
return this.buildRuleOutput();
|
|
8936
9010
|
}
|
|
8937
9011
|
getConditionLabel(value) {
|
|
8938
9012
|
return this.resolveConditionLabel(value);
|
|
8939
9013
|
}
|
|
9014
|
+
getConditionDetailTip(value) {
|
|
9015
|
+
const matchedCondition = this.conditions.find(condition => String(this.getConditionReference(condition)) === String(value));
|
|
9016
|
+
if (!matchedCondition) {
|
|
9017
|
+
return '';
|
|
9018
|
+
}
|
|
9019
|
+
return [
|
|
9020
|
+
matchedCondition.fieldName,
|
|
9021
|
+
matchedCondition.operatorName,
|
|
9022
|
+
matchedCondition.value
|
|
9023
|
+
].filter(Boolean).join(' ');
|
|
9024
|
+
}
|
|
8940
9025
|
getOperatorLabel(value) {
|
|
8941
9026
|
const normalizedValue = value === 'OR' ? 'OR' : 'AND';
|
|
8942
9027
|
const translationKey = normalizedValue === 'AND'
|
|
@@ -8954,12 +9039,12 @@ class UicRuleBuilderComponent {
|
|
|
8954
9039
|
rules.push(expression);
|
|
8955
9040
|
}
|
|
8956
9041
|
syncRuleDefinition() {
|
|
8957
|
-
this.
|
|
9042
|
+
this.editorRules = this.normalizeRules(this.editorRules, true);
|
|
8958
9043
|
}
|
|
8959
9044
|
createConditionRule() {
|
|
8960
9045
|
return {
|
|
8961
9046
|
type: 'condition',
|
|
8962
|
-
value:
|
|
9047
|
+
value: null,
|
|
8963
9048
|
unsaved: true
|
|
8964
9049
|
};
|
|
8965
9050
|
}
|
|
@@ -8970,11 +9055,6 @@ class UicRuleBuilderComponent {
|
|
|
8970
9055
|
unsaved: true
|
|
8971
9056
|
};
|
|
8972
9057
|
}
|
|
8973
|
-
getNextConditionValue() {
|
|
8974
|
-
const usedConditions = new Set(this.collectConditionValues(this.ruleDefinition));
|
|
8975
|
-
const nextOption = this.availableConditions.find(option => option.id != null && !usedConditions.has(String(option.id)));
|
|
8976
|
-
return nextOption?.id ?? this.availableConditions[0]?.id ?? null;
|
|
8977
|
-
}
|
|
8978
9058
|
collectConditionValues(rules) {
|
|
8979
9059
|
return rules.flatMap(rule => {
|
|
8980
9060
|
if (rule.type === 'condition' && rule.value) {
|
|
@@ -9075,9 +9155,9 @@ class UicRuleBuilderComponent {
|
|
|
9075
9155
|
const { rules } = this.parseTokens(tokens);
|
|
9076
9156
|
return this.normalizeRules(rules);
|
|
9077
9157
|
}
|
|
9078
|
-
|
|
9079
|
-
const rules =
|
|
9080
|
-
? this.parseExpression(
|
|
9158
|
+
getRulesFromDefinition(definition) {
|
|
9159
|
+
const rules = definition.trim()
|
|
9160
|
+
? this.parseExpression(definition)
|
|
9081
9161
|
: this.normalizeRules([]);
|
|
9082
9162
|
this.markRulesAsSaved(rules);
|
|
9083
9163
|
return rules;
|
|
@@ -9139,17 +9219,18 @@ class UicRuleBuilderComponent {
|
|
|
9139
9219
|
const conditionReference = this.getConditionReference(normalizedCondition);
|
|
9140
9220
|
const existingIndex = this.conditions.findIndex(item => String(this.getConditionReference(item)) === String(conditionReference));
|
|
9141
9221
|
if (existingIndex >= 0) {
|
|
9142
|
-
this.
|
|
9222
|
+
this._conditions[existingIndex] = normalizedCondition;
|
|
9143
9223
|
}
|
|
9144
9224
|
else {
|
|
9145
|
-
this.
|
|
9225
|
+
this._conditions = [...this._conditions, normalizedCondition];
|
|
9146
9226
|
}
|
|
9147
9227
|
this.refreshAvailableConditions();
|
|
9228
|
+
this.scheduleConditionsStateEmit();
|
|
9148
9229
|
return conditionReference;
|
|
9149
9230
|
}
|
|
9150
9231
|
buildRuleOutput() {
|
|
9151
|
-
const definition = this.buildExpression(this.
|
|
9152
|
-
const usedConditionReferences = new Set(this.collectConditionValues(this.
|
|
9232
|
+
const definition = this.buildExpression(this.editorRules);
|
|
9233
|
+
const usedConditionReferences = new Set(this.collectConditionValues(this.editorRules));
|
|
9153
9234
|
const rulesToCreate = this.conditions
|
|
9154
9235
|
.filter(condition => condition.id === 0 && !!condition.temporalId && usedConditionReferences.has(String(this.getConditionReference(condition))))
|
|
9155
9236
|
.map(condition => ({
|
|
@@ -9164,24 +9245,111 @@ class UicRuleBuilderComponent {
|
|
|
9164
9245
|
rulesToCreate
|
|
9165
9246
|
};
|
|
9166
9247
|
}
|
|
9248
|
+
emitRuleDefinitionState() {
|
|
9249
|
+
const output = this.buildRuleOutput();
|
|
9250
|
+
this.externalRuleDefinition = output;
|
|
9251
|
+
this.ruleDefinitionChange.emit(output);
|
|
9252
|
+
}
|
|
9253
|
+
emitConditionsState() {
|
|
9254
|
+
this.conditionsChange.emit(this._conditions.map(condition => ({ ...condition })));
|
|
9255
|
+
}
|
|
9256
|
+
scheduleRuleDefinitionStateEmit() {
|
|
9257
|
+
if (this.ruleDefinitionEmitScheduled) {
|
|
9258
|
+
return;
|
|
9259
|
+
}
|
|
9260
|
+
this.ruleDefinitionEmitScheduled = true;
|
|
9261
|
+
queueMicrotask(() => {
|
|
9262
|
+
this.ruleDefinitionEmitScheduled = false;
|
|
9263
|
+
this.emitRuleDefinitionState();
|
|
9264
|
+
});
|
|
9265
|
+
}
|
|
9266
|
+
scheduleConditionsStateEmit() {
|
|
9267
|
+
if (this.conditionsEmitScheduled) {
|
|
9268
|
+
return;
|
|
9269
|
+
}
|
|
9270
|
+
this.conditionsEmitScheduled = true;
|
|
9271
|
+
queueMicrotask(() => {
|
|
9272
|
+
this.conditionsEmitScheduled = false;
|
|
9273
|
+
this.emitConditionsState();
|
|
9274
|
+
});
|
|
9275
|
+
}
|
|
9276
|
+
normalizeRuleBuilderValue(value) {
|
|
9277
|
+
if (!value) {
|
|
9278
|
+
return this.createEmptyRuleBuilderValue();
|
|
9279
|
+
}
|
|
9280
|
+
return {
|
|
9281
|
+
definition: String(value.definition ?? ''),
|
|
9282
|
+
rulesToCreate: Array.isArray(value.rulesToCreate)
|
|
9283
|
+
? value.rulesToCreate.map(rule => ({ ...rule }))
|
|
9284
|
+
: []
|
|
9285
|
+
};
|
|
9286
|
+
}
|
|
9287
|
+
createEmptyRuleBuilderValue() {
|
|
9288
|
+
return {
|
|
9289
|
+
definition: '',
|
|
9290
|
+
rulesToCreate: []
|
|
9291
|
+
};
|
|
9292
|
+
}
|
|
9293
|
+
areRuleBuilderValuesEqual(left, right) {
|
|
9294
|
+
return left.definition === right.definition
|
|
9295
|
+
&& JSON.stringify(left.rulesToCreate) === JSON.stringify(right.rulesToCreate);
|
|
9296
|
+
}
|
|
9167
9297
|
refreshAvailableConditions() {
|
|
9168
|
-
|
|
9298
|
+
let changed = false;
|
|
9299
|
+
this._conditions = this._conditions.map(condition => {
|
|
9169
9300
|
if (condition.id !== 0 || condition.temporalId) {
|
|
9170
9301
|
return condition;
|
|
9171
9302
|
}
|
|
9303
|
+
changed = true;
|
|
9172
9304
|
return {
|
|
9173
9305
|
...condition,
|
|
9174
9306
|
temporalId: this.getNextTemporalConditionId()
|
|
9175
9307
|
};
|
|
9176
9308
|
});
|
|
9177
|
-
this.
|
|
9178
|
-
id: this.getConditionReference(condition),
|
|
9179
|
-
text: condition.description
|
|
9180
|
-
}));
|
|
9181
|
-
this.conditionLabels = this.conditions.reduce((labels, condition) => {
|
|
9309
|
+
this.conditionLabels = this._conditions.reduce((labels, condition) => {
|
|
9182
9310
|
labels[String(this.getConditionReference(condition))] = condition.description;
|
|
9183
9311
|
return labels;
|
|
9184
9312
|
}, {});
|
|
9313
|
+
return changed;
|
|
9314
|
+
}
|
|
9315
|
+
syncConditionsWithPersistedConditions() {
|
|
9316
|
+
const persistedConditionsByTemporalId = new Map(this._conditions
|
|
9317
|
+
.filter(condition => condition.id !== 0 && !!condition.temporalId)
|
|
9318
|
+
.map(condition => [String(condition.temporalId), condition]));
|
|
9319
|
+
if (persistedConditionsByTemporalId.size === 0) {
|
|
9320
|
+
return {
|
|
9321
|
+
referencesUpdated: false,
|
|
9322
|
+
conditionsCleaned: false
|
|
9323
|
+
};
|
|
9324
|
+
}
|
|
9325
|
+
const referencesUpdated = this.replaceConditionReferences(this.editorRules, persistedConditionsByTemporalId);
|
|
9326
|
+
const previousLength = this._conditions.length;
|
|
9327
|
+
this._conditions = this._conditions.filter(condition => {
|
|
9328
|
+
return condition.id !== 0
|
|
9329
|
+
|| !condition.temporalId
|
|
9330
|
+
|| !persistedConditionsByTemporalId.has(String(condition.temporalId));
|
|
9331
|
+
});
|
|
9332
|
+
return {
|
|
9333
|
+
referencesUpdated,
|
|
9334
|
+
conditionsCleaned: previousLength !== this._conditions.length
|
|
9335
|
+
};
|
|
9336
|
+
}
|
|
9337
|
+
replaceConditionReferences(rules, persistedConditionsByTemporalId) {
|
|
9338
|
+
let updated = false;
|
|
9339
|
+
for (const rule of rules) {
|
|
9340
|
+
if (rule.type === 'condition' && typeof rule.value === 'string') {
|
|
9341
|
+
const persistedCondition = persistedConditionsByTemporalId.get(rule.value);
|
|
9342
|
+
if (persistedCondition) {
|
|
9343
|
+
rule.value = persistedCondition.id;
|
|
9344
|
+
rule.unsaved = false;
|
|
9345
|
+
updated = true;
|
|
9346
|
+
}
|
|
9347
|
+
}
|
|
9348
|
+
if (rule.type === 'group' && rule.rules) {
|
|
9349
|
+
updated = this.replaceConditionReferences(rule.rules, persistedConditionsByTemporalId) || updated;
|
|
9350
|
+
}
|
|
9351
|
+
}
|
|
9352
|
+
return updated;
|
|
9185
9353
|
}
|
|
9186
9354
|
getConditionReference(condition) {
|
|
9187
9355
|
return condition.id === 0 ? (condition.temporalId ?? '') : condition.id;
|
|
@@ -9193,8 +9361,10 @@ class UicRuleBuilderComponent {
|
|
|
9193
9361
|
}
|
|
9194
9362
|
syncNextTemporalConditionId() {
|
|
9195
9363
|
const references = [
|
|
9196
|
-
...this.conditions
|
|
9197
|
-
|
|
9364
|
+
...this.conditions
|
|
9365
|
+
.flatMap(condition => [String(this.getConditionReference(condition)), String(condition.temporalId ?? '')])
|
|
9366
|
+
.filter(reference => reference !== ''),
|
|
9367
|
+
...this.collectConditionValues(this.editorRules)
|
|
9198
9368
|
];
|
|
9199
9369
|
const nextId = references.reduce((maxId, reference) => {
|
|
9200
9370
|
const match = reference.match(/^temp_(\d+)$/);
|
|
@@ -9206,18 +9376,17 @@ class UicRuleBuilderComponent {
|
|
|
9206
9376
|
this.nextTemporalConditionId = nextId + 1;
|
|
9207
9377
|
}
|
|
9208
9378
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UicRuleBuilderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9209
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: UicRuleBuilderComponent, isStandalone: true, selector: "ui-rule-builder", inputs: { conditions: "conditions", conditionOperators: "conditionOperators", conditionFields: "conditionFields", title: "title",
|
|
9379
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: UicRuleBuilderComponent, isStandalone: true, selector: "ui-rule-builder", inputs: { conditions: "conditions", conditionOperators: "conditionOperators", conditionFields: "conditionFields", title: "title", ruleDefinition: "ruleDefinition" }, outputs: { ruleDefinitionChange: "ruleDefinitionChange", conditionsChange: "conditionsChange" }, ngImport: i0, template: "\r\n<div class=\"rule-tools\">\r\n <h3>\r\n {{resolvedTitle}}\r\n </h3>\r\n @if (editing) {\r\n <ui-button [tip]=\"'rule_builder.add_rule_tip' | uicTranslate\" (click)=\"addRule()\" size=\"s\" type=\"bordered\" icon=\"ri-add-line\">{{'rule_builder.add_rule' | uicTranslate}}</ui-button>\r\n <ui-button [tip]=\"'rule_builder.add_group_tip' | uicTranslate\" (click)=\"addGroup()\" size=\"s\" type=\"bordered\" icon=\"ri-add-line\">{{'rule_builder.add_group' | uicTranslate}}</ui-button>\r\n }@else {\r\n <ui-button [tip]=\"'rule_builder.edit_tip' | uicTranslate\" (click)=\"editing=true\" size=\"s\" type=\"bordered\" icon=\"ri-edit-line\">{{'rule_builder.edit' | uicTranslate}}</ui-button>\r\n }\r\n</div>\r\n<div class=\"rule-container\" [class.focused-box]=\"editing\">\r\n <div class=\"rule-container-workspace\">\r\n @if (editing) {\r\n <ng-container\r\n *ngTemplateOutlet=\"rulesTemplate; context: { rules: editorRules, isGroup: false }\">\r\n </ng-container>\r\n } @else {\r\n <ng-container *ngTemplateOutlet=\"readOnlyTemplate\"></ng-container>\r\n }\r\n @if (editorRules.length==0) {\r\n <div class=\"empty-rule-msg\">{{'rule_builder.no_rules' | uicTranslate}}</div>\r\n }\r\n </div>\r\n @if (editing) {\r\n <div class=\"rule-btns\">\r\n <ui-button color=\"black\" type=\"bordered\" [tip]=\"'rule_builder.reset_tip' | uicTranslate\" (click)=\"reset()\" >{{'rule_builder.reset' | uicTranslate}}</ui-button>\r\n <ui-button color=\"black\" [tip]=\"'rule_builder.save_tip' | uicTranslate\" (click)=\"print()\">{{'rule_builder.save' | uicTranslate}}</ui-button>\r\n </div>\r\n }\r\n</div>\r\n\r\n<ng-template #rulesTemplate let-rules=\"rules\" let-isGroup=\"isGroup\">\r\n @for (rule of rules; track $index; let i = $index) {\r\n @if (rule.type === 'condition') {\r\n <div class=\"rule-condition\" [class.rule-unsaved]=\"rule.unsaved\">\r\n <div [tip]=\"'rule_builder.edit_condition_tip' | uicTranslate\" (click)=\"manageRules(rules, i)\">\r\n <div class=\"condition-box\" [class.condition-box-empty]=\"rule.value == null || rule.value === ''\">{{ rule.value == null || rule.value === '' ? ('rule_builder.select_condition' | uicTranslate) : (conditionLabels[rule.value] || rule.value) }}</div>\r\n </div>\r\n <ui-button [tip]=\"'rule_builder.delete_rule_tip' | uicTranslate\" (click)=\"removeRule(rules, i)\" [iconOnly]=\"true\" size=\"s\" type=\"ghost\" icon=\"ri-delete-bin-line\" color=\"red\"></ui-button>\r\n </div>\r\n }\r\n @if (rule.type === 'operator') {\r\n <div [tip]=\"'rule_builder.toggle_operator_tip' | uicTranslate\"\r\n (click)=\"changeOperator(rules, i)\"\r\n class=\"rule-operator {{rule.value === 'AND' ? 'op-and' : 'op-or'}}\">\r\n {{ getOperatorLabel(rule.value) }}\r\n </div>\r\n }\r\n @if (rule.type === 'group') {\r\n <div class=\"rule-groups\" [class.rule-unsaved]=\"rule.unsaved\">\r\n <div class=\"rule-groups-tools\">\r\n <ui-button [tip]=\"'rule_builder.add_rule_tip' | uicTranslate\" (click)=\"addRule(rule.rules ?? [])\" size=\"s\" type=\"bordered\" icon=\"ri-add-line\">{{'rule_builder.add_rule' | uicTranslate}}</ui-button>\r\n <ui-button [tip]=\"'rule_builder.add_group_tip' | uicTranslate\" (click)=\"addGroup(rule.rules ?? [])\" size=\"s\" type=\"bordered\" icon=\"ri-add-line\">{{'rule_builder.add_group' | uicTranslate}}</ui-button>\r\n <ui-button [tip]=\"'rule_builder.delete_group_tip' | uicTranslate\" (click)=\"removeRule(rules, i)\" [iconOnly]=\"true\" size=\"s\" type=\"ghost\" icon=\"ri-delete-bin-line\" color=\"red\"></ui-button>\r\n </div>\r\n <div class=\"rule-groups-items\">\r\n <ng-container\r\n *ngTemplateOutlet=\"rulesTemplate; context: { rules: rule.rules ?? [], isGroup: true }\">\r\n </ng-container>\r\n </div>\r\n </div>\r\n }\r\n }\r\n</ng-template>\r\n\r\n<ng-template #readOnlyTemplate>\r\n @if (editorRules.length > 0) {\r\n <div class=\"rule-friendly-output\">\r\n <ng-container\r\n *ngTemplateOutlet=\"readOnlyRulesTemplate; context: { rules: editorRules, isGroup: false }\">\r\n </ng-container>\r\n </div>\r\n }\r\n</ng-template>\r\n\r\n<ng-template #readOnlyRulesTemplate let-rules=\"rules\" let-isGroup=\"isGroup\">\r\n <div class=\"readonly\">\r\n @if (isGroup) {\r\n <div class=\"readonly-group\">(</div>\r\n }\r\n \r\n @for (rule of rules; track $index) {\n @if (rule.type === 'condition') {\n <div class=\"readonly-condition\" [tip]=\"getConditionDetailTip(rule.value)\">{{ getConditionLabel(rule.value) }}</div>\n }\n \r\n @if (rule.type === 'operator') {\r\n <div class=\"readonly-operator\">{{ getOperatorLabel(rule.value) }}</div>\r\n }\r\n \r\n @if (rule.type === 'group') {\r\n <div class=\"readonly-group\">\r\n <ng-container\r\n *ngTemplateOutlet=\"readOnlyRulesTemplate; context: { rules: rule.rules ?? [], isGroup: true }\">\r\n </ng-container>\r\n </div>\r\n }\r\n }\r\n \r\n @if (isGroup) {\r\n <div class=\"readonly-group\">)</div>\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: [".rule-tools{display:flex;gap:5px;align-items:center;padding:5px;margin-bottom:5px;justify-content:flex-end}.rule-tools>h3{flex:1 1}.rule-container{padding:5px;border-top:solid 1px var(--grey-300)}.rule-container-workspace{display:flex;align-items:center;flex-wrap:wrap;gap:10px;padding:10px;margin-bottom:10px}.rule-groups{background-color:var(--grey-50);border:solid 1px var(--grey-300);overflow:hidden;border-radius:10px}.rule-groups-tools{display:flex;border-bottom:solid 1px var(--grey-300);background-color:var(--grey-200);gap:5px;padding:5px;justify-content:flex-end}.rule-groups-items{display:flex;padding:5px;align-items:center;gap:10px;flex-wrap:wrap}.rule-condition{padding:5px;border:solid 1px var(--grey-300);border-radius:10px;background-color:#fff;font-size:14px;display:flex;gap:5px;align-items:center}.rule-condition ui-select{min-width:100px}.rule-operator{padding:5px;border-radius:10px;font-size:13px;cursor:pointer;-webkit-user-select:none;user-select:none}.op-or{background-color:var(--red-100);color:var(--red-600)}.op-or:hover{background-color:var(--red-200)}.op-and{background-color:var(--green-100);color:var(--green-700)}.op-and:hover{background-color:var(--green-200)}.rule-btns{border-top:solid 1px var(--grey-300);display:flex;justify-content:flex-end;gap:10px;padding:5px;margin-top:5px}.empty-rule-msg{padding:10px;font-size:13px;text-align:center;width:100%;color:var(--grey-400)}.focused-box{border:solid 1px var(--primary-400);border-radius:10px;box-shadow:0 0 0 3px var(--secondary-alpha)}.rule-unsaved{border-color:var(--yellow-300)!important}.condition-box{font-size:14px;padding:5px 15px;color:var(--blue-700);border:solid 1px var(--blue-500);background-color:var(--blue-100);transition:background-color ease .2s;border-radius:10px;cursor:pointer}.condition-box:hover{background-color:var(--blue-200)}.condition-box-empty{color:var(--red-800);border-color:var(--red-400);background:linear-gradient(135deg,var(--red-100) 0%,#ffdede 100%);box-shadow:inset 0 0 0 1px #b91c1c14}.condition-box-empty:hover{background:linear-gradient(135deg,var(--red-200) 0%,#ffcaca 100%)}.readonly{display:flex;gap:5px;align-items:center}.readonly-condition{font-size:13px;background-color:var(--blue-100);padding:4px 8px;color:var(--blue-800);border-radius:5px;font-weight:400}.readonly-operator{font-size:12px;font-weight:500;color:var(--grey-500)}.readonly-group{font-weight:600;color:var(--red-500)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: UicButtonComponent, selector: "ui-button", inputs: ["text", "icon", "rightIcon", "iconOnly", "disabled", "loading", "size", "type", "color"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: UicToolTipDirective, selector: "[tip]", inputs: ["tip"] }, { kind: "pipe", type: UicTranslatePipe, name: "uicTranslate" }] });
|
|
9210
9380
|
}
|
|
9211
9381
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UicRuleBuilderComponent, decorators: [{
|
|
9212
9382
|
type: Component,
|
|
9213
9383
|
args: [{ selector: 'ui-rule-builder', imports: [
|
|
9214
9384
|
CommonModule,
|
|
9215
9385
|
UicButtonComponent,
|
|
9216
|
-
UicSelectComponent,
|
|
9217
9386
|
FormsModule,
|
|
9218
9387
|
UicToolTipDirective,
|
|
9219
9388
|
UicTranslatePipe
|
|
9220
|
-
], template: "<div class=\"rule-tools\">\r\n <h3>\r\n {{resolvedTitle}}\r\n </h3>\r\n @if (editing) {\r\n <ui-button [tip]=\"'rule_builder.add_rule_tip' | uicTranslate\" (click)=\"addRule()\" size=\"s\" type=\"bordered\" icon=\"ri-add-line\">{{'rule_builder.add_rule' | uicTranslate}}</ui-button>\r\n <ui-button [tip]=\"'rule_builder.add_group_tip' | uicTranslate\" (click)=\"addGroup()\" size=\"s\" type=\"bordered\" icon=\"ri-add-line\">{{'rule_builder.add_group' | uicTranslate}}</ui-button>\r\n }@else {\r\n <ui-button [tip]=\"'rule_builder.edit_tip' | uicTranslate\" (click)=\"editing=true\" size=\"s\" type=\"bordered\" icon=\"ri-edit-line\">{{'rule_builder.edit' | uicTranslate}}</ui-button>\r\n }\r\n</div>\r\n<div class=\"rule-container\" [class.focused-box]=\"editing\">\r\n <div class=\"rule-container-workspace\">\r\n @if (editing) {\r\n <ng-container\r\n *ngTemplateOutlet=\"rulesTemplate; context: { rules:
|
|
9389
|
+
], template: "\r\n<div class=\"rule-tools\">\r\n <h3>\r\n {{resolvedTitle}}\r\n </h3>\r\n @if (editing) {\r\n <ui-button [tip]=\"'rule_builder.add_rule_tip' | uicTranslate\" (click)=\"addRule()\" size=\"s\" type=\"bordered\" icon=\"ri-add-line\">{{'rule_builder.add_rule' | uicTranslate}}</ui-button>\r\n <ui-button [tip]=\"'rule_builder.add_group_tip' | uicTranslate\" (click)=\"addGroup()\" size=\"s\" type=\"bordered\" icon=\"ri-add-line\">{{'rule_builder.add_group' | uicTranslate}}</ui-button>\r\n }@else {\r\n <ui-button [tip]=\"'rule_builder.edit_tip' | uicTranslate\" (click)=\"editing=true\" size=\"s\" type=\"bordered\" icon=\"ri-edit-line\">{{'rule_builder.edit' | uicTranslate}}</ui-button>\r\n }\r\n</div>\r\n<div class=\"rule-container\" [class.focused-box]=\"editing\">\r\n <div class=\"rule-container-workspace\">\r\n @if (editing) {\r\n <ng-container\r\n *ngTemplateOutlet=\"rulesTemplate; context: { rules: editorRules, isGroup: false }\">\r\n </ng-container>\r\n } @else {\r\n <ng-container *ngTemplateOutlet=\"readOnlyTemplate\"></ng-container>\r\n }\r\n @if (editorRules.length==0) {\r\n <div class=\"empty-rule-msg\">{{'rule_builder.no_rules' | uicTranslate}}</div>\r\n }\r\n </div>\r\n @if (editing) {\r\n <div class=\"rule-btns\">\r\n <ui-button color=\"black\" type=\"bordered\" [tip]=\"'rule_builder.reset_tip' | uicTranslate\" (click)=\"reset()\" >{{'rule_builder.reset' | uicTranslate}}</ui-button>\r\n <ui-button color=\"black\" [tip]=\"'rule_builder.save_tip' | uicTranslate\" (click)=\"print()\">{{'rule_builder.save' | uicTranslate}}</ui-button>\r\n </div>\r\n }\r\n</div>\r\n\r\n<ng-template #rulesTemplate let-rules=\"rules\" let-isGroup=\"isGroup\">\r\n @for (rule of rules; track $index; let i = $index) {\r\n @if (rule.type === 'condition') {\r\n <div class=\"rule-condition\" [class.rule-unsaved]=\"rule.unsaved\">\r\n <div [tip]=\"'rule_builder.edit_condition_tip' | uicTranslate\" (click)=\"manageRules(rules, i)\">\r\n <div class=\"condition-box\" [class.condition-box-empty]=\"rule.value == null || rule.value === ''\">{{ rule.value == null || rule.value === '' ? ('rule_builder.select_condition' | uicTranslate) : (conditionLabels[rule.value] || rule.value) }}</div>\r\n </div>\r\n <ui-button [tip]=\"'rule_builder.delete_rule_tip' | uicTranslate\" (click)=\"removeRule(rules, i)\" [iconOnly]=\"true\" size=\"s\" type=\"ghost\" icon=\"ri-delete-bin-line\" color=\"red\"></ui-button>\r\n </div>\r\n }\r\n @if (rule.type === 'operator') {\r\n <div [tip]=\"'rule_builder.toggle_operator_tip' | uicTranslate\"\r\n (click)=\"changeOperator(rules, i)\"\r\n class=\"rule-operator {{rule.value === 'AND' ? 'op-and' : 'op-or'}}\">\r\n {{ getOperatorLabel(rule.value) }}\r\n </div>\r\n }\r\n @if (rule.type === 'group') {\r\n <div class=\"rule-groups\" [class.rule-unsaved]=\"rule.unsaved\">\r\n <div class=\"rule-groups-tools\">\r\n <ui-button [tip]=\"'rule_builder.add_rule_tip' | uicTranslate\" (click)=\"addRule(rule.rules ?? [])\" size=\"s\" type=\"bordered\" icon=\"ri-add-line\">{{'rule_builder.add_rule' | uicTranslate}}</ui-button>\r\n <ui-button [tip]=\"'rule_builder.add_group_tip' | uicTranslate\" (click)=\"addGroup(rule.rules ?? [])\" size=\"s\" type=\"bordered\" icon=\"ri-add-line\">{{'rule_builder.add_group' | uicTranslate}}</ui-button>\r\n <ui-button [tip]=\"'rule_builder.delete_group_tip' | uicTranslate\" (click)=\"removeRule(rules, i)\" [iconOnly]=\"true\" size=\"s\" type=\"ghost\" icon=\"ri-delete-bin-line\" color=\"red\"></ui-button>\r\n </div>\r\n <div class=\"rule-groups-items\">\r\n <ng-container\r\n *ngTemplateOutlet=\"rulesTemplate; context: { rules: rule.rules ?? [], isGroup: true }\">\r\n </ng-container>\r\n </div>\r\n </div>\r\n }\r\n }\r\n</ng-template>\r\n\r\n<ng-template #readOnlyTemplate>\r\n @if (editorRules.length > 0) {\r\n <div class=\"rule-friendly-output\">\r\n <ng-container\r\n *ngTemplateOutlet=\"readOnlyRulesTemplate; context: { rules: editorRules, isGroup: false }\">\r\n </ng-container>\r\n </div>\r\n }\r\n</ng-template>\r\n\r\n<ng-template #readOnlyRulesTemplate let-rules=\"rules\" let-isGroup=\"isGroup\">\r\n <div class=\"readonly\">\r\n @if (isGroup) {\r\n <div class=\"readonly-group\">(</div>\r\n }\r\n \r\n @for (rule of rules; track $index) {\n @if (rule.type === 'condition') {\n <div class=\"readonly-condition\" [tip]=\"getConditionDetailTip(rule.value)\">{{ getConditionLabel(rule.value) }}</div>\n }\n \r\n @if (rule.type === 'operator') {\r\n <div class=\"readonly-operator\">{{ getOperatorLabel(rule.value) }}</div>\r\n }\r\n \r\n @if (rule.type === 'group') {\r\n <div class=\"readonly-group\">\r\n <ng-container\r\n *ngTemplateOutlet=\"readOnlyRulesTemplate; context: { rules: rule.rules ?? [], isGroup: true }\">\r\n </ng-container>\r\n </div>\r\n }\r\n }\r\n \r\n @if (isGroup) {\r\n <div class=\"readonly-group\">)</div>\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: [".rule-tools{display:flex;gap:5px;align-items:center;padding:5px;margin-bottom:5px;justify-content:flex-end}.rule-tools>h3{flex:1 1}.rule-container{padding:5px;border-top:solid 1px var(--grey-300)}.rule-container-workspace{display:flex;align-items:center;flex-wrap:wrap;gap:10px;padding:10px;margin-bottom:10px}.rule-groups{background-color:var(--grey-50);border:solid 1px var(--grey-300);overflow:hidden;border-radius:10px}.rule-groups-tools{display:flex;border-bottom:solid 1px var(--grey-300);background-color:var(--grey-200);gap:5px;padding:5px;justify-content:flex-end}.rule-groups-items{display:flex;padding:5px;align-items:center;gap:10px;flex-wrap:wrap}.rule-condition{padding:5px;border:solid 1px var(--grey-300);border-radius:10px;background-color:#fff;font-size:14px;display:flex;gap:5px;align-items:center}.rule-condition ui-select{min-width:100px}.rule-operator{padding:5px;border-radius:10px;font-size:13px;cursor:pointer;-webkit-user-select:none;user-select:none}.op-or{background-color:var(--red-100);color:var(--red-600)}.op-or:hover{background-color:var(--red-200)}.op-and{background-color:var(--green-100);color:var(--green-700)}.op-and:hover{background-color:var(--green-200)}.rule-btns{border-top:solid 1px var(--grey-300);display:flex;justify-content:flex-end;gap:10px;padding:5px;margin-top:5px}.empty-rule-msg{padding:10px;font-size:13px;text-align:center;width:100%;color:var(--grey-400)}.focused-box{border:solid 1px var(--primary-400);border-radius:10px;box-shadow:0 0 0 3px var(--secondary-alpha)}.rule-unsaved{border-color:var(--yellow-300)!important}.condition-box{font-size:14px;padding:5px 15px;color:var(--blue-700);border:solid 1px var(--blue-500);background-color:var(--blue-100);transition:background-color ease .2s;border-radius:10px;cursor:pointer}.condition-box:hover{background-color:var(--blue-200)}.condition-box-empty{color:var(--red-800);border-color:var(--red-400);background:linear-gradient(135deg,var(--red-100) 0%,#ffdede 100%);box-shadow:inset 0 0 0 1px #b91c1c14}.condition-box-empty:hover{background:linear-gradient(135deg,var(--red-200) 0%,#ffcaca 100%)}.readonly{display:flex;gap:5px;align-items:center}.readonly-condition{font-size:13px;background-color:var(--blue-100);padding:4px 8px;color:var(--blue-800);border-radius:5px;font-weight:400}.readonly-operator{font-size:12px;font-weight:500;color:var(--grey-500)}.readonly-group{font-weight:600;color:var(--red-500)}\n"] }]
|
|
9221
9390
|
}], propDecorators: { conditions: [{
|
|
9222
9391
|
type: Input
|
|
9223
9392
|
}], conditionOperators: [{
|
|
@@ -9226,10 +9395,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
|
|
|
9226
9395
|
type: Input
|
|
9227
9396
|
}], title: [{
|
|
9228
9397
|
type: Input
|
|
9229
|
-
}],
|
|
9398
|
+
}], ruleDefinition: [{
|
|
9230
9399
|
type: Input
|
|
9231
9400
|
}], ruleDefinitionChange: [{
|
|
9232
9401
|
type: Output
|
|
9402
|
+
}], conditionsChange: [{
|
|
9403
|
+
type: Output
|
|
9233
9404
|
}] } });
|
|
9234
9405
|
|
|
9235
9406
|
class FirstCapitalPipe {
|