ngx-t-forms 2.0.31 → 2.0.32
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/{ngx-t-forms-auto-complete-input-element.component-DCKuXHAW.mjs → ngx-t-forms-auto-complete-input-element.component-CaXs4561.mjs} +2 -2
- package/fesm2022/{ngx-t-forms-auto-complete-input-element.component-DCKuXHAW.mjs.map → ngx-t-forms-auto-complete-input-element.component-CaXs4561.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-basic-input-input-element.component-Ce4ipSUc.mjs → ngx-t-forms-basic-input-input-element.component-Dotyd-Qs.mjs} +3 -3
- package/fesm2022/{ngx-t-forms-basic-input-input-element.component-Ce4ipSUc.mjs.map → ngx-t-forms-basic-input-input-element.component-Dotyd-Qs.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-calculated-field-rules.component-C5TPddVe.mjs → ngx-t-forms-calculated-field-rules.component-BhxT6tRq.mjs} +4 -4
- package/fesm2022/{ngx-t-forms-calculated-field-rules.component-C5TPddVe.mjs.map → ngx-t-forms-calculated-field-rules.component-BhxT6tRq.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-chip-options-creator-editor.component-CICQaqz6.mjs → ngx-t-forms-chip-options-creator-editor.component-d4QeVhsp.mjs} +4 -4
- package/fesm2022/{ngx-t-forms-chip-options-creator-editor.component-CICQaqz6.mjs.map → ngx-t-forms-chip-options-creator-editor.component-d4QeVhsp.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-config-mscoa-additional-inputs.component-CzisLSIP.mjs → ngx-t-forms-config-mscoa-additional-inputs.component-Gn8exJ9a.mjs} +2 -2
- package/fesm2022/{ngx-t-forms-config-mscoa-additional-inputs.component-CzisLSIP.mjs.map → ngx-t-forms-config-mscoa-additional-inputs.component-Gn8exJ9a.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-data-source-picker.component-Dzz_o6fJ.mjs → ngx-t-forms-data-source-picker.component-Ebf_if9j.mjs} +6 -6
- package/fesm2022/{ngx-t-forms-data-source-picker.component-Dzz_o6fJ.mjs.map → ngx-t-forms-data-source-picker.component-Ebf_if9j.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-date-picker-input-element.component-CYUbVyzP.mjs → ngx-t-forms-date-picker-input-element.component-kdinBGRA.mjs} +2 -2
- package/fesm2022/{ngx-t-forms-date-picker-input-element.component-CYUbVyzP.mjs.map → ngx-t-forms-date-picker-input-element.component-kdinBGRA.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-date-range-picker-input-element.component-CmoquQGV.mjs → ngx-t-forms-date-range-picker-input-element.component-4W6uvrDU.mjs} +2 -2
- package/fesm2022/{ngx-t-forms-date-range-picker-input-element.component-CmoquQGV.mjs.map → ngx-t-forms-date-range-picker-input-element.component-4W6uvrDU.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-document-list-label-config-editor.component-CLUOXreG.mjs → ngx-t-forms-document-list-label-config-editor.component-CR6EvgJO.mjs} +3 -3
- package/fesm2022/{ngx-t-forms-document-list-label-config-editor.component-CLUOXreG.mjs.map → ngx-t-forms-document-list-label-config-editor.component-CR6EvgJO.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-document-picker.component-qObjcqhE.mjs → ngx-t-forms-document-picker.component-BThdRFec.mjs} +2 -2
- package/fesm2022/{ngx-t-forms-document-picker.component-qObjcqhE.mjs.map → ngx-t-forms-document-picker.component-BThdRFec.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-editor-input-element.component-BLXlfb6F.mjs → ngx-t-forms-editor-input-element.component-1X6uAPeZ.mjs} +3 -3
- package/fesm2022/{ngx-t-forms-editor-input-element.component-BLXlfb6F.mjs.map → ngx-t-forms-editor-input-element.component-1X6uAPeZ.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-editor-js-input.component-BQL0AH7H.mjs → ngx-t-forms-editor-js-input.component-5MD8wRj0.mjs} +2 -2
- package/fesm2022/{ngx-t-forms-editor-js-input.component-BQL0AH7H.mjs.map → ngx-t-forms-editor-js-input.component-5MD8wRj0.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-file-upload-input-element.component-C7mMeEjF.mjs → ngx-t-forms-file-upload-input-element.component-BAtuymMY.mjs} +2 -2
- package/fesm2022/{ngx-t-forms-file-upload-input-element.component-C7mMeEjF.mjs.map → ngx-t-forms-file-upload-input-element.component-BAtuymMY.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-form-input-selector.component-C9u8zq9B.mjs → ngx-t-forms-form-input-selector.component-B42xP3jh.mjs} +2 -2
- package/fesm2022/{ngx-t-forms-form-input-selector.component-C9u8zq9B.mjs.map → ngx-t-forms-form-input-selector.component-B42xP3jh.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-form-json-view.component-856Hx1Bg.mjs → ngx-t-forms-form-json-view.component-DnnLXqR0.mjs} +2 -2
- package/fesm2022/{ngx-t-forms-form-json-view.component-856Hx1Bg.mjs.map → ngx-t-forms-form-json-view.component-DnnLXqR0.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-form-payload-projection.component-CDkTuX9S.mjs → ngx-t-forms-form-payload-projection.component-Ip9ewB18.mjs} +4 -4
- package/fesm2022/{ngx-t-forms-form-payload-projection.component-CDkTuX9S.mjs.map → ngx-t-forms-form-payload-projection.component-Ip9ewB18.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-form-section-stepper.component-Bs50-nEB.mjs → ngx-t-forms-form-section-stepper.component-BPgPfZSy.mjs} +4 -4
- package/fesm2022/{ngx-t-forms-form-section-stepper.component-Bs50-nEB.mjs.map → ngx-t-forms-form-section-stepper.component-BPgPfZSy.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-forms-builder-menu.component-qrhM0jGL.mjs → ngx-t-forms-forms-builder-menu.component-Dv0Dfw79.mjs} +5 -5
- package/fesm2022/{ngx-t-forms-forms-builder-menu.component-qrhM0jGL.mjs.map → ngx-t-forms-forms-builder-menu.component-Dv0Dfw79.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-geo-location.component-Bosp1UzR.mjs → ngx-t-forms-geo-location.component-Bmd84Gcb.mjs} +2 -2
- package/fesm2022/{ngx-t-forms-geo-location.component-Bosp1UzR.mjs.map → ngx-t-forms-geo-location.component-Bmd84Gcb.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-image-capture-input-element.component-C1g7Z0cK.mjs → ngx-t-forms-image-capture-input-element.component-CUd04Ghl.mjs} +2 -2
- package/fesm2022/{ngx-t-forms-image-capture-input-element.component-C1g7Z0cK.mjs.map → ngx-t-forms-image-capture-input-element.component-CUd04Ghl.mjs.map} +1 -1
- package/fesm2022/ngx-t-forms-index-BcrQ01DQ.mjs +2 -0
- package/fesm2022/ngx-t-forms-index-BcrQ01DQ.mjs.map +1 -0
- package/fesm2022/{ngx-t-forms-input-custom.component-BkbHFAyR.mjs → ngx-t-forms-input-custom.component-Cn-KH0Lb.mjs} +2 -2
- package/fesm2022/{ngx-t-forms-input-custom.component-BkbHFAyR.mjs.map → ngx-t-forms-input-custom.component-Cn-KH0Lb.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-input-editor.component-BPUOM9kQ.mjs → ngx-t-forms-input-editor.component-DLru1Ezu.mjs} +17 -5
- package/fesm2022/ngx-t-forms-input-editor.component-DLru1Ezu.mjs.map +1 -0
- package/fesm2022/{ngx-t-forms-map-mat-options-keys-B6hJ7Io5.mjs → ngx-t-forms-map-mat-options-keys-CVlPdrCO.mjs} +2 -2
- package/fesm2022/{ngx-t-forms-map-mat-options-keys-B6hJ7Io5.mjs.map → ngx-t-forms-map-mat-options-keys-CVlPdrCO.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-mat-chip-list-editor.component-c7uZT1sr.mjs → ngx-t-forms-mat-chip-list-editor.component-BWisS3Em.mjs} +4 -4
- package/fesm2022/{ngx-t-forms-mat-chip-list-editor.component-c7uZT1sr.mjs.map → ngx-t-forms-mat-chip-list-editor.component-BWisS3Em.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-missing-form-configs.component-DrnH8qdG.mjs → ngx-t-forms-missing-form-configs.component-DxdynZY6.mjs} +2 -2
- package/fesm2022/{ngx-t-forms-missing-form-configs.component-DrnH8qdG.mjs.map → ngx-t-forms-missing-form-configs.component-DxdynZY6.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-mscoa-chart-toolbar.component-C_abEBQ5.mjs → ngx-t-forms-mscoa-chart-toolbar.component-D4Xa_Yi0.mjs} +2 -2
- package/fesm2022/{ngx-t-forms-mscoa-chart-toolbar.component-C_abEBQ5.mjs.map → ngx-t-forms-mscoa-chart-toolbar.component-D4Xa_Yi0.mjs.map} +1 -1
- package/fesm2022/ngx-t-forms-mscoa-segment-config.component-Bo0aDEMy.mjs +447 -0
- package/fesm2022/ngx-t-forms-mscoa-segment-config.component-Bo0aDEMy.mjs.map +1 -0
- package/fesm2022/{ngx-t-forms-multiple-input-input-element.component-C7y1OGPx.mjs → ngx-t-forms-multiple-input-input-element.component-C8JP3D6r.mjs} +16 -16
- package/fesm2022/{ngx-t-forms-multiple-input-input-element.component-C7y1OGPx.mjs.map → ngx-t-forms-multiple-input-input-element.component-C8JP3D6r.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-ngx-t-forms-u_kigDid.mjs → ngx-t-forms-ngx-t-forms-C2G8_WQk.mjs} +931 -82
- package/fesm2022/ngx-t-forms-ngx-t-forms-C2G8_WQk.mjs.map +1 -0
- package/fesm2022/{ngx-t-forms-paginated-selection-table-AQZSMmhr.mjs → ngx-t-forms-paginated-selection-table-0OI1ikWW.mjs} +2 -2
- package/fesm2022/{ngx-t-forms-paginated-selection-table-AQZSMmhr.mjs.map → ngx-t-forms-paginated-selection-table-0OI1ikWW.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-pipeline-generator.component-DmNSc5aw.mjs → ngx-t-forms-pipeline-generator.component-CZ21sd77.mjs} +3 -3
- package/fesm2022/{ngx-t-forms-pipeline-generator.component-DmNSc5aw.mjs.map → ngx-t-forms-pipeline-generator.component-CZ21sd77.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-record-list-manager.component-CUMMvMch.mjs → ngx-t-forms-record-list-manager.component-CykBq_nW.mjs} +2 -2
- package/fesm2022/{ngx-t-forms-record-list-manager.component-CUMMvMch.mjs.map → ngx-t-forms-record-list-manager.component-CykBq_nW.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-required-inputs.component-Ch2yNcIS.mjs → ngx-t-forms-required-inputs.component-ONbhxVSH.mjs} +2 -2
- package/fesm2022/{ngx-t-forms-required-inputs.component-Ch2yNcIS.mjs.map → ngx-t-forms-required-inputs.component-ONbhxVSH.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-rest-api-call-setup.component-C_aFtdvW.mjs → ngx-t-forms-rest-api-call-setup.component-WPUxtY7Q.mjs} +2 -2
- package/fesm2022/{ngx-t-forms-rest-api-call-setup.component-C_aFtdvW.mjs.map → ngx-t-forms-rest-api-call-setup.component-WPUxtY7Q.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-section-report.component-BxOhR6C0.mjs → ngx-t-forms-section-report.component-C1w16LYm.mjs} +4 -4
- package/fesm2022/{ngx-t-forms-section-report.component-BxOhR6C0.mjs.map → ngx-t-forms-section-report.component-C1w16LYm.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-select-input-element.component-DbgZdNoe.mjs → ngx-t-forms-select-input-element.component-CWcywuS6.mjs} +8 -8
- package/fesm2022/{ngx-t-forms-select-input-element.component-DbgZdNoe.mjs.map → ngx-t-forms-select-input-element.component-CWcywuS6.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-selection-options-editor.component-Dhln81DL.mjs → ngx-t-forms-selection-options-editor.component-KjbZhc2u.mjs} +4 -4
- package/fesm2022/{ngx-t-forms-selection-options-editor.component-Dhln81DL.mjs.map → ngx-t-forms-selection-options-editor.component-KjbZhc2u.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-t-workflow-picker.component-leBokXvM.mjs → ngx-t-forms-t-workflow-picker.component-CtavFAUq.mjs} +3 -3
- package/fesm2022/{ngx-t-forms-t-workflow-picker.component-leBokXvM.mjs.map → ngx-t-forms-t-workflow-picker.component-CtavFAUq.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-textarea-input-element.component-BEbXJjFA.mjs → ngx-t-forms-textarea-input-element.component-DkJkBQif.mjs} +2 -2
- package/fesm2022/{ngx-t-forms-textarea-input-element.component-BEbXJjFA.mjs.map → ngx-t-forms-textarea-input-element.component-DkJkBQif.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-toggle-input-element.component-DDErRUJd.mjs → ngx-t-forms-toggle-input-element.component-Dr7MNli8.mjs} +2 -2
- package/fesm2022/{ngx-t-forms-toggle-input-element.component-DDErRUJd.mjs.map → ngx-t-forms-toggle-input-element.component-Dr7MNli8.mjs.map} +1 -1
- package/fesm2022/{ngx-t-forms-validators-config.component-oGjQVGE2.mjs → ngx-t-forms-validators-config.component-BknyAmV_.mjs} +8 -167
- package/fesm2022/ngx-t-forms-validators-config.component-BknyAmV_.mjs.map +1 -0
- package/fesm2022/{ngx-t-forms-workflow-adjudication.component-CtU8dECN.mjs → ngx-t-forms-workflow-adjudication.component-CPvwm7f4.mjs} +3 -3
- package/fesm2022/{ngx-t-forms-workflow-adjudication.component-CtU8dECN.mjs.map → ngx-t-forms-workflow-adjudication.component-CPvwm7f4.mjs.map} +1 -1
- package/fesm2022/ngx-t-forms.mjs +1 -1
- package/package.json +2 -2
- package/types/ngx-t-forms.d.ts +191 -4
- package/fesm2022/ngx-t-forms-index-dDSobs6A.mjs +0 -2
- package/fesm2022/ngx-t-forms-index-dDSobs6A.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-input-editor.component-BPUOM9kQ.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-mscoa-segment-config.component-C0qsMfsq.mjs +0 -336
- package/fesm2022/ngx-t-forms-mscoa-segment-config.component-C0qsMfsq.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-ngx-t-forms-u_kigDid.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-validators-config.component-oGjQVGE2.mjs.map +0 -1
package/fesm2022/{ngx-t-forms-ngx-t-forms-u_kigDid.mjs → ngx-t-forms-ngx-t-forms-C2G8_WQk.mjs}
RENAMED
|
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
|
|
|
2
2
|
import { InjectionToken, computed, runInInjectionContext, effect, untracked, linkedSignal, resource, inject, Injector, ApplicationRef, signal, Inject, Directive, Injectable, DestroyRef, makeEnvironmentProviders, Pipe, PLATFORM_ID, ChangeDetectionStrategy, Component, input, viewChild, NgZone, output, model, Optional, ViewEncapsulation, NgModule, ChangeDetectorRef, Input, Self, ElementRef } from '@angular/core';
|
|
3
3
|
import { toSignal, toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
4
4
|
import { validateForm, getElementEditorConfig, ElementEditorTypes, AllFormInputPrimaryKeys, DefaultInputConfig, SpecialElementKeys, validateFormColumnInputsWithRequired, ElementTypes, validateFormSlide, FormListSection, DataSources, formColumnInputsSchema, CalculationFunctions, InputTypes, WorkflowFunctionTypes, validateCalculatedFieldRules, FormSubmissionStatus, InputDataTypes, AdjudicationSteps, InputPipeTypes, RichTextEditorType, OptionSelectTypes, MinInputTypes, FormStateErrors, BlurHandleTypes, FunctionTypes as FunctionTypes$2 } from 'ngx-t-forms-types';
|
|
5
|
-
import { of, throwError, take, forkJoin, map as map$1, catchError as catchError$1, EMPTY, tap, switchMap, filter, firstValueFrom, from, concatMap, last, Subject, takeUntil, Subscription, timeout, Observable, BehaviorSubject, shareReplay, concat, finalize, distinctUntilChanged, isObservable, timer, debounceTime, combineLatest, merge, withLatestFrom } from 'rxjs';
|
|
5
|
+
import { of, throwError, take, forkJoin, map as map$1, catchError as catchError$1, EMPTY, tap, switchMap, filter, firstValueFrom, from, concatMap, last, Subject, takeUntil, Subscription, timeout, Observable, BehaviorSubject, shareReplay, concat, finalize, distinctUntilChanged, isObservable, timer, debounceTime, combineLatest, merge, withLatestFrom, startWith as startWith$1 } from 'rxjs';
|
|
6
6
|
import { catchError, map, switchMap as switchMap$1, startWith, debounceTime as debounceTime$1, distinctUntilChanged as distinctUntilChanged$1, shareReplay as shareReplay$1, tap as tap$1, finalize as finalize$1 } from 'rxjs/operators';
|
|
7
7
|
import * as i1$1 from '@angular/forms';
|
|
8
8
|
import { Validators, FormControl, FormGroup, FormArray, FormsModule, ReactiveFormsModule, NgControl } from '@angular/forms';
|
|
@@ -70,9 +70,9 @@ import { CdkStepperModule } from '@angular/cdk/stepper';
|
|
|
70
70
|
import { CdkTableModule } from '@angular/cdk/table';
|
|
71
71
|
import { MatBadgeModule } from '@angular/material/badge';
|
|
72
72
|
import { MatBottomSheetModule } from '@angular/material/bottom-sheet';
|
|
73
|
-
import * as
|
|
73
|
+
import * as i3$5 from '@angular/material/button-toggle';
|
|
74
74
|
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
|
75
|
-
import * as
|
|
75
|
+
import * as i4$3 from '@angular/material/chips';
|
|
76
76
|
import { MatChipsModule } from '@angular/material/chips';
|
|
77
77
|
import { MatDatepickerModule } from '@angular/material/datepicker';
|
|
78
78
|
import { MatGridListModule } from '@angular/material/grid-list';
|
|
@@ -85,7 +85,7 @@ import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
|
|
85
85
|
import * as i10 from '@angular/material/sort';
|
|
86
86
|
import { MatSortModule, MatSort } from '@angular/material/sort';
|
|
87
87
|
import { MatTabsModule } from '@angular/material/tabs';
|
|
88
|
-
import * as i2$
|
|
88
|
+
import * as i2$2 from '@angular/cdk/overlay';
|
|
89
89
|
import { OverlayModule } from '@angular/cdk/overlay';
|
|
90
90
|
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
|
91
91
|
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
|
@@ -4816,13 +4816,18 @@ function _isEqual(prev, next) {
|
|
|
4816
4816
|
const nRe = next;
|
|
4817
4817
|
return pRe.source === nRe.source && pRe.flags === nRe.flags;
|
|
4818
4818
|
}
|
|
4819
|
-
|
|
4820
|
-
|
|
4819
|
+
// A present-but-`undefined` key is treated as an absent key (mirrors
|
|
4820
|
+
// `getChangedProperties` above, JSON semantics, and every idempotency
|
|
4821
|
+
// guard in the store). Without this, an audit pass that adds `vat:
|
|
4822
|
+
// undefined` to a non-VAT segment would never compare equal to the same
|
|
4823
|
+
// value after it round-trips through the form (which drops the undefined
|
|
4824
|
+
// key), and the form ⇄ store ⇄ form graph oscillates — re-firing the
|
|
4825
|
+
// debounced MSCOA validation API forever on the same payload.
|
|
4826
|
+
const prevKeys = Object.keys(prevObj).filter((key) => prevObj[key] !== undefined);
|
|
4827
|
+
const nextKeys = Object.keys(nextObj).filter((key) => nextObj[key] !== undefined);
|
|
4821
4828
|
if (prevKeys.length !== nextKeys.length)
|
|
4822
4829
|
return false;
|
|
4823
4830
|
for (const key of prevKeys) {
|
|
4824
|
-
if (!Object.prototype.hasOwnProperty.call(nextObj, key))
|
|
4825
|
-
return false;
|
|
4826
4831
|
if (!_isEqual(prevObj[key], nextObj[key]))
|
|
4827
4832
|
return false;
|
|
4828
4833
|
}
|
|
@@ -6458,7 +6463,13 @@ function buildValuePostMethodApi(input, ctx) {
|
|
|
6458
6463
|
catch {
|
|
6459
6464
|
return undefined;
|
|
6460
6465
|
}
|
|
6461
|
-
}, ...(ngDevMode ?
|
|
6466
|
+
}, { ...(ngDevMode ? { debugName: "params" } : /* istanbul ignore next */ {}),
|
|
6467
|
+
// `returnMappedData` allocates a fresh object on every recompute, and this
|
|
6468
|
+
// computed re-runs on ANY `#model` change (readDep reads the whole map).
|
|
6469
|
+
// Without structural equality the resource would treat every unrelated
|
|
6470
|
+
// value edit as a params change and reload the API. Emit only when the
|
|
6471
|
+
// mapped dependency values actually change.
|
|
6472
|
+
equal: _isEqual });
|
|
6462
6473
|
return resource({
|
|
6463
6474
|
params,
|
|
6464
6475
|
loader: async ({ params: payload }) => {
|
|
@@ -6808,7 +6819,14 @@ function buildPostComputedOptionsResource(input, ctx) {
|
|
|
6808
6819
|
}
|
|
6809
6820
|
// Build the mapped POST body.
|
|
6810
6821
|
return returnMappedData(snapshot, minInputs, fetchConfig.httpEndPoint);
|
|
6811
|
-
}, ...(ngDevMode ?
|
|
6822
|
+
}, { ...(ngDevMode ? { debugName: "paramsSignal" } : /* istanbul ignore next */ {}),
|
|
6823
|
+
// `returnMappedData` allocates a fresh object on every recompute, and this
|
|
6824
|
+
// computed re-runs on ANY `#model` change (readDep reads the whole map).
|
|
6825
|
+
// Without structural equality the resource would treat every unrelated
|
|
6826
|
+
// value edit (e.g. selecting a row in THIS field) as a params change and
|
|
6827
|
+
// reload the API — a runaway refetch loop. Emit only when the mapped
|
|
6828
|
+
// dependency values actually change.
|
|
6829
|
+
equal: _isEqual });
|
|
6812
6830
|
// Edge-tracker: a plain closure variable (NOT a signal — nothing reads it
|
|
6813
6831
|
// reactively), so the resolved-edge effect below never writes a signal.
|
|
6814
6832
|
let prevStatus = 'idle';
|
|
@@ -7392,6 +7410,16 @@ class FormTowerControllerService {
|
|
|
7392
7410
|
* `(valueChange)` binding. Torn down on close / re-open / re-init.
|
|
7393
7411
|
*/
|
|
7394
7412
|
this.#multipleInputRowSubs = new Map();
|
|
7413
|
+
/**
|
|
7414
|
+
* Live `valueChanges` bridge for mSCOA inner-input controls — the custom form
|
|
7415
|
+
* inputs configured inside an `MscoaSelection` column (e.g. `budgetValue`,
|
|
7416
|
+
* `department`) and rendered inline by the MSCOA chart through a
|
|
7417
|
+
* `ComponentPortal`. A single aggregate subscription: unlike MultipleInput
|
|
7418
|
+
* rows these inner inputs are static (created at form generation, never
|
|
7419
|
+
* toggled), so they are all bound once per init. See
|
|
7420
|
+
* {@link FormTowerControllerService.bindScoaInnerInputControls}.
|
|
7421
|
+
*/
|
|
7422
|
+
this.#scoaInnerInputSub = undefined;
|
|
7395
7423
|
// ──────────────────────────────────────────────────────────────────────────
|
|
7396
7424
|
// Overridable-validation submission gate
|
|
7397
7425
|
// ──────────────────────────────────────────────────────────────────────────
|
|
@@ -7661,6 +7689,11 @@ class FormTowerControllerService {
|
|
|
7661
7689
|
// resource sits `idle` and never fires (and `refresh`/`.reload()` no-ops
|
|
7662
7690
|
// on an idle resource) until the user manually edits the dependency.
|
|
7663
7691
|
this.#seedModelFromDefinition();
|
|
7692
|
+
// 8. Bridge mSCOA inner-input (custom form input) controls into `#model` so
|
|
7693
|
+
// their user edits drive the signal graph. They render inline via the
|
|
7694
|
+
// MSCOA chart's ComponentPortal, which has no `(valueChange)` binding of
|
|
7695
|
+
// its own — mirrors step 5's MultipleInput sub-row bridge.
|
|
7696
|
+
this.bindScoaInnerInputControls();
|
|
7664
7697
|
};
|
|
7665
7698
|
/**
|
|
7666
7699
|
* Marks the form's first slide as active. Called during
|
|
@@ -7790,8 +7823,11 @@ class FormTowerControllerService {
|
|
|
7790
7823
|
continue;
|
|
7791
7824
|
}
|
|
7792
7825
|
if (isMultipleInput) {
|
|
7793
|
-
// ── Phase 2 fence: MultipleInput array-remap branch
|
|
7794
|
-
|
|
7826
|
+
// ── Phase 2 fence: MultipleInput array-remap branch. ──
|
|
7827
|
+
// `??` only guards null/undefined; a non-array value (e.g. an object or a
|
|
7828
|
+
// JSON-string row that pre-processing left unparsed) would reach `.map` and
|
|
7829
|
+
// throw "(value ?? []).map is not a function". Coerce any non-array to [].
|
|
7830
|
+
const v = (Array.isArray(value) ? value : []).map((item) => {
|
|
7795
7831
|
return Object.entries(item).reduce((acc, [key, val]) => {
|
|
7796
7832
|
const inp = allInputs.find((i) => i.formControlName === key);
|
|
7797
7833
|
if (key === 'id') {
|
|
@@ -7868,6 +7904,13 @@ class FormTowerControllerService {
|
|
|
7868
7904
|
catch { /* best-effort */ }
|
|
7869
7905
|
}
|
|
7870
7906
|
this.#multipleInputRowSubs.clear();
|
|
7907
|
+
// Drop the mSCOA inner-input valueChanges bridge (the takeUntil anchor below
|
|
7908
|
+
// also completes its inner subs; this clears the handle).
|
|
7909
|
+
try {
|
|
7910
|
+
this.#scoaInnerInputSub?.unsubscribe();
|
|
7911
|
+
}
|
|
7912
|
+
catch { /* best-effort */ }
|
|
7913
|
+
this.#scoaInnerInputSub = undefined;
|
|
7871
7914
|
this.#definition.set(undefined);
|
|
7872
7915
|
this._mainForm = undefined;
|
|
7873
7916
|
this.#model.set({});
|
|
@@ -8027,6 +8070,54 @@ class FormTowerControllerService {
|
|
|
8027
8070
|
existing.unsubscribe();
|
|
8028
8071
|
this.#multipleInputRowSubs.delete(inputId);
|
|
8029
8072
|
};
|
|
8073
|
+
/**
|
|
8074
|
+
* Bridges live edits of mSCOA inner inputs — the custom form inputs configured
|
|
8075
|
+
* inside an `MscoaSelection` column (e.g. `budgetValue`, `department`) and
|
|
8076
|
+
* rendered inline by the MSCOA chart via a `ComponentPortal` — into the signal
|
|
8077
|
+
* graph.
|
|
8078
|
+
*
|
|
8079
|
+
* Each inner input is a `${mscoaColId}.${innerId}` control sitting in the mSCOA
|
|
8080
|
+
* column's section group. The engine already lists it in `allFormInputs`, so
|
|
8081
|
+
* its derived calc / value-API / options graph is built at init (the OUTPUT
|
|
8082
|
+
* half). But a `ComponentPortal` forwards inputs only and never subscribes the
|
|
8083
|
+
* host's `valueChange` output, so the user's typed value never reached `#model`
|
|
8084
|
+
* — leaving dependent calculations / value-fetches / options blind to it. This
|
|
8085
|
+
* subscribes each such control's `valueChanges` → `updateValue(controlName, …)`,
|
|
8086
|
+
* restoring the INPUT half so an mSCOA custom input behaves exactly like a
|
|
8087
|
+
* primary-form input. Direct mirror of
|
|
8088
|
+
* {@link FormTowerControllerService.bindMultipleInputRowControls}.
|
|
8089
|
+
*
|
|
8090
|
+
* Idempotent (tears down the prior bridge first) and anchored to `_destroyed$`,
|
|
8091
|
+
* so the re-init `clearFormState` drops every inner subscription.
|
|
8092
|
+
*/
|
|
8093
|
+
this.bindScoaInnerInputControls = () => {
|
|
8094
|
+
this.#scoaInnerInputSub?.unsubscribe();
|
|
8095
|
+
this.#scoaInnerInputSub = undefined;
|
|
8096
|
+
if (!this._mainForm)
|
|
8097
|
+
return;
|
|
8098
|
+
const mscoaColumnIds = (this.allFormInputs() ?? [])
|
|
8099
|
+
.filter(input => input.element === ElementTypes.MscoaSelection)
|
|
8100
|
+
.map(input => input.id);
|
|
8101
|
+
if (mscoaColumnIds.length === 0)
|
|
8102
|
+
return;
|
|
8103
|
+
const sub = new Subscription();
|
|
8104
|
+
for (const sectionGroup of Object.values(this._mainForm.controls)) {
|
|
8105
|
+
const group = sectionGroup;
|
|
8106
|
+
if (!group?.controls)
|
|
8107
|
+
continue;
|
|
8108
|
+
for (const [controlName, control] of Object.entries(group.controls)) {
|
|
8109
|
+
// An inner input is a `${mscoaColId}.${innerId}` sibling — never the
|
|
8110
|
+
// column control itself (no dotted suffix; the tower already bridges it
|
|
8111
|
+
// via the explicit `(valueChange)` binding on `<lib-t-form-input>`).
|
|
8112
|
+
if (!mscoaColumnIds.some(colId => controlName.startsWith(`${colId}.`)))
|
|
8113
|
+
continue;
|
|
8114
|
+
sub.add(control.valueChanges
|
|
8115
|
+
.pipe(takeUntil(this._destroyed$))
|
|
8116
|
+
.subscribe(value => this.updateValue(controlName, value)));
|
|
8117
|
+
}
|
|
8118
|
+
}
|
|
8119
|
+
this.#scoaInnerInputSub = sub;
|
|
8120
|
+
};
|
|
8030
8121
|
// ──────────────────────────────────────────────────────────────────────────
|
|
8031
8122
|
// W13 — Refresh / revert family (resource .reload() + #derived membership)
|
|
8032
8123
|
// ──────────────────────────────────────────────────────────────────────────
|
|
@@ -8170,6 +8261,16 @@ class FormTowerControllerService {
|
|
|
8170
8261
|
* `(valueChange)` binding. Torn down on close / re-open / re-init.
|
|
8171
8262
|
*/
|
|
8172
8263
|
#multipleInputRowSubs;
|
|
8264
|
+
/**
|
|
8265
|
+
* Live `valueChanges` bridge for mSCOA inner-input controls — the custom form
|
|
8266
|
+
* inputs configured inside an `MscoaSelection` column (e.g. `budgetValue`,
|
|
8267
|
+
* `department`) and rendered inline by the MSCOA chart through a
|
|
8268
|
+
* `ComponentPortal`. A single aggregate subscription: unlike MultipleInput
|
|
8269
|
+
* rows these inner inputs are static (created at form generation, never
|
|
8270
|
+
* toggled), so they are all bound once per init. See
|
|
8271
|
+
* {@link FormTowerControllerService.bindScoaInnerInputControls}.
|
|
8272
|
+
*/
|
|
8273
|
+
#scoaInnerInputSub;
|
|
8173
8274
|
// ──────────────────────────────────────────────────────────────────────────
|
|
8174
8275
|
// W7 — Getters / setters re-pointed onto the source signals
|
|
8175
8276
|
// ──────────────────────────────────────────────────────────────────────────
|
|
@@ -8284,7 +8385,16 @@ class FormTowerControllerService {
|
|
|
8284
8385
|
void debounceMs;
|
|
8285
8386
|
// One-tick liveness lead-read: force-activate resources + flush effects.
|
|
8286
8387
|
this.#forceLiveness();
|
|
8287
|
-
return firstValueFrom(toObservable(this.settled, { injector: this.#injector }).pipe(filter((isSettled) => isSettled === true), take(1), timeout(timeoutMs), catchError$1(() => of(undefined)), tap(() => undefined))).then(() =>
|
|
8388
|
+
return firstValueFrom(toObservable(this.settled, { injector: this.#injector }).pipe(filter((isSettled) => isSettled === true), take(1), timeout(timeoutMs), catchError$1(() => of(undefined)), tap(() => undefined))).then(() => {
|
|
8389
|
+
// Post-settle projection flush (headless-read guarantee). `settled === true`
|
|
8390
|
+
// only means every resource has resolved into `#value()`; the FormGroup is
|
|
8391
|
+
// patched by the async `#formProjection` effect, which may NOT have run yet —
|
|
8392
|
+
// notably for resources that resolve in a single microtask off a shared
|
|
8393
|
+
// `shareReplay` cache (import cache-hit rows). Headless consumers read
|
|
8394
|
+
// `mainForm.value` (getFormValueNames), so drain the projection effect here
|
|
8395
|
+
// before resolving, otherwise they capture the stale pre-fetch FormGroup.
|
|
8396
|
+
this.#forceLiveness();
|
|
8397
|
+
});
|
|
8288
8398
|
}
|
|
8289
8399
|
/**
|
|
8290
8400
|
* Forces the signal graph live: reads `value()` and every resource `status()`
|
|
@@ -8796,12 +8906,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
8796
8906
|
* ImportRowState { status, settledValue, isValid, validationErrors, colErrors }
|
|
8797
8907
|
* ```
|
|
8798
8908
|
*
|
|
8799
|
-
* **Concurrency strategy:**
|
|
8800
|
-
*
|
|
8801
|
-
*
|
|
8802
|
-
*
|
|
8803
|
-
*
|
|
8804
|
-
*
|
|
8909
|
+
* **Concurrency strategy:** rows are processed **sequentially** (one tower at a
|
|
8910
|
+
* time). Each tower's settle (`waitUntilSettled`) and FormGroup projection rely
|
|
8911
|
+
* on `ApplicationRef.tick()`-driven effect flushes over the application's single
|
|
8912
|
+
* shared `ApplicationRef`; running rows concurrently interleaves those ticks so
|
|
8913
|
+
* `waitUntilSettled` resolves on a spurious `settled === true` before a row's
|
|
8914
|
+
* value resources have drained + projected, leaving most rows with empty
|
|
8915
|
+
* API-derived fields. To still avoid N rows hammering the same endpoint N times,
|
|
8916
|
+
* each tower's `httpGetDataFunction` / `httpPostDataFunction` is wrapped to route
|
|
8917
|
+
* through {@link TFormImportController._cachedGet} /
|
|
8918
|
+
* {@link TFormImportController._cachedPost}, which dedupe identical requests via
|
|
8919
|
+
* `shareReplay(1)` for the lifetime of the session — so sequential rows reuse the
|
|
8920
|
+
* same in-flight/replayed network calls.
|
|
8805
8921
|
*
|
|
8806
8922
|
* **Settle model (Phase 1.5):** the signal-graph engine settles by construction —
|
|
8807
8923
|
* `waitUntilSettled` resolves once every value/options resource and calculation
|
|
@@ -8909,9 +9025,23 @@ class TFormImportController {
|
|
|
8909
9025
|
this._rows$.next(rows.map((originalData, rowIndex) => ({ rowIndex, originalData, status: 'pending' })));
|
|
8910
9026
|
const hasPreProcessInputs = form.slides.some(slide => slide.columns.some(col => this._inputPreProcessors.has(col.element)));
|
|
8911
9027
|
try {
|
|
8912
|
-
|
|
8913
|
-
|
|
8914
|
-
|
|
9028
|
+
// Rows are processed SEQUENTIALLY, not concurrently. Each row spins up its
|
|
9029
|
+
// own tower whose settle (`waitUntilSettled`) and FormGroup projection rely
|
|
9030
|
+
// on `ApplicationRef.tick()`-driven effect flushes over the application's
|
|
9031
|
+
// single shared `ApplicationRef`. Running every row concurrently makes those
|
|
9032
|
+
// ticks interleave across towers, so `waitUntilSettled` resolves on a
|
|
9033
|
+
// spurious `settled === true` (value resources still `idle`, not yet
|
|
9034
|
+
// `loading`) before a row's derived values have drained and projected —
|
|
9035
|
+
// leaving most rows with empty API-derived fields (objectives/nKPA/etc.).
|
|
9036
|
+
// The per-session HTTP caches (`_getCache`/`_postCache`/`_financialCycles$`)
|
|
9037
|
+
// still dedupe identical requests across rows, so sequential processing
|
|
9038
|
+
// reuses the same network calls without the race.
|
|
9039
|
+
for (let i = 0; i < rows.length; i++) {
|
|
9040
|
+
const row = rows[i];
|
|
9041
|
+
if (!row)
|
|
9042
|
+
continue;
|
|
9043
|
+
await this._processRow(form, row, i, hasPreProcessInputs);
|
|
9044
|
+
}
|
|
8915
9045
|
}
|
|
8916
9046
|
finally {
|
|
8917
9047
|
// Always release cached Observables — even if an unexpected error escapes
|
|
@@ -9054,6 +9184,22 @@ class TFormImportController {
|
|
|
9054
9184
|
// Phase 3 makes validation reactive over observed fields).
|
|
9055
9185
|
this._recomputeAllValidationErrors(tower.mainForm);
|
|
9056
9186
|
const settledValue = tower.getFormValueNames();
|
|
9187
|
+
// Value-derived MultipleInputs (those carrying a value-API or calculation)
|
|
9188
|
+
// have their settled value produced by the tower resource, which overrides
|
|
9189
|
+
// the import rows in the tower's value graph. Per import semantics the tower
|
|
9190
|
+
// value is FAVORED, but the import rows must fill any gap it leaves — and a
|
|
9191
|
+
// tower value that resolves to an empty array falls back entirely to the
|
|
9192
|
+
// import rows. Deep-merge (tower favored) so neither the tower's computed
|
|
9193
|
+
// fields nor import-only fields (e.g. user selections) are lost.
|
|
9194
|
+
for (const col of this._valueDerivedMultipleInputs(form)) {
|
|
9195
|
+
const fcn = col.formControlName;
|
|
9196
|
+
if (!fcn)
|
|
9197
|
+
continue;
|
|
9198
|
+
const importVal = resolvedRowData[fcn];
|
|
9199
|
+
if (importVal === undefined)
|
|
9200
|
+
continue;
|
|
9201
|
+
settledValue[fcn] = this._deepMergePreferTower(importVal, settledValue[fcn]);
|
|
9202
|
+
}
|
|
9057
9203
|
const validationErrors = this._collectValidationErrors(tower);
|
|
9058
9204
|
const colErrors = { ...this._collectColErrors(tower), ...preColErrors };
|
|
9059
9205
|
// Partition the settled errors so a row whose only remaining failures are
|
|
@@ -9232,8 +9378,16 @@ class TFormImportController {
|
|
|
9232
9378
|
}
|
|
9233
9379
|
const fcn = input.formControlName;
|
|
9234
9380
|
const rawCandidate = row[fcn];
|
|
9235
|
-
|
|
9236
|
-
|
|
9381
|
+
// Spreadsheet imports deliver every cell as a primitive, so a MultipleInput
|
|
9382
|
+
// column arrives as a JSON-stringified array (e.g. '[{...},{...}]') — never a
|
|
9383
|
+
// parsed array. Mirror _processSelectInput's tolerance: parse a string
|
|
9384
|
+
// candidate into an array before deciding the field has no rows. A non-array
|
|
9385
|
+
// (empty cell '', plain text) normalizes to [] and is treated as no rows.
|
|
9386
|
+
const normalizedCandidate = typeof rawCandidate === 'string'
|
|
9387
|
+
? this._tryParseJsonArray(rawCandidate)
|
|
9388
|
+
: rawCandidate;
|
|
9389
|
+
const rawItems = Array.isArray(normalizedCandidate)
|
|
9390
|
+
? normalizedCandidate
|
|
9237
9391
|
: [];
|
|
9238
9392
|
if (rawItems.length === 0) {
|
|
9239
9393
|
return { errors: [] };
|
|
@@ -9245,7 +9399,7 @@ class TFormImportController {
|
|
|
9245
9399
|
sectionId: input.sectionId,
|
|
9246
9400
|
label: '',
|
|
9247
9401
|
columns: subFormInputs.map(col => ({
|
|
9248
|
-
...col,
|
|
9402
|
+
...this._localizeSubInputDeps(col, input.id),
|
|
9249
9403
|
multipleInputInEditId: undefined, // Prevent nested MultipleInputs from trying to edit the same item in the same shared mock form
|
|
9250
9404
|
})),
|
|
9251
9405
|
}],
|
|
@@ -9254,7 +9408,16 @@ class TFormImportController {
|
|
|
9254
9408
|
const processedItems = new Array(rawItems.length);
|
|
9255
9409
|
const errors = [];
|
|
9256
9410
|
const overridableErrors = [];
|
|
9257
|
-
|
|
9411
|
+
// Sub-rows are processed SEQUENTIALLY for the same reason as the top-level
|
|
9412
|
+
// rows in `runImport` — each sub-row spins its own tower whose settle +
|
|
9413
|
+
// projection rely on `ApplicationRef.tick()` flushes over the shared
|
|
9414
|
+
// `ApplicationRef`; concurrent sub-towers interleave those ticks and resolve
|
|
9415
|
+
// `waitUntilSettled` before their derived values drain. The session HTTP
|
|
9416
|
+
// caches still dedupe identical requests across sub-rows.
|
|
9417
|
+
for (let index = 0; index < rawItems.length; index++) {
|
|
9418
|
+
const item = rawItems[index];
|
|
9419
|
+
if (!item)
|
|
9420
|
+
continue;
|
|
9258
9421
|
// Step 1: resolve raw codes (MSCOA etc.) before the tower sees the data.
|
|
9259
9422
|
// Pass _depth + 1 so nested MultipleInputs increment the depth guard correctly.
|
|
9260
9423
|
const { row: resolvedItem, colErrors: preColErrors, overridableColErrors: preOverridable } = hasPreProcessableSubInputs
|
|
@@ -9296,13 +9459,75 @@ class TFormImportController {
|
|
|
9296
9459
|
finally {
|
|
9297
9460
|
tower.ngOnDestroy();
|
|
9298
9461
|
}
|
|
9299
|
-
}
|
|
9462
|
+
}
|
|
9300
9463
|
return {
|
|
9301
9464
|
value: processedItems,
|
|
9302
9465
|
errors,
|
|
9303
9466
|
overridableErrors,
|
|
9304
9467
|
};
|
|
9305
9468
|
}
|
|
9469
|
+
/**
|
|
9470
|
+
* Rewrites a MultipleInput sub-input's cross-field dependency references from
|
|
9471
|
+
* the live form's COMPOUND id scheme back to the SIMPLE id the per-row mock
|
|
9472
|
+
* form uses.
|
|
9473
|
+
*
|
|
9474
|
+
* In the real form, {@link allFormInputs} flattens a MultipleInput's children
|
|
9475
|
+
* and rewrites each child's id to `${multipleInputId}.${childId}`. Every
|
|
9476
|
+
* dependent field's `mapTo.inputId` (value/options-API `minimumInputRequired`)
|
|
9477
|
+
* is authored against that compound id — so `readDep(compoundId)` resolves and
|
|
9478
|
+
* the dependent fetch fires. The mock form built in
|
|
9479
|
+
* {@link TFormImportController._processMultipleFormInput} hoists those children
|
|
9480
|
+
* to top-level columns, so they keep their SIMPLE ids; the baked-in compound
|
|
9481
|
+
* `mapTo.inputId` references then resolve to nothing, `validateMinInput` fails,
|
|
9482
|
+
* the value-API `params` stay `undefined`, and the resource never fetches —
|
|
9483
|
+
* leaving every derived sub-field null (and dropped by `getFormValueNames`).
|
|
9484
|
+
*
|
|
9485
|
+
* Deep-clones `node` (never mutates the shared form definition) and strips the
|
|
9486
|
+
* `${parentId}.` prefix from any `inputId` that targets a sibling in THIS
|
|
9487
|
+
* MultipleInput, so the sub-tower's signal graph resolves dependencies exactly
|
|
9488
|
+
* as the live form does.
|
|
9489
|
+
*
|
|
9490
|
+
* @param node - The sub-input config (or any nested fragment) to rewrite.
|
|
9491
|
+
* @param parentId - The owning MultipleInput's id (the compound prefix).
|
|
9492
|
+
*/
|
|
9493
|
+
_localizeSubInputDeps(node, parentId) {
|
|
9494
|
+
const prefix = `${parentId}.`;
|
|
9495
|
+
const walk = (value) => {
|
|
9496
|
+
if (Array.isArray(value))
|
|
9497
|
+
return value.map(walk);
|
|
9498
|
+
if (value && typeof value === 'object') {
|
|
9499
|
+
const out = {};
|
|
9500
|
+
for (const [key, val] of Object.entries(value)) {
|
|
9501
|
+
out[key] = key === 'inputId' && typeof val === 'string' && val.startsWith(prefix)
|
|
9502
|
+
? val.slice(prefix.length)
|
|
9503
|
+
: walk(val);
|
|
9504
|
+
}
|
|
9505
|
+
return out;
|
|
9506
|
+
}
|
|
9507
|
+
return value;
|
|
9508
|
+
};
|
|
9509
|
+
return walk(node);
|
|
9510
|
+
}
|
|
9511
|
+
/**
|
|
9512
|
+
* Parses a string MultipleInput cell into an array of row objects.
|
|
9513
|
+
*
|
|
9514
|
+
* Spreadsheet cells are primitives, so a MultipleInput column arrives as a
|
|
9515
|
+
* JSON-stringified array. Returns the parsed array on success; returns the
|
|
9516
|
+
* raw value unchanged on failure (empty string, plain text, malformed JSON,
|
|
9517
|
+
* or a non-array JSON value) so the caller's `Array.isArray` check treats it
|
|
9518
|
+
* as "no rows" rather than throwing.
|
|
9519
|
+
*/
|
|
9520
|
+
_tryParseJsonArray(raw) {
|
|
9521
|
+
const trimmed = raw.trim();
|
|
9522
|
+
if (!trimmed.startsWith('['))
|
|
9523
|
+
return raw;
|
|
9524
|
+
try {
|
|
9525
|
+
return JSON.parse(trimmed);
|
|
9526
|
+
}
|
|
9527
|
+
catch {
|
|
9528
|
+
return raw;
|
|
9529
|
+
}
|
|
9530
|
+
}
|
|
9306
9531
|
/**
|
|
9307
9532
|
* Resolves a single account code to an IScoaAccount.
|
|
9308
9533
|
* Routed through `_cachedGet` so identical codes across concurrent rows share
|
|
@@ -9483,6 +9708,71 @@ class TFormImportController {
|
|
|
9483
9708
|
});
|
|
9484
9709
|
return colErrors;
|
|
9485
9710
|
}
|
|
9711
|
+
/**
|
|
9712
|
+
* Collects the MultipleInput columns whose value is tower-derived — i.e. they
|
|
9713
|
+
* carry a value-API fetch (`matOptions.fetch.value.source === 'api'`) or a
|
|
9714
|
+
* value-producing calculation. These are the columns whose import rows are
|
|
9715
|
+
* overridden by the tower's own value graph and therefore need the
|
|
9716
|
+
* tower-favored deep merge applied in {@link TFormImportController._processRow}.
|
|
9717
|
+
*/
|
|
9718
|
+
_valueDerivedMultipleInputs(form) {
|
|
9719
|
+
return form.slides.flatMap(slide => slide.columns.filter(col => col.element === ElementTypes.MultipleInput && this._isValueDerivedColumn(col)));
|
|
9720
|
+
}
|
|
9721
|
+
/** True iff the column derives its value from a value-API fetch or a calculation. */
|
|
9722
|
+
_isValueDerivedColumn(col) {
|
|
9723
|
+
const valueFetch = col.matOptions?.fetch?.value;
|
|
9724
|
+
const hasApiValue = valueFetch?.source === 'api';
|
|
9725
|
+
let hasCalculation = false;
|
|
9726
|
+
try {
|
|
9727
|
+
hasCalculation = Boolean(validateCalculatedFieldRules(col.calculatedFieldRules)?.value);
|
|
9728
|
+
}
|
|
9729
|
+
catch {
|
|
9730
|
+
hasCalculation = false;
|
|
9731
|
+
}
|
|
9732
|
+
return hasApiValue || hasCalculation;
|
|
9733
|
+
}
|
|
9734
|
+
/**
|
|
9735
|
+
* Deep-merges two values with the **override** (tower-derived) value favored
|
|
9736
|
+
* and the **base** (import) value filling every gap it leaves.
|
|
9737
|
+
*
|
|
9738
|
+
* Rules (mirrors the import-merge contract):
|
|
9739
|
+
* - `override` wins for scalars and for any key it defines.
|
|
9740
|
+
* - Keys present only on `base` are preserved (import fills gaps).
|
|
9741
|
+
* - Arrays merge **element-wise by index** (each element deep-merged), so a
|
|
9742
|
+
* tower row that omits an import-only field keeps that field.
|
|
9743
|
+
* - An **empty** `override` array (or `null`/`undefined`) falls back entirely
|
|
9744
|
+
* to `base` — a tower value that resolves empty never erases the import rows.
|
|
9745
|
+
*/
|
|
9746
|
+
_deepMergePreferTower(base, override) {
|
|
9747
|
+
if (override === undefined || override === null)
|
|
9748
|
+
return base;
|
|
9749
|
+
if (base === undefined || base === null)
|
|
9750
|
+
return override;
|
|
9751
|
+
if (Array.isArray(override) || Array.isArray(base)) {
|
|
9752
|
+
// Empty/absent override array → import covers the value.
|
|
9753
|
+
if (!Array.isArray(override) || override.length === 0)
|
|
9754
|
+
return base;
|
|
9755
|
+
if (!Array.isArray(base))
|
|
9756
|
+
return override;
|
|
9757
|
+
const length = Math.max(base.length, override.length);
|
|
9758
|
+
const out = [];
|
|
9759
|
+
for (let i = 0; i < length; i++) {
|
|
9760
|
+
out[i] = this._deepMergePreferTower(base[i], override[i]);
|
|
9761
|
+
}
|
|
9762
|
+
return out;
|
|
9763
|
+
}
|
|
9764
|
+
if (typeof override === 'object' && typeof base === 'object') {
|
|
9765
|
+
const b = base;
|
|
9766
|
+
const o = override;
|
|
9767
|
+
const out = { ...b };
|
|
9768
|
+
for (const key of Object.keys(o)) {
|
|
9769
|
+
out[key] = this._deepMergePreferTower(b[key], o[key]);
|
|
9770
|
+
}
|
|
9771
|
+
return out;
|
|
9772
|
+
}
|
|
9773
|
+
// Scalars / mismatched shapes: tower value is favored.
|
|
9774
|
+
return override;
|
|
9775
|
+
}
|
|
9486
9776
|
/**
|
|
9487
9777
|
* Immutable row update — clones the rows array and the targeted row before
|
|
9488
9778
|
* pushing through `_rows$` so subscribers downstream of `progress$` always
|
|
@@ -10652,16 +10942,21 @@ const elementBlurFn = (form, inputId, event, element) => {
|
|
|
10652
10942
|
}
|
|
10653
10943
|
};
|
|
10654
10944
|
|
|
10655
|
-
function addScoaExtensionInput(form, sectionId, scoaInputId) {
|
|
10945
|
+
function addScoaExtensionInput(form, sectionId, scoaInputId, linkedSegmentId, inputId) {
|
|
10656
10946
|
try {
|
|
10657
10947
|
if (!form || !sectionId || !scoaInputId) {
|
|
10658
10948
|
throw new Error('Form, sectionId and scoaExtensionInputInEditId are required');
|
|
10659
10949
|
}
|
|
10660
10950
|
// ScoaInnerInput is the actual element type stored in `mscoaConfig.inputs`.
|
|
10661
10951
|
// A stubbed extension entry carries only id + sectionId until the user fills it.
|
|
10952
|
+
// When `linkedSegmentId` is supplied the input is pre-attached to that segment
|
|
10953
|
+
// (its value projects into the segment's bag — see the mscoa chart projection).
|
|
10954
|
+
// `inputId` lets the caller pre-allocate the id so it can open the new input
|
|
10955
|
+
// in the editor right after adding it.
|
|
10662
10956
|
const newInput = {
|
|
10663
|
-
id: v4(),
|
|
10957
|
+
id: inputId ?? v4(),
|
|
10664
10958
|
sectionId,
|
|
10959
|
+
...(linkedSegmentId ? { linkedSegmentId } : {}),
|
|
10665
10960
|
};
|
|
10666
10961
|
return {
|
|
10667
10962
|
...form,
|
|
@@ -10852,8 +11147,58 @@ function formBuilderStoreActions(store) {
|
|
|
10852
11147
|
const form = store.formInEditSnapshot();
|
|
10853
11148
|
if (!form)
|
|
10854
11149
|
return;
|
|
10855
|
-
|
|
11150
|
+
// A custom input is an account-level input (a peer of the SCOA segments). It
|
|
11151
|
+
// starts as an unconfigured stub, so open it in the editor right away for the
|
|
11152
|
+
// builder to set its type/label — otherwise it renders nothing in the chart.
|
|
11153
|
+
const newInputId = v4();
|
|
11154
|
+
const newForm = addScoaExtensionInput(form.form, sectionId, scoaInputId, undefined, newInputId);
|
|
10856
11155
|
applyForm(newForm);
|
|
11156
|
+
store.actions.setInputInEditId({ inputInEdit: newInputId });
|
|
11157
|
+
};
|
|
11158
|
+
/**
|
|
11159
|
+
* Creates or updates a standalone SCOA custom input from the segment-config
|
|
11160
|
+
* quick editor. On create (or when the element type changes) the element
|
|
11161
|
+
* template is applied so the input has all required fields; then the editor
|
|
11162
|
+
* fields (label, control name, single-value-selection, read-only) are merged.
|
|
11163
|
+
*/
|
|
11164
|
+
const saveScoaCustomInput = (sectionId, scoaInputId, config) => {
|
|
11165
|
+
const form = store.formInEditSnapshot();
|
|
11166
|
+
if (!form)
|
|
11167
|
+
return;
|
|
11168
|
+
const inputId = config.id ?? v4();
|
|
11169
|
+
const existing = config.id ? returnAnyFormInputFromForm(form.form, inputId) : undefined;
|
|
11170
|
+
let nextForm = form.form;
|
|
11171
|
+
if (!config.id) {
|
|
11172
|
+
nextForm = addScoaExtensionInput(nextForm, sectionId, scoaInputId, undefined, inputId);
|
|
11173
|
+
}
|
|
11174
|
+
if (!existing || existing.element !== config.element) {
|
|
11175
|
+
nextForm = selectInputTemplateFn(nextForm, inputId, config.element);
|
|
11176
|
+
}
|
|
11177
|
+
nextForm = {
|
|
11178
|
+
...nextForm,
|
|
11179
|
+
slides: nextForm.slides.map((slide) => ({
|
|
11180
|
+
...slide,
|
|
11181
|
+
columns: slide.columns.map((column) => {
|
|
11182
|
+
if (column.element !== ElementTypes.MscoaSelection)
|
|
11183
|
+
return column;
|
|
11184
|
+
return {
|
|
11185
|
+
...column,
|
|
11186
|
+
mscoaConfig: {
|
|
11187
|
+
...column.mscoaConfig,
|
|
11188
|
+
inputs: (column.mscoaConfig.inputs || []).map((input) => input.id === inputId
|
|
11189
|
+
? deepMerge(input, {
|
|
11190
|
+
label: config.label,
|
|
11191
|
+
formControlName: config.formControlName,
|
|
11192
|
+
singleSelect: config.singleSelect,
|
|
11193
|
+
readonly: config.readonly,
|
|
11194
|
+
})
|
|
11195
|
+
: input),
|
|
11196
|
+
},
|
|
11197
|
+
};
|
|
11198
|
+
}),
|
|
11199
|
+
})),
|
|
11200
|
+
};
|
|
11201
|
+
applyForm(nextForm);
|
|
10857
11202
|
};
|
|
10858
11203
|
const applyFormTemplate = (form) => {
|
|
10859
11204
|
if (!form)
|
|
@@ -11017,6 +11362,7 @@ function formBuilderStoreActions(store) {
|
|
|
11017
11362
|
addMultipleFormInput,
|
|
11018
11363
|
clearInputInEdit,
|
|
11019
11364
|
addInputToScoaSelection,
|
|
11365
|
+
saveScoaCustomInput,
|
|
11020
11366
|
};
|
|
11021
11367
|
}
|
|
11022
11368
|
|
|
@@ -11416,10 +11762,17 @@ function setSegmentValues(state, segmentValues) {
|
|
|
11416
11762
|
const accountTreeKeys = ((state.accountTreeKeys && state.accountTreeKeys.length > 0)
|
|
11417
11763
|
? state.accountTreeKeys
|
|
11418
11764
|
: (state.segments?.map(s => s.segment) || []));
|
|
11765
|
+
// Standalone custom-input values live as peer keys in each basis bag (written
|
|
11766
|
+
// by `setCustomInputValue`, preserved by `auditStateValues`). They are NOT
|
|
11767
|
+
// segments, so `mapSegments` must carry them through unchanged — otherwise the
|
|
11768
|
+
// down-path strips a key the up-path keeps, the `_isEqual` guard below never
|
|
11769
|
+
// holds, and the form ⇄ store ⇄ form graph oscillates (re-firing the debounced
|
|
11770
|
+
// MSCOA validation API on every lap).
|
|
11771
|
+
const customInputKeys = new Set((state.inputs || []).filter((input) => !input.linkedSegmentId).map((input) => input.formControlName));
|
|
11419
11772
|
const mapSegments = (source) => {
|
|
11420
11773
|
if (!source || !accountTreeKeys)
|
|
11421
11774
|
return {};
|
|
11422
|
-
|
|
11775
|
+
const mapped = accountTreeKeys.reduce((acc, key) => {
|
|
11423
11776
|
// Matches 'costing' -> 'COSTING' from your log
|
|
11424
11777
|
const upperKey = key.toUpperCase();
|
|
11425
11778
|
const v = source[upperKey] ?? source[key];
|
|
@@ -11427,6 +11780,13 @@ function setSegmentValues(state, segmentValues) {
|
|
|
11427
11780
|
acc[key] = v;
|
|
11428
11781
|
return acc;
|
|
11429
11782
|
}, {});
|
|
11783
|
+
// Preserve standalone custom-input peer values (mirrors auditStateValues).
|
|
11784
|
+
for (const customKey of customInputKeys) {
|
|
11785
|
+
if (customKey && source[customKey] !== undefined) {
|
|
11786
|
+
mapped[customKey] = source[customKey];
|
|
11787
|
+
}
|
|
11788
|
+
}
|
|
11789
|
+
return mapped;
|
|
11430
11790
|
};
|
|
11431
11791
|
// 5. Generate Values
|
|
11432
11792
|
const accrualValue = mapSegments(rawAccrual);
|
|
@@ -11498,11 +11858,80 @@ function setSegmentAccount(state, { segment, account, accountType, isCash }) {
|
|
|
11498
11858
|
}
|
|
11499
11859
|
};
|
|
11500
11860
|
}
|
|
11861
|
+
/**
|
|
11862
|
+
* Writes one **segment-scoped** custom-input value into the segment bag as a
|
|
11863
|
+
* sibling of `debit`/`credit` (e.g. `REGIONAL.budgetValue`, `REGIONAL.DEPARTMENT`).
|
|
11864
|
+
*
|
|
11865
|
+
* The `value` is the custom input's `FormControl` value, projected here so it
|
|
11866
|
+
* lands *inside* the account value object (and thus flows into extracts, the
|
|
11867
|
+
* audit pass, and validation). v1 is segment-scoped: one value per segment, not
|
|
11868
|
+
* per leg. Keying matches {@link setSegmentAccount} (both upper-case the segment
|
|
11869
|
+
* key) so the custom value shares the SAME bag as the debit/credit accounts.
|
|
11870
|
+
*/
|
|
11871
|
+
function setSegmentInput(state, { segmentKey, customKey, value, isCash }) {
|
|
11872
|
+
const basisKey = isCash ? 'cash' : 'accrual';
|
|
11873
|
+
const upperSegmentKey = segmentKey.toUpperCase();
|
|
11874
|
+
const currentBasisGroup = state.segmentValues?.[basisKey] || {};
|
|
11875
|
+
const oldSegmentData = currentBasisGroup[upperSegmentKey] || {
|
|
11876
|
+
debit: undefined,
|
|
11877
|
+
credit: undefined,
|
|
11878
|
+
};
|
|
11879
|
+
// Set the custom key, or omit it entirely when the input is cleared.
|
|
11880
|
+
const newSegmentData = { ...oldSegmentData };
|
|
11881
|
+
if (value === undefined) {
|
|
11882
|
+
delete newSegmentData[customKey];
|
|
11883
|
+
}
|
|
11884
|
+
else {
|
|
11885
|
+
newSegmentData[customKey] = value;
|
|
11886
|
+
}
|
|
11887
|
+
const newSegmentValues = {
|
|
11888
|
+
...state.segmentValues,
|
|
11889
|
+
[basisKey]: {
|
|
11890
|
+
...currentBasisGroup,
|
|
11891
|
+
[upperSegmentKey]: newSegmentData,
|
|
11892
|
+
},
|
|
11893
|
+
};
|
|
11894
|
+
// Idempotency guard (see setSegmentValues / setSegmentAccount): a no-op write
|
|
11895
|
+
// returns the SAME reference so the signal does not emit and the
|
|
11896
|
+
// form ⇄ store ⇄ form graph settles in a single pass instead of oscillating.
|
|
11897
|
+
if (_isEqual(newSegmentValues, state.segmentValues))
|
|
11898
|
+
return state;
|
|
11899
|
+
return { ...state, segmentValues: newSegmentValues };
|
|
11900
|
+
}
|
|
11901
|
+
/** Legs a custom-input value mirrors across under single-value selection. */
|
|
11902
|
+
const CUSTOM_INPUT_LEGS = ['debit', 'credit'];
|
|
11903
|
+
/**
|
|
11904
|
+
* Projects a **standalone (account-level) custom input's** value into the account
|
|
11905
|
+
* value object as a peer of the segments, keyed by its `formControlName`, mirrored
|
|
11906
|
+
* across debit/credit (single value selection). The scalar leg values are written
|
|
11907
|
+
* through the bag's string index signature so they stay type-legal without
|
|
11908
|
+
* weakening the account-bag type. Per-leg distinct entry is a later refinement.
|
|
11909
|
+
*/
|
|
11910
|
+
function setCustomInputValue(state, { inputKey, value, isCash }) {
|
|
11911
|
+
if (!inputKey)
|
|
11912
|
+
return state;
|
|
11913
|
+
const basisKey = isCash ? 'cash' : 'accrual';
|
|
11914
|
+
const currentBasisGroup = state.segmentValues?.[basisKey] || {};
|
|
11915
|
+
const bag = {};
|
|
11916
|
+
for (const leg of CUSTOM_INPUT_LEGS) {
|
|
11917
|
+
bag[leg] = value;
|
|
11918
|
+
}
|
|
11919
|
+
const newSegmentValues = {
|
|
11920
|
+
...state.segmentValues,
|
|
11921
|
+
[basisKey]: { ...currentBasisGroup, [inputKey]: bag },
|
|
11922
|
+
};
|
|
11923
|
+
if (_isEqual(newSegmentValues, state.segmentValues))
|
|
11924
|
+
return state;
|
|
11925
|
+
return { ...state, segmentValues: newSegmentValues };
|
|
11926
|
+
}
|
|
11501
11927
|
/** Recomputes VAT + cash-from-accrual inheritance across all segment values. */
|
|
11502
11928
|
function auditStateValues(state) {
|
|
11503
11929
|
// 1. Safe access to state data
|
|
11504
11930
|
const { cash = {}, accrual = {} } = state.segmentValues || {};
|
|
11505
11931
|
const cashSegmentConfigs = state.cashSegments || [];
|
|
11932
|
+
// Standalone custom-input values live as peer keys in `segmentValues`; they are
|
|
11933
|
+
// NOT segments, so the VAT/inheritance passes below must leave them untouched.
|
|
11934
|
+
const customInputKeys = new Set((state.inputs || []).filter((input) => !input.linkedSegmentId).map((input) => input.formControlName));
|
|
11506
11935
|
// 2. Pre-calculate "Has VAT Applicable" flags for both bases
|
|
11507
11936
|
// (Checks if any segment in the group has a 'vatApplicableTo' flag set)
|
|
11508
11937
|
const hasVatApplicableTo = (val) => val?.vatApplicableTo !== undefined;
|
|
@@ -11542,6 +11971,11 @@ function auditStateValues(state) {
|
|
|
11542
11971
|
}, {});
|
|
11543
11972
|
// 5. Process Accrual First (Source of Truth)
|
|
11544
11973
|
const newAccrual = Object.entries(accrual).reduce((acc, [key, data]) => {
|
|
11974
|
+
// Custom-input peer values pass through untouched (not segments → no VAT).
|
|
11975
|
+
if (customInputKeys.has(key)) {
|
|
11976
|
+
acc[key] = data;
|
|
11977
|
+
return acc;
|
|
11978
|
+
}
|
|
11545
11979
|
const record = data;
|
|
11546
11980
|
acc[key] = {
|
|
11547
11981
|
...record,
|
|
@@ -11551,6 +11985,11 @@ function auditStateValues(state) {
|
|
|
11551
11985
|
}, {});
|
|
11552
11986
|
// 6. Process Cash (With Inheritance)
|
|
11553
11987
|
const newCash = Object.entries(cash).reduce((acc, [key, data]) => {
|
|
11988
|
+
// Custom-input peer values pass through untouched (no VAT / inheritance).
|
|
11989
|
+
if (customInputKeys.has(key)) {
|
|
11990
|
+
acc[key] = data;
|
|
11991
|
+
return acc;
|
|
11992
|
+
}
|
|
11554
11993
|
const record = data;
|
|
11555
11994
|
const shouldInherit = inheritMap[key];
|
|
11556
11995
|
// A. Determine the Source Data
|
|
@@ -11558,13 +11997,26 @@ function auditStateValues(state) {
|
|
|
11558
11997
|
// Otherwise, use the existing Cash data.
|
|
11559
11998
|
let workingData = record;
|
|
11560
11999
|
if (shouldInherit && newAccrual[key]) {
|
|
11561
|
-
|
|
12000
|
+
const accrualRecord = newAccrual[key];
|
|
12001
|
+
const inherited = {
|
|
11562
12002
|
...workingData, // Keep existing cash props (like ID, etc) if needed
|
|
11563
|
-
debit:
|
|
11564
|
-
credit:
|
|
12003
|
+
debit: accrualRecord.debit,
|
|
12004
|
+
credit: accrualRecord.credit,
|
|
11565
12005
|
// Note: We do NOT inherit 'vatApplicableTo' or 'vat' blindly,
|
|
11566
12006
|
// because Cash might have its own VAT context. We recalculate VAT below.
|
|
11567
12007
|
};
|
|
12008
|
+
// Carry over the accrual segment's custom-input values (segment-scoped
|
|
12009
|
+
// siblings of debit/credit) so an inheriting cash segment mirrors them.
|
|
12010
|
+
// Reserved keys are recomputed for cash, so they are skipped here.
|
|
12011
|
+
for (const [customKey, customValue] of Object.entries(accrualRecord)) {
|
|
12012
|
+
if (customKey !== 'debit' &&
|
|
12013
|
+
customKey !== 'credit' &&
|
|
12014
|
+
customKey !== 'vat' &&
|
|
12015
|
+
customKey !== 'vatApplicableTo') {
|
|
12016
|
+
inherited[customKey] = customValue;
|
|
12017
|
+
}
|
|
12018
|
+
}
|
|
12019
|
+
workingData = inherited;
|
|
11568
12020
|
}
|
|
11569
12021
|
// B. Apply Cash-Specific VAT Logic
|
|
11570
12022
|
acc[key] = {
|
|
@@ -11749,6 +12201,21 @@ class MscoaComponentStore {
|
|
|
11749
12201
|
setSegmentAccount(payload) {
|
|
11750
12202
|
this.#state.update((state) => setSegmentAccount(state, payload));
|
|
11751
12203
|
}
|
|
12204
|
+
/**
|
|
12205
|
+
* Projects a segment-scoped custom-input value into the account value object
|
|
12206
|
+
* as a sibling of debit/credit. Called from the chart when a linked custom
|
|
12207
|
+
* input's `FormControl` value changes (see {@link reducers.setSegmentInput}).
|
|
12208
|
+
*/
|
|
12209
|
+
setSegmentInput(payload) {
|
|
12210
|
+
this.#state.update((state) => setSegmentInput(state, payload));
|
|
12211
|
+
}
|
|
12212
|
+
/**
|
|
12213
|
+
* Projects a standalone (account-level) custom input's value into the account
|
|
12214
|
+
* value object as a peer of the segments (see {@link reducers.setCustomInputValue}).
|
|
12215
|
+
*/
|
|
12216
|
+
setCustomInputValue(payload) {
|
|
12217
|
+
this.#state.update((state) => setCustomInputValue(state, payload));
|
|
12218
|
+
}
|
|
11752
12219
|
/** Records the active segment. */
|
|
11753
12220
|
setActiveSegment(activeSegment) {
|
|
11754
12221
|
this.#state.update((state) => setActiveSegment(state, activeSegment));
|
|
@@ -12388,9 +12855,9 @@ class FormBuilderComponent {
|
|
|
12388
12855
|
this.#store.actionsFormBuilder.setFormTitle(value);
|
|
12389
12856
|
}
|
|
12390
12857
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: FormBuilderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
12391
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: FormBuilderComponent, isStandalone: true, selector: "lib-form-builder, app-form-builder", inputs: { formId: { classPropertyName: "formId", publicName: "formId", isSignal: true, isRequired: false, transformFunction: null } }, providers: [FormsStoreService], ngImport: i0, template: "<header style=\"position:fixed;width:100%;left:0px;top:0px\">\r\n <mat-toolbar color=\"primary\">\r\n @if (closeButton) {\r\n <button mat-icon-button [style.color]=\"closeButton.color\" (click)=\"closeButton.onClick()\">\r\n <mat-icon>{{closeButton.icon}}</mat-icon>\r\n </button>\r\n }\r\n\r\n <!-- Navigation group -->\r\n <div class=\"nav-group\">\r\n <button mat-button routerLink=\"/\">Forms</button>\r\n <mat-icon>navigate_next</mat-icon>\r\n </div>\r\n\r\n <!-- Title input with optimized binding -->\r\n @if (selectHasFormId()) {\r\n <input [ngModel]=\"titleValue()\" (ngModelChange)=\"setTitleValue($event)\" class=\"section-title-input\" placeholder=\"Enter Form Title\">\r\n }\r\n\r\n <span class=\"spacer\"></span>\r\n\r\n @defer (on viewport) {\r\n <lib-forms-builder-menu />\r\n } @placeholder {\r\n <div style=\"padding: 50px;display:flex;justify-content:center;align-items:center; text-align: center;\">\r\n <mat-spinner diameter=\"20\" />\r\n </div>\r\n\r\n }\r\n\r\n <span class=\"divider\">|</span>\r\n\r\n <!-- Persist to server: visible once local preview is in sync -->\r\n @if (!pendingExternalRefresh()) {\r\n <button mat-raised-button color=\"accent\" class=\"save-button\" [disabled]=\"!(canSaveForm())\" (click)=\"saveForm()\">\r\n <mat-icon style=\"width: 24px;\">cloud_upload</mat-icon>\r\n @if (selectFormBuilderIsBusy()) {\r\n <span class=\"save-text\">\r\n <span class=\"save-label\">{{(isNewForm()) ? 'Creating form...' : 'Saving changes...'}}</span>\r\n </span>\r\n } @else {\r\n <span class=\"save-text\">\r\n <span class=\"save-label\">{{(isNewForm()) ? 'Save New Form' : 'Save Changes'}}</span>\r\n @if (canSaveForm()) {\r\n <span class=\"save-sub\">Not saved to server yet</span>\r\n }\r\n </span>\r\n }\r\n </button>\r\n }\r\n\r\n <!-- Local sync: applies your changes to the builder preview \u00B7 does NOT save to server -->\r\n @if (pendingExternalRefresh()) {\r\n <button class=\"refresh-button\" matRipple matRippleColor=\"rgba(255,255,255,0.12)\" (click)=\"triggerRefreshNow()\">\r\n <span class=\"countdown-ring\">\r\n <mat-progress-spinner\r\n diameter=\"34\"\r\n mode=\"determinate\"\r\n [value]=\"refreshCountdown() * 20\">\r\n </mat-progress-spinner>\r\n <span class=\"countdown-number\">{{refreshCountdown()}}</span>\r\n </span>\r\n <span class=\"refresh-text\">\r\n <span class=\"refresh-label\">Apply Now</span>\r\n <span class=\"refresh-sub\">Preview updates in {{refreshCountdown()}}s</span>\r\n </span>\r\n <mat-icon class=\"refresh-chevron\">chevron_right</mat-icon>\r\n </button>\r\n }\r\n\r\n </mat-toolbar>\r\n</header>\r\n\r\n<!-- Main content with optimized loading -->\r\n@defer (on viewport) {\r\n<div class=\"container\">\r\n <div class=\"middle\">\r\n <br>\r\n @if (selectLoadingForm()) {\r\n <div class=\"loading-container\">\r\n <mat-spinner />\r\n </div>\r\n } @else {\r\n <lib-form-section-stepper />\r\n }\r\n <br>\r\n @if ((hasMissingConfigs()) && !(selectLoadingForm())) {\r\n <lib-missing-form-configs />\r\n }\r\n <!-- Updated time info -->\r\n @if (!(isNewForm())) {\r\n <div class=\"updated-time\">\r\n <mat-icon>update</mat-icon>\r\n <span>Updated {{ selectFormUpdated() }}</span>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (elementEditorOpen()) {\r\n <lib-input-editor style=\"max-width:480px;height:calc(100vh - 76px);\r\n position:sticky;\r\n top:76px;\r\n z-index:1\" cdkDrag cdkDragBoundary=\"container\" class=\"middle editor-container\" />\r\n }\r\n <!-- Missing fields section -->`\r\n\r\n\r\n</div>\r\n}@placeholder {\r\n<div style=\"padding: 50px;display:flex;justify-content:center;align-items:center; text-align: center;\">\r\n <mat-spinner diameter=\"50\" />\r\n</div>\r\n}", styles: [".container{display:flex;width:100%;height:calc(100% - 64px);padding-top:4em}.side{width:100px;background-color:var(--sem-error-surface)}.middle{flex-grow:1;height:calc(100vh - 68px);overflow:auto;background-color:none}.section-title-input{border:none;background-color:transparent;font-size:.8575em;font-weight:600;color:var(--lib-forms-on-primary);padding-top:12px;padding-bottom:12px;outline:none;width:100%;min-width:268px;transition:border-bottom-color .3s ease-in-out}.section-title-input:focus{border-bottom:1px solid var(--lib-forms-on-primary)}.missing-fields{position:fixed;bottom:0}.updated-time{display:flex;color:var(--mat-sidenav-content-text-color, var(--mat-sys-on-background));gap:8px;align-items:center;line-height:normal;font-size:.875em;bottom:0;position:absolute;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);padding:8px;border-radius:4px}.nav-group{display:flex;align-items:center;gap:8px}.save-button{margin-left:8px;min-width:168px;height:44px}.save-button .save-text{display:flex;flex-direction:column;align-items:flex-start;gap:2px}.save-button .save-text .save-label{font-size:13px;font-weight:600;line-height:1;letter-spacing:.01em;white-space:nowrap}.save-button .save-text .save-sub{font-size:10px;line-height:1;opacity:.78;white-space:nowrap}.refresh-button{margin-left:8px;background:var(--mat-fab-small-container-color, var(--mat-sys-tertiary-container));color:var(--mat-sys-on-tertiary-container);border:1.5px solid var(--mat-sys-outline-variant);border-radius:10px;padding:4px 14px 4px 6px;cursor:pointer;display:inline-flex;align-items:center;gap:12px;height:44px;width:fit-content;box-shadow:0 2px 12px color-mix(in srgb,var(--lib-forms-shadow-color) 18%,transparent);transition:box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing),transform var(--lib-forms-duration-hover) var(--lib-forms-easing);outline:none;overflow:hidden;position:relative}.refresh-button:hover{box-shadow:0 4px 20px color-mix(in srgb,var(--lib-forms-shadow-color) 28%,transparent);transform:translateY(-1px)}.refresh-button:active{transform:translateY(0);box-shadow:0 1px 6px color-mix(in srgb,var(--lib-forms-shadow-color) 12%,transparent)}.refresh-button .countdown-ring{position:relative;width:34px;height:34px;display:flex;align-items:center;justify-content:center;flex-shrink:0}.refresh-button .countdown-ring mat-progress-spinner{position:absolute;inset:0;--mdc-circular-progress-active-indicator-color: var(--mat-sys-on-tertiary-container);--mdc-circular-progress-track-color: color-mix(in srgb, var(--mat-sys-on-tertiary-container) 18%, transparent)}.refresh-button .countdown-ring .countdown-number{font-size:11px;font-weight:600;line-height:1;z-index:1;letter-spacing:-.3px;color:var(--mat-sys-on-tertiary-container)}.refresh-button .refresh-text{display:flex;flex-direction:column;align-items:flex-start;gap:3px}.refresh-button .refresh-text .refresh-label{font-size:13px;font-weight:600;line-height:1;letter-spacing:.01em;white-space:nowrap;color:var(--mat-sys-on-tertiary-container)}.refresh-button .refresh-text .refresh-sub{font-size:10px;line-height:1;opacity:.68;white-space:nowrap;color:var(--mat-sys-on-tertiary-container)}.refresh-button .refresh-chevron{font-size:18px;width:18px;height:18px;opacity:.65;flex-shrink:0;color:var(--mat-sys-on-tertiary-container)}.loading-container{display:flex;height:calc(100% - 150px);justify-content:center;align-items:center}.editor-container{max-width:500px}.divider{margin:0 8px;opacity:.5}app-missing-form-configs{position:absolute;bottom:0;right:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatToolbarModule }, { kind: "component", type: i5.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i1$2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i3$2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatRippleModule }, { kind: "directive", type: i7.MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }, { kind: "ngmodule", type: DragDropModule }, { 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: "ngmodule", type: RouterModule }, { kind: "directive", type: i7$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [import('./ngx-t-forms-forms-builder-menu.component-qrhM0jGL.mjs').then(m => m.FormsBuilderMenuComponent)], () => [i3$1.MatIcon, i3$2.MatProgressSpinner, i1$3.CdkDrag, import('./ngx-t-forms-input-editor.component-BPUOM9kQ.mjs').then(m => m.InputEditorComponent), import('./ngx-t-forms-form-section-stepper.component-Bs50-nEB.mjs').then(m => m.FormSectionStepperComponent), import('./ngx-t-forms-missing-form-configs.component-DrnH8qdG.mjs').then(m => m.MissingFormConfigsComponent)]] }); }
|
|
12858
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: FormBuilderComponent, isStandalone: true, selector: "lib-form-builder, app-form-builder", inputs: { formId: { classPropertyName: "formId", publicName: "formId", isSignal: true, isRequired: false, transformFunction: null } }, providers: [FormsStoreService], ngImport: i0, template: "<header style=\"position:fixed;width:100%;left:0px;top:0px\">\r\n <mat-toolbar color=\"primary\">\r\n @if (closeButton) {\r\n <button mat-icon-button [style.color]=\"closeButton.color\" (click)=\"closeButton.onClick()\">\r\n <mat-icon>{{closeButton.icon}}</mat-icon>\r\n </button>\r\n }\r\n\r\n <!-- Navigation group -->\r\n <div class=\"nav-group\">\r\n <button mat-button routerLink=\"/\">Forms</button>\r\n <mat-icon>navigate_next</mat-icon>\r\n </div>\r\n\r\n <!-- Title input with optimized binding -->\r\n @if (selectHasFormId()) {\r\n <input [ngModel]=\"titleValue()\" (ngModelChange)=\"setTitleValue($event)\" class=\"section-title-input\" placeholder=\"Enter Form Title\">\r\n }\r\n\r\n <span class=\"spacer\"></span>\r\n\r\n @defer (on viewport) {\r\n <lib-forms-builder-menu />\r\n } @placeholder {\r\n <div style=\"padding: 50px;display:flex;justify-content:center;align-items:center; text-align: center;\">\r\n <mat-spinner diameter=\"20\" />\r\n </div>\r\n\r\n }\r\n\r\n <span class=\"divider\">|</span>\r\n\r\n <!-- Persist to server: visible once local preview is in sync -->\r\n @if (!pendingExternalRefresh()) {\r\n <button mat-raised-button color=\"accent\" class=\"save-button\" [disabled]=\"!(canSaveForm())\" (click)=\"saveForm()\">\r\n <mat-icon style=\"width: 24px;\">cloud_upload</mat-icon>\r\n @if (selectFormBuilderIsBusy()) {\r\n <span class=\"save-text\">\r\n <span class=\"save-label\">{{(isNewForm()) ? 'Creating form...' : 'Saving changes...'}}</span>\r\n </span>\r\n } @else {\r\n <span class=\"save-text\">\r\n <span class=\"save-label\">{{(isNewForm()) ? 'Save New Form' : 'Save Changes'}}</span>\r\n @if (canSaveForm()) {\r\n <span class=\"save-sub\">Not saved to server yet</span>\r\n }\r\n </span>\r\n }\r\n </button>\r\n }\r\n\r\n <!-- Local sync: applies your changes to the builder preview \u00B7 does NOT save to server -->\r\n @if (pendingExternalRefresh()) {\r\n <button class=\"refresh-button\" matRipple matRippleColor=\"rgba(255,255,255,0.12)\" (click)=\"triggerRefreshNow()\">\r\n <span class=\"countdown-ring\">\r\n <mat-progress-spinner\r\n diameter=\"34\"\r\n mode=\"determinate\"\r\n [value]=\"refreshCountdown() * 20\">\r\n </mat-progress-spinner>\r\n <span class=\"countdown-number\">{{refreshCountdown()}}</span>\r\n </span>\r\n <span class=\"refresh-text\">\r\n <span class=\"refresh-label\">Apply Now</span>\r\n <span class=\"refresh-sub\">Preview updates in {{refreshCountdown()}}s</span>\r\n </span>\r\n <mat-icon class=\"refresh-chevron\">chevron_right</mat-icon>\r\n </button>\r\n }\r\n\r\n </mat-toolbar>\r\n</header>\r\n\r\n<!-- Main content with optimized loading -->\r\n@defer (on viewport) {\r\n<div class=\"container\">\r\n <div class=\"middle\">\r\n <br>\r\n @if (selectLoadingForm()) {\r\n <div class=\"loading-container\">\r\n <mat-spinner />\r\n </div>\r\n } @else {\r\n <lib-form-section-stepper />\r\n }\r\n <br>\r\n @if ((hasMissingConfigs()) && !(selectLoadingForm())) {\r\n <lib-missing-form-configs />\r\n }\r\n <!-- Updated time info -->\r\n @if (!(isNewForm())) {\r\n <div class=\"updated-time\">\r\n <mat-icon>update</mat-icon>\r\n <span>Updated {{ selectFormUpdated() }}</span>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (elementEditorOpen()) {\r\n <lib-input-editor style=\"max-width:480px;height:calc(100vh - 76px);\r\n position:sticky;\r\n top:76px;\r\n z-index:1\" cdkDrag cdkDragBoundary=\"container\" class=\"middle editor-container\" />\r\n }\r\n <!-- Missing fields section -->`\r\n\r\n\r\n</div>\r\n}@placeholder {\r\n<div style=\"padding: 50px;display:flex;justify-content:center;align-items:center; text-align: center;\">\r\n <mat-spinner diameter=\"50\" />\r\n</div>\r\n}", styles: [".container{display:flex;width:100%;height:calc(100% - 64px);padding-top:4em}.side{width:100px;background-color:var(--sem-error-surface)}.middle{flex-grow:1;height:calc(100vh - 68px);overflow:auto;background-color:none}.section-title-input{border:none;background-color:transparent;font-size:.8575em;font-weight:600;color:var(--lib-forms-on-primary);padding-top:12px;padding-bottom:12px;outline:none;width:100%;min-width:268px;transition:border-bottom-color .3s ease-in-out}.section-title-input:focus{border-bottom:1px solid var(--lib-forms-on-primary)}.missing-fields{position:fixed;bottom:0}.updated-time{display:flex;color:var(--mat-sidenav-content-text-color, var(--mat-sys-on-background));gap:8px;align-items:center;line-height:normal;font-size:.875em;bottom:0;position:absolute;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);padding:8px;border-radius:4px}.nav-group{display:flex;align-items:center;gap:8px}.save-button{margin-left:8px;min-width:168px;height:44px}.save-button .save-text{display:flex;flex-direction:column;align-items:flex-start;gap:2px}.save-button .save-text .save-label{font-size:13px;font-weight:600;line-height:1;letter-spacing:.01em;white-space:nowrap}.save-button .save-text .save-sub{font-size:10px;line-height:1;opacity:.78;white-space:nowrap}.refresh-button{margin-left:8px;background:var(--mat-fab-small-container-color, var(--mat-sys-tertiary-container));color:var(--mat-sys-on-tertiary-container);border:1.5px solid var(--mat-sys-outline-variant);border-radius:10px;padding:4px 14px 4px 6px;cursor:pointer;display:inline-flex;align-items:center;gap:12px;height:44px;width:fit-content;box-shadow:0 2px 12px color-mix(in srgb,var(--lib-forms-shadow-color) 18%,transparent);transition:box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing),transform var(--lib-forms-duration-hover) var(--lib-forms-easing);outline:none;overflow:hidden;position:relative}.refresh-button:hover{box-shadow:0 4px 20px color-mix(in srgb,var(--lib-forms-shadow-color) 28%,transparent);transform:translateY(-1px)}.refresh-button:active{transform:translateY(0);box-shadow:0 1px 6px color-mix(in srgb,var(--lib-forms-shadow-color) 12%,transparent)}.refresh-button .countdown-ring{position:relative;width:34px;height:34px;display:flex;align-items:center;justify-content:center;flex-shrink:0}.refresh-button .countdown-ring mat-progress-spinner{position:absolute;inset:0;--mdc-circular-progress-active-indicator-color: var(--mat-sys-on-tertiary-container);--mdc-circular-progress-track-color: color-mix(in srgb, var(--mat-sys-on-tertiary-container) 18%, transparent)}.refresh-button .countdown-ring .countdown-number{font-size:11px;font-weight:600;line-height:1;z-index:1;letter-spacing:-.3px;color:var(--mat-sys-on-tertiary-container)}.refresh-button .refresh-text{display:flex;flex-direction:column;align-items:flex-start;gap:3px}.refresh-button .refresh-text .refresh-label{font-size:13px;font-weight:600;line-height:1;letter-spacing:.01em;white-space:nowrap;color:var(--mat-sys-on-tertiary-container)}.refresh-button .refresh-text .refresh-sub{font-size:10px;line-height:1;opacity:.68;white-space:nowrap;color:var(--mat-sys-on-tertiary-container)}.refresh-button .refresh-chevron{font-size:18px;width:18px;height:18px;opacity:.65;flex-shrink:0;color:var(--mat-sys-on-tertiary-container)}.loading-container{display:flex;height:calc(100% - 150px);justify-content:center;align-items:center}.editor-container{max-width:500px}.divider{margin:0 8px;opacity:.5}app-missing-form-configs{position:absolute;bottom:0;right:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatToolbarModule }, { kind: "component", type: i5.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i1$2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i3$2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatRippleModule }, { kind: "directive", type: i7.MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }, { kind: "ngmodule", type: DragDropModule }, { 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: "ngmodule", type: RouterModule }, { kind: "directive", type: i7$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [import('./ngx-t-forms-forms-builder-menu.component-Dv0Dfw79.mjs').then(m => m.FormsBuilderMenuComponent)], () => [i3$1.MatIcon, i3$2.MatProgressSpinner, i1$3.CdkDrag, import('./ngx-t-forms-input-editor.component-DLru1Ezu.mjs').then(m => m.InputEditorComponent), import('./ngx-t-forms-form-section-stepper.component-BPgPfZSy.mjs').then(m => m.FormSectionStepperComponent), import('./ngx-t-forms-missing-form-configs.component-DxdynZY6.mjs').then(m => m.MissingFormConfigsComponent)]] }); }
|
|
12392
12859
|
}
|
|
12393
|
-
i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.2.12", ngImport: i0, type: FormBuilderComponent, resolveDeferredDeps: () => [import('./ngx-t-forms-forms-builder-menu.component-
|
|
12860
|
+
i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.2.12", ngImport: i0, type: FormBuilderComponent, resolveDeferredDeps: () => [import('./ngx-t-forms-forms-builder-menu.component-Dv0Dfw79.mjs').then(m => m.FormsBuilderMenuComponent), import('./ngx-t-forms-input-editor.component-DLru1Ezu.mjs').then(m => m.InputEditorComponent), import('./ngx-t-forms-form-section-stepper.component-BPgPfZSy.mjs').then(m => m.FormSectionStepperComponent), import('./ngx-t-forms-missing-form-configs.component-DxdynZY6.mjs').then(m => m.MissingFormConfigsComponent)], resolveMetadata: (FormsBuilderMenuComponent, InputEditorComponent, FormSectionStepperComponent, MissingFormConfigsComponent) => ({ decorators: [{
|
|
12394
12861
|
type: Component,
|
|
12395
12862
|
args: [{ selector: 'lib-form-builder, app-form-builder', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
12396
12863
|
CommonModule,
|
|
@@ -12926,6 +13393,16 @@ class TDynamicDataEditComponent {
|
|
|
12926
13393
|
this.data = input(undefined, ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
12927
13394
|
/** Validation errors surfaced by the parent for display. */
|
|
12928
13395
|
this.validationErrors = input(null, ...(ngDevMode ? [{ debugName: "validationErrors" }] : /* istanbul ignore next */ []));
|
|
13396
|
+
/**
|
|
13397
|
+
* Builder-only: creates or updates an account-level MSCOA custom input (a peer
|
|
13398
|
+
* of the segments) from the segment-config quick editor. Forwarded to that
|
|
13399
|
+
* editor; absent outside the form builder, which hides the related affordance.
|
|
13400
|
+
*/
|
|
13401
|
+
this.mscoaSaveCustomInput = input(undefined, ...(ngDevMode ? [{ debugName: "mscoaSaveCustomInput" }] : /* istanbul ignore next */ []));
|
|
13402
|
+
/** Builder-only: opens an MSCOA custom input in the input editor for advanced configuration. */
|
|
13403
|
+
this.mscoaEditInput = input(undefined, ...(ngDevMode ? [{ debugName: "mscoaEditInput" }] : /* istanbul ignore next */ []));
|
|
13404
|
+
/** Builder-only: removes an MSCOA custom input from the config. */
|
|
13405
|
+
this.mscoaDeleteInput = input(undefined, ...(ngDevMode ? [{ debugName: "mscoaDeleteInput" }] : /* istanbul ignore next */ []));
|
|
12929
13406
|
/** Fires when the edited value changes (debounced). */
|
|
12930
13407
|
this.valueChange = output();
|
|
12931
13408
|
/** Fires when an inner editor loses focus (used for expression-style editors). */
|
|
@@ -13183,9 +13660,9 @@ class TDynamicDataEditComponent {
|
|
|
13183
13660
|
}
|
|
13184
13661
|
}
|
|
13185
13662
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TDynamicDataEditComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
13186
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: TDynamicDataEditComponent, isStandalone: true, selector: "lib-t-dynamic-data-edit", inputs: { editorConfig: { classPropertyName: "editorConfig", publicName: "editorConfig", isSignal: true, isRequired: false, transformFunction: null }, formInputs: { classPropertyName: "formInputs", publicName: "formInputs", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, validationErrors: { classPropertyName: "validationErrors", publicName: "validationErrors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", blur: "blur" }, providers: [{ provide: NESTED_EDITOR_COMPONENT, useValue: TDynamicDataEditComponent }], ngImport: i0, template: "@defer {\n@if (( vm$ |async); as vm) {\n\n @if (vm.isFormFieldControl) {\n <!-- Editor types that resolve to a MatFormFieldControl render inside the field. -->\n <mat-form-field appearance=\"outline\" [color]=\"((validationErrors())||[]).length>0 ? 'warn' : 'primary'\"\n [floatLabel]=\"'always'\" [subscriptSizing]=\"'dynamic'\" [hintLabel]=\"vm.editorConfigValue?.hint||''\">\n <mat-label> {{ (vm. editorConfigValue)?.label }} </mat-label>\n @switch ((vm. editorConfigValue)?.editType) {\n @default {\n <lib-input-custom\n [id]=\"((vm.editorConfigValue)?.id)\"\n [inputConfig]=\"$any(vm.inputConfig)\"\n [placeholder]=\"(vm. editorConfigValue)?.placeholder ||'Enter value'\"\n [required]=\"!!(vm. editorConfigValue)?.required\"\n [disabled]=\"!!(vm.disabled)\"\n [ngModel]=\"(vm.value)\"\n (blur)=\"elementBlur($event)\"\n (input)=\"inputChange($event)\" ></lib-input-custom>\n\n\n }\n @case ( elementEditorTypes.Toggle) {\n <lib-mat-slider-toggle-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [name]=\"((vm. editorConfigValue)?.name||'') \"\n [label]=\"((vm. editorConfigValue)?.label||'')\" [disabled]=\"(vm.disabled)||false\"\n (valueChange)=\"valueChanged(!!$event)\" [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\">\n </lib-mat-slider-toggle-editor>\n\n }\n\n @case (elementEditorTypes.Range) {\n\n\n <lib-mat-slider-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [format]=\"( vm.editorConfigValue)?.format \" [formatLabel]=\" formatLabel\"\n [disabled]=\"(vm.disabled)||false\" [max]=\"( vm.editorConfigValue)?.max || 100\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [min]=\"( vm.editorConfigValue)?.min || 0\"\n (valueChange)=\"inputChange($event)\" [step]=\"( vm.editorConfigValue)?.step || 1\">\n\n\n </lib-mat-slider-editor>\n\n\n\n }\n\n @case (elementEditorTypes.OptionSelect) {\n\n <mat-select\n\n [value]=\"$any(vm.value)\" (selectionChange)=\"valueChanged($event.value)\"\n [disabled]=\"(vm.disabled)||false\">\n @for(option of ( vm.editorConfigValue)?.options || vm.dataOptions;track option.value){\n <mat-option [value]=\"option.value\">{{option.label}}</mat-option>\n }\n </mat-select>\n\n }\n\n @case (elementEditorTypes.RichTextEditor) {\n <lib-editor-js-input\n\n [id]=\"((vm.editorConfigValue)?.id)\"\n [value]=\"$any(vm.value)\" (valueChanged)=\"valueChanged($event)\"\n [disabled]=\"(vm.disabled)||false\" [inputConfig]=\"$any(data())\">\n </lib-editor-js-input>\n }\n\n @case (elementEditorTypes.MongoPipelineBuilder) {\n\n <lib-pipeline-generator [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getWorkflowOptions]=\"getWorkflowOptions$\"\n (valueChanged)=\"valueChanged($event)\"></lib-pipeline-generator>\n\n }\n @case (elementEditorTypes.MapMatOptionsKeys) {\n <lib-map-mat-options-keys [disabled]=\"(vm.disabled)||false\"\n [value]=\"$any(vm.value)\"\n [formInputs]=\"formInputs() || []\"\n [mapToData]=\"vm.dataOptions\"\n [errors]=\"(validationErrors())||[]\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-map-mat-options-keys>\n\n }\n\n @case(elementEditorTypes.CalculatedFieldRules){\n\n <lib-calculated-field-rules [formInputs]=\"formInputs() ||[]\" [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\"\n [mapToData]=\"vm.dataOptions\"></lib-calculated-field-rules>\n }\n\n @case(elementEditorTypes.Validators){\n\n <lib-validators-config [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\" [formInputs]=\"formInputs() ||[]\"\n [mapToData]=\"vm.dataOptions\">\n </lib-validators-config>\n\n }\n @case(elementEditorTypes.ConfigMscoaAdditionalInputs){\n\n <lib-config-mscoa-additional-inputs [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getMscoaTree]=\"getMscoaTree$\" [mapToData]=\"vm.dataOptions\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-config-mscoa-additional-inputs>\n\n }\n @case (elementEditorTypes.DataSourcePicker) {\n <lib-data-source-picker [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [editorConfig]=\"vm. editorConfigValue\"\n (valueChange)=\"valueChanged($event)\" [formInputs]=\"formInputs() ||[]\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\">\n </lib-data-source-picker>\n }\n @case (elementEditorTypes.ListLabelConfigEditor) {\n <lib-document-list-label-config-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [formInputs]=\"formInputs() ||[]\"\n [disabled]=\"(vm.disabled)||false\"\n [editorConfig]=\"vm. editorConfigValue\"\n (valueChange)=\"valueChanged($event)\"\n [value]=\"$any(vm.value)\" [mapToData]=\"vm.dataOptions\"\n [errors]=\"(validationErrors())||[]\">\n\n </lib-document-list-label-config-editor>\n }\n @case(\n elementEditorTypes.WorkflowPicker\n ){\n <lib-t-workflow-picker [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [getWorkflowOptions]=\"getWorkflowOptions$\"\n (valueChanged)=\"valueChanged($event)\" [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\"></lib-t-workflow-picker>\n }\n @case (\n elementEditorTypes.RecordListManager\n ) {\n <lib-record-list-manager\n [id]=\"((vm.editorConfigValue)?.id)\"\n [editorConfig]=\"vm.editorConfigValue\" [disabled]=\"(vm.disabled)||false\"\n [formInputs]=\"formInputs() ||[]\" [mapToData]=\"vm.dataOptions\" (valueChange)=\"valueChanged($event)\"\n\n [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\"></lib-record-list-manager>\n }\n }\n\n @if (vm.inputHasBlurFunction) {\n <button [matTooltip]=\"blurFunctionTooltip((vm.editorConfigValue)?.blurHandle)\"\n [disabled]=\"(vm.disabled)\" [color]=\"blurOff?'':'primary'\" (click)=\"blurOff=!blurOff\" matSuffix\n mat-icon-button>\n <mat-icon>{{\n blurOff?'blur_off':'blur_on'\n }}\n\n\n </mat-icon>\n </button>\n }\n </mat-form-field>\n } @else {\n <!-- Editor types backed by plain (signal-based) components render outside\n the field, since they are not MatFormFieldControls. They are wrapped to\n mirror the outline mat-form-field appearance: the fieldset draws the\n outline, its legend is the notched floating label, and the hint renders\n as a subscript below the box. -->\n <div class=\"non-control-editor\">\n <fieldset class=\"non-control-editor__field\">\n @if ((vm. editorConfigValue)?.label) {\n <legend class=\"non-control-editor__label\">{{ (vm. editorConfigValue)?.label }}</legend>\n }\n @switch ((vm. editorConfigValue)?.editType) {\n\n @case (elementEditorTypes.ChipSelect) {\n\n <lib-mat-chip-list-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [multiple]=\"!!vm.editorConfigValue?.multipleSelection\"\n [disabled]=\"(vm.disabled)||false\"\n [options]=\"(vm.editorConfigValue)?.options || vm.dataOptions\"\n [required]=\"!!( vm.editorConfigValue)?.required\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\"\n (valueChange)=\" valueChanged($event)\"></lib-mat-chip-list-editor>\n\n\n }\n\n @case (elementEditorTypes.SelectionOptions) {\n\n <lib-selection-options-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [errors]=\"(validationErrors())||[]\" [disabled]=\"(vm.disabled)||false\"\n [options]=\"$any(vm.value) || []\" (valueChanged)=\"valueChanged($event)\"></lib-selection-options-editor>\n }\n\n @case (\n elementEditorTypes.ApiCall) {\n\n <lib-rest-api-call-setup\n [id]=\"((vm.editorConfigValue)?.id)\"\n [postmanCollectionConfig]=\"(vm.editorConfigValue)?.postmanCollectionConfig\"\n [httpGetDataFunction]=\"(vm.editorConfigValue)?.httpGetDataFunction\" [disabled]=\"(vm.disabled)||false\"\n [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\">\n\n </lib-rest-api-call-setup>\n\n }\n\n @case (elementEditorTypes.ApiValueAccessRules) {\n\n\n\n <lib-api-value-access-rules [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\"\n [formInputs]=\"formInputs() ||[]\"\n\n [postmanCollectionConfig]=\"(vm.editorConfigValue)?.postmanCollectionConfig\" [mapToData]=\"vm.dataOptions\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-api-value-access-rules>\n\n }\n\n @case (elementEditorTypes.FormInputSelector)\n {\n\n <lib-form-input-selector [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [formInputs]=\"formInputs() ||[]\"\n [errors]=\"(validationErrors())||[]\" [value]=\"$any(vm.value) || []\" (change)=\"valueChanged($event)\">\n </lib-form-input-selector>\n }\n\n @case (\n elementEditorTypes.RequiredInputs\n ){\n\n <lib-required-inputs [formInputs]=\"formInputs() ||[]\" [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\">\n </lib-required-inputs>\n }\n\n @case(elementEditorTypes.ConfigMscoaSegments){\n\n <lib-mscoa-segment-config [disabled]=\"(vm.disabled)||false\" [id]=\"((vm.editorConfigValue)?.id)\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getMscoaTree]=\"getMscoaTree$\" [dataValue]=\"$any(vm.dataValue)\"\n [isCashSegmentConfig]=\"vm.editorConfigValue?.deepBind?.at(-1) === 'cashSegments'\"\n [showAllSegments]=\"vm.dataOptions\" (valueChanged)=\"valueChanged($event)\"></lib-mscoa-segment-config>\n }\n @case (elementEditorTypes.ChipOptionsCreator) {\n <lib-chip-options-creator-editor [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" (valueChange)=\"valueChanged($event)\"\n [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\">\n\n </lib-chip-options-creator-editor>\n\n }\n @case (elementEditorTypes.FormPayloadProjection) {\n <lib-form-payload-projection [disabled]=\"(vm.disabled)||false\" [value]=\"$any(vm.value)\"\n [formInputs]=\"formInputs() ||[]\" [errors]=\"(validationErrors())||[]\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-form-payload-projection>\n\n }\n }\n </fieldset>\n\n @if ((vm. editorConfigValue)?.hint) {\n <small class=\"non-control-editor__hint\">{{ (vm. editorConfigValue)?.hint }}</small>\n }\n </div>\n }\n\n @if (!(vm.value) && (vm. editorConfigValue)?.required ) {\n <mat-error>\n {{ (vm. editorConfigValue)?.label }}'s is required\n </mat-error>}\n\n @for (error of (validationErrors())||[]; track error.key) {\n <mat-error style=\" font-size: 0.75em;\n margin-left: 14px;\n \">\n\n {{error.message}}</mat-error>\n }\n\n}\n\n}@error {\n<mat-card>\n <mat-card-content>\n\n <span>\n Failed to load form inputs\n </span>\n </mat-card-content>\n</mat-card>\n}\n\n\n\n<!-- -\n `TableConfigSetup`\n- `ConditionalInputConfig`\n- `MatrixTable`-->\n", styles: [".showItemValue{opacity:.6}.non-control-editor{display:flex;flex-direction:column;width:100%}.non-control-editor__field{margin:0;min-width:0;width:100%;box-sizing:border-box;display:flex;flex-direction:column;padding:.75rem;border:1px solid var(--mat-sys-outline-variant, var(--mat-app-outline));border-radius:var(--mdc-outlined-text-field-container-shape, 4px)}.non-control-editor__label{padding:0 .25rem;margin-left:.5rem;font-size:.75rem;font-weight:400;line-height:1;color:var(--mat-sys-on-surface-variant, var(--mat-app-on-surface-variant, var(--mat-app-outline)))}.non-control-editor__hint{margin-top:.5rem;padding:0 .875rem;font-size:.75rem;line-height:1.5;color:var(--mat-sys-on-surface-variant, var(--mat-app-on-surface-variant, var(--mat-app-outline)))}mat-form-field{width:100%}mat-slider{width:100%}.range{display:flex;align-items:center}.elementInfo{display:flex;align-items:center;justify-content:center;padding:0;height:24px;width:24px}.infoIcon{font-size:1em;height:16px;width:16px}.toggle-label{margin-left:5px;align-items:center;display:flex;font-weight:500;line-height:normal;justify-content:space-between;color:var(--mdc-filled-text-field-focus-label-text-color, var(--mat-app-primary))}\n"], dependencies: [{ kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatSelectModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i3$3.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i3$3.MatCardContent, selector: "mat-card-content" }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [import('./ngx-t-forms-selection-options-editor.component-Dhln81DL.mjs').then(m => m.SelectionOptionsEditorComponent), import('./ngx-t-forms-form-input-selector.component-C9u8zq9B.mjs').then(m => m.FormInputSelectorComponent), import('./ngx-t-forms-rest-api-call-setup.component-C_aFtdvW.mjs').then(m => m.RestApiCallSetupComponent), Promise.resolve().then(function () { return apiValueAccessRules_component; }).then(m => m.ApiValueAccessRulesComponent), import('./ngx-t-forms-required-inputs.component-Ch2yNcIS.mjs').then(m => m.RequiredInputsComponent), import('./ngx-t-forms-pipeline-generator.component-DmNSc5aw.mjs').then(m => m.PipelineGeneratorComponent), import('./ngx-t-forms-calculated-field-rules.component-C5TPddVe.mjs').then(m => m.CalculatedFieldRulesComponent), import('./ngx-t-forms-validators-config.component-oGjQVGE2.mjs').then(m => m.ValidatorsConfigComponent), import('./ngx-t-forms-config-mscoa-additional-inputs.component-CzisLSIP.mjs').then(m => m.ConfigMscoaAdditionalInputsComponent), import('./ngx-t-forms-mat-slider-editor.component-CTSBrM-j.mjs').then(m => m.MatSliderEditorComponent), import('./ngx-t-forms-mscoa-segment-config.component-C0qsMfsq.mjs').then(m => m.MscoaSegmentConfigComponent), import('./ngx-t-forms-mat-slider-toggle-editor.component-CcYiwx-8.mjs').then(m => m.MatSliderToggleEditorComponent), import('./ngx-t-forms-mat-chip-list-editor.component-c7uZT1sr.mjs').then(m => m.MatChipListEditorComponent), i2.MatFormField, i2.MatLabel, i2.MatError, i2.MatSuffix, i8.MatSelect, i8.MatOption, i1$2.MatIconButton, i3$1.MatIcon, i5$1.MatTooltip, import('./ngx-t-forms-chip-options-creator-editor.component-CICQaqz6.mjs').then(m => m.ChipOptionsCreatorEditorComponent), import('./ngx-t-forms-data-source-picker.component-Dzz_o6fJ.mjs').then(m => m.DataSourcePickerComponent), import('./ngx-t-forms-document-list-label-config-editor.component-CLUOXreG.mjs').then(m => m.DocumentListLabelConfigEditorComponent), import('./ngx-t-forms-t-workflow-picker.component-leBokXvM.mjs').then(m => m.TWorkflowPickerComponent), import('./ngx-t-forms-editor-js-input.component-BQL0AH7H.mjs').then(m => m.EditorJsInputComponent), import('./ngx-t-forms-record-list-manager.component-CUMMvMch.mjs').then(m => m.RecordListManagerComponent), import('./ngx-t-forms-form-payload-projection.component-CDkTuX9S.mjs').then(m => m.FormPayloadProjectionComponent), import('./ngx-t-forms-input-custom.component-BkbHFAyR.mjs').then(m => m.InputCustomComponent), i1$1.NgControlStatus, i1$1.RequiredValidator, i1$1.NgModel, import('./ngx-t-forms-map-mat-options-keys-B6hJ7Io5.mjs').then(m => m.MapMatOptionsKeys), import('@angular/common').then(m => m.AsyncPipe)]] }); }
|
|
13663
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: TDynamicDataEditComponent, isStandalone: true, selector: "lib-t-dynamic-data-edit", inputs: { editorConfig: { classPropertyName: "editorConfig", publicName: "editorConfig", isSignal: true, isRequired: false, transformFunction: null }, formInputs: { classPropertyName: "formInputs", publicName: "formInputs", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, validationErrors: { classPropertyName: "validationErrors", publicName: "validationErrors", isSignal: true, isRequired: false, transformFunction: null }, mscoaSaveCustomInput: { classPropertyName: "mscoaSaveCustomInput", publicName: "mscoaSaveCustomInput", isSignal: true, isRequired: false, transformFunction: null }, mscoaEditInput: { classPropertyName: "mscoaEditInput", publicName: "mscoaEditInput", isSignal: true, isRequired: false, transformFunction: null }, mscoaDeleteInput: { classPropertyName: "mscoaDeleteInput", publicName: "mscoaDeleteInput", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", blur: "blur" }, providers: [{ provide: NESTED_EDITOR_COMPONENT, useValue: TDynamicDataEditComponent }], ngImport: i0, template: "@defer {\n@if (( vm$ |async); as vm) {\n\n @if (vm.isFormFieldControl) {\n <!-- Editor types that resolve to a MatFormFieldControl render inside the field. -->\n <mat-form-field appearance=\"outline\" [color]=\"((validationErrors())||[]).length>0 ? 'warn' : 'primary'\"\n [floatLabel]=\"'always'\" [subscriptSizing]=\"'dynamic'\" [hintLabel]=\"vm.editorConfigValue?.hint||''\">\n <mat-label> {{ (vm. editorConfigValue)?.label }} </mat-label>\n @switch ((vm. editorConfigValue)?.editType) {\n @default {\n <lib-input-custom\n [id]=\"((vm.editorConfigValue)?.id)\"\n [inputConfig]=\"$any(vm.inputConfig)\"\n [placeholder]=\"(vm. editorConfigValue)?.placeholder ||'Enter value'\"\n [required]=\"!!(vm. editorConfigValue)?.required\"\n [disabled]=\"!!(vm.disabled)\"\n [ngModel]=\"(vm.value)\"\n (blur)=\"elementBlur($event)\"\n (input)=\"inputChange($event)\" ></lib-input-custom>\n\n\n }\n @case ( elementEditorTypes.Toggle) {\n <lib-mat-slider-toggle-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [name]=\"((vm. editorConfigValue)?.name||'') \"\n [label]=\"((vm. editorConfigValue)?.label||'')\" [disabled]=\"(vm.disabled)||false\"\n (valueChange)=\"valueChanged(!!$event)\" [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\">\n </lib-mat-slider-toggle-editor>\n\n }\n\n @case (elementEditorTypes.Range) {\n\n\n <lib-mat-slider-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [format]=\"( vm.editorConfigValue)?.format \" [formatLabel]=\" formatLabel\"\n [disabled]=\"(vm.disabled)||false\" [max]=\"( vm.editorConfigValue)?.max || 100\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [min]=\"( vm.editorConfigValue)?.min || 0\"\n (valueChange)=\"inputChange($event)\" [step]=\"( vm.editorConfigValue)?.step || 1\">\n\n\n </lib-mat-slider-editor>\n\n\n\n }\n\n @case (elementEditorTypes.OptionSelect) {\n\n <mat-select\n\n [value]=\"$any(vm.value)\" (selectionChange)=\"valueChanged($event.value)\"\n [disabled]=\"(vm.disabled)||false\">\n @for(option of ( vm.editorConfigValue)?.options || vm.dataOptions;track option.value){\n <mat-option [value]=\"option.value\">{{option.label}}</mat-option>\n }\n </mat-select>\n\n }\n\n @case (elementEditorTypes.RichTextEditor) {\n <lib-editor-js-input\n\n [id]=\"((vm.editorConfigValue)?.id)\"\n [value]=\"$any(vm.value)\" (valueChanged)=\"valueChanged($event)\"\n [disabled]=\"(vm.disabled)||false\" [inputConfig]=\"$any(data())\">\n </lib-editor-js-input>\n }\n\n @case (elementEditorTypes.MongoPipelineBuilder) {\n\n <lib-pipeline-generator [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getWorkflowOptions]=\"getWorkflowOptions$\"\n (valueChanged)=\"valueChanged($event)\"></lib-pipeline-generator>\n\n }\n @case (elementEditorTypes.MapMatOptionsKeys) {\n <lib-map-mat-options-keys [disabled]=\"(vm.disabled)||false\"\n [value]=\"$any(vm.value)\"\n [formInputs]=\"formInputs() || []\"\n [mapToData]=\"vm.dataOptions\"\n [errors]=\"(validationErrors())||[]\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-map-mat-options-keys>\n\n }\n\n @case(elementEditorTypes.CalculatedFieldRules){\n\n <lib-calculated-field-rules [formInputs]=\"formInputs() ||[]\" [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\"\n [mapToData]=\"vm.dataOptions\"></lib-calculated-field-rules>\n }\n\n @case(elementEditorTypes.Validators){\n\n <lib-validators-config [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\" [formInputs]=\"formInputs() ||[]\"\n [mapToData]=\"vm.dataOptions\">\n </lib-validators-config>\n\n }\n @case(elementEditorTypes.ConfigMscoaAdditionalInputs){\n\n <lib-config-mscoa-additional-inputs [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getMscoaTree]=\"getMscoaTree$\" [mapToData]=\"vm.dataOptions\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-config-mscoa-additional-inputs>\n\n }\n @case (elementEditorTypes.DataSourcePicker) {\n <lib-data-source-picker [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [editorConfig]=\"vm. editorConfigValue\"\n (valueChange)=\"valueChanged($event)\" [formInputs]=\"formInputs() ||[]\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\">\n </lib-data-source-picker>\n }\n @case (elementEditorTypes.ListLabelConfigEditor) {\n <lib-document-list-label-config-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [formInputs]=\"formInputs() ||[]\"\n [disabled]=\"(vm.disabled)||false\"\n [editorConfig]=\"vm. editorConfigValue\"\n (valueChange)=\"valueChanged($event)\"\n [value]=\"$any(vm.value)\" [mapToData]=\"vm.dataOptions\"\n [errors]=\"(validationErrors())||[]\">\n\n </lib-document-list-label-config-editor>\n }\n @case(\n elementEditorTypes.WorkflowPicker\n ){\n <lib-t-workflow-picker [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [getWorkflowOptions]=\"getWorkflowOptions$\"\n (valueChanged)=\"valueChanged($event)\" [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\"></lib-t-workflow-picker>\n }\n @case (\n elementEditorTypes.RecordListManager\n ) {\n <lib-record-list-manager\n [id]=\"((vm.editorConfigValue)?.id)\"\n [editorConfig]=\"vm.editorConfigValue\" [disabled]=\"(vm.disabled)||false\"\n [formInputs]=\"formInputs() ||[]\" [mapToData]=\"vm.dataOptions\" (valueChange)=\"valueChanged($event)\"\n\n [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\"></lib-record-list-manager>\n }\n }\n\n @if (vm.inputHasBlurFunction) {\n <button [matTooltip]=\"blurFunctionTooltip((vm.editorConfigValue)?.blurHandle)\"\n [disabled]=\"(vm.disabled)\" [color]=\"blurOff?'':'primary'\" (click)=\"blurOff=!blurOff\" matSuffix\n mat-icon-button>\n <mat-icon>{{\n blurOff?'blur_off':'blur_on'\n }}\n\n\n </mat-icon>\n </button>\n }\n </mat-form-field>\n } @else {\n <!-- Editor types backed by plain (signal-based) components render outside\n the field, since they are not MatFormFieldControls. They are wrapped to\n mirror the outline mat-form-field appearance: the fieldset draws the\n outline, its legend is the notched floating label, and the hint renders\n as a subscript below the box. -->\n <div class=\"non-control-editor\">\n <fieldset class=\"non-control-editor__field\">\n @if ((vm. editorConfigValue)?.label) {\n <legend class=\"non-control-editor__label\">{{ (vm. editorConfigValue)?.label }}</legend>\n }\n @switch ((vm. editorConfigValue)?.editType) {\n\n @case (elementEditorTypes.ChipSelect) {\n\n <lib-mat-chip-list-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [multiple]=\"!!vm.editorConfigValue?.multipleSelection\"\n [disabled]=\"(vm.disabled)||false\"\n [options]=\"(vm.editorConfigValue)?.options || vm.dataOptions\"\n [required]=\"!!( vm.editorConfigValue)?.required\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\"\n (valueChange)=\" valueChanged($event)\"></lib-mat-chip-list-editor>\n\n\n }\n\n @case (elementEditorTypes.SelectionOptions) {\n\n <lib-selection-options-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [errors]=\"(validationErrors())||[]\" [disabled]=\"(vm.disabled)||false\"\n [options]=\"$any(vm.value) || []\" (valueChanged)=\"valueChanged($event)\"></lib-selection-options-editor>\n }\n\n @case (\n elementEditorTypes.ApiCall) {\n\n <lib-rest-api-call-setup\n [id]=\"((vm.editorConfigValue)?.id)\"\n [postmanCollectionConfig]=\"(vm.editorConfigValue)?.postmanCollectionConfig\"\n [httpGetDataFunction]=\"(vm.editorConfigValue)?.httpGetDataFunction\" [disabled]=\"(vm.disabled)||false\"\n [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\">\n\n </lib-rest-api-call-setup>\n\n }\n\n @case (elementEditorTypes.ApiValueAccessRules) {\n\n\n\n <lib-api-value-access-rules [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\"\n [formInputs]=\"formInputs() ||[]\"\n\n [postmanCollectionConfig]=\"(vm.editorConfigValue)?.postmanCollectionConfig\" [mapToData]=\"vm.dataOptions\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-api-value-access-rules>\n\n }\n\n @case (elementEditorTypes.FormInputSelector)\n {\n\n <lib-form-input-selector [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [formInputs]=\"formInputs() ||[]\"\n [errors]=\"(validationErrors())||[]\" [value]=\"$any(vm.value) || []\" (change)=\"valueChanged($event)\">\n </lib-form-input-selector>\n }\n\n @case (\n elementEditorTypes.RequiredInputs\n ){\n\n <lib-required-inputs [formInputs]=\"formInputs() ||[]\" [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\">\n </lib-required-inputs>\n }\n\n @case(elementEditorTypes.ConfigMscoaSegments){\n\n <lib-mscoa-segment-config [disabled]=\"(vm.disabled)||false\" [id]=\"((vm.editorConfigValue)?.id)\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getMscoaTree]=\"getMscoaTree$\" [dataValue]=\"$any(vm.dataValue)\"\n [isCashSegmentConfig]=\"vm.editorConfigValue?.deepBind?.at(-1) === 'cashSegments'\"\n [saveCustomInput]=\"mscoaSaveCustomInput()\"\n [editSegmentInput]=\"mscoaEditInput()\"\n [deleteSegmentInput]=\"mscoaDeleteInput()\"\n [showAllSegments]=\"vm.dataOptions\" (valueChanged)=\"valueChanged($event)\"></lib-mscoa-segment-config>\n }\n @case (elementEditorTypes.ChipOptionsCreator) {\n <lib-chip-options-creator-editor [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" (valueChange)=\"valueChanged($event)\"\n [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\">\n\n </lib-chip-options-creator-editor>\n\n }\n @case (elementEditorTypes.FormPayloadProjection) {\n <lib-form-payload-projection [disabled]=\"(vm.disabled)||false\" [value]=\"$any(vm.value)\"\n [formInputs]=\"formInputs() ||[]\" [errors]=\"(validationErrors())||[]\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-form-payload-projection>\n\n }\n }\n </fieldset>\n\n @if ((vm. editorConfigValue)?.hint) {\n <small class=\"non-control-editor__hint\">{{ (vm. editorConfigValue)?.hint }}</small>\n }\n </div>\n }\n\n @if (!(vm.value) && (vm. editorConfigValue)?.required ) {\n <mat-error>\n {{ (vm. editorConfigValue)?.label }}'s is required\n </mat-error>}\n\n @for (error of (validationErrors())||[]; track error.key) {\n <mat-error style=\" font-size: 0.75em;\n margin-left: 14px;\n \">\n\n {{error.message}}</mat-error>\n }\n\n}\n\n}@error {\n<mat-card>\n <mat-card-content>\n\n <span>\n Failed to load form inputs\n </span>\n </mat-card-content>\n</mat-card>\n}\n\n\n\n<!-- -\n `TableConfigSetup`\n- `ConditionalInputConfig`\n- `MatrixTable`-->\n", styles: [".showItemValue{opacity:.6}.non-control-editor{display:flex;flex-direction:column;width:100%}.non-control-editor__field{margin:0;min-width:0;width:100%;box-sizing:border-box;display:flex;flex-direction:column;padding:.75rem;border:1px solid var(--mat-sys-outline-variant, var(--mat-app-outline));border-radius:var(--mdc-outlined-text-field-container-shape, 4px)}.non-control-editor__label{padding:0 .25rem;margin-left:.5rem;font-size:.75rem;font-weight:400;line-height:1;color:var(--mat-sys-on-surface-variant, var(--mat-app-on-surface-variant, var(--mat-app-outline)))}.non-control-editor__hint{margin-top:.5rem;padding:0 .875rem;font-size:.75rem;line-height:1.5;color:var(--mat-sys-on-surface-variant, var(--mat-app-on-surface-variant, var(--mat-app-outline)))}mat-form-field{width:100%}mat-slider{width:100%}.range{display:flex;align-items:center}.elementInfo{display:flex;align-items:center;justify-content:center;padding:0;height:24px;width:24px}.infoIcon{font-size:1em;height:16px;width:16px}.toggle-label{margin-left:5px;align-items:center;display:flex;font-weight:500;line-height:normal;justify-content:space-between;color:var(--mdc-filled-text-field-focus-label-text-color, var(--mat-app-primary))}\n"], dependencies: [{ kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatSelectModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i3$3.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i3$3.MatCardContent, selector: "mat-card-content" }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [import('./ngx-t-forms-selection-options-editor.component-KjbZhc2u.mjs').then(m => m.SelectionOptionsEditorComponent), import('./ngx-t-forms-form-input-selector.component-B42xP3jh.mjs').then(m => m.FormInputSelectorComponent), import('./ngx-t-forms-rest-api-call-setup.component-WPUxtY7Q.mjs').then(m => m.RestApiCallSetupComponent), Promise.resolve().then(function () { return apiValueAccessRules_component; }).then(m => m.ApiValueAccessRulesComponent), import('./ngx-t-forms-required-inputs.component-ONbhxVSH.mjs').then(m => m.RequiredInputsComponent), import('./ngx-t-forms-pipeline-generator.component-CZ21sd77.mjs').then(m => m.PipelineGeneratorComponent), import('./ngx-t-forms-calculated-field-rules.component-BhxT6tRq.mjs').then(m => m.CalculatedFieldRulesComponent), import('./ngx-t-forms-validators-config.component-BknyAmV_.mjs').then(m => m.ValidatorsConfigComponent), import('./ngx-t-forms-config-mscoa-additional-inputs.component-Gn8exJ9a.mjs').then(m => m.ConfigMscoaAdditionalInputsComponent), import('./ngx-t-forms-mat-slider-editor.component-CTSBrM-j.mjs').then(m => m.MatSliderEditorComponent), import('./ngx-t-forms-mscoa-segment-config.component-Bo0aDEMy.mjs').then(m => m.MscoaSegmentConfigComponent), import('./ngx-t-forms-mat-slider-toggle-editor.component-CcYiwx-8.mjs').then(m => m.MatSliderToggleEditorComponent), import('./ngx-t-forms-mat-chip-list-editor.component-BWisS3Em.mjs').then(m => m.MatChipListEditorComponent), i2.MatFormField, i2.MatLabel, i2.MatError, i2.MatSuffix, i8.MatSelect, i8.MatOption, i1$2.MatIconButton, i3$1.MatIcon, i5$1.MatTooltip, import('./ngx-t-forms-chip-options-creator-editor.component-d4QeVhsp.mjs').then(m => m.ChipOptionsCreatorEditorComponent), import('./ngx-t-forms-data-source-picker.component-Ebf_if9j.mjs').then(m => m.DataSourcePickerComponent), import('./ngx-t-forms-document-list-label-config-editor.component-CR6EvgJO.mjs').then(m => m.DocumentListLabelConfigEditorComponent), import('./ngx-t-forms-t-workflow-picker.component-CtavFAUq.mjs').then(m => m.TWorkflowPickerComponent), import('./ngx-t-forms-editor-js-input.component-5MD8wRj0.mjs').then(m => m.EditorJsInputComponent), import('./ngx-t-forms-record-list-manager.component-CykBq_nW.mjs').then(m => m.RecordListManagerComponent), import('./ngx-t-forms-form-payload-projection.component-Ip9ewB18.mjs').then(m => m.FormPayloadProjectionComponent), import('./ngx-t-forms-input-custom.component-Cn-KH0Lb.mjs').then(m => m.InputCustomComponent), i1$1.NgControlStatus, i1$1.RequiredValidator, i1$1.NgModel, import('./ngx-t-forms-map-mat-options-keys-CVlPdrCO.mjs').then(m => m.MapMatOptionsKeys), import('@angular/common').then(m => m.AsyncPipe)]] }); }
|
|
13187
13664
|
}
|
|
13188
|
-
i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.2.12", ngImport: i0, type: TDynamicDataEditComponent, resolveDeferredDeps: () => [import('./ngx-t-forms-selection-options-editor.component-
|
|
13665
|
+
i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.2.12", ngImport: i0, type: TDynamicDataEditComponent, resolveDeferredDeps: () => [import('./ngx-t-forms-selection-options-editor.component-KjbZhc2u.mjs').then(m => m.SelectionOptionsEditorComponent), import('./ngx-t-forms-form-input-selector.component-B42xP3jh.mjs').then(m => m.FormInputSelectorComponent), import('./ngx-t-forms-rest-api-call-setup.component-WPUxtY7Q.mjs').then(m => m.RestApiCallSetupComponent), Promise.resolve().then(function () { return apiValueAccessRules_component; }).then(m => m.ApiValueAccessRulesComponent), import('./ngx-t-forms-required-inputs.component-ONbhxVSH.mjs').then(m => m.RequiredInputsComponent), import('./ngx-t-forms-pipeline-generator.component-CZ21sd77.mjs').then(m => m.PipelineGeneratorComponent), import('./ngx-t-forms-calculated-field-rules.component-BhxT6tRq.mjs').then(m => m.CalculatedFieldRulesComponent), import('./ngx-t-forms-validators-config.component-BknyAmV_.mjs').then(m => m.ValidatorsConfigComponent), import('./ngx-t-forms-config-mscoa-additional-inputs.component-Gn8exJ9a.mjs').then(m => m.ConfigMscoaAdditionalInputsComponent), import('./ngx-t-forms-mat-slider-editor.component-CTSBrM-j.mjs').then(m => m.MatSliderEditorComponent), import('./ngx-t-forms-mscoa-segment-config.component-Bo0aDEMy.mjs').then(m => m.MscoaSegmentConfigComponent), import('./ngx-t-forms-mat-slider-toggle-editor.component-CcYiwx-8.mjs').then(m => m.MatSliderToggleEditorComponent), import('./ngx-t-forms-mat-chip-list-editor.component-BWisS3Em.mjs').then(m => m.MatChipListEditorComponent), import('./ngx-t-forms-chip-options-creator-editor.component-d4QeVhsp.mjs').then(m => m.ChipOptionsCreatorEditorComponent), import('./ngx-t-forms-data-source-picker.component-Ebf_if9j.mjs').then(m => m.DataSourcePickerComponent), import('./ngx-t-forms-document-list-label-config-editor.component-CR6EvgJO.mjs').then(m => m.DocumentListLabelConfigEditorComponent), import('./ngx-t-forms-t-workflow-picker.component-CtavFAUq.mjs').then(m => m.TWorkflowPickerComponent), import('./ngx-t-forms-editor-js-input.component-5MD8wRj0.mjs').then(m => m.EditorJsInputComponent), import('./ngx-t-forms-record-list-manager.component-CykBq_nW.mjs').then(m => m.RecordListManagerComponent), import('./ngx-t-forms-form-payload-projection.component-Ip9ewB18.mjs').then(m => m.FormPayloadProjectionComponent), import('./ngx-t-forms-input-custom.component-Cn-KH0Lb.mjs').then(m => m.InputCustomComponent), import('./ngx-t-forms-map-mat-options-keys-CVlPdrCO.mjs').then(m => m.MapMatOptionsKeys), import('@angular/common').then(m => m.AsyncPipe)], resolveMetadata: (SelectionOptionsEditorComponent, FormInputSelectorComponent, RestApiCallSetupComponent, ApiValueAccessRulesComponent, RequiredInputsComponent, PipelineGeneratorComponent, CalculatedFieldRulesComponent, ValidatorsConfigComponent, ConfigMscoaAdditionalInputsComponent, MatSliderEditorComponent, MscoaSegmentConfigComponent, MatSliderToggleEditorComponent, MatChipListEditorComponent, ChipOptionsCreatorEditorComponent, DataSourcePickerComponent, DocumentListLabelConfigEditorComponent, TWorkflowPickerComponent, EditorJsInputComponent, RecordListManagerComponent, FormPayloadProjectionComponent, InputCustomComponent, MapMatOptionsKeys, AsyncPipe) => ({ decorators: [{
|
|
13189
13666
|
type: Component,
|
|
13190
13667
|
args: [{ selector: 'lib-t-dynamic-data-edit', imports: [
|
|
13191
13668
|
AsyncPipe,
|
|
@@ -13218,8 +13695,8 @@ i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.2.12", n
|
|
|
13218
13695
|
InputCustomComponent,
|
|
13219
13696
|
FormsModule,
|
|
13220
13697
|
MapMatOptionsKeys,
|
|
13221
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, providers: [{ provide: NESTED_EDITOR_COMPONENT, useValue: TDynamicDataEditComponent }], template: "@defer {\n@if (( vm$ |async); as vm) {\n\n @if (vm.isFormFieldControl) {\n <!-- Editor types that resolve to a MatFormFieldControl render inside the field. -->\n <mat-form-field appearance=\"outline\" [color]=\"((validationErrors())||[]).length>0 ? 'warn' : 'primary'\"\n [floatLabel]=\"'always'\" [subscriptSizing]=\"'dynamic'\" [hintLabel]=\"vm.editorConfigValue?.hint||''\">\n <mat-label> {{ (vm. editorConfigValue)?.label }} </mat-label>\n @switch ((vm. editorConfigValue)?.editType) {\n @default {\n <lib-input-custom\n [id]=\"((vm.editorConfigValue)?.id)\"\n [inputConfig]=\"$any(vm.inputConfig)\"\n [placeholder]=\"(vm. editorConfigValue)?.placeholder ||'Enter value'\"\n [required]=\"!!(vm. editorConfigValue)?.required\"\n [disabled]=\"!!(vm.disabled)\"\n [ngModel]=\"(vm.value)\"\n (blur)=\"elementBlur($event)\"\n (input)=\"inputChange($event)\" ></lib-input-custom>\n\n\n }\n @case ( elementEditorTypes.Toggle) {\n <lib-mat-slider-toggle-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [name]=\"((vm. editorConfigValue)?.name||'') \"\n [label]=\"((vm. editorConfigValue)?.label||'')\" [disabled]=\"(vm.disabled)||false\"\n (valueChange)=\"valueChanged(!!$event)\" [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\">\n </lib-mat-slider-toggle-editor>\n\n }\n\n @case (elementEditorTypes.Range) {\n\n\n <lib-mat-slider-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [format]=\"( vm.editorConfigValue)?.format \" [formatLabel]=\" formatLabel\"\n [disabled]=\"(vm.disabled)||false\" [max]=\"( vm.editorConfigValue)?.max || 100\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [min]=\"( vm.editorConfigValue)?.min || 0\"\n (valueChange)=\"inputChange($event)\" [step]=\"( vm.editorConfigValue)?.step || 1\">\n\n\n </lib-mat-slider-editor>\n\n\n\n }\n\n @case (elementEditorTypes.OptionSelect) {\n\n <mat-select\n\n [value]=\"$any(vm.value)\" (selectionChange)=\"valueChanged($event.value)\"\n [disabled]=\"(vm.disabled)||false\">\n @for(option of ( vm.editorConfigValue)?.options || vm.dataOptions;track option.value){\n <mat-option [value]=\"option.value\">{{option.label}}</mat-option>\n }\n </mat-select>\n\n }\n\n @case (elementEditorTypes.RichTextEditor) {\n <lib-editor-js-input\n\n [id]=\"((vm.editorConfigValue)?.id)\"\n [value]=\"$any(vm.value)\" (valueChanged)=\"valueChanged($event)\"\n [disabled]=\"(vm.disabled)||false\" [inputConfig]=\"$any(data())\">\n </lib-editor-js-input>\n }\n\n @case (elementEditorTypes.MongoPipelineBuilder) {\n\n <lib-pipeline-generator [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getWorkflowOptions]=\"getWorkflowOptions$\"\n (valueChanged)=\"valueChanged($event)\"></lib-pipeline-generator>\n\n }\n @case (elementEditorTypes.MapMatOptionsKeys) {\n <lib-map-mat-options-keys [disabled]=\"(vm.disabled)||false\"\n [value]=\"$any(vm.value)\"\n [formInputs]=\"formInputs() || []\"\n [mapToData]=\"vm.dataOptions\"\n [errors]=\"(validationErrors())||[]\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-map-mat-options-keys>\n\n }\n\n @case(elementEditorTypes.CalculatedFieldRules){\n\n <lib-calculated-field-rules [formInputs]=\"formInputs() ||[]\" [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\"\n [mapToData]=\"vm.dataOptions\"></lib-calculated-field-rules>\n }\n\n @case(elementEditorTypes.Validators){\n\n <lib-validators-config [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\" [formInputs]=\"formInputs() ||[]\"\n [mapToData]=\"vm.dataOptions\">\n </lib-validators-config>\n\n }\n @case(elementEditorTypes.ConfigMscoaAdditionalInputs){\n\n <lib-config-mscoa-additional-inputs [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getMscoaTree]=\"getMscoaTree$\" [mapToData]=\"vm.dataOptions\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-config-mscoa-additional-inputs>\n\n }\n @case (elementEditorTypes.DataSourcePicker) {\n <lib-data-source-picker [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [editorConfig]=\"vm. editorConfigValue\"\n (valueChange)=\"valueChanged($event)\" [formInputs]=\"formInputs() ||[]\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\">\n </lib-data-source-picker>\n }\n @case (elementEditorTypes.ListLabelConfigEditor) {\n <lib-document-list-label-config-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [formInputs]=\"formInputs() ||[]\"\n [disabled]=\"(vm.disabled)||false\"\n [editorConfig]=\"vm. editorConfigValue\"\n (valueChange)=\"valueChanged($event)\"\n [value]=\"$any(vm.value)\" [mapToData]=\"vm.dataOptions\"\n [errors]=\"(validationErrors())||[]\">\n\n </lib-document-list-label-config-editor>\n }\n @case(\n elementEditorTypes.WorkflowPicker\n ){\n <lib-t-workflow-picker [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [getWorkflowOptions]=\"getWorkflowOptions$\"\n (valueChanged)=\"valueChanged($event)\" [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\"></lib-t-workflow-picker>\n }\n @case (\n elementEditorTypes.RecordListManager\n ) {\n <lib-record-list-manager\n [id]=\"((vm.editorConfigValue)?.id)\"\n [editorConfig]=\"vm.editorConfigValue\" [disabled]=\"(vm.disabled)||false\"\n [formInputs]=\"formInputs() ||[]\" [mapToData]=\"vm.dataOptions\" (valueChange)=\"valueChanged($event)\"\n\n [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\"></lib-record-list-manager>\n }\n }\n\n @if (vm.inputHasBlurFunction) {\n <button [matTooltip]=\"blurFunctionTooltip((vm.editorConfigValue)?.blurHandle)\"\n [disabled]=\"(vm.disabled)\" [color]=\"blurOff?'':'primary'\" (click)=\"blurOff=!blurOff\" matSuffix\n mat-icon-button>\n <mat-icon>{{\n blurOff?'blur_off':'blur_on'\n }}\n\n\n </mat-icon>\n </button>\n }\n </mat-form-field>\n } @else {\n <!-- Editor types backed by plain (signal-based) components render outside\n the field, since they are not MatFormFieldControls. They are wrapped to\n mirror the outline mat-form-field appearance: the fieldset draws the\n outline, its legend is the notched floating label, and the hint renders\n as a subscript below the box. -->\n <div class=\"non-control-editor\">\n <fieldset class=\"non-control-editor__field\">\n @if ((vm. editorConfigValue)?.label) {\n <legend class=\"non-control-editor__label\">{{ (vm. editorConfigValue)?.label }}</legend>\n }\n @switch ((vm. editorConfigValue)?.editType) {\n\n @case (elementEditorTypes.ChipSelect) {\n\n <lib-mat-chip-list-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [multiple]=\"!!vm.editorConfigValue?.multipleSelection\"\n [disabled]=\"(vm.disabled)||false\"\n [options]=\"(vm.editorConfigValue)?.options || vm.dataOptions\"\n [required]=\"!!( vm.editorConfigValue)?.required\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\"\n (valueChange)=\" valueChanged($event)\"></lib-mat-chip-list-editor>\n\n\n }\n\n @case (elementEditorTypes.SelectionOptions) {\n\n <lib-selection-options-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [errors]=\"(validationErrors())||[]\" [disabled]=\"(vm.disabled)||false\"\n [options]=\"$any(vm.value) || []\" (valueChanged)=\"valueChanged($event)\"></lib-selection-options-editor>\n }\n\n @case (\n elementEditorTypes.ApiCall) {\n\n <lib-rest-api-call-setup\n [id]=\"((vm.editorConfigValue)?.id)\"\n [postmanCollectionConfig]=\"(vm.editorConfigValue)?.postmanCollectionConfig\"\n [httpGetDataFunction]=\"(vm.editorConfigValue)?.httpGetDataFunction\" [disabled]=\"(vm.disabled)||false\"\n [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\">\n\n </lib-rest-api-call-setup>\n\n }\n\n @case (elementEditorTypes.ApiValueAccessRules) {\n\n\n\n <lib-api-value-access-rules [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\"\n [formInputs]=\"formInputs() ||[]\"\n\n [postmanCollectionConfig]=\"(vm.editorConfigValue)?.postmanCollectionConfig\" [mapToData]=\"vm.dataOptions\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-api-value-access-rules>\n\n }\n\n @case (elementEditorTypes.FormInputSelector)\n {\n\n <lib-form-input-selector [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [formInputs]=\"formInputs() ||[]\"\n [errors]=\"(validationErrors())||[]\" [value]=\"$any(vm.value) || []\" (change)=\"valueChanged($event)\">\n </lib-form-input-selector>\n }\n\n @case (\n elementEditorTypes.RequiredInputs\n ){\n\n <lib-required-inputs [formInputs]=\"formInputs() ||[]\" [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\">\n </lib-required-inputs>\n }\n\n @case(elementEditorTypes.ConfigMscoaSegments){\n\n <lib-mscoa-segment-config [disabled]=\"(vm.disabled)||false\" [id]=\"((vm.editorConfigValue)?.id)\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getMscoaTree]=\"getMscoaTree$\" [dataValue]=\"$any(vm.dataValue)\"\n [isCashSegmentConfig]=\"vm.editorConfigValue?.deepBind?.at(-1) === 'cashSegments'\"\n [showAllSegments]=\"vm.dataOptions\" (valueChanged)=\"valueChanged($event)\"></lib-mscoa-segment-config>\n }\n @case (elementEditorTypes.ChipOptionsCreator) {\n <lib-chip-options-creator-editor [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" (valueChange)=\"valueChanged($event)\"\n [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\">\n\n </lib-chip-options-creator-editor>\n\n }\n @case (elementEditorTypes.FormPayloadProjection) {\n <lib-form-payload-projection [disabled]=\"(vm.disabled)||false\" [value]=\"$any(vm.value)\"\n [formInputs]=\"formInputs() ||[]\" [errors]=\"(validationErrors())||[]\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-form-payload-projection>\n\n }\n }\n </fieldset>\n\n @if ((vm. editorConfigValue)?.hint) {\n <small class=\"non-control-editor__hint\">{{ (vm. editorConfigValue)?.hint }}</small>\n }\n </div>\n }\n\n @if (!(vm.value) && (vm. editorConfigValue)?.required ) {\n <mat-error>\n {{ (vm. editorConfigValue)?.label }}'s is required\n </mat-error>}\n\n @for (error of (validationErrors())||[]; track error.key) {\n <mat-error style=\" font-size: 0.75em;\n margin-left: 14px;\n \">\n\n {{error.message}}</mat-error>\n }\n\n}\n\n}@error {\n<mat-card>\n <mat-card-content>\n\n <span>\n Failed to load form inputs\n </span>\n </mat-card-content>\n</mat-card>\n}\n\n\n\n<!-- -\n `TableConfigSetup`\n- `ConditionalInputConfig`\n- `MatrixTable`-->\n", styles: [".showItemValue{opacity:.6}.non-control-editor{display:flex;flex-direction:column;width:100%}.non-control-editor__field{margin:0;min-width:0;width:100%;box-sizing:border-box;display:flex;flex-direction:column;padding:.75rem;border:1px solid var(--mat-sys-outline-variant, var(--mat-app-outline));border-radius:var(--mdc-outlined-text-field-container-shape, 4px)}.non-control-editor__label{padding:0 .25rem;margin-left:.5rem;font-size:.75rem;font-weight:400;line-height:1;color:var(--mat-sys-on-surface-variant, var(--mat-app-on-surface-variant, var(--mat-app-outline)))}.non-control-editor__hint{margin-top:.5rem;padding:0 .875rem;font-size:.75rem;line-height:1.5;color:var(--mat-sys-on-surface-variant, var(--mat-app-on-surface-variant, var(--mat-app-outline)))}mat-form-field{width:100%}mat-slider{width:100%}.range{display:flex;align-items:center}.elementInfo{display:flex;align-items:center;justify-content:center;padding:0;height:24px;width:24px}.infoIcon{font-size:1em;height:16px;width:16px}.toggle-label{margin-left:5px;align-items:center;display:flex;font-weight:500;line-height:normal;justify-content:space-between;color:var(--mdc-filled-text-field-focus-label-text-color, var(--mat-app-primary))}\n"] }]
|
|
13222
|
-
}], ctorParameters: null, propDecorators: { editorConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "editorConfig", required: false }] }], formInputs: [{ type: i0.Input, args: [{ isSignal: true, alias: "formInputs", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], validationErrors: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationErrors", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], blur: [{ type: i0.Output, args: ["blur"] }] } }) });
|
|
13698
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, providers: [{ provide: NESTED_EDITOR_COMPONENT, useValue: TDynamicDataEditComponent }], template: "@defer {\n@if (( vm$ |async); as vm) {\n\n @if (vm.isFormFieldControl) {\n <!-- Editor types that resolve to a MatFormFieldControl render inside the field. -->\n <mat-form-field appearance=\"outline\" [color]=\"((validationErrors())||[]).length>0 ? 'warn' : 'primary'\"\n [floatLabel]=\"'always'\" [subscriptSizing]=\"'dynamic'\" [hintLabel]=\"vm.editorConfigValue?.hint||''\">\n <mat-label> {{ (vm. editorConfigValue)?.label }} </mat-label>\n @switch ((vm. editorConfigValue)?.editType) {\n @default {\n <lib-input-custom\n [id]=\"((vm.editorConfigValue)?.id)\"\n [inputConfig]=\"$any(vm.inputConfig)\"\n [placeholder]=\"(vm. editorConfigValue)?.placeholder ||'Enter value'\"\n [required]=\"!!(vm. editorConfigValue)?.required\"\n [disabled]=\"!!(vm.disabled)\"\n [ngModel]=\"(vm.value)\"\n (blur)=\"elementBlur($event)\"\n (input)=\"inputChange($event)\" ></lib-input-custom>\n\n\n }\n @case ( elementEditorTypes.Toggle) {\n <lib-mat-slider-toggle-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [name]=\"((vm. editorConfigValue)?.name||'') \"\n [label]=\"((vm. editorConfigValue)?.label||'')\" [disabled]=\"(vm.disabled)||false\"\n (valueChange)=\"valueChanged(!!$event)\" [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\">\n </lib-mat-slider-toggle-editor>\n\n }\n\n @case (elementEditorTypes.Range) {\n\n\n <lib-mat-slider-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [format]=\"( vm.editorConfigValue)?.format \" [formatLabel]=\" formatLabel\"\n [disabled]=\"(vm.disabled)||false\" [max]=\"( vm.editorConfigValue)?.max || 100\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [min]=\"( vm.editorConfigValue)?.min || 0\"\n (valueChange)=\"inputChange($event)\" [step]=\"( vm.editorConfigValue)?.step || 1\">\n\n\n </lib-mat-slider-editor>\n\n\n\n }\n\n @case (elementEditorTypes.OptionSelect) {\n\n <mat-select\n\n [value]=\"$any(vm.value)\" (selectionChange)=\"valueChanged($event.value)\"\n [disabled]=\"(vm.disabled)||false\">\n @for(option of ( vm.editorConfigValue)?.options || vm.dataOptions;track option.value){\n <mat-option [value]=\"option.value\">{{option.label}}</mat-option>\n }\n </mat-select>\n\n }\n\n @case (elementEditorTypes.RichTextEditor) {\n <lib-editor-js-input\n\n [id]=\"((vm.editorConfigValue)?.id)\"\n [value]=\"$any(vm.value)\" (valueChanged)=\"valueChanged($event)\"\n [disabled]=\"(vm.disabled)||false\" [inputConfig]=\"$any(data())\">\n </lib-editor-js-input>\n }\n\n @case (elementEditorTypes.MongoPipelineBuilder) {\n\n <lib-pipeline-generator [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getWorkflowOptions]=\"getWorkflowOptions$\"\n (valueChanged)=\"valueChanged($event)\"></lib-pipeline-generator>\n\n }\n @case (elementEditorTypes.MapMatOptionsKeys) {\n <lib-map-mat-options-keys [disabled]=\"(vm.disabled)||false\"\n [value]=\"$any(vm.value)\"\n [formInputs]=\"formInputs() || []\"\n [mapToData]=\"vm.dataOptions\"\n [errors]=\"(validationErrors())||[]\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-map-mat-options-keys>\n\n }\n\n @case(elementEditorTypes.CalculatedFieldRules){\n\n <lib-calculated-field-rules [formInputs]=\"formInputs() ||[]\" [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\"\n [mapToData]=\"vm.dataOptions\"></lib-calculated-field-rules>\n }\n\n @case(elementEditorTypes.Validators){\n\n <lib-validators-config [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\" [formInputs]=\"formInputs() ||[]\"\n [mapToData]=\"vm.dataOptions\">\n </lib-validators-config>\n\n }\n @case(elementEditorTypes.ConfigMscoaAdditionalInputs){\n\n <lib-config-mscoa-additional-inputs [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getMscoaTree]=\"getMscoaTree$\" [mapToData]=\"vm.dataOptions\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-config-mscoa-additional-inputs>\n\n }\n @case (elementEditorTypes.DataSourcePicker) {\n <lib-data-source-picker [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [editorConfig]=\"vm. editorConfigValue\"\n (valueChange)=\"valueChanged($event)\" [formInputs]=\"formInputs() ||[]\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\">\n </lib-data-source-picker>\n }\n @case (elementEditorTypes.ListLabelConfigEditor) {\n <lib-document-list-label-config-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [formInputs]=\"formInputs() ||[]\"\n [disabled]=\"(vm.disabled)||false\"\n [editorConfig]=\"vm. editorConfigValue\"\n (valueChange)=\"valueChanged($event)\"\n [value]=\"$any(vm.value)\" [mapToData]=\"vm.dataOptions\"\n [errors]=\"(validationErrors())||[]\">\n\n </lib-document-list-label-config-editor>\n }\n @case(\n elementEditorTypes.WorkflowPicker\n ){\n <lib-t-workflow-picker [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [getWorkflowOptions]=\"getWorkflowOptions$\"\n (valueChanged)=\"valueChanged($event)\" [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\"></lib-t-workflow-picker>\n }\n @case (\n elementEditorTypes.RecordListManager\n ) {\n <lib-record-list-manager\n [id]=\"((vm.editorConfigValue)?.id)\"\n [editorConfig]=\"vm.editorConfigValue\" [disabled]=\"(vm.disabled)||false\"\n [formInputs]=\"formInputs() ||[]\" [mapToData]=\"vm.dataOptions\" (valueChange)=\"valueChanged($event)\"\n\n [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\"></lib-record-list-manager>\n }\n }\n\n @if (vm.inputHasBlurFunction) {\n <button [matTooltip]=\"blurFunctionTooltip((vm.editorConfigValue)?.blurHandle)\"\n [disabled]=\"(vm.disabled)\" [color]=\"blurOff?'':'primary'\" (click)=\"blurOff=!blurOff\" matSuffix\n mat-icon-button>\n <mat-icon>{{\n blurOff?'blur_off':'blur_on'\n }}\n\n\n </mat-icon>\n </button>\n }\n </mat-form-field>\n } @else {\n <!-- Editor types backed by plain (signal-based) components render outside\n the field, since they are not MatFormFieldControls. They are wrapped to\n mirror the outline mat-form-field appearance: the fieldset draws the\n outline, its legend is the notched floating label, and the hint renders\n as a subscript below the box. -->\n <div class=\"non-control-editor\">\n <fieldset class=\"non-control-editor__field\">\n @if ((vm. editorConfigValue)?.label) {\n <legend class=\"non-control-editor__label\">{{ (vm. editorConfigValue)?.label }}</legend>\n }\n @switch ((vm. editorConfigValue)?.editType) {\n\n @case (elementEditorTypes.ChipSelect) {\n\n <lib-mat-chip-list-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [multiple]=\"!!vm.editorConfigValue?.multipleSelection\"\n [disabled]=\"(vm.disabled)||false\"\n [options]=\"(vm.editorConfigValue)?.options || vm.dataOptions\"\n [required]=\"!!( vm.editorConfigValue)?.required\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\"\n (valueChange)=\" valueChanged($event)\"></lib-mat-chip-list-editor>\n\n\n }\n\n @case (elementEditorTypes.SelectionOptions) {\n\n <lib-selection-options-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [errors]=\"(validationErrors())||[]\" [disabled]=\"(vm.disabled)||false\"\n [options]=\"$any(vm.value) || []\" (valueChanged)=\"valueChanged($event)\"></lib-selection-options-editor>\n }\n\n @case (\n elementEditorTypes.ApiCall) {\n\n <lib-rest-api-call-setup\n [id]=\"((vm.editorConfigValue)?.id)\"\n [postmanCollectionConfig]=\"(vm.editorConfigValue)?.postmanCollectionConfig\"\n [httpGetDataFunction]=\"(vm.editorConfigValue)?.httpGetDataFunction\" [disabled]=\"(vm.disabled)||false\"\n [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\">\n\n </lib-rest-api-call-setup>\n\n }\n\n @case (elementEditorTypes.ApiValueAccessRules) {\n\n\n\n <lib-api-value-access-rules [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\"\n [formInputs]=\"formInputs() ||[]\"\n\n [postmanCollectionConfig]=\"(vm.editorConfigValue)?.postmanCollectionConfig\" [mapToData]=\"vm.dataOptions\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-api-value-access-rules>\n\n }\n\n @case (elementEditorTypes.FormInputSelector)\n {\n\n <lib-form-input-selector [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [formInputs]=\"formInputs() ||[]\"\n [errors]=\"(validationErrors())||[]\" [value]=\"$any(vm.value) || []\" (change)=\"valueChanged($event)\">\n </lib-form-input-selector>\n }\n\n @case (\n elementEditorTypes.RequiredInputs\n ){\n\n <lib-required-inputs [formInputs]=\"formInputs() ||[]\" [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\">\n </lib-required-inputs>\n }\n\n @case(elementEditorTypes.ConfigMscoaSegments){\n\n <lib-mscoa-segment-config [disabled]=\"(vm.disabled)||false\" [id]=\"((vm.editorConfigValue)?.id)\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getMscoaTree]=\"getMscoaTree$\" [dataValue]=\"$any(vm.dataValue)\"\n [isCashSegmentConfig]=\"vm.editorConfigValue?.deepBind?.at(-1) === 'cashSegments'\"\n [saveCustomInput]=\"mscoaSaveCustomInput()\"\n [editSegmentInput]=\"mscoaEditInput()\"\n [deleteSegmentInput]=\"mscoaDeleteInput()\"\n [showAllSegments]=\"vm.dataOptions\" (valueChanged)=\"valueChanged($event)\"></lib-mscoa-segment-config>\n }\n @case (elementEditorTypes.ChipOptionsCreator) {\n <lib-chip-options-creator-editor [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" (valueChange)=\"valueChanged($event)\"\n [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\">\n\n </lib-chip-options-creator-editor>\n\n }\n @case (elementEditorTypes.FormPayloadProjection) {\n <lib-form-payload-projection [disabled]=\"(vm.disabled)||false\" [value]=\"$any(vm.value)\"\n [formInputs]=\"formInputs() ||[]\" [errors]=\"(validationErrors())||[]\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-form-payload-projection>\n\n }\n }\n </fieldset>\n\n @if ((vm. editorConfigValue)?.hint) {\n <small class=\"non-control-editor__hint\">{{ (vm. editorConfigValue)?.hint }}</small>\n }\n </div>\n }\n\n @if (!(vm.value) && (vm. editorConfigValue)?.required ) {\n <mat-error>\n {{ (vm. editorConfigValue)?.label }}'s is required\n </mat-error>}\n\n @for (error of (validationErrors())||[]; track error.key) {\n <mat-error style=\" font-size: 0.75em;\n margin-left: 14px;\n \">\n\n {{error.message}}</mat-error>\n }\n\n}\n\n}@error {\n<mat-card>\n <mat-card-content>\n\n <span>\n Failed to load form inputs\n </span>\n </mat-card-content>\n</mat-card>\n}\n\n\n\n<!-- -\n `TableConfigSetup`\n- `ConditionalInputConfig`\n- `MatrixTable`-->\n", styles: [".showItemValue{opacity:.6}.non-control-editor{display:flex;flex-direction:column;width:100%}.non-control-editor__field{margin:0;min-width:0;width:100%;box-sizing:border-box;display:flex;flex-direction:column;padding:.75rem;border:1px solid var(--mat-sys-outline-variant, var(--mat-app-outline));border-radius:var(--mdc-outlined-text-field-container-shape, 4px)}.non-control-editor__label{padding:0 .25rem;margin-left:.5rem;font-size:.75rem;font-weight:400;line-height:1;color:var(--mat-sys-on-surface-variant, var(--mat-app-on-surface-variant, var(--mat-app-outline)))}.non-control-editor__hint{margin-top:.5rem;padding:0 .875rem;font-size:.75rem;line-height:1.5;color:var(--mat-sys-on-surface-variant, var(--mat-app-on-surface-variant, var(--mat-app-outline)))}mat-form-field{width:100%}mat-slider{width:100%}.range{display:flex;align-items:center}.elementInfo{display:flex;align-items:center;justify-content:center;padding:0;height:24px;width:24px}.infoIcon{font-size:1em;height:16px;width:16px}.toggle-label{margin-left:5px;align-items:center;display:flex;font-weight:500;line-height:normal;justify-content:space-between;color:var(--mdc-filled-text-field-focus-label-text-color, var(--mat-app-primary))}\n"] }]
|
|
13699
|
+
}], ctorParameters: null, propDecorators: { editorConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "editorConfig", required: false }] }], formInputs: [{ type: i0.Input, args: [{ isSignal: true, alias: "formInputs", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], validationErrors: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationErrors", required: false }] }], mscoaSaveCustomInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "mscoaSaveCustomInput", required: false }] }], mscoaEditInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "mscoaEditInput", required: false }] }], mscoaDeleteInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "mscoaDeleteInput", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], blur: [{ type: i0.Output, args: ["blur"] }] } }) });
|
|
13223
13700
|
|
|
13224
13701
|
const isEmptyPath = (path) => path.length === 0;
|
|
13225
13702
|
const isEmptyTree = (tree) => tree.length === 0;
|
|
@@ -13732,41 +14209,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
13732
14209
|
const ELEMENT_REGISTRY = {
|
|
13733
14210
|
[ElementTypes.Location]: {
|
|
13734
14211
|
builderAware: true,
|
|
13735
|
-
load: () => import('./ngx-t-forms-geo-location.component-
|
|
14212
|
+
load: () => import('./ngx-t-forms-geo-location.component-Bmd84Gcb.mjs').then(m => m.GeoLocationComponent),
|
|
13736
14213
|
},
|
|
13737
14214
|
[ElementTypes.AutoCompleteInput]: {
|
|
13738
|
-
load: () => import('./ngx-t-forms-auto-complete-input-element.component-
|
|
14215
|
+
load: () => import('./ngx-t-forms-auto-complete-input-element.component-CaXs4561.mjs').then(m => m.AutoCompleteInputElementComponent),
|
|
13739
14216
|
},
|
|
13740
14217
|
[ElementTypes.Toggle]: {
|
|
13741
|
-
load: () => import('./ngx-t-forms-toggle-input-element.component-
|
|
14218
|
+
load: () => import('./ngx-t-forms-toggle-input-element.component-Dr7MNli8.mjs').then(m => m.ToggleInputElementComponent),
|
|
13742
14219
|
},
|
|
13743
14220
|
[ElementTypes.Select]: {
|
|
13744
|
-
load: () => import('./ngx-t-forms-select-input-element.component-
|
|
14221
|
+
load: () => import('./ngx-t-forms-select-input-element.component-CWcywuS6.mjs').then(m => m.SelectInputElementComponent),
|
|
13745
14222
|
},
|
|
13746
14223
|
[ElementTypes.Textarea]: {
|
|
13747
|
-
load: () => import('./ngx-t-forms-textarea-input-element.component-
|
|
14224
|
+
load: () => import('./ngx-t-forms-textarea-input-element.component-DkJkBQif.mjs').then(m => m.TextareaInputElementComponent),
|
|
13748
14225
|
},
|
|
13749
14226
|
[ElementTypes.DateRangePicker]: {
|
|
13750
|
-
load: () => import('./ngx-t-forms-date-range-picker-input-element.component-
|
|
14227
|
+
load: () => import('./ngx-t-forms-date-range-picker-input-element.component-4W6uvrDU.mjs').then(m => m.DateRangePickerInputElementComponent),
|
|
13751
14228
|
},
|
|
13752
14229
|
[ElementTypes.DatePicker]: {
|
|
13753
|
-
load: () => import('./ngx-t-forms-date-picker-input-element.component-
|
|
14230
|
+
load: () => import('./ngx-t-forms-date-picker-input-element.component-kdinBGRA.mjs').then(m => m.DatePickerInputElementComponent),
|
|
13754
14231
|
},
|
|
13755
14232
|
[ElementTypes.FileUpload]: {
|
|
13756
|
-
load: () => import('./ngx-t-forms-file-upload-input-element.component-
|
|
14233
|
+
load: () => import('./ngx-t-forms-file-upload-input-element.component-BAtuymMY.mjs').then(m => m.FileUploadInputElementComponent),
|
|
13757
14234
|
},
|
|
13758
14235
|
[ElementTypes.ImageCapture]: {
|
|
13759
|
-
load: () => import('./ngx-t-forms-image-capture-input-element.component-
|
|
14236
|
+
load: () => import('./ngx-t-forms-image-capture-input-element.component-CUd04Ghl.mjs').then(m => m.ImageCaptureInputElementComponent),
|
|
13760
14237
|
},
|
|
13761
14238
|
[ElementTypes.Editor]: {
|
|
13762
|
-
load: () => import('./ngx-t-forms-editor-input-element.component-
|
|
14239
|
+
load: () => import('./ngx-t-forms-editor-input-element.component-1X6uAPeZ.mjs').then(m => m.EditorInputElementComponent),
|
|
13763
14240
|
},
|
|
13764
14241
|
[ElementTypes.Signature]: {
|
|
13765
14242
|
load: () => Promise.resolve().then(function () { return signatureInputElement_component; }).then(m => m.SignatureInputElementComponent),
|
|
13766
14243
|
},
|
|
13767
14244
|
[ElementTypes.MultipleInput]: {
|
|
13768
14245
|
builderAware: true,
|
|
13769
|
-
load: () => import('./ngx-t-forms-multiple-input-input-element.component-
|
|
14246
|
+
load: () => import('./ngx-t-forms-multiple-input-input-element.component-C8JP3D6r.mjs').then(m => m.MultipleInputInputElementComponent),
|
|
13770
14247
|
},
|
|
13771
14248
|
[ElementTypes.MscoaSelection]: {
|
|
13772
14249
|
builderAware: true,
|
|
@@ -13774,14 +14251,14 @@ const ELEMENT_REGISTRY = {
|
|
|
13774
14251
|
},
|
|
13775
14252
|
[ElementTypes.WorkflowDocumentPicker]: {
|
|
13776
14253
|
builderAware: true,
|
|
13777
|
-
load: () => import('./ngx-t-forms-document-picker.component-
|
|
14254
|
+
load: () => import('./ngx-t-forms-document-picker.component-BThdRFec.mjs').then(m => m.DocumentPickerComponent),
|
|
13778
14255
|
},
|
|
13779
14256
|
[ElementTypes.WorkflowAdjudication]: {
|
|
13780
14257
|
builderAware: true,
|
|
13781
|
-
load: () => import('./ngx-t-forms-workflow-adjudication.component-
|
|
14258
|
+
load: () => import('./ngx-t-forms-workflow-adjudication.component-CPvwm7f4.mjs').then(m => m.WorkflowAdjudicationComponent),
|
|
13782
14259
|
},
|
|
13783
14260
|
[ElementTypes.PaginatedSelectionTable]: {
|
|
13784
|
-
load: () => import('./ngx-t-forms-paginated-selection-table-
|
|
14261
|
+
load: () => import('./ngx-t-forms-paginated-selection-table-0OI1ikWW.mjs').then(m => m.PaginatedSelectionTable),
|
|
13785
14262
|
},
|
|
13786
14263
|
};
|
|
13787
14264
|
/**
|
|
@@ -13789,7 +14266,7 @@ const ELEMENT_REGISTRY = {
|
|
|
13789
14266
|
* `@default` switch branch (a basic input).
|
|
13790
14267
|
*/
|
|
13791
14268
|
const FALLBACK_ELEMENT = {
|
|
13792
|
-
load: () => import('./ngx-t-forms-basic-input-input-element.component-
|
|
14269
|
+
load: () => import('./ngx-t-forms-basic-input-input-element.component-Dotyd-Qs.mjs').then(m => m.BasicInputInputElementComponent),
|
|
13793
14270
|
};
|
|
13794
14271
|
/**
|
|
13795
14272
|
* Resolves the renderer entry for a given element type, falling back to the
|
|
@@ -15590,6 +16067,9 @@ class MscoaChartComponent {
|
|
|
15590
16067
|
// Form-builder functions, mirrored for dialog / portal use (read-only here).
|
|
15591
16068
|
#formBuilderFunctions;
|
|
15592
16069
|
#previousInputsHash;
|
|
16070
|
+
// Control keys already wired to the custom-input value projection (control → store),
|
|
16071
|
+
// guarding against duplicate subscriptions across input refreshes.
|
|
16072
|
+
#wiredInputProjections;
|
|
15593
16073
|
#prevValidating;
|
|
15594
16074
|
/**
|
|
15595
16075
|
* Gets the success message for a specific accounting basis
|
|
@@ -15691,6 +16171,9 @@ class MscoaChartComponent {
|
|
|
15691
16171
|
// Form-builder functions, mirrored for dialog / portal use (read-only here).
|
|
15692
16172
|
this.#formBuilderFunctions = undefined;
|
|
15693
16173
|
this.#previousInputsHash = '';
|
|
16174
|
+
// Control keys already wired to the custom-input value projection (control → store),
|
|
16175
|
+
// guarding against duplicate subscriptions across input refreshes.
|
|
16176
|
+
this.#wiredInputProjections = new Set();
|
|
15694
16177
|
// Portal management — the portal component is loaded lazily via `import('../../../t-form-input/...')`
|
|
15695
16178
|
// at runtime, so the eager `ComponentPortal<T>` generic cannot be tightened without breaking the
|
|
15696
16179
|
// lazy module boundary. `ComponentPortal<T>` is invariant in T so `unknown` is not assignable from
|
|
@@ -15771,6 +16254,7 @@ class MscoaChartComponent {
|
|
|
15771
16254
|
}))
|
|
15772
16255
|
.subscribe(inputs => {
|
|
15773
16256
|
this.setupPortals(inputs);
|
|
16257
|
+
this.#wireCustomInputProjections(inputs);
|
|
15774
16258
|
this.#cdr.markForCheck();
|
|
15775
16259
|
});
|
|
15776
16260
|
// Show shield icon on validated cells when validation completes (true -> false)
|
|
@@ -15884,13 +16368,62 @@ class MscoaChartComponent {
|
|
|
15884
16368
|
setupPortals(inputs) {
|
|
15885
16369
|
this.#setupPortalsInternal(inputs);
|
|
15886
16370
|
}
|
|
16371
|
+
/**
|
|
16372
|
+
* Wires each standalone (account-level) custom input's `FormControl` to the
|
|
16373
|
+
* store so its value is projected into the account value object as a peer of
|
|
16374
|
+
* the segments — single value selection mirrors the value across debit/credit.
|
|
16375
|
+
* Projects to the configured accounting basis (both for dual). `startWith`
|
|
16376
|
+
* seeds the store from the control on wire-up; `distinctUntilChanged` plus the
|
|
16377
|
+
* reducer's idempotency guard keep the form ⇄ store graph from oscillating.
|
|
16378
|
+
* Each control is wired at most once. (Per-leg distinct entry is a later step.)
|
|
16379
|
+
*/
|
|
16380
|
+
#wireCustomInputProjections(inputs) {
|
|
16381
|
+
const formGroup = this.formGroup();
|
|
16382
|
+
const mscoaId = this.inputConfig()?.id;
|
|
16383
|
+
if (!formGroup || !mscoaId)
|
|
16384
|
+
return;
|
|
16385
|
+
const basis = this.config()?.accountingBasis;
|
|
16386
|
+
const cashFlags = basis === ACCOUNTING_BASIS.CASH ? [true]
|
|
16387
|
+
: basis === ACCOUNTING_BASIS.DUAL ? [false, true]
|
|
16388
|
+
: [false];
|
|
16389
|
+
for (const input of inputs) {
|
|
16390
|
+
if (input.linkedSegmentId || !input.formControlName)
|
|
16391
|
+
continue;
|
|
16392
|
+
const controlKey = `${mscoaId}.${input.id}`;
|
|
16393
|
+
const control = formGroup.controls[controlKey];
|
|
16394
|
+
if (!control)
|
|
16395
|
+
continue;
|
|
16396
|
+
if (this.#wiredInputProjections.has(controlKey))
|
|
16397
|
+
continue;
|
|
16398
|
+
this.#wiredInputProjections.add(controlKey);
|
|
16399
|
+
const inputKey = input.formControlName;
|
|
16400
|
+
control.valueChanges.pipe(startWith$1(control.value), distinctUntilChanged((a, b) => _isEqual(a, b)), takeUntilDestroyed(this.#destroyRef)).subscribe(value => {
|
|
16401
|
+
for (const isCash of cashFlags) {
|
|
16402
|
+
this.#store.setCustomInputValue({ inputKey, value, isCash });
|
|
16403
|
+
}
|
|
16404
|
+
});
|
|
16405
|
+
}
|
|
16406
|
+
}
|
|
15887
16407
|
/**
|
|
15888
16408
|
* Creates a hash of inputs array for comparison
|
|
15889
16409
|
*/
|
|
15890
16410
|
getInputsHash(inputs) {
|
|
15891
16411
|
if (!inputs || inputs.length === 0)
|
|
15892
16412
|
return '';
|
|
15893
|
-
|
|
16413
|
+
// Hash the FULL config, not just id/element/formControlName. A custom input's
|
|
16414
|
+
// `type`, `validators`, `pattern`, `min`/`max`, calc/API rules etc. are all
|
|
16415
|
+
// edited through the advanced editor WITHOUT changing element/formControlName,
|
|
16416
|
+
// and each portal carries a STATIC `inputConfig` snapshot — so it must rebuild
|
|
16417
|
+
// whenever ANY of those change, or the live edit silently never reaches the
|
|
16418
|
+
// rendered input (it keeps behaving like a bare text field). Emissions here
|
|
16419
|
+
// are config-driven (not per-keystroke), so serializing is cheap.
|
|
16420
|
+
try {
|
|
16421
|
+
return JSON.stringify(inputs);
|
|
16422
|
+
}
|
|
16423
|
+
catch {
|
|
16424
|
+
// Non-serializable config (cycles): fall back to identity fields.
|
|
16425
|
+
return inputs.map(i => `${i.id}:${i.element ?? ''}:${i.formControlName ?? ''}`).sort().join(',');
|
|
16426
|
+
}
|
|
15894
16427
|
}
|
|
15895
16428
|
/**
|
|
15896
16429
|
* Generates a consistent portal key for an input
|
|
@@ -16484,9 +17017,9 @@ class MscoaChartComponent {
|
|
|
16484
17017
|
}
|
|
16485
17018
|
}
|
|
16486
17019
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: MscoaChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
16487
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: MscoaChartComponent, isStandalone: true, selector: "lib-mscoa-chart", inputs: { inputConfig: { classPropertyName: "inputConfig", publicName: "inputConfig", isSignal: true, isRequired: true, transformFunction: null }, editorMode: { classPropertyName: "editorMode", publicName: "editorMode", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, formGroup: { classPropertyName: "formGroup", publicName: "formGroup", isSignal: true, isRequired: false, transformFunction: null }, formBuilderFunctions: { classPropertyName: "formBuilderFunctions", publicName: "formBuilderFunctions", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onContainerClick: "onContainerClick", interaction: "interaction" }, ngImport: i0, template: "@if ((viewData$ | async); as viewData) {\r\n<section\r\n (click)=\"setAsTouched($event)\"\r\n class=\"mscoa-chart__container\"\r\n [class.mscoa-chart__container--touched]=\"touched()\"\r\n role=\"region\"\r\n [attr.aria-label]=\"'MSCOA Account Chart'\"\r\n [attr.aria-busy]=\"viewData.loading || viewData.validatingValue\">\r\n\r\n @if (viewData.loading) {\r\n <div class=\"mscoa-chart__loading-container\" role=\"status\" aria-live=\"polite\">\r\n <mat-spinner [diameter]=\"40\"></mat-spinner>\r\n <span class=\"sr-only\">Loading account chart data...</span>\r\n </div>\r\n } @else {\r\n @defer () {\r\n @if (viewData.accountTreeKeys || viewData.cashAccountTreeKeys) {\r\n <div class=\"mscoa-chart__table-container\">\r\n @if (isDualAccountBasis) {\r\n <div class=\"dual-basis-container\" role=\"group\" aria-label=\"Dual accounting basis tables\">\r\n <div class=\"dual-basis-container__item\">\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: ACCOUNTING_BASIS.ACCRUAL,\r\n canCollapse: true,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n </div>\r\n\r\n <div class=\"dual-basis-container__item\">\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: ACCOUNTING_BASIS.CASH,\r\n canCollapse: true,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n </div>\r\n </div>\r\n } @else {\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: config()?.accountingBasis,\r\n canCollapse: false,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n }\r\n </div>\r\n }\r\n\r\n <ng-template\r\n #selectionTable\r\n let-accountingBasis=\"accountingBasis\"\r\n let-canCollapse=\"canCollapse\"\r\n let-viewData=\"viewData\">\r\n\r\n <div class=\"mscoa-chart-table\" role=\"group\" [attr.aria-label]=\"'Accounting basis: ' + (accountingBasis || 'Accrual')\">\r\n <!-- Toolbar -->\r\n <lib-mscoa-chart-toolbar\r\n [accountingBasis]=\"accountingBasis\"\r\n [canCollapse]=\"canCollapse\"\r\n [isExpanded]=\"getExpansionState(accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\"\r\n (toggleExpansion)=\"toggleDualBasisExpansion(accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\">\r\n </lib-mscoa-chart-toolbar>\r\n\r\n @if (shouldShowTable(isDualAccountBasis, getExpansionState(accountingBasis || ACCOUNTING_BASIS.ACCRUAL), accountingBasis)) {\r\n <div class=\"account-selection-table-wrapper\">\r\n <div\r\n class=\"account-selection-table-container\"\r\n [class.account-selection-table-container--accrual]=\"!accountingBasis || accountingBasis === ACCOUNTING_BASIS.ACCRUAL\"\r\n [class.account-selection-table-container--cash]=\"accountingBasis === ACCOUNTING_BASIS.CASH\"\r\n role=\"table\"\r\n [attr.aria-label]=\"'Account selection table for ' + (accountingBasis || 'Accrual') + ' basis'\">\r\n\r\n <table\r\n mat-table\r\n [dataSource]=\"accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashTableData : viewData.tableData\"\r\n [trackBy]=\"trackByRow\"\r\n class=\"table\"\r\n [attr.aria-label]=\"'Account selection table for ' + (accountingBasis || 'Accrual') + ' basis'\"\r\n [attr.aria-describedby]=\"'table-description-' + (accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\"\r\n role=\"table\">\r\n <span [id]=\"'table-description-' + (accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\" class=\"sr-only\">\r\n Use arrow keys to navigate between cells. Press Enter or Space to select an account.\r\n </span>\r\n\r\n @for (\r\n col of (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols);\r\n track trackByColumn($index, col);\r\n let i = $index\r\n ) {\r\n <ng-container [matColumnDef]=\"col\" [sticky]=\"i === 0\">\r\n <!-- Header Cell -->\r\n <th\r\n mat-header-cell\r\n *matHeaderCellDef\r\n [class.table__header-cell--segment]=\"isSegmentColumn(i)\"\r\n [class.table__header-cell--regular]=\"!isSegmentColumn(i)\"\r\n [style.width.%]=\"getColumnWidthPercent(isSegmentColumn(i), (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols).length)\"\r\n [style.min-width.px]=\"isSegmentColumn(i) ? 150 : 200\"\r\n [attr.aria-sort]=\"i === 0 ? 'none' : null\"\r\n [attr.scope]=\"'col'\"\r\n [attr.aria-label]=\"getHeaderText(col, i, accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashHasMultiSelect : viewData.hasMultiSelect) + ' column'\">\r\n {{ getHeaderText(col, i, accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashHasMultiSelect : viewData.hasMultiSelect) | titlecase | unCamelCase }}\r\n </th>\r\n\r\n <!-- Data Cell -->\r\n <td\r\n mat-cell\r\n *matCellDef=\"let row\"\r\n [class.table__cell--segment]=\"isSegmentColumn(i)\"\r\n [class.table__cell--regular]=\"!isSegmentColumn(i)\"\r\n [class.table__cell--active]=\"editSelection?.segment === row['segment'] && activeColumn === col\"\r\n [class.table__cell--business-error]=\"!isSegmentColumn(i) && getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-label]=\"'Cell for ' + row['segment'] + ' segment, ' + col + ' column'\"\r\n [attr.aria-selected]=\"!!row[col]\"\r\n [attr.aria-invalid]=\"!isSegmentColumn(i) && !!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.role]=\"'gridcell'\"\r\n [attr.tabindex]=\"isSegmentColumn(i) ? -1 : (row[col] ? 0 : -1)\">\r\n\r\n @if (isSegmentColumn(i)) {\r\n <!-- Segment Column -->\r\n <div class=\"segment-cell-content\">\r\n @if (editorMode() && row.innerInput?.id) {\r\n <button\r\n mat-icon-button\r\n [matMenuTriggerData]=\"{innerInput: row.innerInput}\"\r\n [matMenuTriggerFor]=\"inputMenu\"\r\n [matTooltip]=\"'Options for: ' + row.innerInput.label\"\r\n [attr.aria-label]=\"'Options menu for ' + row.innerInput.label\"\r\n (click)=\"$event.stopPropagation()\">\r\n <mat-icon>more_vert</mat-icon>\r\n </button>\r\n }\r\n <span class=\"segment-cell-content__label\">{{ row['label'] }}</span>\r\n </div>\r\n } @else {\r\n <!-- Regular Column -->\r\n @if (row.innerInput?.id && formGroup() && inputPortals[getPortalKey(row.innerInput.id)]) {\r\n <div class=\"portal-container\">\r\n <ng-template [cdkPortalOutlet]=\"inputPortals[getPortalKey(row.innerInput.id)]\"></ng-template>\r\n </div>\r\n } @else {\r\n @if (row[col]) {\r\n <!-- Account Selected -->\r\n @if (getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment']); as cellError) {\r\n <div class=\"account-cell-wrapper\"\r\n [class.account-cell-wrapper--expandable]=\"isTextTruncated(row[col] | unCamelCase)\">\r\n <button\r\n [disabled]=\"row['singleSelect'] === true && col === COLUMNS.CREDIT\"\r\n (mousedown)=\"$event.preventDefault(); $event.stopPropagation(); selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n color=\"primary\"\r\n mat-button\r\n class=\"cell-button cell-button--selected cell-button--business-error\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase) + ' for ' + row['segment'] + ' segment, ' + col + ' column. Business error: ' + cellError.message\"\r\n [attr.aria-invalid]=\"true\"\r\n [attr.aria-pressed]=\"true\"\r\n [matTooltip]=\"cellError.message\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label selected-acount-label--tag selected-acount-label--business-error\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase)\">\r\n {{ row[col] | unCamelCase }}\r\n @if (shouldShowVatChip(row, col)) {\r\n <span\r\n class=\"vat-badge\"\r\n [attr.aria-label]=\"'VAT applicable to ' + col + ' column'\"\r\n [matTooltip]=\"'VAT is applicable to this ' + col + ' account selection'\">\r\n VAT\r\n </span>\r\n }\r\n </span>\r\n <mat-icon class=\"business-error-indicator\" aria-hidden=\"true\">error</mat-icon>\r\n </div>\r\n </button>\r\n </div>\r\n } @else {\r\n <div class=\"account-cell-wrapper\"\r\n [class.account-cell-wrapper--expandable]=\"isTextTruncated(row[col] | unCamelCase)\">\r\n <button\r\n [disabled]=\"(row['singleSelect'] === true && col === COLUMNS.CREDIT) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n (mousedown)=\"$event.preventDefault(); $event.stopPropagation(); selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n color=\"primary\"\r\n mat-button\r\n class=\"cell-button cell-button--selected\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase) + ' for ' + row['segment'] + ' segment, ' + col + ' column. Press Enter or Space to change'\"\r\n [attr.aria-invalid]=\"false\"\r\n [attr.aria-disabled]=\"(row['singleSelect'] === true && col === COLUMNS.CREDIT) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-pressed]=\"true\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label selected-acount-label--tag\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase)\">\r\n {{ row[col] | unCamelCase }}\r\n @if (shouldShowVatChip(row, col)) {\r\n <span\r\n class=\"vat-badge\"\r\n [attr.aria-label]=\"'VAT applicable to ' + col + ' column'\"\r\n [matTooltip]=\"'VAT is applicable to this ' + col + ' account selection'\">\r\n VAT\r\n </span>\r\n }\r\n </span>\r\n @if (showValidationSuccessIndicators) {\r\n <mat-icon class=\"validated-indicator\" aria-hidden=\"true\" [matTooltip]=\"'Validated'\">shield</mat-icon>\r\n } @else {\r\n <mat-icon class=\"success-indicator\" aria-hidden=\"true\">check_circle</mat-icon>\r\n }\r\n </div>\r\n </button>\r\n </div>\r\n }\r\n } @else {\r\n <!-- No Account Selected -->\r\n <div class=\"cell-button-wrapper\">\r\n <button\r\n [disabled]=\"selectionDisabled(row, col) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [color]=\"\"\r\n (click)=\"selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); $event.stopPropagation(); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n mat-button\r\n class=\"cell-button\"\r\n [class.cell-button--business-error]=\"!!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-label]=\"shouldShowAutoSelectedLabel(row, col) ? 'Auto selected for ' + row['segment'] + ' segment, ' + col + ' column' : 'Select account for ' + row['segment'] + ' segment, ' + col + ' column'\"\r\n [attr.aria-disabled]=\"selectionDisabled(row, col) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-describedby]=\"getValidationHint(row, col, accountingBasis || ACCOUNTING_BASIS.ACCRUAL) ? 'hint-' + row['segment'] + '-' + col : null\"\r\n [attr.aria-invalid]=\"hasError(touched(), inputConfig().required || false, !!row[col]) || !!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-required]=\"inputConfig().required && !row[col]\"\r\n [matTooltip]=\"getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])?.message\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label\"\r\n [class.selected-acount-label--error]=\"hasError(touched(), inputConfig().required || false, !!row[col])\"\r\n [class.selected-acount-label--business-error]=\"!!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\">\r\n {{ (shouldShowAutoSelectedLabel(row, col) ? 'auto selected' : 'Select account') | unCamelCase }}\r\n @if (inputConfig().required && !row[col]) {\r\n <span class=\"required-indicator\" aria-label=\"Required field\">*</span>\r\n }\r\n </span>\r\n @if (getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])) {\r\n <mat-icon class=\"business-error-indicator\" aria-hidden=\"true\">error</mat-icon>\r\n } @else if (shouldShowDropdownIcon(row, col)) {\r\n <mat-icon aria-hidden=\"true\">arrow_drop_down</mat-icon>\r\n }\r\n </div>\r\n </button>\r\n @if (getValidationHint(row, col, accountingBasis || ACCOUNTING_BASIS.ACCRUAL); as hint) {\r\n <span\r\n class=\"inline-hint\"\r\n [id]=\"'hint-' + row['segment'] + '-' + col\"\r\n role=\"tooltip\"\r\n aria-live=\"polite\">\r\n {{ hint }}\r\n </span>\r\n }\r\n </div>\r\n }\r\n }\r\n }\r\n </td>\r\n </ng-container>\r\n }\r\n\r\n <tr mat-header-row *matHeaderRowDef=\"accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols\"></tr>\r\n <tr mat-row *matRowDef=\"let row; columns: (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols)\"></tr>\r\n </table>\r\n </div>\r\n </div>\r\n\r\n <!-- Empty State -->\r\n @if ((accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashAccountTreeKeys : viewData.accountTreeKeys).length === 0) {\r\n <section class=\"empty-state\" role=\"status\" aria-live=\"polite\">\r\n <mat-icon aria-hidden=\"true\">info</mat-icon>\r\n <span>\r\n No account segments are currently configured.\r\n Please configure account segments to proceed.\r\n </span>\r\n </section>\r\n }\r\n\r\n <!-- Success Messages (Temporary) -->\r\n @if ((successMessage$ | async); as successMessages) {\r\n @if (getSuccessMessage(successMessages, accountingBasis || ACCOUNTING_BASIS.ACCRUAL); as msg) {\r\n <lib-mscoa-temporary-hint\r\n [message]=\"getSuccessMessage(successMessages, accountingBasis || ACCOUNTING_BASIS.ACCRUAL) ?? ''\"\r\n [type]=\"'info'\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-temporary-hint>\r\n }\r\n }\r\n\r\n <!-- Business Rule Errors (Temporary display, keeps error styling) -->\r\n @if ((viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL] || []).length > 0) {\r\n <lib-mscoa-error-display\r\n [errors]=\"viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL] || []\"\r\n type=\"error\"\r\n [context]=\"{ accountingBasis: accountingBasis || ACCOUNTING_BASIS.ACCRUAL }\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-error-display>\r\n }\r\n\r\n <!-- Temporary Contextual Hints -->\r\n @if (temporaryHintMessage) {\r\n <lib-mscoa-temporary-hint\r\n [message]=\"temporaryHintMessage\"\r\n [type]=\"temporaryHintType\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-temporary-hint>\r\n }\r\n\r\n <!-- Validation Hints (Context-Aware) -->\r\n @if (!touched() && inputConfig().required && !viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL]?.length && (!isDualAccountBasis || accountingBasis === ACCOUNTING_BASIS.ACCRUAL || !accountingBasis)) {\r\n <div class=\"validation-hints\" role=\"region\" aria-label=\"Validation guidance\">\r\n <p class=\"validation-hints__title\">Guidance:</p>\r\n <ul class=\"validation-hints__list\">\r\n <li>Account combinations are validated automatically. Select accounts that belong to compatible reporting categories.</li>\r\n <li>Required fields are marked with an asterisk (*). Complete all required selections to proceed.</li>\r\n <li>Some fields may be automatically populated based on your selections to ensure consistency.</li>\r\n </ul>\r\n </div>\r\n }\r\n }\r\n </div>\r\n </ng-template>\r\n } @placeholder {\r\n <div class=\"loading-placeholder\" role=\"status\" aria-live=\"polite\">\r\n <p>Loading data...</p>\r\n </div>\r\n } @loading (minimum 100ms) {\r\n <div class=\"loading-spinner-container\" role=\"status\" aria-live=\"polite\">\r\n <mat-progress-spinner mode=\"indeterminate\" [diameter]=\"40\"></mat-progress-spinner>\r\n <span class=\"sr-only\">Loading account chart...</span>\r\n </div>\r\n } @error {\r\n <div class=\"error-state\" role=\"alert\" aria-live=\"assertive\">\r\n <p>Error loading data. Please try again.</p>\r\n </div>\r\n }\r\n }\r\n</section>\r\n}\r\n\r\n<!-- Input Menu -->\r\n<mat-menu #inputMenu=\"matMenu\">\r\n <ng-template matMenuContent let-innerInput=\"innerInput\">\r\n <lib-mscoa-chart-input-menu\r\n [innerInput]=\"innerInput\"\r\n [countdownSeconds]=\"inputWillBeRemovedIn(innerInput.id)\"\r\n [hoveredId]=\"hoveredInputId\"\r\n (edit)=\"onInputMenuEdit($event)\"\r\n (delete)=\"onInputMenuDelete($event)\"\r\n (cancelDelete)=\"onInputMenuCancelDelete($event)\"\r\n (hoverStart)=\"onInputMenuHoverStart($event)\"\r\n (hoverEnd)=\"onInputMenuHoverEnd()\">\r\n </lib-mscoa-chart-input-menu>\r\n </ng-template>\r\n</mat-menu>\r\n", styles: ["@charset \"UTF-8\";:host{--mscoa-chart-spacing-xs: 4px;--mscoa-chart-spacing-sm: 8px;--mscoa-chart-spacing-md: 16px;--mscoa-chart-spacing-lg: 24px;--mscoa-chart-spacing-xl: 32px;--mscoa-chart-border-radius: 4px;--mscoa-chart-transition: var(--lib-forms-duration-hover) var(--lib-forms-easing);--mscoa-chart-font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;--mscoa-chart-font-size-base: 14px;--mscoa-chart-line-height: 1.5;display:block;font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height)}.mscoa-chart__container{padding:0;transition:background-color var(--mscoa-chart-transition);width:100%;max-width:100%;overflow-x:hidden;box-sizing:border-box}.mscoa-chart__loading-container{padding:var(--mscoa-chart-spacing-lg);display:flex;align-items:center;justify-content:center}.mscoa-chart__table-container{position:relative;width:100%;max-width:100%;overflow-x:auto;overflow-y:visible;box-sizing:border-box}.dual-basis-container{display:flex;flex-direction:column;gap:var(--mscoa-chart-spacing-sm)}.dual-basis-container__item{flex:1}:host .single-base{gap:var(--mscoa-chart-spacing-sm);height:48px;font-size:.875em;font-weight:500;transition:background-color var(--mscoa-chart-transition)}:host .single-base--cash{background:var(--mat-sys-inverse-primary)}.account-selection-table-wrapper{position:relative;width:100%}.account-selection-table-container{border-radius:var(--mscoa-chart-border-radius);overflow-x:auto;overflow-y:visible;transition:border-color var(--mscoa-chart-transition);width:100%;max-width:100%;box-sizing:border-box;display:block}.account-selection-table-container--accrual{border:solid 1px var(--mat-sys-primary)}.account-selection-table-container--cash{border:solid 1px var(--mat-sys-inverse-primary)}.account-selection-table-container::-webkit-scrollbar{height:8px}.account-selection-table-container::-webkit-scrollbar-track{background:var(--lib-forms-surface-container-low);border-radius:4px}.account-selection-table-container::-webkit-scrollbar-thumb{background:var(--lib-forms-outline-variant);border-radius:4px}.account-selection-table-container::-webkit-scrollbar-thumb:hover{background:var(--lib-forms-outline)}.table{width:100%;table-layout:fixed;font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height);border-collapse:separate;border-spacing:0;display:table;box-sizing:border-box;max-width:100%}.table__header-cell{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;box-sizing:border-box}.table__header-cell--segment{text-align:right;padding-right:var(--mscoa-chart-spacing-md);min-width:150px;max-width:200px}.table__header-cell--regular{padding-left:var(--mscoa-chart-spacing-lg);min-width:200px;max-width:none}.table__cell{overflow:visible;box-sizing:border-box;position:relative;vertical-align:top}.table__cell--segment{background:var(--mat-list-active-indicator-color, var(--mat-sys-secondary-container));text-align:right;font-weight:500;padding-right:var(--mscoa-chart-spacing-md);min-width:150px;max-width:200px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;vertical-align:middle}.table__cell--regular{padding:0;min-width:200px;max-width:none;word-wrap:break-word;vertical-align:top;overflow:visible}.table__cell--active{background-color:var(--mat-sys-primary-container);transition:background-color var(--mscoa-chart-transition)}mat-header-cell{background:var(--mat-sys-surface-container);font-weight:600;font-size:var(--mscoa-chart-font-size-base);padding:var(--mscoa-chart-spacing-md)}.mscoa-chart-table{display:flex;flex-direction:column}.portal-container{width:100%}.account-cell-wrapper{position:relative;width:100%;max-width:100%;overflow:visible;z-index:1;min-height:38px;display:flex;flex-direction:column;gap:4px}.cell-button-wrapper{position:relative;width:100%;max-width:100%;overflow:hidden}.cell-button{height:fit-content;min-height:38px;width:100%;max-width:100%;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),transform var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing);font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height);position:relative;overflow:visible;padding:8px}.cell-button:hover:not(:disabled){background-color:var(--mat-sys-surface-container);transform:translateY(-1px);box-shadow:0 2px 4px #0000001a}.cell-button:focus-visible{outline:3px solid var(--mat-sys-primary);outline-offset:2px;z-index:1}.cell-button:disabled{opacity:.6;cursor:not-allowed}.cell-button--selected{background-color:transparent}.cell-button--selected:hover:not(:disabled){background-color:var(--lib-forms-surface-container-low);border-color:var(--lib-forms-primary)}.cell-button.cell-button--selected{animation:fadeInSuccess var(--mscoa-chart-transition)}.cell-button.cell-button--business-error{border-color:var(--lib-forms-error)}.cell-button.cell-button--business-error .selected-acount-label--business-error{color:var(--mat-sys-error);border-color:var(--mat-sys-error)}.success-indicator{color:var(--sem-success);font-size:18px;width:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;height:18px;margin-left:var(--mscoa-chart-spacing-xs);animation:scaleIn var(--mscoa-chart-transition);flex-shrink:0}.validated-indicator{color:var(--lib-forms-primary);font-size:18px;width:18px;height:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;margin-left:var(--mscoa-chart-spacing-xs);flex-shrink:0;animation:validatedShieldIn .3s ease-out forwards}.business-error-indicator{color:var(--lib-forms-error);font-size:18px;width:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;height:18px;margin-left:var(--mscoa-chart-spacing-xs);flex-shrink:0}.required-indicator{color:var(--lib-forms-error);font-weight:600;margin-left:2px}.inline-hint{display:block;font-size:12px;color:var(--lib-forms-on-surface-variant);margin-top:var(--mscoa-chart-spacing-xs);padding:var(--mscoa-chart-spacing-xs) var(--mscoa-chart-spacing-sm);background-color:var(--lib-forms-surface-container-low);border-radius:var(--mscoa-chart-border-radius);line-height:1.4;max-width:100%;word-wrap:break-word}.content{padding:0;display:flex;gap:6px;width:100%;max-width:100%;overflow:visible;min-width:0;flex-wrap:wrap;align-items:center}.selected-acount-label{text-align:left;flex:1;font-weight:400;transition:color var(--mscoa-chart-transition)}.selected-acount-label--error,.selected-acount-label--business-error{color:var(--mat-sys-error);font-weight:500}.selected-acount-label--tag{display:inline-block;padding:4px 10px;background-color:var(--lib-forms-primary-container);color:var(--lib-forms-on-primary-container);border-radius:16px;font-size:13px;font-weight:500;line-height:1.5;border:1px solid var(--lib-forms-primary);box-shadow:0 1px 2px #0000001a;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing);width:100%;max-width:100%;overflow:visible;white-space:normal;word-wrap:break-word;word-break:break-word;cursor:pointer;box-sizing:border-box;position:relative}.selected-acount-label--tag:hover{background-color:var(--sem-info-surface);box-shadow:0 2px 4px #1976d226}.segment-cell-content{display:flex;align-items:center;justify-content:flex-end;font-weight:500}.vat-badge{display:inline-flex;align-items:center;justify-content:center;height:16px;padding:2px 6px;border-radius:8px;font-size:9px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;background-color:var(--sem-success-surface);color:var(--sem-warning);border:1px solid var(--lib-forms-outline-variant);box-shadow:none;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),border-color var(--lib-forms-duration-hover) var(--lib-forms-easing);flex-shrink:0;align-self:flex-start;margin-top:2px;line-height:1}.vat-badge:hover{background-color:var(--sem-warning-surface);border-color:var(--sem-warning)}.vat-chip-container{padding-left:var(--mscoa-chart-spacing-sm);padding-right:var(--mscoa-chart-spacing-sm);padding-bottom:var(--mscoa-chart-spacing-xs);margin-top:var(--mscoa-chart-spacing-xs)}.vat-chip{display:inline-flex;align-items:center;gap:4px;height:24px;padding:4px 8px;border-radius:12px;font-size:11px;font-weight:600;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing),transform var(--lib-forms-duration-hover) var(--lib-forms-easing);box-shadow:0 1px 3px #0000001f}.vat-chip--applicable{background:linear-gradient(135deg,var(--sem-warning) 0%,var(--sem-warning) 100%);color:var(--lib-forms-on-primary);border:1px solid var(--sem-warning)}.vat-chip--applicable:hover{box-shadow:0 2px 6px #f57c004d;transform:translateY(-1px)}.vat-chip__icon{font-size:14px;width:14px;height:14px;opacity:.9}.vat-chip__text{font-size:11px;font-weight:600;letter-spacing:.3px}.info-box{display:flex;align-items:center;gap:var(--mscoa-chart-spacing-sm);padding:12px;background:var(--sem-info-surface);border-radius:var(--mscoa-chart-border-radius);margin-bottom:var(--mscoa-chart-spacing-md)}.info-icon{min-width:38px;margin:auto;margin-top:var(--mscoa-chart-spacing-sm)}.empty-state{padding:var(--mscoa-chart-spacing-md);text-align:center;display:flex;align-items:center;justify-content:center;gap:var(--mscoa-chart-spacing-sm);color:var(--mat-sys-on-surface-variant)}.validation-hints{margin-top:var(--mscoa-chart-spacing-md);padding:var(--mscoa-chart-spacing-md);background-color:var(--lib-forms-surface-container-low);border-radius:var(--mscoa-chart-border-radius);border-left:4px solid var(--lib-forms-primary);box-shadow:0 1px 3px #00000014}.validation-hints__title{font-weight:600;font-size:var(--mscoa-chart-font-size-base);margin:0 0 var(--mscoa-chart-spacing-sm) 0;color:var(--lib-forms-on-surface);display:flex;align-items:center;gap:var(--mscoa-chart-spacing-xs)}.validation-hints__title:before{content:\"\\1f4a1\";font-size:16px}.validation-hints__list{margin:0;padding-left:var(--mscoa-chart-spacing-md);color:var(--lib-forms-on-surface-variant);font-size:13px;line-height:1.6}.validation-hints__list li{margin-bottom:var(--mscoa-chart-spacing-sm);position:relative}.validation-hints__list li::marker{color:var(--lib-forms-primary)}.validation-hints__list li:last-child{margin-bottom:0}mat-error{font-size:.75em;margin-top:var(--mscoa-chart-spacing-xs)}mat-error ul{margin:0;padding-left:var(--mscoa-chart-spacing-md)}mat-error li{margin-bottom:var(--mscoa-chart-spacing-xs)}.loading-placeholder{padding:var(--mscoa-chart-spacing-md);color:var(--mat-sys-on-surface-variant)}.loading-spinner-container{display:flex;justify-content:center;align-items:center;height:256px}.error-state{padding:var(--mscoa-chart-spacing-md);color:var(--mat-sys-error)}mat-panel-description{font-size:.875em;line-height:1.4}:host .main-expanse-content{background:var(--mat-sys-surface-container)}@media(max-width:768px){.dual-basis-container{gap:var(--mscoa-chart-spacing-md)}.cell-button{min-height:44px;font-size:15px;max-width:300px}.content{padding:var(--mscoa-chart-spacing-md)}.validation-hints{font-size:13px;padding:var(--mscoa-chart-spacing-sm)}.inline-hint{font-size:11px}}.cell-button:focus-visible,button:focus-visible{outline:3px solid var(--mat-sys-primary);outline-offset:2px;outline-style:solid}@media(prefers-contrast:high){.cell-button{border:2px solid currentColor}.cell-button:focus-visible{outline-width:4px}.selected-acount-label--error{font-weight:600}}@media(prefers-reduced-motion:reduce){.cell-button,.success-indicator,.fade-in,.validated-indicator{animation:none;transition:none}}.table__cell--active{background-color:var(--mat-sys-primary-container);color:var(--mat-sys-on-primary-container)}@media(prefers-contrast:high){.table__cell--active{background-color:var(--mat-sys-primary);color:var(--mat-sys-on-primary)}}.table__cell--business-error{background-color:var(--lib-forms-error-container);border-left:3px solid var(--lib-forms-error)}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeInSuccess{0%{background-color:transparent}50%{background-color:var(--sem-success-surface)}to{background-color:var(--mat-sys-primary-container)}}@keyframes scaleIn{0%{transform:scale(0);opacity:0}to{transform:scale(1);opacity:1}}@keyframes validatedShieldIn{0%{opacity:0;transform:scale(.6)}70%{opacity:1;transform:scale(1.1)}to{opacity:1;transform:scale(1)}}.fade-in{animation:fadeIn var(--mscoa-chart-transition)}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.skeleton-loader{background:linear-gradient(90deg,var(--mat-sys-surface-container) 25%,var(--mat-sys-surface-container-high) 50%,var(--mat-sys-surface-container) 75%);background-size:200% 100%;animation:loading 1.5s ease-in-out infinite;border-radius:var(--mscoa-chart-border-radius)}@keyframes loading{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-row{height:48px;margin-bottom:var(--mscoa-chart-spacing-xs)}.skeleton-cell{height:100%;margin-right:var(--mscoa-chart-spacing-md)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: PortalModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i6.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "directive", type: i6.MatMenuContent, selector: "ng-template[matMenuContent]" }, { kind: "ngmodule", type: MatTableModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i3$2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: MscoaChartInputMenuComponent, selector: "lib-mscoa-chart-input-menu", inputs: ["innerInput", "countdownSeconds", "hoveredId"], outputs: ["edit", "delete", "cancelDelete", "hoverStart", "hoverEnd"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [i3.NgTemplateOutlet, i4$2.CdkPortalOutlet, i1$2.MatButton, i1$2.MatIconButton, i3$1.MatIcon, i6.MatMenuTrigger, i5$2.MatTable, i5$2.MatHeaderCellDef, i5$2.MatHeaderRowDef, i5$2.MatColumnDef, i5$2.MatCellDef, i5$2.MatRowDef, i5$2.MatHeaderCell, i5$2.MatCell, i5$2.MatHeaderRow, i5$2.MatRow, i5$1.MatTooltip, import('./ngx-t-forms-mscoa-chart-toolbar.component-C_abEBQ5.mjs').then(m => m.MscoaChartToolbarComponent), import('./ngx-t-forms-mscoa-error-display.component-99DpVSy7.mjs').then(m => m.MscoaErrorDisplayComponent), import('./ngx-t-forms-mscoa-temporary-hint.component-B1Z-IXSL.mjs').then(m => m.MscoaTemporaryHintComponent), i3.AsyncPipe, i3.TitleCasePipe, Promise.resolve().then(function () { return daysAgo_pipe; }).then(m => m.ConvertCamelCasePipe)]] }); }
|
|
17020
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: MscoaChartComponent, isStandalone: true, selector: "lib-mscoa-chart", inputs: { inputConfig: { classPropertyName: "inputConfig", publicName: "inputConfig", isSignal: true, isRequired: true, transformFunction: null }, editorMode: { classPropertyName: "editorMode", publicName: "editorMode", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, formGroup: { classPropertyName: "formGroup", publicName: "formGroup", isSignal: true, isRequired: false, transformFunction: null }, formBuilderFunctions: { classPropertyName: "formBuilderFunctions", publicName: "formBuilderFunctions", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onContainerClick: "onContainerClick", interaction: "interaction" }, ngImport: i0, template: "@if ((viewData$ | async); as viewData) {\r\n<section\r\n (click)=\"setAsTouched($event)\"\r\n class=\"mscoa-chart__container\"\r\n [class.mscoa-chart__container--touched]=\"touched()\"\r\n role=\"region\"\r\n [attr.aria-label]=\"'MSCOA Account Chart'\"\r\n [attr.aria-busy]=\"viewData.loading || viewData.validatingValue\">\r\n\r\n @if (viewData.loading) {\r\n <div class=\"mscoa-chart__loading-container\" role=\"status\" aria-live=\"polite\">\r\n <mat-spinner [diameter]=\"40\"></mat-spinner>\r\n <span class=\"sr-only\">Loading account chart data...</span>\r\n </div>\r\n } @else {\r\n @defer () {\r\n @if (viewData.accountTreeKeys || viewData.cashAccountTreeKeys) {\r\n <div class=\"mscoa-chart__table-container\">\r\n @if (isDualAccountBasis) {\r\n <div class=\"dual-basis-container\" role=\"group\" aria-label=\"Dual accounting basis tables\">\r\n <div class=\"dual-basis-container__item\">\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: ACCOUNTING_BASIS.ACCRUAL,\r\n canCollapse: true,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n </div>\r\n\r\n <div class=\"dual-basis-container__item\">\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: ACCOUNTING_BASIS.CASH,\r\n canCollapse: true,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n </div>\r\n </div>\r\n } @else {\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: config()?.accountingBasis,\r\n canCollapse: false,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n }\r\n </div>\r\n }\r\n\r\n <ng-template\r\n #selectionTable\r\n let-accountingBasis=\"accountingBasis\"\r\n let-canCollapse=\"canCollapse\"\r\n let-viewData=\"viewData\">\r\n\r\n <div class=\"mscoa-chart-table\" role=\"group\" [attr.aria-label]=\"'Accounting basis: ' + (accountingBasis || 'Accrual')\">\r\n <!-- Toolbar -->\r\n <lib-mscoa-chart-toolbar\r\n [accountingBasis]=\"accountingBasis\"\r\n [canCollapse]=\"canCollapse\"\r\n [isExpanded]=\"getExpansionState(accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\"\r\n (toggleExpansion)=\"toggleDualBasisExpansion(accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\">\r\n </lib-mscoa-chart-toolbar>\r\n\r\n @if (shouldShowTable(isDualAccountBasis, getExpansionState(accountingBasis || ACCOUNTING_BASIS.ACCRUAL), accountingBasis)) {\r\n <div class=\"account-selection-table-wrapper\">\r\n <div\r\n class=\"account-selection-table-container\"\r\n [class.account-selection-table-container--accrual]=\"!accountingBasis || accountingBasis === ACCOUNTING_BASIS.ACCRUAL\"\r\n [class.account-selection-table-container--cash]=\"accountingBasis === ACCOUNTING_BASIS.CASH\"\r\n role=\"table\"\r\n [attr.aria-label]=\"'Account selection table for ' + (accountingBasis || 'Accrual') + ' basis'\">\r\n\r\n <table\r\n mat-table\r\n [dataSource]=\"accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashTableData : viewData.tableData\"\r\n [trackBy]=\"trackByRow\"\r\n class=\"table\"\r\n [attr.aria-label]=\"'Account selection table for ' + (accountingBasis || 'Accrual') + ' basis'\"\r\n [attr.aria-describedby]=\"'table-description-' + (accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\"\r\n role=\"table\">\r\n <span [id]=\"'table-description-' + (accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\" class=\"sr-only\">\r\n Use arrow keys to navigate between cells. Press Enter or Space to select an account.\r\n </span>\r\n\r\n @for (\r\n col of (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols);\r\n track trackByColumn($index, col);\r\n let i = $index\r\n ) {\r\n <ng-container [matColumnDef]=\"col\" [sticky]=\"i === 0\">\r\n <!-- Header Cell -->\r\n <th\r\n mat-header-cell\r\n *matHeaderCellDef\r\n [class.table__header-cell--segment]=\"isSegmentColumn(i)\"\r\n [class.table__header-cell--regular]=\"!isSegmentColumn(i)\"\r\n [style.width.%]=\"getColumnWidthPercent(isSegmentColumn(i), (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols).length)\"\r\n [style.min-width.px]=\"isSegmentColumn(i) ? 150 : 200\"\r\n [attr.aria-sort]=\"i === 0 ? 'none' : null\"\r\n [attr.scope]=\"'col'\"\r\n [attr.aria-label]=\"getHeaderText(col, i, accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashHasMultiSelect : viewData.hasMultiSelect) + ' column'\">\r\n {{ getHeaderText(col, i, accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashHasMultiSelect : viewData.hasMultiSelect) | titlecase | unCamelCase }}\r\n </th>\r\n\r\n <!-- Data Cell -->\r\n <td\r\n mat-cell\r\n *matCellDef=\"let row\"\r\n [class.table__cell--segment]=\"isSegmentColumn(i)\"\r\n [class.table__cell--regular]=\"!isSegmentColumn(i)\"\r\n [class.table__cell--active]=\"editSelection?.segment === row['segment'] && activeColumn === col\"\r\n [class.table__cell--business-error]=\"!isSegmentColumn(i) && getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-label]=\"'Cell for ' + row['segment'] + ' segment, ' + col + ' column'\"\r\n [attr.aria-selected]=\"!!row[col]\"\r\n [attr.aria-invalid]=\"!isSegmentColumn(i) && !!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.role]=\"'gridcell'\"\r\n [attr.tabindex]=\"isSegmentColumn(i) ? -1 : (row[col] ? 0 : -1)\">\r\n\r\n @if (isSegmentColumn(i)) {\r\n <!-- Segment Column -->\r\n <div class=\"segment-cell-content\">\r\n @if (editorMode() && row.innerInput?.id) {\r\n <button\r\n mat-icon-button\r\n [matMenuTriggerData]=\"{innerInput: row.innerInput}\"\r\n [matMenuTriggerFor]=\"inputMenu\"\r\n [matTooltip]=\"'Options for: ' + row.innerInput.label\"\r\n [attr.aria-label]=\"'Options menu for ' + row.innerInput.label\"\r\n (click)=\"$event.stopPropagation()\">\r\n <mat-icon>more_vert</mat-icon>\r\n </button>\r\n }\r\n <span class=\"segment-cell-content__label\">{{ row['label'] }}</span>\r\n </div>\r\n } @else {\r\n <!-- Regular Column -->\r\n @if (row.innerInput?.id) {\r\n <!-- Custom-input row (peer of the segments): the value is entered inline via the\r\n input portal on the primary (debit) leg; other legs mirror it and render no\r\n control. `innerInput.id` is already the namespaced portal key, so it is looked\r\n up directly \u2014 prepending it again (getPortalKey) double-namespaces and misses. -->\r\n @if (col === COLUMNS.DEBIT && formGroup() && inputPortals[row.innerInput.id]) {\r\n <div class=\"portal-container\">\r\n <ng-template [cdkPortalOutlet]=\"inputPortals[row.innerInput.id]\"></ng-template>\r\n </div>\r\n }\r\n } @else {\r\n @if (row[col]) {\r\n <!-- Account Selected -->\r\n @if (getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment']); as cellError) {\r\n <div class=\"account-cell-wrapper\"\r\n [class.account-cell-wrapper--expandable]=\"isTextTruncated(row[col] | unCamelCase)\">\r\n <button\r\n [disabled]=\"row['singleSelect'] === true && col === COLUMNS.CREDIT\"\r\n (mousedown)=\"$event.preventDefault(); $event.stopPropagation(); selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n color=\"primary\"\r\n mat-button\r\n class=\"cell-button cell-button--selected cell-button--business-error\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase) + ' for ' + row['segment'] + ' segment, ' + col + ' column. Business error: ' + cellError.message\"\r\n [attr.aria-invalid]=\"true\"\r\n [attr.aria-pressed]=\"true\"\r\n [matTooltip]=\"cellError.message\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label selected-acount-label--tag selected-acount-label--business-error\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase)\">\r\n {{ row[col] | unCamelCase }}\r\n @if (shouldShowVatChip(row, col)) {\r\n <span\r\n class=\"vat-badge\"\r\n [attr.aria-label]=\"'VAT applicable to ' + col + ' column'\"\r\n [matTooltip]=\"'VAT is applicable to this ' + col + ' account selection'\">\r\n VAT\r\n </span>\r\n }\r\n </span>\r\n <mat-icon class=\"business-error-indicator\" aria-hidden=\"true\">error</mat-icon>\r\n </div>\r\n </button>\r\n </div>\r\n } @else {\r\n <div class=\"account-cell-wrapper\"\r\n [class.account-cell-wrapper--expandable]=\"isTextTruncated(row[col] | unCamelCase)\">\r\n <button\r\n [disabled]=\"(row['singleSelect'] === true && col === COLUMNS.CREDIT) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n (mousedown)=\"$event.preventDefault(); $event.stopPropagation(); selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n color=\"primary\"\r\n mat-button\r\n class=\"cell-button cell-button--selected\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase) + ' for ' + row['segment'] + ' segment, ' + col + ' column. Press Enter or Space to change'\"\r\n [attr.aria-invalid]=\"false\"\r\n [attr.aria-disabled]=\"(row['singleSelect'] === true && col === COLUMNS.CREDIT) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-pressed]=\"true\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label selected-acount-label--tag\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase)\">\r\n {{ row[col] | unCamelCase }}\r\n @if (shouldShowVatChip(row, col)) {\r\n <span\r\n class=\"vat-badge\"\r\n [attr.aria-label]=\"'VAT applicable to ' + col + ' column'\"\r\n [matTooltip]=\"'VAT is applicable to this ' + col + ' account selection'\">\r\n VAT\r\n </span>\r\n }\r\n </span>\r\n @if (showValidationSuccessIndicators) {\r\n <mat-icon class=\"validated-indicator\" aria-hidden=\"true\" [matTooltip]=\"'Validated'\">shield</mat-icon>\r\n } @else {\r\n <mat-icon class=\"success-indicator\" aria-hidden=\"true\">check_circle</mat-icon>\r\n }\r\n </div>\r\n </button>\r\n </div>\r\n }\r\n } @else {\r\n <!-- No Account Selected -->\r\n <div class=\"cell-button-wrapper\">\r\n <button\r\n [disabled]=\"selectionDisabled(row, col) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [color]=\"\"\r\n (click)=\"selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); $event.stopPropagation(); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n mat-button\r\n class=\"cell-button\"\r\n [class.cell-button--business-error]=\"!!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-label]=\"shouldShowAutoSelectedLabel(row, col) ? 'Auto selected for ' + row['segment'] + ' segment, ' + col + ' column' : 'Select account for ' + row['segment'] + ' segment, ' + col + ' column'\"\r\n [attr.aria-disabled]=\"selectionDisabled(row, col) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-describedby]=\"getValidationHint(row, col, accountingBasis || ACCOUNTING_BASIS.ACCRUAL) ? 'hint-' + row['segment'] + '-' + col : null\"\r\n [attr.aria-invalid]=\"hasError(touched(), inputConfig().required || false, !!row[col]) || !!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-required]=\"inputConfig().required && !row[col]\"\r\n [matTooltip]=\"getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])?.message\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label\"\r\n [class.selected-acount-label--error]=\"hasError(touched(), inputConfig().required || false, !!row[col])\"\r\n [class.selected-acount-label--business-error]=\"!!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\">\r\n {{ (shouldShowAutoSelectedLabel(row, col) ? 'auto selected' : 'Select account') | unCamelCase }}\r\n @if (inputConfig().required && !row[col]) {\r\n <span class=\"required-indicator\" aria-label=\"Required field\">*</span>\r\n }\r\n </span>\r\n @if (getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])) {\r\n <mat-icon class=\"business-error-indicator\" aria-hidden=\"true\">error</mat-icon>\r\n } @else if (shouldShowDropdownIcon(row, col)) {\r\n <mat-icon aria-hidden=\"true\">arrow_drop_down</mat-icon>\r\n }\r\n </div>\r\n </button>\r\n @if (getValidationHint(row, col, accountingBasis || ACCOUNTING_BASIS.ACCRUAL); as hint) {\r\n <span\r\n class=\"inline-hint\"\r\n [id]=\"'hint-' + row['segment'] + '-' + col\"\r\n role=\"tooltip\"\r\n aria-live=\"polite\">\r\n {{ hint }}\r\n </span>\r\n }\r\n </div>\r\n }\r\n }\r\n }\r\n </td>\r\n </ng-container>\r\n }\r\n\r\n <tr mat-header-row *matHeaderRowDef=\"accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols\"></tr>\r\n <tr mat-row *matRowDef=\"let row; columns: (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols)\"></tr>\r\n </table>\r\n </div>\r\n </div>\r\n\r\n <!-- Empty State -->\r\n @if ((accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashAccountTreeKeys : viewData.accountTreeKeys).length === 0) {\r\n <section class=\"empty-state\" role=\"status\" aria-live=\"polite\">\r\n <mat-icon aria-hidden=\"true\">info</mat-icon>\r\n <span>\r\n No account segments are currently configured.\r\n Please configure account segments to proceed.\r\n </span>\r\n </section>\r\n }\r\n\r\n <!-- Success Messages (Temporary) -->\r\n @if ((successMessage$ | async); as successMessages) {\r\n @if (getSuccessMessage(successMessages, accountingBasis || ACCOUNTING_BASIS.ACCRUAL); as msg) {\r\n <lib-mscoa-temporary-hint\r\n [message]=\"getSuccessMessage(successMessages, accountingBasis || ACCOUNTING_BASIS.ACCRUAL) ?? ''\"\r\n [type]=\"'info'\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-temporary-hint>\r\n }\r\n }\r\n\r\n <!-- Business Rule Errors (Temporary display, keeps error styling) -->\r\n @if ((viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL] || []).length > 0) {\r\n <lib-mscoa-error-display\r\n [errors]=\"viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL] || []\"\r\n type=\"error\"\r\n [context]=\"{ accountingBasis: accountingBasis || ACCOUNTING_BASIS.ACCRUAL }\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-error-display>\r\n }\r\n\r\n <!-- Temporary Contextual Hints -->\r\n @if (temporaryHintMessage) {\r\n <lib-mscoa-temporary-hint\r\n [message]=\"temporaryHintMessage\"\r\n [type]=\"temporaryHintType\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-temporary-hint>\r\n }\r\n\r\n <!-- Validation Hints (Context-Aware) -->\r\n @if (!touched() && inputConfig().required && !viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL]?.length && (!isDualAccountBasis || accountingBasis === ACCOUNTING_BASIS.ACCRUAL || !accountingBasis)) {\r\n <div class=\"validation-hints\" role=\"region\" aria-label=\"Validation guidance\">\r\n <p class=\"validation-hints__title\">Guidance:</p>\r\n <ul class=\"validation-hints__list\">\r\n <li>Account combinations are validated automatically. Select accounts that belong to compatible reporting categories.</li>\r\n <li>Required fields are marked with an asterisk (*). Complete all required selections to proceed.</li>\r\n <li>Some fields may be automatically populated based on your selections to ensure consistency.</li>\r\n </ul>\r\n </div>\r\n }\r\n }\r\n </div>\r\n </ng-template>\r\n } @placeholder {\r\n <div class=\"loading-placeholder\" role=\"status\" aria-live=\"polite\">\r\n <p>Loading data...</p>\r\n </div>\r\n } @loading (minimum 100ms) {\r\n <div class=\"loading-spinner-container\" role=\"status\" aria-live=\"polite\">\r\n <mat-progress-spinner mode=\"indeterminate\" [diameter]=\"40\"></mat-progress-spinner>\r\n <span class=\"sr-only\">Loading account chart...</span>\r\n </div>\r\n } @error {\r\n <div class=\"error-state\" role=\"alert\" aria-live=\"assertive\">\r\n <p>Error loading data. Please try again.</p>\r\n </div>\r\n }\r\n }\r\n</section>\r\n}\r\n\r\n<!-- Input Menu -->\r\n<mat-menu #inputMenu=\"matMenu\">\r\n <ng-template matMenuContent let-innerInput=\"innerInput\">\r\n <lib-mscoa-chart-input-menu\r\n [innerInput]=\"innerInput\"\r\n [countdownSeconds]=\"inputWillBeRemovedIn(innerInput.id)\"\r\n [hoveredId]=\"hoveredInputId\"\r\n (edit)=\"onInputMenuEdit($event)\"\r\n (delete)=\"onInputMenuDelete($event)\"\r\n (cancelDelete)=\"onInputMenuCancelDelete($event)\"\r\n (hoverStart)=\"onInputMenuHoverStart($event)\"\r\n (hoverEnd)=\"onInputMenuHoverEnd()\">\r\n </lib-mscoa-chart-input-menu>\r\n </ng-template>\r\n</mat-menu>\r\n", styles: ["@charset \"UTF-8\";:host{--mscoa-chart-spacing-xs: 4px;--mscoa-chart-spacing-sm: 8px;--mscoa-chart-spacing-md: 16px;--mscoa-chart-spacing-lg: 24px;--mscoa-chart-spacing-xl: 32px;--mscoa-chart-border-radius: 4px;--mscoa-chart-transition: var(--lib-forms-duration-hover) var(--lib-forms-easing);--mscoa-chart-font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;--mscoa-chart-font-size-base: 14px;--mscoa-chart-line-height: 1.5;display:block;font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height)}.mscoa-chart__container{padding:0;transition:background-color var(--mscoa-chart-transition);width:100%;max-width:100%;overflow-x:hidden;box-sizing:border-box}.mscoa-chart__loading-container{padding:var(--mscoa-chart-spacing-lg);display:flex;align-items:center;justify-content:center}.mscoa-chart__table-container{position:relative;width:100%;max-width:100%;overflow-x:auto;overflow-y:visible;box-sizing:border-box}.dual-basis-container{display:flex;flex-direction:column;gap:var(--mscoa-chart-spacing-sm)}.dual-basis-container__item{flex:1}:host .single-base{gap:var(--mscoa-chart-spacing-sm);height:48px;font-size:.875em;font-weight:500;transition:background-color var(--mscoa-chart-transition)}:host .single-base--cash{background:var(--mat-sys-inverse-primary)}.account-selection-table-wrapper{position:relative;width:100%}.account-selection-table-container{border-radius:var(--mscoa-chart-border-radius);overflow-x:auto;overflow-y:visible;transition:border-color var(--mscoa-chart-transition);width:100%;max-width:100%;box-sizing:border-box;display:block}.account-selection-table-container--accrual{border:solid 1px var(--mat-sys-primary)}.account-selection-table-container--cash{border:solid 1px var(--mat-sys-inverse-primary)}.account-selection-table-container::-webkit-scrollbar{height:8px}.account-selection-table-container::-webkit-scrollbar-track{background:var(--lib-forms-surface-container-low);border-radius:4px}.account-selection-table-container::-webkit-scrollbar-thumb{background:var(--lib-forms-outline-variant);border-radius:4px}.account-selection-table-container::-webkit-scrollbar-thumb:hover{background:var(--lib-forms-outline)}.table{width:100%;table-layout:fixed;font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height);border-collapse:separate;border-spacing:0;display:table;box-sizing:border-box;max-width:100%}.table__header-cell{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;box-sizing:border-box}.table__header-cell--segment{text-align:right;padding-right:var(--mscoa-chart-spacing-md);min-width:150px;max-width:200px}.table__header-cell--regular{padding-left:var(--mscoa-chart-spacing-lg);min-width:200px;max-width:none}.table__cell{overflow:visible;box-sizing:border-box;position:relative;vertical-align:top}.table__cell--segment{background:var(--mat-list-active-indicator-color, var(--mat-sys-secondary-container));text-align:right;font-weight:500;padding-right:var(--mscoa-chart-spacing-md);min-width:150px;max-width:200px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;vertical-align:middle}.table__cell--regular{padding:0;min-width:200px;max-width:none;word-wrap:break-word;vertical-align:top;overflow:visible}.table__cell--active{background-color:var(--mat-sys-primary-container);transition:background-color var(--mscoa-chart-transition)}mat-header-cell{background:var(--mat-sys-surface-container);font-weight:600;font-size:var(--mscoa-chart-font-size-base);padding:var(--mscoa-chart-spacing-md)}.mscoa-chart-table{display:flex;flex-direction:column}.portal-container{width:100%}.account-cell-wrapper{position:relative;width:100%;max-width:100%;overflow:visible;z-index:1;min-height:38px;display:flex;flex-direction:column;gap:4px}.cell-button-wrapper{position:relative;width:100%;max-width:100%;overflow:hidden}.cell-button{height:fit-content;min-height:38px;width:100%;max-width:100%;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),transform var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing);font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height);position:relative;overflow:visible;padding:8px}.cell-button:hover:not(:disabled){background-color:var(--mat-sys-surface-container);transform:translateY(-1px);box-shadow:0 2px 4px #0000001a}.cell-button:focus-visible{outline:3px solid var(--mat-sys-primary);outline-offset:2px;z-index:1}.cell-button:disabled{opacity:.6;cursor:not-allowed}.cell-button--selected{background-color:transparent}.cell-button--selected:hover:not(:disabled){background-color:var(--lib-forms-surface-container-low);border-color:var(--lib-forms-primary)}.cell-button.cell-button--selected{animation:fadeInSuccess var(--mscoa-chart-transition)}.cell-button.cell-button--business-error{border-color:var(--lib-forms-error)}.cell-button.cell-button--business-error .selected-acount-label--business-error{color:var(--mat-sys-error);border-color:var(--mat-sys-error)}.success-indicator{color:var(--sem-success);font-size:18px;width:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;height:18px;margin-left:var(--mscoa-chart-spacing-xs);animation:scaleIn var(--mscoa-chart-transition);flex-shrink:0}.validated-indicator{color:var(--lib-forms-primary);font-size:18px;width:18px;height:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;margin-left:var(--mscoa-chart-spacing-xs);flex-shrink:0;animation:validatedShieldIn .3s ease-out forwards}.business-error-indicator{color:var(--lib-forms-error);font-size:18px;width:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;height:18px;margin-left:var(--mscoa-chart-spacing-xs);flex-shrink:0}.required-indicator{color:var(--lib-forms-error);font-weight:600;margin-left:2px}.inline-hint{display:block;font-size:12px;color:var(--lib-forms-on-surface-variant);margin-top:var(--mscoa-chart-spacing-xs);padding:var(--mscoa-chart-spacing-xs) var(--mscoa-chart-spacing-sm);background-color:var(--lib-forms-surface-container-low);border-radius:var(--mscoa-chart-border-radius);line-height:1.4;max-width:100%;word-wrap:break-word}.content{padding:0;display:flex;gap:6px;width:100%;max-width:100%;overflow:visible;min-width:0;flex-wrap:wrap;align-items:center}.selected-acount-label{text-align:left;flex:1;font-weight:400;transition:color var(--mscoa-chart-transition)}.selected-acount-label--error,.selected-acount-label--business-error{color:var(--mat-sys-error);font-weight:500}.selected-acount-label--tag{display:inline-block;padding:4px 10px;background-color:var(--lib-forms-primary-container);color:var(--lib-forms-on-primary-container);border-radius:16px;font-size:13px;font-weight:500;line-height:1.5;border:1px solid var(--lib-forms-primary);box-shadow:0 1px 2px #0000001a;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing);width:100%;max-width:100%;overflow:visible;white-space:normal;word-wrap:break-word;word-break:break-word;cursor:pointer;box-sizing:border-box;position:relative}.selected-acount-label--tag:hover{background-color:var(--sem-info-surface);box-shadow:0 2px 4px #1976d226}.segment-cell-content{display:flex;align-items:center;justify-content:flex-end;font-weight:500}.vat-badge{display:inline-flex;align-items:center;justify-content:center;height:16px;padding:2px 6px;border-radius:8px;font-size:9px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;background-color:var(--sem-success-surface);color:var(--sem-warning);border:1px solid var(--lib-forms-outline-variant);box-shadow:none;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),border-color var(--lib-forms-duration-hover) var(--lib-forms-easing);flex-shrink:0;align-self:flex-start;margin-top:2px;line-height:1}.vat-badge:hover{background-color:var(--sem-warning-surface);border-color:var(--sem-warning)}.vat-chip-container{padding-left:var(--mscoa-chart-spacing-sm);padding-right:var(--mscoa-chart-spacing-sm);padding-bottom:var(--mscoa-chart-spacing-xs);margin-top:var(--mscoa-chart-spacing-xs)}.vat-chip{display:inline-flex;align-items:center;gap:4px;height:24px;padding:4px 8px;border-radius:12px;font-size:11px;font-weight:600;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing),transform var(--lib-forms-duration-hover) var(--lib-forms-easing);box-shadow:0 1px 3px #0000001f}.vat-chip--applicable{background:linear-gradient(135deg,var(--sem-warning) 0%,var(--sem-warning) 100%);color:var(--lib-forms-on-primary);border:1px solid var(--sem-warning)}.vat-chip--applicable:hover{box-shadow:0 2px 6px #f57c004d;transform:translateY(-1px)}.vat-chip__icon{font-size:14px;width:14px;height:14px;opacity:.9}.vat-chip__text{font-size:11px;font-weight:600;letter-spacing:.3px}.info-box{display:flex;align-items:center;gap:var(--mscoa-chart-spacing-sm);padding:12px;background:var(--sem-info-surface);border-radius:var(--mscoa-chart-border-radius);margin-bottom:var(--mscoa-chart-spacing-md)}.info-icon{min-width:38px;margin:auto;margin-top:var(--mscoa-chart-spacing-sm)}.empty-state{padding:var(--mscoa-chart-spacing-md);text-align:center;display:flex;align-items:center;justify-content:center;gap:var(--mscoa-chart-spacing-sm);color:var(--mat-sys-on-surface-variant)}.validation-hints{margin-top:var(--mscoa-chart-spacing-md);padding:var(--mscoa-chart-spacing-md);background-color:var(--lib-forms-surface-container-low);border-radius:var(--mscoa-chart-border-radius);border-left:4px solid var(--lib-forms-primary);box-shadow:0 1px 3px #00000014}.validation-hints__title{font-weight:600;font-size:var(--mscoa-chart-font-size-base);margin:0 0 var(--mscoa-chart-spacing-sm) 0;color:var(--lib-forms-on-surface);display:flex;align-items:center;gap:var(--mscoa-chart-spacing-xs)}.validation-hints__title:before{content:\"\\1f4a1\";font-size:16px}.validation-hints__list{margin:0;padding-left:var(--mscoa-chart-spacing-md);color:var(--lib-forms-on-surface-variant);font-size:13px;line-height:1.6}.validation-hints__list li{margin-bottom:var(--mscoa-chart-spacing-sm);position:relative}.validation-hints__list li::marker{color:var(--lib-forms-primary)}.validation-hints__list li:last-child{margin-bottom:0}mat-error{font-size:.75em;margin-top:var(--mscoa-chart-spacing-xs)}mat-error ul{margin:0;padding-left:var(--mscoa-chart-spacing-md)}mat-error li{margin-bottom:var(--mscoa-chart-spacing-xs)}.loading-placeholder{padding:var(--mscoa-chart-spacing-md);color:var(--mat-sys-on-surface-variant)}.loading-spinner-container{display:flex;justify-content:center;align-items:center;height:256px}.error-state{padding:var(--mscoa-chart-spacing-md);color:var(--mat-sys-error)}mat-panel-description{font-size:.875em;line-height:1.4}:host .main-expanse-content{background:var(--mat-sys-surface-container)}@media(max-width:768px){.dual-basis-container{gap:var(--mscoa-chart-spacing-md)}.cell-button{min-height:44px;font-size:15px;max-width:300px}.content{padding:var(--mscoa-chart-spacing-md)}.validation-hints{font-size:13px;padding:var(--mscoa-chart-spacing-sm)}.inline-hint{font-size:11px}}.cell-button:focus-visible,button:focus-visible{outline:3px solid var(--mat-sys-primary);outline-offset:2px;outline-style:solid}@media(prefers-contrast:high){.cell-button{border:2px solid currentColor}.cell-button:focus-visible{outline-width:4px}.selected-acount-label--error{font-weight:600}}@media(prefers-reduced-motion:reduce){.cell-button,.success-indicator,.fade-in,.validated-indicator{animation:none;transition:none}}.table__cell--active{background-color:var(--mat-sys-primary-container);color:var(--mat-sys-on-primary-container)}@media(prefers-contrast:high){.table__cell--active{background-color:var(--mat-sys-primary);color:var(--mat-sys-on-primary)}}.table__cell--business-error{background-color:var(--lib-forms-error-container);border-left:3px solid var(--lib-forms-error)}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeInSuccess{0%{background-color:transparent}50%{background-color:var(--sem-success-surface)}to{background-color:var(--mat-sys-primary-container)}}@keyframes scaleIn{0%{transform:scale(0);opacity:0}to{transform:scale(1);opacity:1}}@keyframes validatedShieldIn{0%{opacity:0;transform:scale(.6)}70%{opacity:1;transform:scale(1.1)}to{opacity:1;transform:scale(1)}}.fade-in{animation:fadeIn var(--mscoa-chart-transition)}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.skeleton-loader{background:linear-gradient(90deg,var(--mat-sys-surface-container) 25%,var(--mat-sys-surface-container-high) 50%,var(--mat-sys-surface-container) 75%);background-size:200% 100%;animation:loading 1.5s ease-in-out infinite;border-radius:var(--mscoa-chart-border-radius)}@keyframes loading{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-row{height:48px;margin-bottom:var(--mscoa-chart-spacing-xs)}.skeleton-cell{height:100%;margin-right:var(--mscoa-chart-spacing-md)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: PortalModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i6.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "directive", type: i6.MatMenuContent, selector: "ng-template[matMenuContent]" }, { kind: "ngmodule", type: MatTableModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i3$2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: MscoaChartInputMenuComponent, selector: "lib-mscoa-chart-input-menu", inputs: ["innerInput", "countdownSeconds", "hoveredId"], outputs: ["edit", "delete", "cancelDelete", "hoverStart", "hoverEnd"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [i3.NgTemplateOutlet, i4$2.CdkPortalOutlet, i1$2.MatButton, i1$2.MatIconButton, i3$1.MatIcon, i6.MatMenuTrigger, i5$2.MatTable, i5$2.MatHeaderCellDef, i5$2.MatHeaderRowDef, i5$2.MatColumnDef, i5$2.MatCellDef, i5$2.MatRowDef, i5$2.MatHeaderCell, i5$2.MatCell, i5$2.MatHeaderRow, i5$2.MatRow, i5$1.MatTooltip, import('./ngx-t-forms-mscoa-chart-toolbar.component-D4Xa_Yi0.mjs').then(m => m.MscoaChartToolbarComponent), import('./ngx-t-forms-mscoa-error-display.component-99DpVSy7.mjs').then(m => m.MscoaErrorDisplayComponent), import('./ngx-t-forms-mscoa-temporary-hint.component-B1Z-IXSL.mjs').then(m => m.MscoaTemporaryHintComponent), i3.AsyncPipe, i3.TitleCasePipe, Promise.resolve().then(function () { return daysAgo_pipe; }).then(m => m.ConvertCamelCasePipe)]] }); }
|
|
16488
17021
|
}
|
|
16489
|
-
i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.2.12", ngImport: i0, type: MscoaChartComponent, resolveDeferredDeps: () => [import('./ngx-t-forms-mscoa-chart-toolbar.component-
|
|
17022
|
+
i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.2.12", ngImport: i0, type: MscoaChartComponent, resolveDeferredDeps: () => [import('./ngx-t-forms-mscoa-chart-toolbar.component-D4Xa_Yi0.mjs').then(m => m.MscoaChartToolbarComponent), import('./ngx-t-forms-mscoa-error-display.component-99DpVSy7.mjs').then(m => m.MscoaErrorDisplayComponent), import('./ngx-t-forms-mscoa-temporary-hint.component-B1Z-IXSL.mjs').then(m => m.MscoaTemporaryHintComponent), Promise.resolve().then(function () { return daysAgo_pipe; }).then(m => m.ConvertCamelCasePipe)], resolveMetadata: (MscoaChartToolbarComponent, MscoaErrorDisplayComponent, MscoaTemporaryHintComponent, ConvertCamelCasePipe) => ({ decorators: [{
|
|
16490
17023
|
type: Component,
|
|
16491
17024
|
args: [{ selector: 'lib-mscoa-chart', imports: [
|
|
16492
17025
|
CommonModule,
|
|
@@ -16503,7 +17036,7 @@ i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.2.12", n
|
|
|
16503
17036
|
MscoaChartInputMenuComponent,
|
|
16504
17037
|
MscoaErrorDisplayComponent,
|
|
16505
17038
|
MscoaTemporaryHintComponent
|
|
16506
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if ((viewData$ | async); as viewData) {\r\n<section\r\n (click)=\"setAsTouched($event)\"\r\n class=\"mscoa-chart__container\"\r\n [class.mscoa-chart__container--touched]=\"touched()\"\r\n role=\"region\"\r\n [attr.aria-label]=\"'MSCOA Account Chart'\"\r\n [attr.aria-busy]=\"viewData.loading || viewData.validatingValue\">\r\n\r\n @if (viewData.loading) {\r\n <div class=\"mscoa-chart__loading-container\" role=\"status\" aria-live=\"polite\">\r\n <mat-spinner [diameter]=\"40\"></mat-spinner>\r\n <span class=\"sr-only\">Loading account chart data...</span>\r\n </div>\r\n } @else {\r\n @defer () {\r\n @if (viewData.accountTreeKeys || viewData.cashAccountTreeKeys) {\r\n <div class=\"mscoa-chart__table-container\">\r\n @if (isDualAccountBasis) {\r\n <div class=\"dual-basis-container\" role=\"group\" aria-label=\"Dual accounting basis tables\">\r\n <div class=\"dual-basis-container__item\">\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: ACCOUNTING_BASIS.ACCRUAL,\r\n canCollapse: true,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n </div>\r\n\r\n <div class=\"dual-basis-container__item\">\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: ACCOUNTING_BASIS.CASH,\r\n canCollapse: true,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n </div>\r\n </div>\r\n } @else {\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: config()?.accountingBasis,\r\n canCollapse: false,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n }\r\n </div>\r\n }\r\n\r\n <ng-template\r\n #selectionTable\r\n let-accountingBasis=\"accountingBasis\"\r\n let-canCollapse=\"canCollapse\"\r\n let-viewData=\"viewData\">\r\n\r\n <div class=\"mscoa-chart-table\" role=\"group\" [attr.aria-label]=\"'Accounting basis: ' + (accountingBasis || 'Accrual')\">\r\n <!-- Toolbar -->\r\n <lib-mscoa-chart-toolbar\r\n [accountingBasis]=\"accountingBasis\"\r\n [canCollapse]=\"canCollapse\"\r\n [isExpanded]=\"getExpansionState(accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\"\r\n (toggleExpansion)=\"toggleDualBasisExpansion(accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\">\r\n </lib-mscoa-chart-toolbar>\r\n\r\n @if (shouldShowTable(isDualAccountBasis, getExpansionState(accountingBasis || ACCOUNTING_BASIS.ACCRUAL), accountingBasis)) {\r\n <div class=\"account-selection-table-wrapper\">\r\n <div\r\n class=\"account-selection-table-container\"\r\n [class.account-selection-table-container--accrual]=\"!accountingBasis || accountingBasis === ACCOUNTING_BASIS.ACCRUAL\"\r\n [class.account-selection-table-container--cash]=\"accountingBasis === ACCOUNTING_BASIS.CASH\"\r\n role=\"table\"\r\n [attr.aria-label]=\"'Account selection table for ' + (accountingBasis || 'Accrual') + ' basis'\">\r\n\r\n <table\r\n mat-table\r\n [dataSource]=\"accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashTableData : viewData.tableData\"\r\n [trackBy]=\"trackByRow\"\r\n class=\"table\"\r\n [attr.aria-label]=\"'Account selection table for ' + (accountingBasis || 'Accrual') + ' basis'\"\r\n [attr.aria-describedby]=\"'table-description-' + (accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\"\r\n role=\"table\">\r\n <span [id]=\"'table-description-' + (accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\" class=\"sr-only\">\r\n Use arrow keys to navigate between cells. Press Enter or Space to select an account.\r\n </span>\r\n\r\n @for (\r\n col of (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols);\r\n track trackByColumn($index, col);\r\n let i = $index\r\n ) {\r\n <ng-container [matColumnDef]=\"col\" [sticky]=\"i === 0\">\r\n <!-- Header Cell -->\r\n <th\r\n mat-header-cell\r\n *matHeaderCellDef\r\n [class.table__header-cell--segment]=\"isSegmentColumn(i)\"\r\n [class.table__header-cell--regular]=\"!isSegmentColumn(i)\"\r\n [style.width.%]=\"getColumnWidthPercent(isSegmentColumn(i), (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols).length)\"\r\n [style.min-width.px]=\"isSegmentColumn(i) ? 150 : 200\"\r\n [attr.aria-sort]=\"i === 0 ? 'none' : null\"\r\n [attr.scope]=\"'col'\"\r\n [attr.aria-label]=\"getHeaderText(col, i, accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashHasMultiSelect : viewData.hasMultiSelect) + ' column'\">\r\n {{ getHeaderText(col, i, accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashHasMultiSelect : viewData.hasMultiSelect) | titlecase | unCamelCase }}\r\n </th>\r\n\r\n <!-- Data Cell -->\r\n <td\r\n mat-cell\r\n *matCellDef=\"let row\"\r\n [class.table__cell--segment]=\"isSegmentColumn(i)\"\r\n [class.table__cell--regular]=\"!isSegmentColumn(i)\"\r\n [class.table__cell--active]=\"editSelection?.segment === row['segment'] && activeColumn === col\"\r\n [class.table__cell--business-error]=\"!isSegmentColumn(i) && getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-label]=\"'Cell for ' + row['segment'] + ' segment, ' + col + ' column'\"\r\n [attr.aria-selected]=\"!!row[col]\"\r\n [attr.aria-invalid]=\"!isSegmentColumn(i) && !!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.role]=\"'gridcell'\"\r\n [attr.tabindex]=\"isSegmentColumn(i) ? -1 : (row[col] ? 0 : -1)\">\r\n\r\n @if (isSegmentColumn(i)) {\r\n <!-- Segment Column -->\r\n <div class=\"segment-cell-content\">\r\n @if (editorMode() && row.innerInput?.id) {\r\n <button\r\n mat-icon-button\r\n [matMenuTriggerData]=\"{innerInput: row.innerInput}\"\r\n [matMenuTriggerFor]=\"inputMenu\"\r\n [matTooltip]=\"'Options for: ' + row.innerInput.label\"\r\n [attr.aria-label]=\"'Options menu for ' + row.innerInput.label\"\r\n (click)=\"$event.stopPropagation()\">\r\n <mat-icon>more_vert</mat-icon>\r\n </button>\r\n }\r\n <span class=\"segment-cell-content__label\">{{ row['label'] }}</span>\r\n </div>\r\n } @else {\r\n <!-- Regular Column -->\r\n @if (row.innerInput?.id && formGroup() && inputPortals[getPortalKey(row.innerInput.id)]) {\r\n <div class=\"portal-container\">\r\n <ng-template [cdkPortalOutlet]=\"inputPortals[getPortalKey(row.innerInput.id)]\"></ng-template>\r\n </div>\r\n } @else {\r\n @if (row[col]) {\r\n <!-- Account Selected -->\r\n @if (getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment']); as cellError) {\r\n <div class=\"account-cell-wrapper\"\r\n [class.account-cell-wrapper--expandable]=\"isTextTruncated(row[col] | unCamelCase)\">\r\n <button\r\n [disabled]=\"row['singleSelect'] === true && col === COLUMNS.CREDIT\"\r\n (mousedown)=\"$event.preventDefault(); $event.stopPropagation(); selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n color=\"primary\"\r\n mat-button\r\n class=\"cell-button cell-button--selected cell-button--business-error\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase) + ' for ' + row['segment'] + ' segment, ' + col + ' column. Business error: ' + cellError.message\"\r\n [attr.aria-invalid]=\"true\"\r\n [attr.aria-pressed]=\"true\"\r\n [matTooltip]=\"cellError.message\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label selected-acount-label--tag selected-acount-label--business-error\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase)\">\r\n {{ row[col] | unCamelCase }}\r\n @if (shouldShowVatChip(row, col)) {\r\n <span\r\n class=\"vat-badge\"\r\n [attr.aria-label]=\"'VAT applicable to ' + col + ' column'\"\r\n [matTooltip]=\"'VAT is applicable to this ' + col + ' account selection'\">\r\n VAT\r\n </span>\r\n }\r\n </span>\r\n <mat-icon class=\"business-error-indicator\" aria-hidden=\"true\">error</mat-icon>\r\n </div>\r\n </button>\r\n </div>\r\n } @else {\r\n <div class=\"account-cell-wrapper\"\r\n [class.account-cell-wrapper--expandable]=\"isTextTruncated(row[col] | unCamelCase)\">\r\n <button\r\n [disabled]=\"(row['singleSelect'] === true && col === COLUMNS.CREDIT) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n (mousedown)=\"$event.preventDefault(); $event.stopPropagation(); selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n color=\"primary\"\r\n mat-button\r\n class=\"cell-button cell-button--selected\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase) + ' for ' + row['segment'] + ' segment, ' + col + ' column. Press Enter or Space to change'\"\r\n [attr.aria-invalid]=\"false\"\r\n [attr.aria-disabled]=\"(row['singleSelect'] === true && col === COLUMNS.CREDIT) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-pressed]=\"true\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label selected-acount-label--tag\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase)\">\r\n {{ row[col] | unCamelCase }}\r\n @if (shouldShowVatChip(row, col)) {\r\n <span\r\n class=\"vat-badge\"\r\n [attr.aria-label]=\"'VAT applicable to ' + col + ' column'\"\r\n [matTooltip]=\"'VAT is applicable to this ' + col + ' account selection'\">\r\n VAT\r\n </span>\r\n }\r\n </span>\r\n @if (showValidationSuccessIndicators) {\r\n <mat-icon class=\"validated-indicator\" aria-hidden=\"true\" [matTooltip]=\"'Validated'\">shield</mat-icon>\r\n } @else {\r\n <mat-icon class=\"success-indicator\" aria-hidden=\"true\">check_circle</mat-icon>\r\n }\r\n </div>\r\n </button>\r\n </div>\r\n }\r\n } @else {\r\n <!-- No Account Selected -->\r\n <div class=\"cell-button-wrapper\">\r\n <button\r\n [disabled]=\"selectionDisabled(row, col) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [color]=\"\"\r\n (click)=\"selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); $event.stopPropagation(); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n mat-button\r\n class=\"cell-button\"\r\n [class.cell-button--business-error]=\"!!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-label]=\"shouldShowAutoSelectedLabel(row, col) ? 'Auto selected for ' + row['segment'] + ' segment, ' + col + ' column' : 'Select account for ' + row['segment'] + ' segment, ' + col + ' column'\"\r\n [attr.aria-disabled]=\"selectionDisabled(row, col) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-describedby]=\"getValidationHint(row, col, accountingBasis || ACCOUNTING_BASIS.ACCRUAL) ? 'hint-' + row['segment'] + '-' + col : null\"\r\n [attr.aria-invalid]=\"hasError(touched(), inputConfig().required || false, !!row[col]) || !!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-required]=\"inputConfig().required && !row[col]\"\r\n [matTooltip]=\"getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])?.message\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label\"\r\n [class.selected-acount-label--error]=\"hasError(touched(), inputConfig().required || false, !!row[col])\"\r\n [class.selected-acount-label--business-error]=\"!!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\">\r\n {{ (shouldShowAutoSelectedLabel(row, col) ? 'auto selected' : 'Select account') | unCamelCase }}\r\n @if (inputConfig().required && !row[col]) {\r\n <span class=\"required-indicator\" aria-label=\"Required field\">*</span>\r\n }\r\n </span>\r\n @if (getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])) {\r\n <mat-icon class=\"business-error-indicator\" aria-hidden=\"true\">error</mat-icon>\r\n } @else if (shouldShowDropdownIcon(row, col)) {\r\n <mat-icon aria-hidden=\"true\">arrow_drop_down</mat-icon>\r\n }\r\n </div>\r\n </button>\r\n @if (getValidationHint(row, col, accountingBasis || ACCOUNTING_BASIS.ACCRUAL); as hint) {\r\n <span\r\n class=\"inline-hint\"\r\n [id]=\"'hint-' + row['segment'] + '-' + col\"\r\n role=\"tooltip\"\r\n aria-live=\"polite\">\r\n {{ hint }}\r\n </span>\r\n }\r\n </div>\r\n }\r\n }\r\n }\r\n </td>\r\n </ng-container>\r\n }\r\n\r\n <tr mat-header-row *matHeaderRowDef=\"accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols\"></tr>\r\n <tr mat-row *matRowDef=\"let row; columns: (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols)\"></tr>\r\n </table>\r\n </div>\r\n </div>\r\n\r\n <!-- Empty State -->\r\n @if ((accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashAccountTreeKeys : viewData.accountTreeKeys).length === 0) {\r\n <section class=\"empty-state\" role=\"status\" aria-live=\"polite\">\r\n <mat-icon aria-hidden=\"true\">info</mat-icon>\r\n <span>\r\n No account segments are currently configured.\r\n Please configure account segments to proceed.\r\n </span>\r\n </section>\r\n }\r\n\r\n <!-- Success Messages (Temporary) -->\r\n @if ((successMessage$ | async); as successMessages) {\r\n @if (getSuccessMessage(successMessages, accountingBasis || ACCOUNTING_BASIS.ACCRUAL); as msg) {\r\n <lib-mscoa-temporary-hint\r\n [message]=\"getSuccessMessage(successMessages, accountingBasis || ACCOUNTING_BASIS.ACCRUAL) ?? ''\"\r\n [type]=\"'info'\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-temporary-hint>\r\n }\r\n }\r\n\r\n <!-- Business Rule Errors (Temporary display, keeps error styling) -->\r\n @if ((viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL] || []).length > 0) {\r\n <lib-mscoa-error-display\r\n [errors]=\"viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL] || []\"\r\n type=\"error\"\r\n [context]=\"{ accountingBasis: accountingBasis || ACCOUNTING_BASIS.ACCRUAL }\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-error-display>\r\n }\r\n\r\n <!-- Temporary Contextual Hints -->\r\n @if (temporaryHintMessage) {\r\n <lib-mscoa-temporary-hint\r\n [message]=\"temporaryHintMessage\"\r\n [type]=\"temporaryHintType\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-temporary-hint>\r\n }\r\n\r\n <!-- Validation Hints (Context-Aware) -->\r\n @if (!touched() && inputConfig().required && !viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL]?.length && (!isDualAccountBasis || accountingBasis === ACCOUNTING_BASIS.ACCRUAL || !accountingBasis)) {\r\n <div class=\"validation-hints\" role=\"region\" aria-label=\"Validation guidance\">\r\n <p class=\"validation-hints__title\">Guidance:</p>\r\n <ul class=\"validation-hints__list\">\r\n <li>Account combinations are validated automatically. Select accounts that belong to compatible reporting categories.</li>\r\n <li>Required fields are marked with an asterisk (*). Complete all required selections to proceed.</li>\r\n <li>Some fields may be automatically populated based on your selections to ensure consistency.</li>\r\n </ul>\r\n </div>\r\n }\r\n }\r\n </div>\r\n </ng-template>\r\n } @placeholder {\r\n <div class=\"loading-placeholder\" role=\"status\" aria-live=\"polite\">\r\n <p>Loading data...</p>\r\n </div>\r\n } @loading (minimum 100ms) {\r\n <div class=\"loading-spinner-container\" role=\"status\" aria-live=\"polite\">\r\n <mat-progress-spinner mode=\"indeterminate\" [diameter]=\"40\"></mat-progress-spinner>\r\n <span class=\"sr-only\">Loading account chart...</span>\r\n </div>\r\n } @error {\r\n <div class=\"error-state\" role=\"alert\" aria-live=\"assertive\">\r\n <p>Error loading data. Please try again.</p>\r\n </div>\r\n }\r\n }\r\n</section>\r\n}\r\n\r\n<!-- Input Menu -->\r\n<mat-menu #inputMenu=\"matMenu\">\r\n <ng-template matMenuContent let-innerInput=\"innerInput\">\r\n <lib-mscoa-chart-input-menu\r\n [innerInput]=\"innerInput\"\r\n [countdownSeconds]=\"inputWillBeRemovedIn(innerInput.id)\"\r\n [hoveredId]=\"hoveredInputId\"\r\n (edit)=\"onInputMenuEdit($event)\"\r\n (delete)=\"onInputMenuDelete($event)\"\r\n (cancelDelete)=\"onInputMenuCancelDelete($event)\"\r\n (hoverStart)=\"onInputMenuHoverStart($event)\"\r\n (hoverEnd)=\"onInputMenuHoverEnd()\">\r\n </lib-mscoa-chart-input-menu>\r\n </ng-template>\r\n</mat-menu>\r\n", styles: ["@charset \"UTF-8\";:host{--mscoa-chart-spacing-xs: 4px;--mscoa-chart-spacing-sm: 8px;--mscoa-chart-spacing-md: 16px;--mscoa-chart-spacing-lg: 24px;--mscoa-chart-spacing-xl: 32px;--mscoa-chart-border-radius: 4px;--mscoa-chart-transition: var(--lib-forms-duration-hover) var(--lib-forms-easing);--mscoa-chart-font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;--mscoa-chart-font-size-base: 14px;--mscoa-chart-line-height: 1.5;display:block;font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height)}.mscoa-chart__container{padding:0;transition:background-color var(--mscoa-chart-transition);width:100%;max-width:100%;overflow-x:hidden;box-sizing:border-box}.mscoa-chart__loading-container{padding:var(--mscoa-chart-spacing-lg);display:flex;align-items:center;justify-content:center}.mscoa-chart__table-container{position:relative;width:100%;max-width:100%;overflow-x:auto;overflow-y:visible;box-sizing:border-box}.dual-basis-container{display:flex;flex-direction:column;gap:var(--mscoa-chart-spacing-sm)}.dual-basis-container__item{flex:1}:host .single-base{gap:var(--mscoa-chart-spacing-sm);height:48px;font-size:.875em;font-weight:500;transition:background-color var(--mscoa-chart-transition)}:host .single-base--cash{background:var(--mat-sys-inverse-primary)}.account-selection-table-wrapper{position:relative;width:100%}.account-selection-table-container{border-radius:var(--mscoa-chart-border-radius);overflow-x:auto;overflow-y:visible;transition:border-color var(--mscoa-chart-transition);width:100%;max-width:100%;box-sizing:border-box;display:block}.account-selection-table-container--accrual{border:solid 1px var(--mat-sys-primary)}.account-selection-table-container--cash{border:solid 1px var(--mat-sys-inverse-primary)}.account-selection-table-container::-webkit-scrollbar{height:8px}.account-selection-table-container::-webkit-scrollbar-track{background:var(--lib-forms-surface-container-low);border-radius:4px}.account-selection-table-container::-webkit-scrollbar-thumb{background:var(--lib-forms-outline-variant);border-radius:4px}.account-selection-table-container::-webkit-scrollbar-thumb:hover{background:var(--lib-forms-outline)}.table{width:100%;table-layout:fixed;font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height);border-collapse:separate;border-spacing:0;display:table;box-sizing:border-box;max-width:100%}.table__header-cell{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;box-sizing:border-box}.table__header-cell--segment{text-align:right;padding-right:var(--mscoa-chart-spacing-md);min-width:150px;max-width:200px}.table__header-cell--regular{padding-left:var(--mscoa-chart-spacing-lg);min-width:200px;max-width:none}.table__cell{overflow:visible;box-sizing:border-box;position:relative;vertical-align:top}.table__cell--segment{background:var(--mat-list-active-indicator-color, var(--mat-sys-secondary-container));text-align:right;font-weight:500;padding-right:var(--mscoa-chart-spacing-md);min-width:150px;max-width:200px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;vertical-align:middle}.table__cell--regular{padding:0;min-width:200px;max-width:none;word-wrap:break-word;vertical-align:top;overflow:visible}.table__cell--active{background-color:var(--mat-sys-primary-container);transition:background-color var(--mscoa-chart-transition)}mat-header-cell{background:var(--mat-sys-surface-container);font-weight:600;font-size:var(--mscoa-chart-font-size-base);padding:var(--mscoa-chart-spacing-md)}.mscoa-chart-table{display:flex;flex-direction:column}.portal-container{width:100%}.account-cell-wrapper{position:relative;width:100%;max-width:100%;overflow:visible;z-index:1;min-height:38px;display:flex;flex-direction:column;gap:4px}.cell-button-wrapper{position:relative;width:100%;max-width:100%;overflow:hidden}.cell-button{height:fit-content;min-height:38px;width:100%;max-width:100%;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),transform var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing);font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height);position:relative;overflow:visible;padding:8px}.cell-button:hover:not(:disabled){background-color:var(--mat-sys-surface-container);transform:translateY(-1px);box-shadow:0 2px 4px #0000001a}.cell-button:focus-visible{outline:3px solid var(--mat-sys-primary);outline-offset:2px;z-index:1}.cell-button:disabled{opacity:.6;cursor:not-allowed}.cell-button--selected{background-color:transparent}.cell-button--selected:hover:not(:disabled){background-color:var(--lib-forms-surface-container-low);border-color:var(--lib-forms-primary)}.cell-button.cell-button--selected{animation:fadeInSuccess var(--mscoa-chart-transition)}.cell-button.cell-button--business-error{border-color:var(--lib-forms-error)}.cell-button.cell-button--business-error .selected-acount-label--business-error{color:var(--mat-sys-error);border-color:var(--mat-sys-error)}.success-indicator{color:var(--sem-success);font-size:18px;width:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;height:18px;margin-left:var(--mscoa-chart-spacing-xs);animation:scaleIn var(--mscoa-chart-transition);flex-shrink:0}.validated-indicator{color:var(--lib-forms-primary);font-size:18px;width:18px;height:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;margin-left:var(--mscoa-chart-spacing-xs);flex-shrink:0;animation:validatedShieldIn .3s ease-out forwards}.business-error-indicator{color:var(--lib-forms-error);font-size:18px;width:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;height:18px;margin-left:var(--mscoa-chart-spacing-xs);flex-shrink:0}.required-indicator{color:var(--lib-forms-error);font-weight:600;margin-left:2px}.inline-hint{display:block;font-size:12px;color:var(--lib-forms-on-surface-variant);margin-top:var(--mscoa-chart-spacing-xs);padding:var(--mscoa-chart-spacing-xs) var(--mscoa-chart-spacing-sm);background-color:var(--lib-forms-surface-container-low);border-radius:var(--mscoa-chart-border-radius);line-height:1.4;max-width:100%;word-wrap:break-word}.content{padding:0;display:flex;gap:6px;width:100%;max-width:100%;overflow:visible;min-width:0;flex-wrap:wrap;align-items:center}.selected-acount-label{text-align:left;flex:1;font-weight:400;transition:color var(--mscoa-chart-transition)}.selected-acount-label--error,.selected-acount-label--business-error{color:var(--mat-sys-error);font-weight:500}.selected-acount-label--tag{display:inline-block;padding:4px 10px;background-color:var(--lib-forms-primary-container);color:var(--lib-forms-on-primary-container);border-radius:16px;font-size:13px;font-weight:500;line-height:1.5;border:1px solid var(--lib-forms-primary);box-shadow:0 1px 2px #0000001a;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing);width:100%;max-width:100%;overflow:visible;white-space:normal;word-wrap:break-word;word-break:break-word;cursor:pointer;box-sizing:border-box;position:relative}.selected-acount-label--tag:hover{background-color:var(--sem-info-surface);box-shadow:0 2px 4px #1976d226}.segment-cell-content{display:flex;align-items:center;justify-content:flex-end;font-weight:500}.vat-badge{display:inline-flex;align-items:center;justify-content:center;height:16px;padding:2px 6px;border-radius:8px;font-size:9px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;background-color:var(--sem-success-surface);color:var(--sem-warning);border:1px solid var(--lib-forms-outline-variant);box-shadow:none;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),border-color var(--lib-forms-duration-hover) var(--lib-forms-easing);flex-shrink:0;align-self:flex-start;margin-top:2px;line-height:1}.vat-badge:hover{background-color:var(--sem-warning-surface);border-color:var(--sem-warning)}.vat-chip-container{padding-left:var(--mscoa-chart-spacing-sm);padding-right:var(--mscoa-chart-spacing-sm);padding-bottom:var(--mscoa-chart-spacing-xs);margin-top:var(--mscoa-chart-spacing-xs)}.vat-chip{display:inline-flex;align-items:center;gap:4px;height:24px;padding:4px 8px;border-radius:12px;font-size:11px;font-weight:600;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing),transform var(--lib-forms-duration-hover) var(--lib-forms-easing);box-shadow:0 1px 3px #0000001f}.vat-chip--applicable{background:linear-gradient(135deg,var(--sem-warning) 0%,var(--sem-warning) 100%);color:var(--lib-forms-on-primary);border:1px solid var(--sem-warning)}.vat-chip--applicable:hover{box-shadow:0 2px 6px #f57c004d;transform:translateY(-1px)}.vat-chip__icon{font-size:14px;width:14px;height:14px;opacity:.9}.vat-chip__text{font-size:11px;font-weight:600;letter-spacing:.3px}.info-box{display:flex;align-items:center;gap:var(--mscoa-chart-spacing-sm);padding:12px;background:var(--sem-info-surface);border-radius:var(--mscoa-chart-border-radius);margin-bottom:var(--mscoa-chart-spacing-md)}.info-icon{min-width:38px;margin:auto;margin-top:var(--mscoa-chart-spacing-sm)}.empty-state{padding:var(--mscoa-chart-spacing-md);text-align:center;display:flex;align-items:center;justify-content:center;gap:var(--mscoa-chart-spacing-sm);color:var(--mat-sys-on-surface-variant)}.validation-hints{margin-top:var(--mscoa-chart-spacing-md);padding:var(--mscoa-chart-spacing-md);background-color:var(--lib-forms-surface-container-low);border-radius:var(--mscoa-chart-border-radius);border-left:4px solid var(--lib-forms-primary);box-shadow:0 1px 3px #00000014}.validation-hints__title{font-weight:600;font-size:var(--mscoa-chart-font-size-base);margin:0 0 var(--mscoa-chart-spacing-sm) 0;color:var(--lib-forms-on-surface);display:flex;align-items:center;gap:var(--mscoa-chart-spacing-xs)}.validation-hints__title:before{content:\"\\1f4a1\";font-size:16px}.validation-hints__list{margin:0;padding-left:var(--mscoa-chart-spacing-md);color:var(--lib-forms-on-surface-variant);font-size:13px;line-height:1.6}.validation-hints__list li{margin-bottom:var(--mscoa-chart-spacing-sm);position:relative}.validation-hints__list li::marker{color:var(--lib-forms-primary)}.validation-hints__list li:last-child{margin-bottom:0}mat-error{font-size:.75em;margin-top:var(--mscoa-chart-spacing-xs)}mat-error ul{margin:0;padding-left:var(--mscoa-chart-spacing-md)}mat-error li{margin-bottom:var(--mscoa-chart-spacing-xs)}.loading-placeholder{padding:var(--mscoa-chart-spacing-md);color:var(--mat-sys-on-surface-variant)}.loading-spinner-container{display:flex;justify-content:center;align-items:center;height:256px}.error-state{padding:var(--mscoa-chart-spacing-md);color:var(--mat-sys-error)}mat-panel-description{font-size:.875em;line-height:1.4}:host .main-expanse-content{background:var(--mat-sys-surface-container)}@media(max-width:768px){.dual-basis-container{gap:var(--mscoa-chart-spacing-md)}.cell-button{min-height:44px;font-size:15px;max-width:300px}.content{padding:var(--mscoa-chart-spacing-md)}.validation-hints{font-size:13px;padding:var(--mscoa-chart-spacing-sm)}.inline-hint{font-size:11px}}.cell-button:focus-visible,button:focus-visible{outline:3px solid var(--mat-sys-primary);outline-offset:2px;outline-style:solid}@media(prefers-contrast:high){.cell-button{border:2px solid currentColor}.cell-button:focus-visible{outline-width:4px}.selected-acount-label--error{font-weight:600}}@media(prefers-reduced-motion:reduce){.cell-button,.success-indicator,.fade-in,.validated-indicator{animation:none;transition:none}}.table__cell--active{background-color:var(--mat-sys-primary-container);color:var(--mat-sys-on-primary-container)}@media(prefers-contrast:high){.table__cell--active{background-color:var(--mat-sys-primary);color:var(--mat-sys-on-primary)}}.table__cell--business-error{background-color:var(--lib-forms-error-container);border-left:3px solid var(--lib-forms-error)}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeInSuccess{0%{background-color:transparent}50%{background-color:var(--sem-success-surface)}to{background-color:var(--mat-sys-primary-container)}}@keyframes scaleIn{0%{transform:scale(0);opacity:0}to{transform:scale(1);opacity:1}}@keyframes validatedShieldIn{0%{opacity:0;transform:scale(.6)}70%{opacity:1;transform:scale(1.1)}to{opacity:1;transform:scale(1)}}.fade-in{animation:fadeIn var(--mscoa-chart-transition)}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.skeleton-loader{background:linear-gradient(90deg,var(--mat-sys-surface-container) 25%,var(--mat-sys-surface-container-high) 50%,var(--mat-sys-surface-container) 75%);background-size:200% 100%;animation:loading 1.5s ease-in-out infinite;border-radius:var(--mscoa-chart-border-radius)}@keyframes loading{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-row{height:48px;margin-bottom:var(--mscoa-chart-spacing-xs)}.skeleton-cell{height:100%;margin-right:var(--mscoa-chart-spacing-md)}\n"] }]
|
|
17039
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if ((viewData$ | async); as viewData) {\r\n<section\r\n (click)=\"setAsTouched($event)\"\r\n class=\"mscoa-chart__container\"\r\n [class.mscoa-chart__container--touched]=\"touched()\"\r\n role=\"region\"\r\n [attr.aria-label]=\"'MSCOA Account Chart'\"\r\n [attr.aria-busy]=\"viewData.loading || viewData.validatingValue\">\r\n\r\n @if (viewData.loading) {\r\n <div class=\"mscoa-chart__loading-container\" role=\"status\" aria-live=\"polite\">\r\n <mat-spinner [diameter]=\"40\"></mat-spinner>\r\n <span class=\"sr-only\">Loading account chart data...</span>\r\n </div>\r\n } @else {\r\n @defer () {\r\n @if (viewData.accountTreeKeys || viewData.cashAccountTreeKeys) {\r\n <div class=\"mscoa-chart__table-container\">\r\n @if (isDualAccountBasis) {\r\n <div class=\"dual-basis-container\" role=\"group\" aria-label=\"Dual accounting basis tables\">\r\n <div class=\"dual-basis-container__item\">\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: ACCOUNTING_BASIS.ACCRUAL,\r\n canCollapse: true,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n </div>\r\n\r\n <div class=\"dual-basis-container__item\">\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: ACCOUNTING_BASIS.CASH,\r\n canCollapse: true,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n </div>\r\n </div>\r\n } @else {\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: config()?.accountingBasis,\r\n canCollapse: false,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n }\r\n </div>\r\n }\r\n\r\n <ng-template\r\n #selectionTable\r\n let-accountingBasis=\"accountingBasis\"\r\n let-canCollapse=\"canCollapse\"\r\n let-viewData=\"viewData\">\r\n\r\n <div class=\"mscoa-chart-table\" role=\"group\" [attr.aria-label]=\"'Accounting basis: ' + (accountingBasis || 'Accrual')\">\r\n <!-- Toolbar -->\r\n <lib-mscoa-chart-toolbar\r\n [accountingBasis]=\"accountingBasis\"\r\n [canCollapse]=\"canCollapse\"\r\n [isExpanded]=\"getExpansionState(accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\"\r\n (toggleExpansion)=\"toggleDualBasisExpansion(accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\">\r\n </lib-mscoa-chart-toolbar>\r\n\r\n @if (shouldShowTable(isDualAccountBasis, getExpansionState(accountingBasis || ACCOUNTING_BASIS.ACCRUAL), accountingBasis)) {\r\n <div class=\"account-selection-table-wrapper\">\r\n <div\r\n class=\"account-selection-table-container\"\r\n [class.account-selection-table-container--accrual]=\"!accountingBasis || accountingBasis === ACCOUNTING_BASIS.ACCRUAL\"\r\n [class.account-selection-table-container--cash]=\"accountingBasis === ACCOUNTING_BASIS.CASH\"\r\n role=\"table\"\r\n [attr.aria-label]=\"'Account selection table for ' + (accountingBasis || 'Accrual') + ' basis'\">\r\n\r\n <table\r\n mat-table\r\n [dataSource]=\"accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashTableData : viewData.tableData\"\r\n [trackBy]=\"trackByRow\"\r\n class=\"table\"\r\n [attr.aria-label]=\"'Account selection table for ' + (accountingBasis || 'Accrual') + ' basis'\"\r\n [attr.aria-describedby]=\"'table-description-' + (accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\"\r\n role=\"table\">\r\n <span [id]=\"'table-description-' + (accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\" class=\"sr-only\">\r\n Use arrow keys to navigate between cells. Press Enter or Space to select an account.\r\n </span>\r\n\r\n @for (\r\n col of (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols);\r\n track trackByColumn($index, col);\r\n let i = $index\r\n ) {\r\n <ng-container [matColumnDef]=\"col\" [sticky]=\"i === 0\">\r\n <!-- Header Cell -->\r\n <th\r\n mat-header-cell\r\n *matHeaderCellDef\r\n [class.table__header-cell--segment]=\"isSegmentColumn(i)\"\r\n [class.table__header-cell--regular]=\"!isSegmentColumn(i)\"\r\n [style.width.%]=\"getColumnWidthPercent(isSegmentColumn(i), (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols).length)\"\r\n [style.min-width.px]=\"isSegmentColumn(i) ? 150 : 200\"\r\n [attr.aria-sort]=\"i === 0 ? 'none' : null\"\r\n [attr.scope]=\"'col'\"\r\n [attr.aria-label]=\"getHeaderText(col, i, accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashHasMultiSelect : viewData.hasMultiSelect) + ' column'\">\r\n {{ getHeaderText(col, i, accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashHasMultiSelect : viewData.hasMultiSelect) | titlecase | unCamelCase }}\r\n </th>\r\n\r\n <!-- Data Cell -->\r\n <td\r\n mat-cell\r\n *matCellDef=\"let row\"\r\n [class.table__cell--segment]=\"isSegmentColumn(i)\"\r\n [class.table__cell--regular]=\"!isSegmentColumn(i)\"\r\n [class.table__cell--active]=\"editSelection?.segment === row['segment'] && activeColumn === col\"\r\n [class.table__cell--business-error]=\"!isSegmentColumn(i) && getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-label]=\"'Cell for ' + row['segment'] + ' segment, ' + col + ' column'\"\r\n [attr.aria-selected]=\"!!row[col]\"\r\n [attr.aria-invalid]=\"!isSegmentColumn(i) && !!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.role]=\"'gridcell'\"\r\n [attr.tabindex]=\"isSegmentColumn(i) ? -1 : (row[col] ? 0 : -1)\">\r\n\r\n @if (isSegmentColumn(i)) {\r\n <!-- Segment Column -->\r\n <div class=\"segment-cell-content\">\r\n @if (editorMode() && row.innerInput?.id) {\r\n <button\r\n mat-icon-button\r\n [matMenuTriggerData]=\"{innerInput: row.innerInput}\"\r\n [matMenuTriggerFor]=\"inputMenu\"\r\n [matTooltip]=\"'Options for: ' + row.innerInput.label\"\r\n [attr.aria-label]=\"'Options menu for ' + row.innerInput.label\"\r\n (click)=\"$event.stopPropagation()\">\r\n <mat-icon>more_vert</mat-icon>\r\n </button>\r\n }\r\n <span class=\"segment-cell-content__label\">{{ row['label'] }}</span>\r\n </div>\r\n } @else {\r\n <!-- Regular Column -->\r\n @if (row.innerInput?.id) {\r\n <!-- Custom-input row (peer of the segments): the value is entered inline via the\r\n input portal on the primary (debit) leg; other legs mirror it and render no\r\n control. `innerInput.id` is already the namespaced portal key, so it is looked\r\n up directly \u2014 prepending it again (getPortalKey) double-namespaces and misses. -->\r\n @if (col === COLUMNS.DEBIT && formGroup() && inputPortals[row.innerInput.id]) {\r\n <div class=\"portal-container\">\r\n <ng-template [cdkPortalOutlet]=\"inputPortals[row.innerInput.id]\"></ng-template>\r\n </div>\r\n }\r\n } @else {\r\n @if (row[col]) {\r\n <!-- Account Selected -->\r\n @if (getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment']); as cellError) {\r\n <div class=\"account-cell-wrapper\"\r\n [class.account-cell-wrapper--expandable]=\"isTextTruncated(row[col] | unCamelCase)\">\r\n <button\r\n [disabled]=\"row['singleSelect'] === true && col === COLUMNS.CREDIT\"\r\n (mousedown)=\"$event.preventDefault(); $event.stopPropagation(); selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n color=\"primary\"\r\n mat-button\r\n class=\"cell-button cell-button--selected cell-button--business-error\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase) + ' for ' + row['segment'] + ' segment, ' + col + ' column. Business error: ' + cellError.message\"\r\n [attr.aria-invalid]=\"true\"\r\n [attr.aria-pressed]=\"true\"\r\n [matTooltip]=\"cellError.message\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label selected-acount-label--tag selected-acount-label--business-error\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase)\">\r\n {{ row[col] | unCamelCase }}\r\n @if (shouldShowVatChip(row, col)) {\r\n <span\r\n class=\"vat-badge\"\r\n [attr.aria-label]=\"'VAT applicable to ' + col + ' column'\"\r\n [matTooltip]=\"'VAT is applicable to this ' + col + ' account selection'\">\r\n VAT\r\n </span>\r\n }\r\n </span>\r\n <mat-icon class=\"business-error-indicator\" aria-hidden=\"true\">error</mat-icon>\r\n </div>\r\n </button>\r\n </div>\r\n } @else {\r\n <div class=\"account-cell-wrapper\"\r\n [class.account-cell-wrapper--expandable]=\"isTextTruncated(row[col] | unCamelCase)\">\r\n <button\r\n [disabled]=\"(row['singleSelect'] === true && col === COLUMNS.CREDIT) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n (mousedown)=\"$event.preventDefault(); $event.stopPropagation(); selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n color=\"primary\"\r\n mat-button\r\n class=\"cell-button cell-button--selected\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase) + ' for ' + row['segment'] + ' segment, ' + col + ' column. Press Enter or Space to change'\"\r\n [attr.aria-invalid]=\"false\"\r\n [attr.aria-disabled]=\"(row['singleSelect'] === true && col === COLUMNS.CREDIT) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-pressed]=\"true\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label selected-acount-label--tag\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase)\">\r\n {{ row[col] | unCamelCase }}\r\n @if (shouldShowVatChip(row, col)) {\r\n <span\r\n class=\"vat-badge\"\r\n [attr.aria-label]=\"'VAT applicable to ' + col + ' column'\"\r\n [matTooltip]=\"'VAT is applicable to this ' + col + ' account selection'\">\r\n VAT\r\n </span>\r\n }\r\n </span>\r\n @if (showValidationSuccessIndicators) {\r\n <mat-icon class=\"validated-indicator\" aria-hidden=\"true\" [matTooltip]=\"'Validated'\">shield</mat-icon>\r\n } @else {\r\n <mat-icon class=\"success-indicator\" aria-hidden=\"true\">check_circle</mat-icon>\r\n }\r\n </div>\r\n </button>\r\n </div>\r\n }\r\n } @else {\r\n <!-- No Account Selected -->\r\n <div class=\"cell-button-wrapper\">\r\n <button\r\n [disabled]=\"selectionDisabled(row, col) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [color]=\"\"\r\n (click)=\"selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); $event.stopPropagation(); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n mat-button\r\n class=\"cell-button\"\r\n [class.cell-button--business-error]=\"!!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-label]=\"shouldShowAutoSelectedLabel(row, col) ? 'Auto selected for ' + row['segment'] + ' segment, ' + col + ' column' : 'Select account for ' + row['segment'] + ' segment, ' + col + ' column'\"\r\n [attr.aria-disabled]=\"selectionDisabled(row, col) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-describedby]=\"getValidationHint(row, col, accountingBasis || ACCOUNTING_BASIS.ACCRUAL) ? 'hint-' + row['segment'] + '-' + col : null\"\r\n [attr.aria-invalid]=\"hasError(touched(), inputConfig().required || false, !!row[col]) || !!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-required]=\"inputConfig().required && !row[col]\"\r\n [matTooltip]=\"getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])?.message\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label\"\r\n [class.selected-acount-label--error]=\"hasError(touched(), inputConfig().required || false, !!row[col])\"\r\n [class.selected-acount-label--business-error]=\"!!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\">\r\n {{ (shouldShowAutoSelectedLabel(row, col) ? 'auto selected' : 'Select account') | unCamelCase }}\r\n @if (inputConfig().required && !row[col]) {\r\n <span class=\"required-indicator\" aria-label=\"Required field\">*</span>\r\n }\r\n </span>\r\n @if (getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])) {\r\n <mat-icon class=\"business-error-indicator\" aria-hidden=\"true\">error</mat-icon>\r\n } @else if (shouldShowDropdownIcon(row, col)) {\r\n <mat-icon aria-hidden=\"true\">arrow_drop_down</mat-icon>\r\n }\r\n </div>\r\n </button>\r\n @if (getValidationHint(row, col, accountingBasis || ACCOUNTING_BASIS.ACCRUAL); as hint) {\r\n <span\r\n class=\"inline-hint\"\r\n [id]=\"'hint-' + row['segment'] + '-' + col\"\r\n role=\"tooltip\"\r\n aria-live=\"polite\">\r\n {{ hint }}\r\n </span>\r\n }\r\n </div>\r\n }\r\n }\r\n }\r\n </td>\r\n </ng-container>\r\n }\r\n\r\n <tr mat-header-row *matHeaderRowDef=\"accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols\"></tr>\r\n <tr mat-row *matRowDef=\"let row; columns: (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols)\"></tr>\r\n </table>\r\n </div>\r\n </div>\r\n\r\n <!-- Empty State -->\r\n @if ((accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashAccountTreeKeys : viewData.accountTreeKeys).length === 0) {\r\n <section class=\"empty-state\" role=\"status\" aria-live=\"polite\">\r\n <mat-icon aria-hidden=\"true\">info</mat-icon>\r\n <span>\r\n No account segments are currently configured.\r\n Please configure account segments to proceed.\r\n </span>\r\n </section>\r\n }\r\n\r\n <!-- Success Messages (Temporary) -->\r\n @if ((successMessage$ | async); as successMessages) {\r\n @if (getSuccessMessage(successMessages, accountingBasis || ACCOUNTING_BASIS.ACCRUAL); as msg) {\r\n <lib-mscoa-temporary-hint\r\n [message]=\"getSuccessMessage(successMessages, accountingBasis || ACCOUNTING_BASIS.ACCRUAL) ?? ''\"\r\n [type]=\"'info'\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-temporary-hint>\r\n }\r\n }\r\n\r\n <!-- Business Rule Errors (Temporary display, keeps error styling) -->\r\n @if ((viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL] || []).length > 0) {\r\n <lib-mscoa-error-display\r\n [errors]=\"viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL] || []\"\r\n type=\"error\"\r\n [context]=\"{ accountingBasis: accountingBasis || ACCOUNTING_BASIS.ACCRUAL }\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-error-display>\r\n }\r\n\r\n <!-- Temporary Contextual Hints -->\r\n @if (temporaryHintMessage) {\r\n <lib-mscoa-temporary-hint\r\n [message]=\"temporaryHintMessage\"\r\n [type]=\"temporaryHintType\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-temporary-hint>\r\n }\r\n\r\n <!-- Validation Hints (Context-Aware) -->\r\n @if (!touched() && inputConfig().required && !viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL]?.length && (!isDualAccountBasis || accountingBasis === ACCOUNTING_BASIS.ACCRUAL || !accountingBasis)) {\r\n <div class=\"validation-hints\" role=\"region\" aria-label=\"Validation guidance\">\r\n <p class=\"validation-hints__title\">Guidance:</p>\r\n <ul class=\"validation-hints__list\">\r\n <li>Account combinations are validated automatically. Select accounts that belong to compatible reporting categories.</li>\r\n <li>Required fields are marked with an asterisk (*). Complete all required selections to proceed.</li>\r\n <li>Some fields may be automatically populated based on your selections to ensure consistency.</li>\r\n </ul>\r\n </div>\r\n }\r\n }\r\n </div>\r\n </ng-template>\r\n } @placeholder {\r\n <div class=\"loading-placeholder\" role=\"status\" aria-live=\"polite\">\r\n <p>Loading data...</p>\r\n </div>\r\n } @loading (minimum 100ms) {\r\n <div class=\"loading-spinner-container\" role=\"status\" aria-live=\"polite\">\r\n <mat-progress-spinner mode=\"indeterminate\" [diameter]=\"40\"></mat-progress-spinner>\r\n <span class=\"sr-only\">Loading account chart...</span>\r\n </div>\r\n } @error {\r\n <div class=\"error-state\" role=\"alert\" aria-live=\"assertive\">\r\n <p>Error loading data. Please try again.</p>\r\n </div>\r\n }\r\n }\r\n</section>\r\n}\r\n\r\n<!-- Input Menu -->\r\n<mat-menu #inputMenu=\"matMenu\">\r\n <ng-template matMenuContent let-innerInput=\"innerInput\">\r\n <lib-mscoa-chart-input-menu\r\n [innerInput]=\"innerInput\"\r\n [countdownSeconds]=\"inputWillBeRemovedIn(innerInput.id)\"\r\n [hoveredId]=\"hoveredInputId\"\r\n (edit)=\"onInputMenuEdit($event)\"\r\n (delete)=\"onInputMenuDelete($event)\"\r\n (cancelDelete)=\"onInputMenuCancelDelete($event)\"\r\n (hoverStart)=\"onInputMenuHoverStart($event)\"\r\n (hoverEnd)=\"onInputMenuHoverEnd()\">\r\n </lib-mscoa-chart-input-menu>\r\n </ng-template>\r\n</mat-menu>\r\n", styles: ["@charset \"UTF-8\";:host{--mscoa-chart-spacing-xs: 4px;--mscoa-chart-spacing-sm: 8px;--mscoa-chart-spacing-md: 16px;--mscoa-chart-spacing-lg: 24px;--mscoa-chart-spacing-xl: 32px;--mscoa-chart-border-radius: 4px;--mscoa-chart-transition: var(--lib-forms-duration-hover) var(--lib-forms-easing);--mscoa-chart-font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;--mscoa-chart-font-size-base: 14px;--mscoa-chart-line-height: 1.5;display:block;font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height)}.mscoa-chart__container{padding:0;transition:background-color var(--mscoa-chart-transition);width:100%;max-width:100%;overflow-x:hidden;box-sizing:border-box}.mscoa-chart__loading-container{padding:var(--mscoa-chart-spacing-lg);display:flex;align-items:center;justify-content:center}.mscoa-chart__table-container{position:relative;width:100%;max-width:100%;overflow-x:auto;overflow-y:visible;box-sizing:border-box}.dual-basis-container{display:flex;flex-direction:column;gap:var(--mscoa-chart-spacing-sm)}.dual-basis-container__item{flex:1}:host .single-base{gap:var(--mscoa-chart-spacing-sm);height:48px;font-size:.875em;font-weight:500;transition:background-color var(--mscoa-chart-transition)}:host .single-base--cash{background:var(--mat-sys-inverse-primary)}.account-selection-table-wrapper{position:relative;width:100%}.account-selection-table-container{border-radius:var(--mscoa-chart-border-radius);overflow-x:auto;overflow-y:visible;transition:border-color var(--mscoa-chart-transition);width:100%;max-width:100%;box-sizing:border-box;display:block}.account-selection-table-container--accrual{border:solid 1px var(--mat-sys-primary)}.account-selection-table-container--cash{border:solid 1px var(--mat-sys-inverse-primary)}.account-selection-table-container::-webkit-scrollbar{height:8px}.account-selection-table-container::-webkit-scrollbar-track{background:var(--lib-forms-surface-container-low);border-radius:4px}.account-selection-table-container::-webkit-scrollbar-thumb{background:var(--lib-forms-outline-variant);border-radius:4px}.account-selection-table-container::-webkit-scrollbar-thumb:hover{background:var(--lib-forms-outline)}.table{width:100%;table-layout:fixed;font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height);border-collapse:separate;border-spacing:0;display:table;box-sizing:border-box;max-width:100%}.table__header-cell{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;box-sizing:border-box}.table__header-cell--segment{text-align:right;padding-right:var(--mscoa-chart-spacing-md);min-width:150px;max-width:200px}.table__header-cell--regular{padding-left:var(--mscoa-chart-spacing-lg);min-width:200px;max-width:none}.table__cell{overflow:visible;box-sizing:border-box;position:relative;vertical-align:top}.table__cell--segment{background:var(--mat-list-active-indicator-color, var(--mat-sys-secondary-container));text-align:right;font-weight:500;padding-right:var(--mscoa-chart-spacing-md);min-width:150px;max-width:200px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;vertical-align:middle}.table__cell--regular{padding:0;min-width:200px;max-width:none;word-wrap:break-word;vertical-align:top;overflow:visible}.table__cell--active{background-color:var(--mat-sys-primary-container);transition:background-color var(--mscoa-chart-transition)}mat-header-cell{background:var(--mat-sys-surface-container);font-weight:600;font-size:var(--mscoa-chart-font-size-base);padding:var(--mscoa-chart-spacing-md)}.mscoa-chart-table{display:flex;flex-direction:column}.portal-container{width:100%}.account-cell-wrapper{position:relative;width:100%;max-width:100%;overflow:visible;z-index:1;min-height:38px;display:flex;flex-direction:column;gap:4px}.cell-button-wrapper{position:relative;width:100%;max-width:100%;overflow:hidden}.cell-button{height:fit-content;min-height:38px;width:100%;max-width:100%;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),transform var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing);font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height);position:relative;overflow:visible;padding:8px}.cell-button:hover:not(:disabled){background-color:var(--mat-sys-surface-container);transform:translateY(-1px);box-shadow:0 2px 4px #0000001a}.cell-button:focus-visible{outline:3px solid var(--mat-sys-primary);outline-offset:2px;z-index:1}.cell-button:disabled{opacity:.6;cursor:not-allowed}.cell-button--selected{background-color:transparent}.cell-button--selected:hover:not(:disabled){background-color:var(--lib-forms-surface-container-low);border-color:var(--lib-forms-primary)}.cell-button.cell-button--selected{animation:fadeInSuccess var(--mscoa-chart-transition)}.cell-button.cell-button--business-error{border-color:var(--lib-forms-error)}.cell-button.cell-button--business-error .selected-acount-label--business-error{color:var(--mat-sys-error);border-color:var(--mat-sys-error)}.success-indicator{color:var(--sem-success);font-size:18px;width:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;height:18px;margin-left:var(--mscoa-chart-spacing-xs);animation:scaleIn var(--mscoa-chart-transition);flex-shrink:0}.validated-indicator{color:var(--lib-forms-primary);font-size:18px;width:18px;height:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;margin-left:var(--mscoa-chart-spacing-xs);flex-shrink:0;animation:validatedShieldIn .3s ease-out forwards}.business-error-indicator{color:var(--lib-forms-error);font-size:18px;width:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;height:18px;margin-left:var(--mscoa-chart-spacing-xs);flex-shrink:0}.required-indicator{color:var(--lib-forms-error);font-weight:600;margin-left:2px}.inline-hint{display:block;font-size:12px;color:var(--lib-forms-on-surface-variant);margin-top:var(--mscoa-chart-spacing-xs);padding:var(--mscoa-chart-spacing-xs) var(--mscoa-chart-spacing-sm);background-color:var(--lib-forms-surface-container-low);border-radius:var(--mscoa-chart-border-radius);line-height:1.4;max-width:100%;word-wrap:break-word}.content{padding:0;display:flex;gap:6px;width:100%;max-width:100%;overflow:visible;min-width:0;flex-wrap:wrap;align-items:center}.selected-acount-label{text-align:left;flex:1;font-weight:400;transition:color var(--mscoa-chart-transition)}.selected-acount-label--error,.selected-acount-label--business-error{color:var(--mat-sys-error);font-weight:500}.selected-acount-label--tag{display:inline-block;padding:4px 10px;background-color:var(--lib-forms-primary-container);color:var(--lib-forms-on-primary-container);border-radius:16px;font-size:13px;font-weight:500;line-height:1.5;border:1px solid var(--lib-forms-primary);box-shadow:0 1px 2px #0000001a;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing);width:100%;max-width:100%;overflow:visible;white-space:normal;word-wrap:break-word;word-break:break-word;cursor:pointer;box-sizing:border-box;position:relative}.selected-acount-label--tag:hover{background-color:var(--sem-info-surface);box-shadow:0 2px 4px #1976d226}.segment-cell-content{display:flex;align-items:center;justify-content:flex-end;font-weight:500}.vat-badge{display:inline-flex;align-items:center;justify-content:center;height:16px;padding:2px 6px;border-radius:8px;font-size:9px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;background-color:var(--sem-success-surface);color:var(--sem-warning);border:1px solid var(--lib-forms-outline-variant);box-shadow:none;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),border-color var(--lib-forms-duration-hover) var(--lib-forms-easing);flex-shrink:0;align-self:flex-start;margin-top:2px;line-height:1}.vat-badge:hover{background-color:var(--sem-warning-surface);border-color:var(--sem-warning)}.vat-chip-container{padding-left:var(--mscoa-chart-spacing-sm);padding-right:var(--mscoa-chart-spacing-sm);padding-bottom:var(--mscoa-chart-spacing-xs);margin-top:var(--mscoa-chart-spacing-xs)}.vat-chip{display:inline-flex;align-items:center;gap:4px;height:24px;padding:4px 8px;border-radius:12px;font-size:11px;font-weight:600;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing),transform var(--lib-forms-duration-hover) var(--lib-forms-easing);box-shadow:0 1px 3px #0000001f}.vat-chip--applicable{background:linear-gradient(135deg,var(--sem-warning) 0%,var(--sem-warning) 100%);color:var(--lib-forms-on-primary);border:1px solid var(--sem-warning)}.vat-chip--applicable:hover{box-shadow:0 2px 6px #f57c004d;transform:translateY(-1px)}.vat-chip__icon{font-size:14px;width:14px;height:14px;opacity:.9}.vat-chip__text{font-size:11px;font-weight:600;letter-spacing:.3px}.info-box{display:flex;align-items:center;gap:var(--mscoa-chart-spacing-sm);padding:12px;background:var(--sem-info-surface);border-radius:var(--mscoa-chart-border-radius);margin-bottom:var(--mscoa-chart-spacing-md)}.info-icon{min-width:38px;margin:auto;margin-top:var(--mscoa-chart-spacing-sm)}.empty-state{padding:var(--mscoa-chart-spacing-md);text-align:center;display:flex;align-items:center;justify-content:center;gap:var(--mscoa-chart-spacing-sm);color:var(--mat-sys-on-surface-variant)}.validation-hints{margin-top:var(--mscoa-chart-spacing-md);padding:var(--mscoa-chart-spacing-md);background-color:var(--lib-forms-surface-container-low);border-radius:var(--mscoa-chart-border-radius);border-left:4px solid var(--lib-forms-primary);box-shadow:0 1px 3px #00000014}.validation-hints__title{font-weight:600;font-size:var(--mscoa-chart-font-size-base);margin:0 0 var(--mscoa-chart-spacing-sm) 0;color:var(--lib-forms-on-surface);display:flex;align-items:center;gap:var(--mscoa-chart-spacing-xs)}.validation-hints__title:before{content:\"\\1f4a1\";font-size:16px}.validation-hints__list{margin:0;padding-left:var(--mscoa-chart-spacing-md);color:var(--lib-forms-on-surface-variant);font-size:13px;line-height:1.6}.validation-hints__list li{margin-bottom:var(--mscoa-chart-spacing-sm);position:relative}.validation-hints__list li::marker{color:var(--lib-forms-primary)}.validation-hints__list li:last-child{margin-bottom:0}mat-error{font-size:.75em;margin-top:var(--mscoa-chart-spacing-xs)}mat-error ul{margin:0;padding-left:var(--mscoa-chart-spacing-md)}mat-error li{margin-bottom:var(--mscoa-chart-spacing-xs)}.loading-placeholder{padding:var(--mscoa-chart-spacing-md);color:var(--mat-sys-on-surface-variant)}.loading-spinner-container{display:flex;justify-content:center;align-items:center;height:256px}.error-state{padding:var(--mscoa-chart-spacing-md);color:var(--mat-sys-error)}mat-panel-description{font-size:.875em;line-height:1.4}:host .main-expanse-content{background:var(--mat-sys-surface-container)}@media(max-width:768px){.dual-basis-container{gap:var(--mscoa-chart-spacing-md)}.cell-button{min-height:44px;font-size:15px;max-width:300px}.content{padding:var(--mscoa-chart-spacing-md)}.validation-hints{font-size:13px;padding:var(--mscoa-chart-spacing-sm)}.inline-hint{font-size:11px}}.cell-button:focus-visible,button:focus-visible{outline:3px solid var(--mat-sys-primary);outline-offset:2px;outline-style:solid}@media(prefers-contrast:high){.cell-button{border:2px solid currentColor}.cell-button:focus-visible{outline-width:4px}.selected-acount-label--error{font-weight:600}}@media(prefers-reduced-motion:reduce){.cell-button,.success-indicator,.fade-in,.validated-indicator{animation:none;transition:none}}.table__cell--active{background-color:var(--mat-sys-primary-container);color:var(--mat-sys-on-primary-container)}@media(prefers-contrast:high){.table__cell--active{background-color:var(--mat-sys-primary);color:var(--mat-sys-on-primary)}}.table__cell--business-error{background-color:var(--lib-forms-error-container);border-left:3px solid var(--lib-forms-error)}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeInSuccess{0%{background-color:transparent}50%{background-color:var(--sem-success-surface)}to{background-color:var(--mat-sys-primary-container)}}@keyframes scaleIn{0%{transform:scale(0);opacity:0}to{transform:scale(1);opacity:1}}@keyframes validatedShieldIn{0%{opacity:0;transform:scale(.6)}70%{opacity:1;transform:scale(1.1)}to{opacity:1;transform:scale(1)}}.fade-in{animation:fadeIn var(--mscoa-chart-transition)}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.skeleton-loader{background:linear-gradient(90deg,var(--mat-sys-surface-container) 25%,var(--mat-sys-surface-container-high) 50%,var(--mat-sys-surface-container) 75%);background-size:200% 100%;animation:loading 1.5s ease-in-out infinite;border-radius:var(--mscoa-chart-border-radius)}@keyframes loading{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-row{height:48px;margin-bottom:var(--mscoa-chart-spacing-xs)}.skeleton-cell{height:100%;margin-right:var(--mscoa-chart-spacing-md)}\n"] }]
|
|
16507
17040
|
}], ctorParameters: () => [], propDecorators: { inputConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputConfig", required: true }] }], editorMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "editorMode", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], formGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "formGroup", required: false }] }], formBuilderFunctions: [{ type: i0.Input, args: [{ isSignal: true, alias: "formBuilderFunctions", required: false }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], onContainerClick: [{ type: i0.Output, args: ["onContainerClick"] }], interaction: [{ type: i0.Output, args: ["interaction"] }] } }) });
|
|
16508
17041
|
|
|
16509
17042
|
/**
|
|
@@ -17799,9 +18332,9 @@ function builderKind(fn) {
|
|
|
17799
18332
|
}
|
|
17800
18333
|
}
|
|
17801
18334
|
// --- helpers ----------------------------------------------------------------
|
|
17802
|
-
const KEYWORD_OPS = ['includes', 'startsWith', 'endsWith', 'matches', 'in'];
|
|
17803
|
-
const SYMBOLIC_OPS = ['===', '!==', '==', '!=', '>=', '<=', '>', '<'];
|
|
17804
|
-
const unquote = (v) => {
|
|
18335
|
+
const KEYWORD_OPS$1 = ['includes', 'startsWith', 'endsWith', 'matches', 'in'];
|
|
18336
|
+
const SYMBOLIC_OPS$1 = ['===', '!==', '==', '!=', '>=', '<=', '>', '<'];
|
|
18337
|
+
const unquote$1 = (v) => {
|
|
17805
18338
|
const t = v.trim();
|
|
17806
18339
|
if (t.length >= 2) {
|
|
17807
18340
|
const a = t[0];
|
|
@@ -17811,28 +18344,28 @@ const unquote = (v) => {
|
|
|
17811
18344
|
}
|
|
17812
18345
|
return t;
|
|
17813
18346
|
};
|
|
17814
|
-
const isBareLiteral = (v) => v === 'true' || v === 'false' || v === 'null' || (v.trim() !== '' && !Number.isNaN(Number(v)));
|
|
18347
|
+
const isBareLiteral$1 = (v) => v === 'true' || v === 'false' || v === 'null' || (v.trim() !== '' && !Number.isNaN(Number(v)));
|
|
17815
18348
|
/** Formats a builder value for the expression string (bare for numbers/bools, else quoted). */
|
|
17816
|
-
const formatValue = (v) => (isBareLiteral(v.trim()) ? v.trim() : `"${v}"`);
|
|
18349
|
+
const formatValue = (v) => (isBareLiteral$1(v.trim()) ? v.trim() : `"${v}"`);
|
|
17817
18350
|
const toNum = (v, fallback = 0) => {
|
|
17818
18351
|
const n = Number(v);
|
|
17819
18352
|
return Number.isNaN(n) ? fallback : n;
|
|
17820
18353
|
};
|
|
17821
18354
|
// --- parse ------------------------------------------------------------------
|
|
17822
|
-
function parseCondition(part) {
|
|
18355
|
+
function parseCondition$1(part) {
|
|
17823
18356
|
const p = part.trim();
|
|
17824
|
-
for (const kw of KEYWORD_OPS) {
|
|
18357
|
+
for (const kw of KEYWORD_OPS$1) {
|
|
17825
18358
|
const m = p.match(new RegExp(`^(.+?)\\s+${kw}\\s+(.+)$`, 'i'));
|
|
17826
18359
|
if (m && m[1] && m[2])
|
|
17827
|
-
return { field: m[1].trim(), operator: kw, value: unquote(m[2]) };
|
|
18360
|
+
return { field: m[1].trim(), operator: kw, value: unquote$1(m[2]) };
|
|
17828
18361
|
}
|
|
17829
|
-
for (const op of SYMBOLIC_OPS) {
|
|
18362
|
+
for (const op of SYMBOLIC_OPS$1) {
|
|
17830
18363
|
const idx = p.indexOf(op);
|
|
17831
18364
|
if (idx > 0) {
|
|
17832
18365
|
const field = p.slice(0, idx).trim();
|
|
17833
18366
|
const value = p.slice(idx + op.length).trim();
|
|
17834
18367
|
if (field && value)
|
|
17835
|
-
return { field, operator: op, value: unquote(value) };
|
|
18368
|
+
return { field, operator: op, value: unquote$1(value) };
|
|
17836
18369
|
}
|
|
17837
18370
|
}
|
|
17838
18371
|
return null;
|
|
@@ -17851,7 +18384,7 @@ function parsePredicate(expr) {
|
|
|
17851
18384
|
const parts = hasOr ? e.split('||') : hasAnd ? e.split('&&') : [e];
|
|
17852
18385
|
const conditions = [];
|
|
17853
18386
|
for (const part of parts) {
|
|
17854
|
-
const c = parseCondition(part);
|
|
18387
|
+
const c = parseCondition$1(part);
|
|
17855
18388
|
if (!c)
|
|
17856
18389
|
return null;
|
|
17857
18390
|
conditions.push(c);
|
|
@@ -17884,7 +18417,7 @@ function parseProjection(expr) {
|
|
|
17884
18417
|
items.push({ type: 'rename', alias: (segs[segs.length - 1] ?? '').trim(), path });
|
|
17885
18418
|
}
|
|
17886
18419
|
else if (!hasBrace && c !== -1) {
|
|
17887
|
-
items.push({ type: 'literal', alias: t.slice(0, c).trim(), value: unquote(t.slice(c + 1)) });
|
|
18420
|
+
items.push({ type: 'literal', alias: t.slice(0, c).trim(), value: unquote$1(t.slice(c + 1)) });
|
|
17888
18421
|
}
|
|
17889
18422
|
else if (/^[\w.$-]+$/.test(t)) {
|
|
17890
18423
|
items.push({ type: 'field', field: t });
|
|
@@ -18562,7 +19095,7 @@ class DataTreeComponent {
|
|
|
18562
19095
|
setTimeout(() => textarea?.setSelectionRange(newCursorPosition, newCursorPosition), 0);
|
|
18563
19096
|
}
|
|
18564
19097
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: DataTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
18565
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: DataTreeComponent, isStandalone: true, selector: "lib-data-tree", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, formInputs: { classPropertyName: "formInputs", publicName: "formInputs", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pathChanged: "pathChanged" }, host: { classAttribute: "lib-data-tree" }, viewQueries: [{ propertyName: "textareaElementRef", first: true, predicate: ["textarea"], descendants: true, isSignal: true }], ngImport: i0, template: "<mat-accordion multi class=\"surface\">\n <!-- 1 - Pick the data -->\n <mat-expansion-panel expanded>\n <mat-expansion-panel-header>\n <mat-panel-title>\n <mat-icon class=\"title-icon\">dataset_linked</mat-icon>\n <span class=\"panel-title\">1 · Pick your data</span>\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <div class=\"content\">\n <p class=\"hint-line\">\n <mat-icon class=\"info-icon\">touch_app</mat-icon>\n <span>Tick a field to map it. Pick an array (<mat-icon class=\"inline-icon\">data_array</mat-icon>) to transform its items next.</span>\n </p>\n\n <mat-tree [dataSource]=\"treeClass.dataSource\" [treeControl]=\"treeClass.treeControl\" class=\"data-tree\">\n <mat-tree-node *matTreeNodeDef=\"let node\" matTreeNodePadding>\n <span class=\"node-spacer\" aria-hidden=\"true\"></span>\n <mat-checkbox (change)=\"update(node)\" [checked]=\"nodeIsChecked(node)\" class=\"node-checkbox\"\n [matTooltip]=\"'Map field: ' + node.key\">\n <span class=\"node-key\">{{ node.key }}</span>\n <span class=\"node-value\" [style.color]=\"getNodeValueColor(node.value)\">{{ node.value }}</span>\n </mat-checkbox>\n </mat-tree-node>\n\n <mat-tree-node *matTreeNodeDef=\"let node; when: treeClass.hasChild\" matTreeNodePadding>\n <button class=\"node-toggle\" mat-icon-button matTreeNodeToggle [attr.aria-label]=\"'Toggle ' + node.key\">\n <mat-icon>{{ treeClass.treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right' }}</mat-icon>\n </button>\n <mat-checkbox (change)=\"update(node)\" [checked]=\"nodeIsChecked(node)\" [matTooltip]=\"'Select ' + node.key\">\n <span class=\"node-key\">{{ node.key }}</span>\n </mat-checkbox>\n </mat-tree-node>\n </mat-tree>\n </div>\n </mat-expansion-panel>\n\n <!-- 2 - Build the pipeline -->\n <mat-expansion-panel expanded>\n <mat-expansion-panel-header>\n <mat-panel-title>\n <mat-icon class=\"title-icon\">account_tree</mat-icon>\n <span class=\"panel-title\">2 · Transform your data</span>\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <div class=\"content\">\n @if (treeClass.activePath.length === 0) {\n <p class=\"hint-line\">\n <mat-icon class=\"info-icon\">arrow_upward</mat-icon>\n <span>Select a field above to begin.</span>\n </p>\n } @else {\n <nav class=\"breadcrumb\" aria-label=\"Selected path\">\n @for (path of treeClass.activePath; track trackByPath($index, path); let isLast = $last) {\n <button type=\"button\" class=\"crumb\" [class.crumb-active]=\"path.inEdit\"\n [class.crumb-array]=\"path.keyIsArrayIndex\" [disabled]=\"!path.keyIsArrayIndex && !path.inEdit\"\n [matTooltip]=\"path.keyIsArrayIndex ? 'Transform this array' : path.key\" (click)=\"setupPath(path)\">\n <mat-icon>{{ path.keyIsArrayIndex ? 'data_array' : 'folder' }}</mat-icon>\n <span class=\"crumb-text\">{{ path.key }}</span>\n @if (path.functions.length > 0) { <span class=\"crumb-badge\">{{ path.functions.length }}</span> }\n </button>\n @if (!isLast) { <mat-icon class=\"crumb-sep\">chevron_right</mat-icon> }\n }\n </nav>\n\n @if (hasANodeInEdit()) {\n <div class=\"pipeline\" role=\"list\" aria-label=\"Transform pipeline\">\n <span class=\"stage stage-source\" role=\"listitem\">\n <mat-icon>database</mat-icon>\n <span class=\"stage-label\">Source</span>\n </span>\n\n @for (step of steps; track step.id; let i = $index) {\n <mat-icon class=\"flow-arrow\">chevron_right</mat-icon>\n <button class=\"stage stage-step\" role=\"listitem\" [class.stage-active]=\"step.inEdit\"\n [class.stage-empty]=\"!step.function\" (click)=\"editFunction(step.id)\"\n [matTooltip]=\"functionMeta(step.function)?.hint || 'Choose an operation'\">\n <mat-icon>{{ functionMeta(step.function)?.icon || 'help_outline' }}</mat-icon>\n <span class=\"stage-label\">{{ (step.function | titlecase) || 'Choose' }}</span>\n @if (stepRowCount(i); as n) {\n <span class=\"stage-count\">{{ n }} {{ n === 1 ? 'row' : 'rows' }}</span>\n }\n </button>\n }\n\n <mat-icon class=\"flow-arrow\">chevron_right</mat-icon>\n <button class=\"stage stage-add\" [matMenuTriggerFor]=\"addMenu\" matTooltip=\"Add a transform step\">\n <mat-icon>add</mat-icon>\n <span class=\"stage-label\">Add</span>\n </button>\n <mat-menu #addMenu=\"matMenu\">\n @for (option of functionOptions; track option.value) {\n <button mat-menu-item (click)=\"addStep(option.value)\">\n <mat-icon>{{ option.icon }}</mat-icon>\n <span>{{ option.label }}</span>\n <span class=\"menu-hint\">{{ option.hint }}</span>\n </button>\n }\n </mat-menu>\n </div>\n\n @if (getFunctionInEdit(); as fn) {\n <section class=\"editor\">\n <label class=\"f-field full\">\n <span class=\"f-label\">Operation</span>\n <select class=\"f-control\" [value]=\"fn.function\" (change)=\"functionChanged(inputValue($event))\">\n <option value=\"\" disabled>Choose what this step does</option>\n @for (option of functionOptions; track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n </label>\n @if (fn.function && activeFunctionMeta(); as meta) {\n <p class=\"sub-hint\">{{ meta.hint }}</p>\n }\n\n @if (!fn.function) {\n <p class=\"hint-line\">\n <mat-icon class=\"info-icon\">info</mat-icon>\n <span>Choose an operation to configure this step.</span>\n </p>\n } @else {\n @if (rawMode()) {\n <label class=\"f-field full\">\n <span class=\"f-label\">Expression</span>\n <textarea class=\"f-control f-textarea\" #textarea rows=\"2\" [value]=\"fn.expression\"\n (input)=\"onRawChange($event)\" (focus)=\"onFocus()\" placeholder=\"Type the raw expression\"></textarea>\n </label>\n <p class=\"sub-hint\">Type <code>$</code> to insert a field or operator.</p>\n\n @if (showSuggestions()) {\n <div class=\"suggestions\">\n <div class=\"suggestion-group\">\n <span class=\"field-label\">Operators</span>\n <div class=\"chip-row\">\n @for (method of getMethods(); track method.value) {\n <button mat-stroked-button class=\"ins-chip\" (click)=\"selectSuggestionInput(method.value)\">\n {{ method.value }}\n </button>\n }\n </div>\n </div>\n <div class=\"suggestion-group\">\n <span class=\"field-label\">Inputs</span>\n <div class=\"chip-row\">\n @for (input of getAllInputs(); track input.formControlName) {\n <button mat-stroked-button class=\"ins-chip\" (click)=\"selectSuggestionInput(input.formControlName)\">\n {{ input.label }}\n </button>\n }\n </div>\n </div>\n </div>\n }\n } @else {\n @switch (activeKind()) {\n @case ('predicate') {\n @if (predicate(); as p) {\n @if (p.conditions.length > 1) {\n <div class=\"match-row\">\n <span class=\"field-label\">Match</span>\n <mat-button-toggle-group class=\"seg\" [value]=\"p.connector\" hideSingleSelectionIndicator\n (change)=\"setConnector($event.value)\">\n <mat-button-toggle value=\"&&\">All</mat-button-toggle>\n <mat-button-toggle value=\"||\">Any</mat-button-toggle>\n </mat-button-toggle-group>\n <span class=\"muted\">of the conditions</span>\n </div>\n }\n @for (cond of p.conditions; track $index) {\n <div class=\"q-item\">\n <div class=\"q-stack\">\n <label class=\"f-field\">\n <span class=\"f-label\">Field</span>\n <select class=\"f-control\" [value]=\"cond.field\"\n (change)=\"updateCondition($index, { field: inputValue($event) })\">\n @for (f of fieldOptionsWith(cond.field); track f) { <option [value]=\"f\">{{ f }}</option> }\n </select>\n </label>\n <div class=\"q-pair q-pair-op\">\n <label class=\"f-field\">\n <span class=\"f-label\">Operator</span>\n <select class=\"f-control\" [value]=\"cond.operator\"\n (change)=\"updateCondition($index, { operator: inputValue($event) })\">\n @for (op of operators; track op.value) { <option [value]=\"op.value\">{{ op.label }}</option> }\n </select>\n </label>\n <label class=\"f-field\">\n <span class=\"f-label\">Value</span>\n <input class=\"f-control\" [value]=\"cond.value\" placeholder=\"active, 18, Durban\"\n (input)=\"updateCondition($index, { value: inputValue($event) })\">\n </label>\n </div>\n </div>\n <button mat-icon-button class=\"q-remove\" (click)=\"removeCondition($index)\"\n matTooltip=\"Remove\"><mat-icon>close</mat-icon></button>\n </div>\n }\n <button type=\"button\" class=\"link-btn\" (click)=\"addCondition()\">\n <mat-icon>add</mat-icon> Add condition\n </button>\n }\n }\n\n @case ('project') {\n @if (projection(); as proj) {\n <span class=\"field-label\">Keep fields</span>\n <div class=\"checklist\">\n @for (f of availableFields(); track f) {\n <mat-checkbox [checked]=\"fieldPicked(f)\" (change)=\"toggleField(f)\">{{ f }}</mat-checkbox>\n }\n <mat-checkbox [checked]=\"hasSpread()\" (change)=\"toggleSpread()\"\n matTooltip=\"Include every field\">everything (*)</mat-checkbox>\n </div>\n\n <div class=\"section-head\">\n <span class=\"field-label\">Mapped fields</span>\n <span class=\"section-actions\">\n <button type=\"button\" class=\"link-btn\" (click)=\"addRename()\"><mat-icon>add</mat-icon> Field</button>\n <button type=\"button\" class=\"link-btn\" (click)=\"addLiteral()\"><mat-icon>add</mat-icon> Constant</button>\n </span>\n </div>\n\n @for (r of renameItems(); track r.index) {\n <div class=\"map-row\">\n <label class=\"f-field\">\n <span class=\"f-label\">New name</span>\n <input class=\"f-control\" [value]=\"r.item.alias\"\n (input)=\"updateItem(r.index, { alias: inputValue($event) })\">\n </label>\n <div class=\"f-field\">\n <span class=\"f-label\">From path</span>\n <button type=\"button\" class=\"f-control f-picker\" [matMenuTriggerFor]=\"pathMenu\">\n <span class=\"f-picker-text\" [class.f-placeholder]=\"!r.item.path\">{{ r.item.path || 'Select a path' }}</span>\n <mat-icon>account_tree</mat-icon>\n </button>\n <mat-menu #pathMenu=\"matMenu\" class=\"path-menu\">\n @for (p of availableDeepPaths(); track p.path) {\n <button mat-menu-item class=\"path-item\" [style.padding-left.px]=\"12 + p.depth * 14\"\n (click)=\"updateItem(r.index, { path: p.path })\">\n <mat-icon class=\"path-icon\">{{ p.leaf ? 'chevron_right' : 'folder_open' }}</mat-icon>\n <span>{{ p.name }}</span>\n </button>\n } @empty {\n <button mat-menu-item disabled>No paths detected</button>\n }\n </mat-menu>\n </div>\n <button mat-icon-button class=\"q-remove\" (click)=\"removeItem(r.index)\"\n matTooltip=\"Remove\"><mat-icon>close</mat-icon></button>\n </div>\n }\n @for (l of literalItems(); track l.index) {\n <div class=\"map-row\">\n <label class=\"f-field\">\n <span class=\"f-label\">Field name</span>\n <input class=\"f-control\" [value]=\"l.item.alias\"\n (input)=\"updateItem(l.index, { alias: inputValue($event) })\">\n </label>\n <label class=\"f-field\">\n <span class=\"f-label\">Constant</span>\n <input class=\"f-control\" [value]=\"l.item.value\" placeholder='\"api\", 1, true'\n (input)=\"updateItem(l.index, { value: inputValue($event) })\">\n </label>\n <button mat-icon-button class=\"q-remove\" (click)=\"removeItem(l.index)\"\n matTooltip=\"Remove\"><mat-icon>close</mat-icon></button>\n </div>\n }\n }\n }\n\n @case ('sort') {\n @if (sort(); as s) {\n @for (key of s.keys; track $index) {\n <div class=\"q-item\">\n <div class=\"q-pair q-pair-sort\">\n <label class=\"f-field\">\n <span class=\"f-label\">Sort by</span>\n <select class=\"f-control\" [value]=\"key.field\"\n (change)=\"updateSortKey($index, { field: inputValue($event) })\">\n @for (f of fieldOptionsWith(key.field); track f) { <option [value]=\"f\">{{ f }}</option> }\n </select>\n </label>\n <mat-button-toggle-group class=\"seg seg-dir\" [value]=\"key.dir\" hideSingleSelectionIndicator\n (change)=\"updateSortKey($index, { dir: $event.value })\">\n <mat-button-toggle value=\"asc\" matTooltip=\"Ascending\"><mat-icon>arrow_upward</mat-icon></mat-button-toggle>\n <mat-button-toggle value=\"desc\" matTooltip=\"Descending\"><mat-icon>arrow_downward</mat-icon></mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <button mat-icon-button class=\"q-remove\" (click)=\"removeSortKey($index)\"\n matTooltip=\"Remove\"><mat-icon>close</mat-icon></button>\n </div>\n }\n <button type=\"button\" class=\"link-btn\" (click)=\"addSortKey()\">\n <mat-icon>add</mat-icon> Add sort key\n </button>\n }\n }\n\n @case ('slice') {\n @if (slice(); as sl) {\n <div class=\"field-grid\">\n <label class=\"f-field\">\n <span class=\"f-label\">Take</span>\n <select class=\"f-control\" [value]=\"sl.mode\" (change)=\"setSliceMode(inputValue($event))\">\n @for (mode of sliceModes; track mode.value) { <option [value]=\"mode.value\">{{ mode.label }}</option> }\n </select>\n </label>\n @switch (sl.mode) {\n @case ('range') {\n <label class=\"f-field\"><span class=\"f-label\">Start</span>\n <input class=\"f-control\" type=\"number\" [value]=\"sl.a\" (input)=\"setSliceA($event)\"></label>\n <label class=\"f-field\"><span class=\"f-label\">End</span>\n <input class=\"f-control\" type=\"number\" [value]=\"sl.b\" (input)=\"setSliceB($event)\"></label>\n }\n @case ('fromCount') {\n <label class=\"f-field\"><span class=\"f-label\">From index</span>\n <input class=\"f-control\" type=\"number\" [value]=\"sl.a\" (input)=\"setSliceA($event)\"></label>\n <label class=\"f-field\"><span class=\"f-label\">Count</span>\n <input class=\"f-control\" type=\"number\" [value]=\"sl.b\" (input)=\"setSliceB($event)\"></label>\n }\n @default {\n <label class=\"f-field\"><span class=\"f-label\">How many</span>\n <input class=\"f-control\" type=\"number\" [value]=\"sl.b\" (input)=\"setSliceB($event)\"></label>\n }\n }\n </div>\n }\n }\n\n @case ('keys') {\n @if (keysModel(); as k) {\n <span class=\"field-label\">\n @if (isUnique(fn.function)) { Unique by — none = whole row } @else { Group by }\n </span>\n <div class=\"checklist\">\n @for (f of availableFields(); track f) {\n <mat-checkbox [checked]=\"keyPicked(f)\" (change)=\"toggleKey(f)\">{{ f }}</mat-checkbox>\n }\n </div>\n @if (availableFields().length === 0) {\n <p class=\"hint-line\"><mat-icon class=\"info-icon\">info</mat-icon>\n <span>No fields detected — use Advanced to type a key path.</span></p>\n }\n }\n }\n\n @case ('flatten') {\n @if (flatten(); as fl) {\n <label class=\"f-field full\">\n <span class=\"f-label\">Flatten</span>\n <select class=\"f-control\" [value]=\"fl.path\" (change)=\"setFlatten(inputValue($event))\">\n <option [value]=\"''\">nested arrays (one level)</option>\n @for (f of fieldOptionsWith(fl.path); track f) { <option [value]=\"f\">items in {{ f }}</option> }\n </select>\n </label>\n <p class=\"sub-hint\">Blank flattens one level; a field flat-maps that child array.</p>\n }\n }\n\n @case ('reduce') {\n @if (reduce(); as red) {\n @for (agg of red.aggs; track $index) {\n <div class=\"q-item\">\n <div class=\"q-stack\">\n @if (red.aggs.length > 1) {\n <label class=\"f-field\">\n <span class=\"f-label\">Output name</span>\n <input class=\"f-control\" [value]=\"agg.alias\"\n (input)=\"updateAgg($index, { alias: inputValue($event) })\">\n </label>\n }\n <div class=\"q-pair\">\n <label class=\"f-field\">\n <span class=\"f-label\">Aggregate</span>\n <select class=\"f-control\" [value]=\"agg.agg\"\n (change)=\"updateAgg($index, { agg: inputValue($event) })\">\n @for (a of aggregates; track a.value) { <option [value]=\"a.value\">{{ a.label }}</option> }\n </select>\n </label>\n @if (aggNeedsField(agg.agg)) {\n <label class=\"f-field\">\n <span class=\"f-label\">Field</span>\n <select class=\"f-control\" [value]=\"agg.field\"\n (change)=\"updateAgg($index, { field: inputValue($event) })\">\n @for (f of fieldOptionsWith(agg.field); track f) { <option [value]=\"f\">{{ f }}</option> }\n </select>\n </label>\n }\n </div>\n </div>\n <button mat-icon-button class=\"q-remove\" (click)=\"removeAgg($index)\"\n matTooltip=\"Remove\"><mat-icon>close</mat-icon></button>\n </div>\n }\n <button type=\"button\" class=\"link-btn\" (click)=\"addAgg()\">\n <mat-icon>add</mat-icon> Add aggregate\n </button>\n }\n }\n }\n }\n\n <div class=\"editor-foot\">\n <button type=\"button\" class=\"link-btn\" (click)=\"toggleRaw()\">\n @if (rawMode()) { <mat-icon>view_module</mat-icon> Guided }\n @else { <mat-icon>code</mat-icon> Advanced }\n </button>\n </div>\n }\n\n <div class=\"editor-actions\">\n <button mat-icon-button (click)=\"moveStep(fn.id, -1)\" matTooltip=\"Move earlier\"\n aria-label=\"Move step earlier\"><mat-icon>chevron_left</mat-icon></button>\n <button mat-icon-button (click)=\"moveStep(fn.id, 1)\" matTooltip=\"Move later\"\n aria-label=\"Move step later\"><mat-icon>chevron_right</mat-icon></button>\n <button mat-icon-button (click)=\"removeFunction(fn.id)\" matTooltip=\"Remove step\"\n aria-label=\"Remove step\"><mat-icon>delete_outline</mat-icon></button>\n <span class=\"spacer\"></span>\n <button mat-flat-button color=\"primary\" (click)=\"saveNodeInEdit()\">\n <mat-icon>check</mat-icon> Apply\n </button>\n </div>\n </section>\n }\n } @else {\n <p class=\"hint-line\">\n <mat-icon class=\"info-icon\">data_array</mat-icon>\n <span>Click an array (<mat-icon class=\"inline-icon\">data_array</mat-icon>) in the path above to add steps.</span>\n </p>\n }\n }\n </div>\n </mat-expansion-panel>\n\n <!-- 3 - Preview -->\n <mat-expansion-panel expanded>\n <mat-expansion-panel-header>\n <mat-panel-title>\n <mat-icon class=\"title-icon\">preview</mat-icon>\n <span class=\"panel-title\">3 · Result preview</span>\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <div class=\"content\">\n @if (resultRowCount(); as n) {\n <span class=\"result-count\"><mat-icon>check_circle</mat-icon> {{ n }} {{ n === 1 ? 'result' : 'results' }}</span>\n }\n <div class=\"mapped-value\">\n <pre>{{ mappedValue | json }}</pre>\n </div>\n </div>\n </mat-expansion-panel>\n</mat-accordion>\n", styles: ["@charset \"UTF-8\";:host{display:block}.surface mat-expansion-panel{background:var(--mat-sys-surface-container-low, var(--lib-forms-surface-container-low))}:host ::ng-deep .mat-expansion-panel-header{height:44px;padding:0 .875rem}:host ::ng-deep .mat-expansion-panel-body{padding:0 .875rem .75rem}button mat-icon{vertical-align:middle}.panel-title{font-size:.875rem;font-weight:500;letter-spacing:-.01em}.title-icon{margin-right:.625rem;vertical-align:middle;color:var(--lib-forms-on-surface-variant)}.content{display:flex;flex-direction:column;gap:.875rem;padding:.5rem 0 .25rem}.hint-line{display:flex;align-items:center;gap:.5rem;margin:0;font-size:.8125rem;color:var(--lib-forms-on-surface-variant)}.info-icon{color:var(--sem-info, var(--lib-forms-primary));flex:none}.inline-icon{font-size:1rem;width:1rem;height:1rem;vertical-align:text-bottom}.field-label{font-size:.625rem;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--lib-forms-on-surface-variant)}.muted{font-size:.8125rem;color:var(--lib-forms-on-surface-variant)}.data-tree{background:var(--lib-forms-surface-container-low);border-radius:var(--lib-forms-radius-md);padding:.5rem .75rem;min-width:fit-content}:host mat-tree-node{min-height:34px}.node-spacer{display:inline-block;width:36px}.node-toggle{color:var(--lib-forms-on-surface-variant)}.node-checkbox{width:100%}.node-key{font-weight:500;color:var(--lib-forms-on-surface);margin-right:.5rem}.node-value{font-family:var(--lib-forms-font-mono, monospace);padding:.0625rem .4375rem;background:var(--lib-forms-surface-container);border-radius:var(--lib-forms-radius-sm);font-size:.8125rem;white-space:nowrap}.breadcrumb{display:flex;align-items:center;flex-wrap:wrap;gap:.125rem}.crumb{display:inline-flex;align-items:center;gap:.25rem;height:1.75rem;max-width:9rem;padding:0 .5rem;font:inherit;font-size:.8125rem;font-weight:500;color:var(--lib-forms-on-surface-variant);background:transparent;border:0;border-radius:var(--lib-forms-radius-pill);cursor:pointer;white-space:nowrap;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),color var(--lib-forms-duration-hover) var(--lib-forms-easing)}.crumb:hover:not(:disabled){background:var(--lib-forms-surface-container-high)}.crumb:disabled{cursor:default;opacity:.65}.crumb mat-icon{flex:none;font-size:1.0625rem;width:1.0625rem;height:1.0625rem}.crumb-text{overflow:hidden;text-overflow:ellipsis}.crumb-array{color:var(--lib-forms-primary)}.crumb-active,.crumb-active:hover:not(:disabled){background:var(--lib-forms-primary-container);color:var(--lib-forms-on-surface)}.crumb-badge{min-width:1.0625rem;padding:0 .3125rem;border-radius:var(--lib-forms-radius-pill);background:var(--lib-forms-primary);color:var(--mat-sys-on-primary, #fff);font-size:.625rem;line-height:1.0625rem;text-align:center}.crumb-sep{color:var(--lib-forms-outline);font-size:1rem;width:1rem;height:1rem}.pipeline{display:flex;align-items:stretch;flex-wrap:wrap;gap:.375rem}.stage{display:inline-flex;flex-direction:column;align-items:center;justify-content:center;gap:.0625rem;min-width:4rem;padding:.375rem .5rem;border:1px solid var(--lib-forms-outline-variant);border-radius:var(--lib-forms-radius-md);background:var(--lib-forms-surface-container-low);color:var(--lib-forms-on-surface);cursor:pointer;transition:border-color var(--lib-forms-duration-hover) var(--lib-forms-easing),background-color var(--lib-forms-duration-hover) var(--lib-forms-easing)}.stage mat-icon{font-size:1.125rem;width:1.125rem;height:1.125rem}.stage-source{cursor:default;color:var(--lib-forms-on-surface-variant);background:transparent;border-style:dashed}.stage-active{border-color:var(--lib-forms-primary);background:var(--lib-forms-primary-container)}.stage-empty{border-style:dashed;color:var(--lib-forms-on-surface-variant)}.stage-add{border-style:dashed;color:var(--lib-forms-primary);min-width:3.75rem}.stage-label{font-size:.75rem;font-weight:500}.stage-count{font-size:.625rem;color:var(--lib-forms-on-surface-variant)}.flow-arrow{align-self:center;color:var(--lib-forms-outline);font-size:1.125rem;width:1rem;height:1.125rem}.menu-hint{display:block;font-size:.6875rem;color:var(--lib-forms-on-surface-variant)}.editor{display:flex;flex-direction:column;gap:.75rem;padding:1.125rem;border-radius:var(--lib-forms-radius-lg);background:var(--lib-forms-surface-container-low);box-shadow:var(--mat-sys-level1, 0 1px 3px rgba(0, 0, 0, .12))}.full{width:100%}.f-field{display:flex;flex-direction:column;gap:.1875rem;min-width:0}.f-label{font-size:.625rem;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--lib-forms-on-surface-variant)}.f-control{box-sizing:border-box;width:100%;min-width:0;height:2rem;padding:.3125rem .5rem;font-family:inherit;font-size:.8125rem;line-height:1.25;color:var(--lib-forms-on-surface);background:var(--lib-forms-surface-container-lowest);border:1px solid var(--lib-forms-outline-variant);border-radius:var(--lib-forms-radius-sm);transition:border-color var(--lib-forms-duration-hover) var(--lib-forms-easing)}select.f-control{cursor:pointer}.f-textarea{height:auto;min-height:3rem;line-height:1.4;resize:vertical}.f-control:hover{border-color:var(--lib-forms-outline)}.f-control:focus{outline:none;border-color:var(--lib-forms-primary);box-shadow:0 0 0 1px var(--lib-forms-primary)}.sub-hint{margin:-.25rem 0 0;font-size:.75rem;color:var(--lib-forms-on-surface-variant)}.section-head{display:flex;align-items:center;justify-content:space-between;gap:.5rem;margin-top:.25rem}.section-actions{display:flex;gap:.25rem}.map-row{display:grid;grid-template-columns:1fr 1fr auto;align-items:end;gap:.5rem;padding:.5rem .5rem .5rem .625rem;background:var(--lib-forms-surface-container);border-radius:var(--lib-forms-radius-sm)}.q-item{display:grid;grid-template-columns:1fr auto;align-items:center;gap:.25rem;padding:.5rem .5rem .5rem .625rem;background:var(--lib-forms-surface-container);border-radius:var(--lib-forms-radius-sm)}.q-stack{display:flex;flex-direction:column;gap:.5rem;min-width:0}.q-pair{display:grid;grid-template-columns:1fr 1fr;gap:.5rem;min-width:0}.q-pair-op{grid-template-columns:8rem 1fr}.q-pair-sort{grid-template-columns:1fr auto;align-items:end}.q-remove{color:var(--lib-forms-on-surface-variant)}.field-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(6.5rem,1fr));gap:.5rem}.match-row{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.seg{--mat-standard-button-toggle-height: 34px;height:34px}.checklist{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.125rem 1rem;padding:.25rem 0}.link-btn{display:inline-flex;align-items:center;align-self:flex-start;gap:.25rem;height:1.75rem;padding:0 .5rem;font:inherit;font-size:.8125rem;font-weight:500;color:var(--lib-forms-primary);background:transparent;border:0;border-radius:var(--lib-forms-radius-sm);cursor:pointer;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing)}.link-btn:hover{background:var(--lib-forms-primary-container)}.link-btn mat-icon{flex:none;font-size:1.0625rem;width:1.0625rem;height:1.0625rem}.f-picker{display:flex;align-items:center;justify-content:space-between;gap:.25rem;text-align:left;cursor:pointer}.f-picker-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.f-placeholder{color:var(--lib-forms-on-surface-variant)}.f-picker mat-icon{flex:none;font-size:1.0625rem;width:1.0625rem;height:1.0625rem;color:var(--lib-forms-on-surface-variant)}.path-icon{margin-right:.25rem;font-size:1rem;width:1rem;height:1rem;color:var(--lib-forms-on-surface-variant)}.editor-foot{display:flex;justify-content:flex-end;margin-top:-.25rem}.editor-actions{display:flex;align-items:center;gap:.125rem;padding-top:.5rem}.spacer{flex:1}.suggestions{display:flex;gap:1rem;flex-wrap:wrap;padding:.75rem;border-radius:var(--lib-forms-radius-md);background:var(--sem-info-surface, var(--lib-forms-surface-container))}.suggestion-group{flex:1 1 10rem;display:flex;flex-direction:column;gap:.375rem}.chip-row{display:flex;flex-wrap:wrap;gap:.25rem}.ins-chip{font-size:.75rem}.result-count{display:inline-flex;align-items:center;gap:.375rem;font-size:.8125rem;font-weight:500;color:var(--sem-emerald, var(--lib-forms-method-get))}.result-count mat-icon{font-size:1.125rem;width:1.125rem;height:1.125rem}.mapped-value{padding:1rem 1.25rem;background:var(--lib-forms-on-surface);color:var(--lib-forms-surface);border-radius:var(--lib-forms-radius-md);overflow:auto}.mapped-value pre{margin:0;font-family:var(--lib-forms-font-mono, monospace);font-size:.8125rem}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i1$2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "directive", type: i2$2.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i2$2.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i3$4.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "directive", type: i5$3.MatAccordion, selector: "mat-accordion", inputs: ["hideToggle", "displayMode", "togglePosition"], exportAs: ["matAccordion"] }, { kind: "component", type: i5$3.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i5$3.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i5$3.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i6.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i6.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i6.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatTreeModule }, { kind: "directive", type: i1$4.MatTreeNodeDef, selector: "[matTreeNodeDef]", inputs: ["matTreeNodeDefWhen", "matTreeNode"] }, { kind: "directive", type: i1$4.MatTreeNodePadding, selector: "[matTreeNodePadding]", inputs: ["matTreeNodePadding", "matTreeNodePaddingIndent"] }, { kind: "directive", type: i1$4.MatTreeNodeToggle, selector: "[matTreeNodeToggle]", inputs: ["matTreeNodeToggleRecursive"] }, { kind: "component", type: i1$4.MatTree, selector: "mat-tree", exportAs: ["matTree"] }, { kind: "directive", type: i1$4.MatTreeNode, selector: "mat-tree-node", inputs: ["tabIndex", "disabled"], outputs: ["activation", "expandedChange"], exportAs: ["matTreeNode"] }, { kind: "pipe", type: JsonPipe, name: "json" }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
19098
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: DataTreeComponent, isStandalone: true, selector: "lib-data-tree", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, formInputs: { classPropertyName: "formInputs", publicName: "formInputs", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pathChanged: "pathChanged" }, host: { classAttribute: "lib-data-tree" }, viewQueries: [{ propertyName: "textareaElementRef", first: true, predicate: ["textarea"], descendants: true, isSignal: true }], ngImport: i0, template: "<mat-accordion multi class=\"surface\">\n <!-- 1 - Pick the data -->\n <mat-expansion-panel expanded>\n <mat-expansion-panel-header>\n <mat-panel-title>\n <mat-icon class=\"title-icon\">dataset_linked</mat-icon>\n <span class=\"panel-title\">1 · Pick your data</span>\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <div class=\"content\">\n <p class=\"hint-line\">\n <mat-icon class=\"info-icon\">touch_app</mat-icon>\n <span>Tick a field to map it. Pick an array (<mat-icon class=\"inline-icon\">data_array</mat-icon>) to transform its items next.</span>\n </p>\n\n <mat-tree [dataSource]=\"treeClass.dataSource\" [treeControl]=\"treeClass.treeControl\" class=\"data-tree\">\n <mat-tree-node *matTreeNodeDef=\"let node\" matTreeNodePadding>\n <span class=\"node-spacer\" aria-hidden=\"true\"></span>\n <mat-checkbox (change)=\"update(node)\" [checked]=\"nodeIsChecked(node)\" class=\"node-checkbox\"\n [matTooltip]=\"'Map field: ' + node.key\">\n <span class=\"node-key\">{{ node.key }}</span>\n <span class=\"node-value\" [style.color]=\"getNodeValueColor(node.value)\">{{ node.value }}</span>\n </mat-checkbox>\n </mat-tree-node>\n\n <mat-tree-node *matTreeNodeDef=\"let node; when: treeClass.hasChild\" matTreeNodePadding>\n <button class=\"node-toggle\" mat-icon-button matTreeNodeToggle [attr.aria-label]=\"'Toggle ' + node.key\">\n <mat-icon>{{ treeClass.treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right' }}</mat-icon>\n </button>\n <mat-checkbox (change)=\"update(node)\" [checked]=\"nodeIsChecked(node)\" [matTooltip]=\"'Select ' + node.key\">\n <span class=\"node-key\">{{ node.key }}</span>\n </mat-checkbox>\n </mat-tree-node>\n </mat-tree>\n </div>\n </mat-expansion-panel>\n\n <!-- 2 - Build the pipeline -->\n <mat-expansion-panel expanded>\n <mat-expansion-panel-header>\n <mat-panel-title>\n <mat-icon class=\"title-icon\">account_tree</mat-icon>\n <span class=\"panel-title\">2 · Transform your data</span>\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <div class=\"content\">\n @if (treeClass.activePath.length === 0) {\n <p class=\"hint-line\">\n <mat-icon class=\"info-icon\">arrow_upward</mat-icon>\n <span>Select a field above to begin.</span>\n </p>\n } @else {\n <nav class=\"breadcrumb\" aria-label=\"Selected path\">\n @for (path of treeClass.activePath; track trackByPath($index, path); let isLast = $last) {\n <button type=\"button\" class=\"crumb\" [class.crumb-active]=\"path.inEdit\"\n [class.crumb-array]=\"path.keyIsArrayIndex\" [disabled]=\"!path.keyIsArrayIndex && !path.inEdit\"\n [matTooltip]=\"path.keyIsArrayIndex ? 'Transform this array' : path.key\" (click)=\"setupPath(path)\">\n <mat-icon>{{ path.keyIsArrayIndex ? 'data_array' : 'folder' }}</mat-icon>\n <span class=\"crumb-text\">{{ path.key }}</span>\n @if (path.functions.length > 0) { <span class=\"crumb-badge\">{{ path.functions.length }}</span> }\n </button>\n @if (!isLast) { <mat-icon class=\"crumb-sep\">chevron_right</mat-icon> }\n }\n </nav>\n\n @if (hasANodeInEdit()) {\n <div class=\"pipeline\" role=\"list\" aria-label=\"Transform pipeline\">\n <span class=\"stage stage-source\" role=\"listitem\">\n <mat-icon>database</mat-icon>\n <span class=\"stage-label\">Source</span>\n </span>\n\n @for (step of steps; track step.id; let i = $index) {\n <mat-icon class=\"flow-arrow\">chevron_right</mat-icon>\n <button class=\"stage stage-step\" role=\"listitem\" [class.stage-active]=\"step.inEdit\"\n [class.stage-empty]=\"!step.function\" (click)=\"editFunction(step.id)\"\n [matTooltip]=\"functionMeta(step.function)?.hint || 'Choose an operation'\">\n <mat-icon>{{ functionMeta(step.function)?.icon || 'help_outline' }}</mat-icon>\n <span class=\"stage-label\">{{ (step.function | titlecase) || 'Choose' }}</span>\n @if (stepRowCount(i); as n) {\n <span class=\"stage-count\">{{ n }} {{ n === 1 ? 'row' : 'rows' }}</span>\n }\n </button>\n }\n\n <mat-icon class=\"flow-arrow\">chevron_right</mat-icon>\n <button class=\"stage stage-add\" [matMenuTriggerFor]=\"addMenu\" matTooltip=\"Add a transform step\">\n <mat-icon>add</mat-icon>\n <span class=\"stage-label\">Add</span>\n </button>\n <mat-menu #addMenu=\"matMenu\">\n @for (option of functionOptions; track option.value) {\n <button mat-menu-item (click)=\"addStep(option.value)\">\n <mat-icon>{{ option.icon }}</mat-icon>\n <span>{{ option.label }}</span>\n <span class=\"menu-hint\">{{ option.hint }}</span>\n </button>\n }\n </mat-menu>\n </div>\n\n @if (getFunctionInEdit(); as fn) {\n <section class=\"editor\">\n <label class=\"f-field full\">\n <span class=\"f-label\">Operation</span>\n <select class=\"f-control\" [value]=\"fn.function\" (change)=\"functionChanged(inputValue($event))\">\n <option value=\"\" disabled>Choose what this step does</option>\n @for (option of functionOptions; track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n </label>\n @if (fn.function && activeFunctionMeta(); as meta) {\n <p class=\"sub-hint\">{{ meta.hint }}</p>\n }\n\n @if (!fn.function) {\n <p class=\"hint-line\">\n <mat-icon class=\"info-icon\">info</mat-icon>\n <span>Choose an operation to configure this step.</span>\n </p>\n } @else {\n @if (rawMode()) {\n <label class=\"f-field full\">\n <span class=\"f-label\">Expression</span>\n <textarea class=\"f-control f-textarea\" #textarea rows=\"2\" [value]=\"fn.expression\"\n (input)=\"onRawChange($event)\" (focus)=\"onFocus()\" placeholder=\"Type the raw expression\"></textarea>\n </label>\n <p class=\"sub-hint\">Type <code>$</code> to insert a field or operator.</p>\n\n @if (showSuggestions()) {\n <div class=\"suggestions\">\n <div class=\"suggestion-group\">\n <span class=\"field-label\">Operators</span>\n <div class=\"chip-row\">\n @for (method of getMethods(); track method.value) {\n <button mat-stroked-button class=\"ins-chip\" (click)=\"selectSuggestionInput(method.value)\">\n {{ method.value }}\n </button>\n }\n </div>\n </div>\n <div class=\"suggestion-group\">\n <span class=\"field-label\">Inputs</span>\n <div class=\"chip-row\">\n @for (input of getAllInputs(); track input.formControlName) {\n <button mat-stroked-button class=\"ins-chip\" (click)=\"selectSuggestionInput(input.formControlName)\">\n {{ input.label }}\n </button>\n }\n </div>\n </div>\n </div>\n }\n } @else {\n @switch (activeKind()) {\n @case ('predicate') {\n @if (predicate(); as p) {\n @if (p.conditions.length > 1) {\n <div class=\"match-row\">\n <span class=\"field-label\">Match</span>\n <mat-button-toggle-group class=\"seg\" [value]=\"p.connector\" hideSingleSelectionIndicator\n (change)=\"setConnector($event.value)\">\n <mat-button-toggle value=\"&&\">All</mat-button-toggle>\n <mat-button-toggle value=\"||\">Any</mat-button-toggle>\n </mat-button-toggle-group>\n <span class=\"muted\">of the conditions</span>\n </div>\n }\n @for (cond of p.conditions; track $index) {\n <div class=\"q-item\">\n <div class=\"q-stack\">\n <label class=\"f-field\">\n <span class=\"f-label\">Field</span>\n <select class=\"f-control\" [value]=\"cond.field\"\n (change)=\"updateCondition($index, { field: inputValue($event) })\">\n @for (f of fieldOptionsWith(cond.field); track f) { <option [value]=\"f\">{{ f }}</option> }\n </select>\n </label>\n <div class=\"q-pair q-pair-op\">\n <label class=\"f-field\">\n <span class=\"f-label\">Operator</span>\n <select class=\"f-control\" [value]=\"cond.operator\"\n (change)=\"updateCondition($index, { operator: inputValue($event) })\">\n @for (op of operators; track op.value) { <option [value]=\"op.value\">{{ op.label }}</option> }\n </select>\n </label>\n <label class=\"f-field\">\n <span class=\"f-label\">Value</span>\n <input class=\"f-control\" [value]=\"cond.value\" placeholder=\"active, 18, Durban\"\n (input)=\"updateCondition($index, { value: inputValue($event) })\">\n </label>\n </div>\n </div>\n <button mat-icon-button class=\"q-remove\" (click)=\"removeCondition($index)\"\n matTooltip=\"Remove\"><mat-icon>close</mat-icon></button>\n </div>\n }\n <button type=\"button\" class=\"link-btn\" (click)=\"addCondition()\">\n <mat-icon>add</mat-icon> Add condition\n </button>\n }\n }\n\n @case ('project') {\n @if (projection(); as proj) {\n <span class=\"field-label\">Keep fields</span>\n <div class=\"checklist\">\n @for (f of availableFields(); track f) {\n <mat-checkbox [checked]=\"fieldPicked(f)\" (change)=\"toggleField(f)\">{{ f }}</mat-checkbox>\n }\n <mat-checkbox [checked]=\"hasSpread()\" (change)=\"toggleSpread()\"\n matTooltip=\"Include every field\">everything (*)</mat-checkbox>\n </div>\n\n <div class=\"section-head\">\n <span class=\"field-label\">Mapped fields</span>\n <span class=\"section-actions\">\n <button type=\"button\" class=\"link-btn\" (click)=\"addRename()\"><mat-icon>add</mat-icon> Field</button>\n <button type=\"button\" class=\"link-btn\" (click)=\"addLiteral()\"><mat-icon>add</mat-icon> Constant</button>\n </span>\n </div>\n\n @for (r of renameItems(); track r.index) {\n <div class=\"map-row\">\n <label class=\"f-field\">\n <span class=\"f-label\">New name</span>\n <input class=\"f-control\" [value]=\"r.item.alias\"\n (input)=\"updateItem(r.index, { alias: inputValue($event) })\">\n </label>\n <div class=\"f-field\">\n <span class=\"f-label\">From path</span>\n <button type=\"button\" class=\"f-control f-picker\" [matMenuTriggerFor]=\"pathMenu\">\n <span class=\"f-picker-text\" [class.f-placeholder]=\"!r.item.path\">{{ r.item.path || 'Select a path' }}</span>\n <mat-icon>account_tree</mat-icon>\n </button>\n <mat-menu #pathMenu=\"matMenu\" class=\"path-menu\">\n @for (p of availableDeepPaths(); track p.path) {\n <button mat-menu-item class=\"path-item\" [style.padding-left.px]=\"12 + p.depth * 14\"\n (click)=\"updateItem(r.index, { path: p.path })\">\n <mat-icon class=\"path-icon\">{{ p.leaf ? 'chevron_right' : 'folder_open' }}</mat-icon>\n <span>{{ p.name }}</span>\n </button>\n } @empty {\n <button mat-menu-item disabled>No paths detected</button>\n }\n </mat-menu>\n </div>\n <button mat-icon-button class=\"q-remove\" (click)=\"removeItem(r.index)\"\n matTooltip=\"Remove\"><mat-icon>close</mat-icon></button>\n </div>\n }\n @for (l of literalItems(); track l.index) {\n <div class=\"map-row\">\n <label class=\"f-field\">\n <span class=\"f-label\">Field name</span>\n <input class=\"f-control\" [value]=\"l.item.alias\"\n (input)=\"updateItem(l.index, { alias: inputValue($event) })\">\n </label>\n <label class=\"f-field\">\n <span class=\"f-label\">Constant</span>\n <input class=\"f-control\" [value]=\"l.item.value\" placeholder='\"api\", 1, true'\n (input)=\"updateItem(l.index, { value: inputValue($event) })\">\n </label>\n <button mat-icon-button class=\"q-remove\" (click)=\"removeItem(l.index)\"\n matTooltip=\"Remove\"><mat-icon>close</mat-icon></button>\n </div>\n }\n }\n }\n\n @case ('sort') {\n @if (sort(); as s) {\n @for (key of s.keys; track $index) {\n <div class=\"q-item\">\n <div class=\"q-pair q-pair-sort\">\n <label class=\"f-field\">\n <span class=\"f-label\">Sort by</span>\n <select class=\"f-control\" [value]=\"key.field\"\n (change)=\"updateSortKey($index, { field: inputValue($event) })\">\n @for (f of fieldOptionsWith(key.field); track f) { <option [value]=\"f\">{{ f }}</option> }\n </select>\n </label>\n <mat-button-toggle-group class=\"seg seg-dir\" [value]=\"key.dir\" hideSingleSelectionIndicator\n (change)=\"updateSortKey($index, { dir: $event.value })\">\n <mat-button-toggle value=\"asc\" matTooltip=\"Ascending\"><mat-icon>arrow_upward</mat-icon></mat-button-toggle>\n <mat-button-toggle value=\"desc\" matTooltip=\"Descending\"><mat-icon>arrow_downward</mat-icon></mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <button mat-icon-button class=\"q-remove\" (click)=\"removeSortKey($index)\"\n matTooltip=\"Remove\"><mat-icon>close</mat-icon></button>\n </div>\n }\n <button type=\"button\" class=\"link-btn\" (click)=\"addSortKey()\">\n <mat-icon>add</mat-icon> Add sort key\n </button>\n }\n }\n\n @case ('slice') {\n @if (slice(); as sl) {\n <div class=\"field-grid\">\n <label class=\"f-field\">\n <span class=\"f-label\">Take</span>\n <select class=\"f-control\" [value]=\"sl.mode\" (change)=\"setSliceMode(inputValue($event))\">\n @for (mode of sliceModes; track mode.value) { <option [value]=\"mode.value\">{{ mode.label }}</option> }\n </select>\n </label>\n @switch (sl.mode) {\n @case ('range') {\n <label class=\"f-field\"><span class=\"f-label\">Start</span>\n <input class=\"f-control\" type=\"number\" [value]=\"sl.a\" (input)=\"setSliceA($event)\"></label>\n <label class=\"f-field\"><span class=\"f-label\">End</span>\n <input class=\"f-control\" type=\"number\" [value]=\"sl.b\" (input)=\"setSliceB($event)\"></label>\n }\n @case ('fromCount') {\n <label class=\"f-field\"><span class=\"f-label\">From index</span>\n <input class=\"f-control\" type=\"number\" [value]=\"sl.a\" (input)=\"setSliceA($event)\"></label>\n <label class=\"f-field\"><span class=\"f-label\">Count</span>\n <input class=\"f-control\" type=\"number\" [value]=\"sl.b\" (input)=\"setSliceB($event)\"></label>\n }\n @default {\n <label class=\"f-field\"><span class=\"f-label\">How many</span>\n <input class=\"f-control\" type=\"number\" [value]=\"sl.b\" (input)=\"setSliceB($event)\"></label>\n }\n }\n </div>\n }\n }\n\n @case ('keys') {\n @if (keysModel(); as k) {\n <span class=\"field-label\">\n @if (isUnique(fn.function)) { Unique by — none = whole row } @else { Group by }\n </span>\n <div class=\"checklist\">\n @for (f of availableFields(); track f) {\n <mat-checkbox [checked]=\"keyPicked(f)\" (change)=\"toggleKey(f)\">{{ f }}</mat-checkbox>\n }\n </div>\n @if (availableFields().length === 0) {\n <p class=\"hint-line\"><mat-icon class=\"info-icon\">info</mat-icon>\n <span>No fields detected — use Advanced to type a key path.</span></p>\n }\n }\n }\n\n @case ('flatten') {\n @if (flatten(); as fl) {\n <label class=\"f-field full\">\n <span class=\"f-label\">Flatten</span>\n <select class=\"f-control\" [value]=\"fl.path\" (change)=\"setFlatten(inputValue($event))\">\n <option [value]=\"''\">nested arrays (one level)</option>\n @for (f of fieldOptionsWith(fl.path); track f) { <option [value]=\"f\">items in {{ f }}</option> }\n </select>\n </label>\n <p class=\"sub-hint\">Blank flattens one level; a field flat-maps that child array.</p>\n }\n }\n\n @case ('reduce') {\n @if (reduce(); as red) {\n @for (agg of red.aggs; track $index) {\n <div class=\"q-item\">\n <div class=\"q-stack\">\n @if (red.aggs.length > 1) {\n <label class=\"f-field\">\n <span class=\"f-label\">Output name</span>\n <input class=\"f-control\" [value]=\"agg.alias\"\n (input)=\"updateAgg($index, { alias: inputValue($event) })\">\n </label>\n }\n <div class=\"q-pair\">\n <label class=\"f-field\">\n <span class=\"f-label\">Aggregate</span>\n <select class=\"f-control\" [value]=\"agg.agg\"\n (change)=\"updateAgg($index, { agg: inputValue($event) })\">\n @for (a of aggregates; track a.value) { <option [value]=\"a.value\">{{ a.label }}</option> }\n </select>\n </label>\n @if (aggNeedsField(agg.agg)) {\n <label class=\"f-field\">\n <span class=\"f-label\">Field</span>\n <select class=\"f-control\" [value]=\"agg.field\"\n (change)=\"updateAgg($index, { field: inputValue($event) })\">\n @for (f of fieldOptionsWith(agg.field); track f) { <option [value]=\"f\">{{ f }}</option> }\n </select>\n </label>\n }\n </div>\n </div>\n <button mat-icon-button class=\"q-remove\" (click)=\"removeAgg($index)\"\n matTooltip=\"Remove\"><mat-icon>close</mat-icon></button>\n </div>\n }\n <button type=\"button\" class=\"link-btn\" (click)=\"addAgg()\">\n <mat-icon>add</mat-icon> Add aggregate\n </button>\n }\n }\n }\n }\n\n <div class=\"editor-foot\">\n <button type=\"button\" class=\"link-btn\" (click)=\"toggleRaw()\">\n @if (rawMode()) { <mat-icon>view_module</mat-icon> Guided }\n @else { <mat-icon>code</mat-icon> Advanced }\n </button>\n </div>\n }\n\n <div class=\"editor-actions\">\n <button mat-icon-button (click)=\"moveStep(fn.id, -1)\" matTooltip=\"Move earlier\"\n aria-label=\"Move step earlier\"><mat-icon>chevron_left</mat-icon></button>\n <button mat-icon-button (click)=\"moveStep(fn.id, 1)\" matTooltip=\"Move later\"\n aria-label=\"Move step later\"><mat-icon>chevron_right</mat-icon></button>\n <button mat-icon-button (click)=\"removeFunction(fn.id)\" matTooltip=\"Remove step\"\n aria-label=\"Remove step\"><mat-icon>delete_outline</mat-icon></button>\n <span class=\"spacer\"></span>\n <button mat-flat-button color=\"primary\" (click)=\"saveNodeInEdit()\">\n <mat-icon>check</mat-icon> Apply\n </button>\n </div>\n </section>\n }\n } @else {\n <p class=\"hint-line\">\n <mat-icon class=\"info-icon\">data_array</mat-icon>\n <span>Click an array (<mat-icon class=\"inline-icon\">data_array</mat-icon>) in the path above to add steps.</span>\n </p>\n }\n }\n </div>\n </mat-expansion-panel>\n\n <!-- 3 - Preview -->\n <mat-expansion-panel expanded>\n <mat-expansion-panel-header>\n <mat-panel-title>\n <mat-icon class=\"title-icon\">preview</mat-icon>\n <span class=\"panel-title\">3 · Result preview</span>\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <div class=\"content\">\n @if (resultRowCount(); as n) {\n <span class=\"result-count\"><mat-icon>check_circle</mat-icon> {{ n }} {{ n === 1 ? 'result' : 'results' }}</span>\n }\n <div class=\"mapped-value\">\n <pre>{{ mappedValue | json }}</pre>\n </div>\n </div>\n </mat-expansion-panel>\n</mat-accordion>\n", styles: ["@charset \"UTF-8\";:host{display:block}.surface mat-expansion-panel{background:var(--mat-sys-surface-container-low, var(--lib-forms-surface-container-low))}:host ::ng-deep .mat-expansion-panel-header{height:44px;padding:0 .875rem}:host ::ng-deep .mat-expansion-panel-body{padding:0 .875rem .75rem}button mat-icon{vertical-align:middle}.panel-title{font-size:.875rem;font-weight:500;letter-spacing:-.01em}.title-icon{margin-right:.625rem;vertical-align:middle;color:var(--lib-forms-on-surface-variant)}.content{display:flex;flex-direction:column;gap:.875rem;padding:.5rem 0 .25rem}.hint-line{display:flex;align-items:center;gap:.5rem;margin:0;font-size:.8125rem;color:var(--lib-forms-on-surface-variant)}.info-icon{color:var(--sem-info, var(--lib-forms-primary));flex:none}.inline-icon{font-size:1rem;width:1rem;height:1rem;vertical-align:text-bottom}.field-label{font-size:.625rem;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--lib-forms-on-surface-variant)}.muted{font-size:.8125rem;color:var(--lib-forms-on-surface-variant)}.data-tree{background:var(--lib-forms-surface-container-low);border-radius:var(--lib-forms-radius-md);padding:.5rem .75rem;min-width:fit-content}:host mat-tree-node{min-height:34px}.node-spacer{display:inline-block;width:36px}.node-toggle{color:var(--lib-forms-on-surface-variant)}.node-checkbox{width:100%}.node-key{font-weight:500;color:var(--lib-forms-on-surface);margin-right:.5rem}.node-value{font-family:var(--lib-forms-font-mono, monospace);padding:.0625rem .4375rem;background:var(--lib-forms-surface-container);border-radius:var(--lib-forms-radius-sm);font-size:.8125rem;white-space:nowrap}.breadcrumb{display:flex;align-items:center;flex-wrap:wrap;gap:.125rem}.crumb{display:inline-flex;align-items:center;gap:.25rem;height:1.75rem;max-width:9rem;padding:0 .5rem;font:inherit;font-size:.8125rem;font-weight:500;color:var(--lib-forms-on-surface-variant);background:transparent;border:0;border-radius:var(--lib-forms-radius-pill);cursor:pointer;white-space:nowrap;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),color var(--lib-forms-duration-hover) var(--lib-forms-easing)}.crumb:hover:not(:disabled){background:var(--lib-forms-surface-container-high)}.crumb:disabled{cursor:default;opacity:.65}.crumb mat-icon{flex:none;font-size:1.0625rem;width:1.0625rem;height:1.0625rem}.crumb-text{overflow:hidden;text-overflow:ellipsis}.crumb-array{color:var(--lib-forms-primary)}.crumb-active,.crumb-active:hover:not(:disabled){background:var(--lib-forms-primary-container);color:var(--lib-forms-on-surface)}.crumb-badge{min-width:1.0625rem;padding:0 .3125rem;border-radius:var(--lib-forms-radius-pill);background:var(--lib-forms-primary);color:var(--mat-sys-on-primary, #fff);font-size:.625rem;line-height:1.0625rem;text-align:center}.crumb-sep{color:var(--lib-forms-outline);font-size:1rem;width:1rem;height:1rem}.pipeline{display:flex;align-items:stretch;flex-wrap:wrap;gap:.375rem}.stage{display:inline-flex;flex-direction:column;align-items:center;justify-content:center;gap:.0625rem;min-width:4rem;padding:.375rem .5rem;border:1px solid var(--lib-forms-outline-variant);border-radius:var(--lib-forms-radius-md);background:var(--lib-forms-surface-container-low);color:var(--lib-forms-on-surface);cursor:pointer;transition:border-color var(--lib-forms-duration-hover) var(--lib-forms-easing),background-color var(--lib-forms-duration-hover) var(--lib-forms-easing)}.stage mat-icon{font-size:1.125rem;width:1.125rem;height:1.125rem}.stage-source{cursor:default;color:var(--lib-forms-on-surface-variant);background:transparent;border-style:dashed}.stage-active{border-color:var(--lib-forms-primary);background:var(--lib-forms-primary-container)}.stage-empty{border-style:dashed;color:var(--lib-forms-on-surface-variant)}.stage-add{border-style:dashed;color:var(--lib-forms-primary);min-width:3.75rem}.stage-label{font-size:.75rem;font-weight:500}.stage-count{font-size:.625rem;color:var(--lib-forms-on-surface-variant)}.flow-arrow{align-self:center;color:var(--lib-forms-outline);font-size:1.125rem;width:1rem;height:1.125rem}.menu-hint{display:block;font-size:.6875rem;color:var(--lib-forms-on-surface-variant)}.editor{display:flex;flex-direction:column;gap:.75rem;padding:1.125rem;border-radius:var(--lib-forms-radius-lg);background:var(--lib-forms-surface-container-low);box-shadow:var(--mat-sys-level1, 0 1px 3px rgba(0, 0, 0, .12))}.full{width:100%}.f-field{display:flex;flex-direction:column;gap:.1875rem;min-width:0}.f-label{font-size:.625rem;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--lib-forms-on-surface-variant)}.f-control{box-sizing:border-box;width:100%;min-width:0;height:2rem;padding:.3125rem .5rem;font-family:inherit;font-size:.8125rem;line-height:1.25;color:var(--lib-forms-on-surface);background:var(--lib-forms-surface-container-lowest);border:1px solid var(--lib-forms-outline-variant);border-radius:var(--lib-forms-radius-sm);transition:border-color var(--lib-forms-duration-hover) var(--lib-forms-easing)}select.f-control{cursor:pointer}.f-textarea{height:auto;min-height:3rem;line-height:1.4;resize:vertical}.f-control:hover{border-color:var(--lib-forms-outline)}.f-control:focus{outline:none;border-color:var(--lib-forms-primary);box-shadow:0 0 0 1px var(--lib-forms-primary)}.sub-hint{margin:-.25rem 0 0;font-size:.75rem;color:var(--lib-forms-on-surface-variant)}.section-head{display:flex;align-items:center;justify-content:space-between;gap:.5rem;margin-top:.25rem}.section-actions{display:flex;gap:.25rem}.map-row{display:grid;grid-template-columns:1fr 1fr auto;align-items:end;gap:.5rem;padding:.5rem .5rem .5rem .625rem;background:var(--lib-forms-surface-container);border-radius:var(--lib-forms-radius-sm)}.q-item{display:grid;grid-template-columns:1fr auto;align-items:center;gap:.25rem;padding:.5rem .5rem .5rem .625rem;background:var(--lib-forms-surface-container);border-radius:var(--lib-forms-radius-sm)}.q-stack{display:flex;flex-direction:column;gap:.5rem;min-width:0}.q-pair{display:grid;grid-template-columns:1fr 1fr;gap:.5rem;min-width:0}.q-pair-op{grid-template-columns:8rem 1fr}.q-pair-sort{grid-template-columns:1fr auto;align-items:end}.q-remove{color:var(--lib-forms-on-surface-variant)}.field-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(6.5rem,1fr));gap:.5rem}.match-row{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.seg{--mat-standard-button-toggle-height: 34px;height:34px}.checklist{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.125rem 1rem;padding:.25rem 0}.link-btn{display:inline-flex;align-items:center;align-self:flex-start;gap:.25rem;height:1.75rem;padding:0 .5rem;font:inherit;font-size:.8125rem;font-weight:500;color:var(--lib-forms-primary);background:transparent;border:0;border-radius:var(--lib-forms-radius-sm);cursor:pointer;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing)}.link-btn:hover{background:var(--lib-forms-primary-container)}.link-btn mat-icon{flex:none;font-size:1.0625rem;width:1.0625rem;height:1.0625rem}.f-picker{display:flex;align-items:center;justify-content:space-between;gap:.25rem;text-align:left;cursor:pointer}.f-picker-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.f-placeholder{color:var(--lib-forms-on-surface-variant)}.f-picker mat-icon{flex:none;font-size:1.0625rem;width:1.0625rem;height:1.0625rem;color:var(--lib-forms-on-surface-variant)}.path-icon{margin-right:.25rem;font-size:1rem;width:1rem;height:1rem;color:var(--lib-forms-on-surface-variant)}.editor-foot{display:flex;justify-content:flex-end;margin-top:-.25rem}.editor-actions{display:flex;align-items:center;gap:.125rem;padding-top:.5rem}.spacer{flex:1}.suggestions{display:flex;gap:1rem;flex-wrap:wrap;padding:.75rem;border-radius:var(--lib-forms-radius-md);background:var(--sem-info-surface, var(--lib-forms-surface-container))}.suggestion-group{flex:1 1 10rem;display:flex;flex-direction:column;gap:.375rem}.chip-row{display:flex;flex-wrap:wrap;gap:.25rem}.ins-chip{font-size:.75rem}.result-count{display:inline-flex;align-items:center;gap:.375rem;font-size:.8125rem;font-weight:500;color:var(--sem-emerald, var(--lib-forms-method-get))}.result-count mat-icon{font-size:1.125rem;width:1.125rem;height:1.125rem}.mapped-value{padding:1rem 1.25rem;background:var(--lib-forms-on-surface);color:var(--lib-forms-surface);border-radius:var(--lib-forms-radius-md);overflow:auto}.mapped-value pre{margin:0;font-family:var(--lib-forms-font-mono, monospace);font-size:.8125rem}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i1$2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "directive", type: i3$5.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i3$5.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i3$4.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "directive", type: i5$3.MatAccordion, selector: "mat-accordion", inputs: ["hideToggle", "displayMode", "togglePosition"], exportAs: ["matAccordion"] }, { kind: "component", type: i5$3.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i5$3.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i5$3.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i6.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i6.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i6.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatTreeModule }, { kind: "directive", type: i1$4.MatTreeNodeDef, selector: "[matTreeNodeDef]", inputs: ["matTreeNodeDefWhen", "matTreeNode"] }, { kind: "directive", type: i1$4.MatTreeNodePadding, selector: "[matTreeNodePadding]", inputs: ["matTreeNodePadding", "matTreeNodePaddingIndent"] }, { kind: "directive", type: i1$4.MatTreeNodeToggle, selector: "[matTreeNodeToggle]", inputs: ["matTreeNodeToggleRecursive"] }, { kind: "component", type: i1$4.MatTree, selector: "mat-tree", exportAs: ["matTree"] }, { kind: "directive", type: i1$4.MatTreeNode, selector: "mat-tree-node", inputs: ["tabIndex", "disabled"], outputs: ["activation", "expandedChange"], exportAs: ["matTreeNode"] }, { kind: "pipe", type: JsonPipe, name: "json" }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
18566
19099
|
}
|
|
18567
19100
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: DataTreeComponent, decorators: [{
|
|
18568
19101
|
type: Component,
|
|
@@ -19049,7 +19582,7 @@ class ApiValueAccessRulesComponent {
|
|
|
19049
19582
|
}
|
|
19050
19583
|
}
|
|
19051
19584
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: ApiValueAccessRulesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
19052
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: ApiValueAccessRulesComponent, isStandalone: true, selector: "lib-api-value-access-rules", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, multipleBind: { classPropertyName: "multipleBind", publicName: "multipleBind", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, formInputs: { classPropertyName: "formInputs", publicName: "formInputs", isSignal: true, isRequired: false, transformFunction: null }, mapToData: { classPropertyName: "mapToData", publicName: "mapToData", isSignal: true, isRequired: false, transformFunction: null }, postmanCollectionConfig: { classPropertyName: "postmanCollectionConfig", publicName: "postmanCollectionConfig", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChanged: "valueChanged", reload: "reload" }, host: { classAttribute: "lib-api-value-access-rules" }, ngImport: i0, template: "@if (hasErrors()) {\n <lib-error-list [errors]=\"errors()\" />\n}\n\n<div class=\"mode-toggle\">\n <mat-button-toggle-group name=\"valueAccessMode\" aria-label=\"Value access mode\" [value]=\"viewMode()\">\n <mat-button-toggle (click)=\"setViewMode('map')\" [checked]=\"viewMode() === 'map'\" value=\"map\">\n Value Mapping\n </mat-button-toggle>\n <mat-button-toggle (click)=\"setViewMode('sync')\" [checked]=\"viewMode() === 'sync'\" value=\"sync\">\n Data Sync\n </mat-button-toggle>\n </mat-button-toggle-group>\n</div>\n\n@if (error(); as err) {\n <lib-empty-state icon=\"error_outline\"\n [message]=\"err.error || err.message || 'Failed to load the collection.'\" />\n}\n\n@switch (viewMode()) {\n @case ('sync') {\n @if (parsedRequestBody(); as body) {\n <lib-json-editor (valueChange)=\"requestBodyChanged($event)\" [value]=\"body\" />\n } @else {\n <lib-empty-state icon=\"data_object\"\n message=\"No request body found in the selected API request.\" />\n }\n\n <div class=\"run-bar\">\n <p class=\"run-bar__hint\">Run the API call with the body above to load a live response.</p>\n <span class=\"run-bar__spacer\"></span>\n <button mat-stroked-button type=\"button\" [disabled]=\"loading()\" (click)=\"runApiCall()\"\n [attr.aria-busy]=\"loading()\" aria-label=\"Run API call\">\n @if (loading()) {\n <mat-spinner diameter=\"16\" />\n } @else {\n <mat-icon>play_arrow</mat-icon>\n }\n <span>{{ loading() ? 'Running API\u2026' : 'Run API Call' }}</span>\n </button>\n </div>\n }\n\n @case ('map') {\n @if (multipleBind(); as controls) {\n @for (controlName of controls; track controlName) {\n <section class=\"mapping-section\">\n <label class=\"mapping-section__label\" [attr.for]=\"controlName\">\n Map <strong>{{ controlName }}</strong>\n </label>\n <lib-data-tree [formInputs]=\"formInputs()\" [data]=\"treeData()\"\n [value]=\"keyedValueFor(controlName)\"\n (pathChanged)=\"pathChanged($event, controlName)\" />\n </section>\n }\n } @else {\n <lib-data-tree [formInputs]=\"formInputs()\" [data]=\"treeData()\" [value]=\"singleValue()\"\n (pathChanged)=\"pathChanged($event)\" />\n }\n }\n}\n\n<!-- CDK overlay shown while disabled -->\n<ng-template cdkConnectedOverlay [cdkConnectedOverlayOpen]=\"disabled()\">\n <div class=\"disabled-overlay\" aria-hidden=\"true\"></div>\n</ng-template>\n", styles: [":host{display:block;position:relative}.mode-toggle{display:flex;justify-content:center;margin-bottom:1rem}.run-bar{display:flex;align-items:center;gap:1rem;flex-wrap:wrap;margin-top:1.5rem;padding:1rem 1.25rem;background:var(--lib-forms-surface);border:1px solid color-mix(in srgb,var(--lib-forms-outline) 15%,transparent);border-radius:var(--lib-forms-radius-lg, 12px);box-shadow:var(--lib-forms-shadow-resting)}.run-bar__hint{margin:0;font-size:.8125rem;line-height:1.4;color:var(--lib-forms-on-surface-variant)}.run-bar__spacer{flex:1 1 auto}.mapping-section{margin-bottom:1.5rem}.mapping-section__label{display:block;margin-bottom:.75rem;font-size:.875rem;color:var(--lib-forms-on-surface)}.disabled-overlay{position:absolute;inset:0;background:color-mix(in srgb,var(--lib-forms-on-surface) 30%,transparent);border-radius:var(--lib-forms-radius-lg, 12px);z-index:10}\n"], dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i2$
|
|
19585
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: ApiValueAccessRulesComponent, isStandalone: true, selector: "lib-api-value-access-rules", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, multipleBind: { classPropertyName: "multipleBind", publicName: "multipleBind", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, formInputs: { classPropertyName: "formInputs", publicName: "formInputs", isSignal: true, isRequired: false, transformFunction: null }, mapToData: { classPropertyName: "mapToData", publicName: "mapToData", isSignal: true, isRequired: false, transformFunction: null }, postmanCollectionConfig: { classPropertyName: "postmanCollectionConfig", publicName: "postmanCollectionConfig", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChanged: "valueChanged", reload: "reload" }, host: { classAttribute: "lib-api-value-access-rules" }, ngImport: i0, template: "@if (hasErrors()) {\n <lib-error-list [errors]=\"errors()\" />\n}\n\n<div class=\"mode-toggle\">\n <mat-button-toggle-group name=\"valueAccessMode\" aria-label=\"Value access mode\" [value]=\"viewMode()\">\n <mat-button-toggle (click)=\"setViewMode('map')\" [checked]=\"viewMode() === 'map'\" value=\"map\">\n Value Mapping\n </mat-button-toggle>\n <mat-button-toggle (click)=\"setViewMode('sync')\" [checked]=\"viewMode() === 'sync'\" value=\"sync\">\n Data Sync\n </mat-button-toggle>\n </mat-button-toggle-group>\n</div>\n\n@if (error(); as err) {\n <lib-empty-state icon=\"error_outline\"\n [message]=\"err.error || err.message || 'Failed to load the collection.'\" />\n}\n\n@switch (viewMode()) {\n @case ('sync') {\n @if (parsedRequestBody(); as body) {\n <lib-json-editor (valueChange)=\"requestBodyChanged($event)\" [value]=\"body\" />\n } @else {\n <lib-empty-state icon=\"data_object\"\n message=\"No request body found in the selected API request.\" />\n }\n\n <div class=\"run-bar\">\n <p class=\"run-bar__hint\">Run the API call with the body above to load a live response.</p>\n <span class=\"run-bar__spacer\"></span>\n <button mat-stroked-button type=\"button\" [disabled]=\"loading()\" (click)=\"runApiCall()\"\n [attr.aria-busy]=\"loading()\" aria-label=\"Run API call\">\n @if (loading()) {\n <mat-spinner diameter=\"16\" />\n } @else {\n <mat-icon>play_arrow</mat-icon>\n }\n <span>{{ loading() ? 'Running API\u2026' : 'Run API Call' }}</span>\n </button>\n </div>\n }\n\n @case ('map') {\n @if (multipleBind(); as controls) {\n @for (controlName of controls; track controlName) {\n <section class=\"mapping-section\">\n <label class=\"mapping-section__label\" [attr.for]=\"controlName\">\n Map <strong>{{ controlName }}</strong>\n </label>\n <lib-data-tree [formInputs]=\"formInputs()\" [data]=\"treeData()\"\n [value]=\"keyedValueFor(controlName)\"\n (pathChanged)=\"pathChanged($event, controlName)\" />\n </section>\n }\n } @else {\n <lib-data-tree [formInputs]=\"formInputs()\" [data]=\"treeData()\" [value]=\"singleValue()\"\n (pathChanged)=\"pathChanged($event)\" />\n }\n }\n}\n\n<!-- CDK overlay shown while disabled -->\n<ng-template cdkConnectedOverlay [cdkConnectedOverlayOpen]=\"disabled()\">\n <div class=\"disabled-overlay\" aria-hidden=\"true\"></div>\n</ng-template>\n", styles: [":host{display:block;position:relative}.mode-toggle{display:flex;justify-content:center;margin-bottom:1rem}.run-bar{display:flex;align-items:center;gap:1rem;flex-wrap:wrap;margin-top:1.5rem;padding:1rem 1.25rem;background:var(--lib-forms-surface);border:1px solid color-mix(in srgb,var(--lib-forms-outline) 15%,transparent);border-radius:var(--lib-forms-radius-lg, 12px);box-shadow:var(--lib-forms-shadow-resting)}.run-bar__hint{margin:0;font-size:.8125rem;line-height:1.4;color:var(--lib-forms-on-surface-variant)}.run-bar__spacer{flex:1 1 auto}.mapping-section{margin-bottom:1.5rem}.mapping-section__label{display:block;margin-bottom:.75rem;font-size:.875rem;color:var(--lib-forms-on-surface)}.disabled-overlay{position:absolute;inset:0;background:color-mix(in srgb,var(--lib-forms-on-surface) 30%,transparent);border-radius:var(--lib-forms-radius-lg, 12px);z-index:10}\n"], dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i2$2.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "directive", type: i3$5.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i3$5.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i3$2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: DataTreeComponent, selector: "lib-data-tree", inputs: ["data", "value", "formInputs"], outputs: ["pathChanged"] }, { kind: "component", type: JsonEditorComponent, selector: "lib-json-editor", inputs: ["value", "height", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: EmptyStateComponent, selector: "lib-empty-state", inputs: ["icon", "message"] }, { kind: "component", type: ErrorListComponent, selector: "lib-error-list", inputs: ["errors"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
19053
19586
|
}
|
|
19054
19587
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: ApiValueAccessRulesComponent, decorators: [{
|
|
19055
19588
|
type: Component,
|
|
@@ -19071,6 +19604,165 @@ var apiValueAccessRules_component = /*#__PURE__*/Object.freeze({
|
|
|
19071
19604
|
ApiValueAccessRulesComponent: ApiValueAccessRulesComponent
|
|
19072
19605
|
});
|
|
19073
19606
|
|
|
19607
|
+
/** Canonical operator value keyed by its lower-cased spelling (for parse normalisation). */
|
|
19608
|
+
const OPERATOR_BY_KEY = new Map(PREDICATE_OPERATORS.map((op) => [op.value.toLowerCase(), op.value]));
|
|
19609
|
+
/** Symbolic operators, longest-match first so `===` wins over `==`. */
|
|
19610
|
+
const SYMBOLIC_OPS = ['===', '!==', '>=', '<=', '==', '!=', '>', '<'];
|
|
19611
|
+
/** Keyword operators (matched case-insensitively, surrounded by whitespace). */
|
|
19612
|
+
const KEYWORD_OPS = ['includes', 'startsWith', 'endsWith', 'matches', 'in'];
|
|
19613
|
+
/** An empty condition seeded with the given field and a sensible default operator. */
|
|
19614
|
+
function emptyCondition(field = '') {
|
|
19615
|
+
return { field, operator: '===', compareTo: 'value', value: '' };
|
|
19616
|
+
}
|
|
19617
|
+
const isBareLiteral = (v) => v === 'true' || v === 'false' || v === 'null' || (v.trim() !== '' && !Number.isNaN(Number(v)));
|
|
19618
|
+
const isQuoted = (v) => {
|
|
19619
|
+
const t = v.trim();
|
|
19620
|
+
if (t.length < 2)
|
|
19621
|
+
return false;
|
|
19622
|
+
const a = t[0];
|
|
19623
|
+
const b = t[t.length - 1];
|
|
19624
|
+
return (a === '"' && b === '"') || (a === "'" && b === "'");
|
|
19625
|
+
};
|
|
19626
|
+
const unquote = (v) => (isQuoted(v) ? v.trim().slice(1, -1) : v.trim());
|
|
19627
|
+
/** Formats a literal: bare for numbers/booleans/null, otherwise a quoted, escaped string. */
|
|
19628
|
+
function formatLiteral(value) {
|
|
19629
|
+
const t = value.trim();
|
|
19630
|
+
if (t === '')
|
|
19631
|
+
return '""';
|
|
19632
|
+
if (isBareLiteral(t))
|
|
19633
|
+
return t;
|
|
19634
|
+
return `"${t.replace(/"/g, '\\"')}"`;
|
|
19635
|
+
}
|
|
19636
|
+
/** The expression token for a condition's right operand. */
|
|
19637
|
+
function rightToken(condition) {
|
|
19638
|
+
return condition.compareTo === 'field' ? condition.value.trim() : formatLiteral(condition.value);
|
|
19639
|
+
}
|
|
19640
|
+
/** Whether a condition is complete enough to contribute to the expression. */
|
|
19641
|
+
function isComplete(condition) {
|
|
19642
|
+
if (condition.field.trim() === '')
|
|
19643
|
+
return false;
|
|
19644
|
+
if (condition.compareTo === 'field')
|
|
19645
|
+
return condition.value.trim() !== '';
|
|
19646
|
+
return true;
|
|
19647
|
+
}
|
|
19648
|
+
/**
|
|
19649
|
+
* Serialises a condition group into a predicate expression string. Incomplete
|
|
19650
|
+
* conditions are dropped, so an empty/half-built group yields `''` (which the
|
|
19651
|
+
* editor treats as "nothing to save yet").
|
|
19652
|
+
*/
|
|
19653
|
+
function serializeConditions(group) {
|
|
19654
|
+
return group.conditions
|
|
19655
|
+
.filter(isComplete)
|
|
19656
|
+
.map((c) => `${c.field.trim()} ${c.operator} ${rightToken(c)}`)
|
|
19657
|
+
.join(` ${group.connector} `);
|
|
19658
|
+
}
|
|
19659
|
+
/** Resolves a raw operator spelling to its canonical {@link PREDICATE_OPERATORS} value, or `null`. */
|
|
19660
|
+
function canonicalOperator(raw) {
|
|
19661
|
+
return OPERATOR_BY_KEY.get(raw.toLowerCase()) ?? null;
|
|
19662
|
+
}
|
|
19663
|
+
/** Classifies a raw right-hand operand as a field reference or a literal value. */
|
|
19664
|
+
function classifyRight(raw, fieldNames) {
|
|
19665
|
+
const t = raw.trim();
|
|
19666
|
+
if (isQuoted(t))
|
|
19667
|
+
return { compareTo: 'value', value: unquote(t) };
|
|
19668
|
+
if (fieldNames.has(t))
|
|
19669
|
+
return { compareTo: 'field', value: t };
|
|
19670
|
+
return { compareTo: 'value', value: t };
|
|
19671
|
+
}
|
|
19672
|
+
/** Parses a single `left op right` comparison, or `null` if it is not representable. */
|
|
19673
|
+
function parseCondition(part, fieldNames) {
|
|
19674
|
+
const p = part.trim();
|
|
19675
|
+
for (const op of SYMBOLIC_OPS) {
|
|
19676
|
+
const idx = p.indexOf(op);
|
|
19677
|
+
if (idx > 0) {
|
|
19678
|
+
const operator = canonicalOperator(op);
|
|
19679
|
+
if (!operator)
|
|
19680
|
+
return null;
|
|
19681
|
+
const field = p.slice(0, idx).trim();
|
|
19682
|
+
const right = p.slice(idx + op.length).trim();
|
|
19683
|
+
if (field === '' || right === '')
|
|
19684
|
+
return null;
|
|
19685
|
+
return { field, operator, ...classifyRight(right, fieldNames) };
|
|
19686
|
+
}
|
|
19687
|
+
}
|
|
19688
|
+
for (const kw of KEYWORD_OPS) {
|
|
19689
|
+
const m = p.match(new RegExp(`^(.+?)\\s+${kw}\\s+(.+)$`, 'i'));
|
|
19690
|
+
if (m && m[1] && m[2]) {
|
|
19691
|
+
const operator = canonicalOperator(kw);
|
|
19692
|
+
if (!operator)
|
|
19693
|
+
return null;
|
|
19694
|
+
return { field: m[1].trim(), operator, ...classifyRight(m[2], fieldNames) };
|
|
19695
|
+
}
|
|
19696
|
+
}
|
|
19697
|
+
return null;
|
|
19698
|
+
}
|
|
19699
|
+
/**
|
|
19700
|
+
* Best-effort parse of an expression into a guided condition group. Returns
|
|
19701
|
+
* `null` (→ raw editor) for anything the builder cannot represent losslessly:
|
|
19702
|
+
* grouping `()`, mixed `&&`/`||`, unary `!`, or an unknown operator.
|
|
19703
|
+
*/
|
|
19704
|
+
function parseConditions(expression, fieldNames) {
|
|
19705
|
+
const e = expression.trim();
|
|
19706
|
+
if (e === '')
|
|
19707
|
+
return { connector: '&&', conditions: [] };
|
|
19708
|
+
if (/[()]/.test(e))
|
|
19709
|
+
return null; // grouping → raw
|
|
19710
|
+
if (/!(?!=)/.test(e))
|
|
19711
|
+
return null; // unary negation (`!field`) → raw
|
|
19712
|
+
const hasAnd = e.includes('&&');
|
|
19713
|
+
const hasOr = e.includes('||');
|
|
19714
|
+
if (hasAnd && hasOr)
|
|
19715
|
+
return null; // mixed connectors → raw
|
|
19716
|
+
const connector = hasOr ? '||' : '&&';
|
|
19717
|
+
const parts = hasOr ? e.split('||') : hasAnd ? e.split('&&') : [e];
|
|
19718
|
+
const conditions = [];
|
|
19719
|
+
for (const part of parts) {
|
|
19720
|
+
const condition = parseCondition(part, fieldNames);
|
|
19721
|
+
if (!condition)
|
|
19722
|
+
return null;
|
|
19723
|
+
conditions.push(condition);
|
|
19724
|
+
}
|
|
19725
|
+
return { connector, conditions };
|
|
19726
|
+
}
|
|
19727
|
+
/** Returns the unique identifier tokens referenced in an expression. */
|
|
19728
|
+
function referencedTokens(expression) {
|
|
19729
|
+
return new Set(expression.match(/[A-Za-z_][A-Za-z0-9_]*/g) ?? []);
|
|
19730
|
+
}
|
|
19731
|
+
/**
|
|
19732
|
+
* Derives the `inputsObservedForChanges` dependency list from an expression by
|
|
19733
|
+
* matching identifier tokens against the editor's resolved {@link FieldBinding}s.
|
|
19734
|
+
* Works for both guided and raw expressions, so observed inputs always reflect
|
|
19735
|
+
* what the expression actually references — no manual add/remove, no orphans.
|
|
19736
|
+
*
|
|
19737
|
+
* When an aggregate has been chosen for a field (only possible for a
|
|
19738
|
+
* multiple-input column), the binding carries `parentInputId` + `function` so
|
|
19739
|
+
* the engine reduces its row array to a scalar. Otherwise it resolves directly
|
|
19740
|
+
* (a scalar primary input, or a per-row list value).
|
|
19741
|
+
*/
|
|
19742
|
+
function deriveObservedInputs(expression, fields, functions) {
|
|
19743
|
+
const tokens = referencedTokens(expression);
|
|
19744
|
+
const observed = [];
|
|
19745
|
+
const seen = new Set();
|
|
19746
|
+
for (const field of fields) {
|
|
19747
|
+
if (!tokens.has(field.variable) || seen.has(field.variable))
|
|
19748
|
+
continue;
|
|
19749
|
+
seen.add(field.variable);
|
|
19750
|
+
const aggregate = functions[field.variable];
|
|
19751
|
+
if (aggregate && field.parentInputId) {
|
|
19752
|
+
observed.push({
|
|
19753
|
+
inputId: field.inputId,
|
|
19754
|
+
variable: field.variable,
|
|
19755
|
+
parentInputId: field.parentInputId,
|
|
19756
|
+
function: aggregate,
|
|
19757
|
+
});
|
|
19758
|
+
}
|
|
19759
|
+
else {
|
|
19760
|
+
observed.push({ inputId: field.inputId, variable: field.variable });
|
|
19761
|
+
}
|
|
19762
|
+
}
|
|
19763
|
+
return observed;
|
|
19764
|
+
}
|
|
19765
|
+
|
|
19074
19766
|
/**
|
|
19075
19767
|
* Builder-side editor for authoring a boolean expression (used for guarded
|
|
19076
19768
|
* navigation, conditional validation, and API path-selection rules). Validates
|
|
@@ -19099,6 +19791,12 @@ var apiValueAccessRules_component = /*#__PURE__*/Object.freeze({
|
|
|
19099
19791
|
*/
|
|
19100
19792
|
class ValidationExpressioCreatorComponent {
|
|
19101
19793
|
#cursorPosition;
|
|
19794
|
+
/** Whether the expression is authored via the guided rows or the raw editor. */
|
|
19795
|
+
#mode;
|
|
19796
|
+
/** Guided builder model mirroring the current expression. */
|
|
19797
|
+
#group;
|
|
19798
|
+
/** Reactive mirror of the control value (the control itself is not a signal). */
|
|
19799
|
+
#expressionText;
|
|
19102
19800
|
/** Local mutable mirror of incoming `valueAccessRules`. */
|
|
19103
19801
|
#valueAccessRules;
|
|
19104
19802
|
#destroyRef;
|
|
@@ -19118,7 +19816,9 @@ class ValidationExpressioCreatorComponent {
|
|
|
19118
19816
|
this.valueAccessRules = input({}, ...(ngDevMode ? [{ debugName: "valueAccessRules" }] : /* istanbul ignore next */ []));
|
|
19119
19817
|
/** Fires when either the expression text or its derived value-access tree changes. */
|
|
19120
19818
|
this.expressionChange = output();
|
|
19121
|
-
|
|
19819
|
+
// Optional: the raw textarea only exists in Advanced mode, so the guided
|
|
19820
|
+
// builder must not assume it is in the DOM.
|
|
19821
|
+
this.textareaElementRef = viewChild('textarea', ...(ngDevMode ? [{ debugName: "textareaElementRef" }] : /* istanbul ignore next */ []));
|
|
19122
19822
|
this.expressionControl = new FormControl('', [
|
|
19123
19823
|
Validators.required,
|
|
19124
19824
|
expressionSyntaxValidator(),
|
|
@@ -19127,6 +19827,52 @@ class ValidationExpressioCreatorComponent {
|
|
|
19127
19827
|
this.optionsSearch = signal(undefined, ...(ngDevMode ? [{ debugName: "optionsSearch" }] : /* istanbul ignore next */ []));
|
|
19128
19828
|
this.variableInEdit = signal(null, ...(ngDevMode ? [{ debugName: "variableInEdit" }] : /* istanbul ignore next */ []));
|
|
19129
19829
|
this.#cursorPosition = 0;
|
|
19830
|
+
/** Operator choices, shared with the validators builder for label parity. */
|
|
19831
|
+
this.operators = PREDICATE_OPERATORS;
|
|
19832
|
+
/** Whether the expression is authored via the guided rows or the raw editor. */
|
|
19833
|
+
this.#mode = signal('guided', ...(ngDevMode ? [{ debugName: "#mode" }] : /* istanbul ignore next */ []));
|
|
19834
|
+
this.mode = this.#mode.asReadonly();
|
|
19835
|
+
/** Guided builder model mirroring the current expression. */
|
|
19836
|
+
this.#group = signal({ connector: '&&', conditions: [] }, ...(ngDevMode ? [{ debugName: "#group" }] : /* istanbul ignore next */ []));
|
|
19837
|
+
this.group = this.#group.asReadonly();
|
|
19838
|
+
/** Reactive mirror of the control value (the control itself is not a signal). */
|
|
19839
|
+
this.#expressionText = signal('', ...(ngDevMode ? [{ debugName: "#expressionText" }] : /* istanbul ignore next */ []));
|
|
19840
|
+
this.expressionText = this.#expressionText.asReadonly();
|
|
19841
|
+
/** Fields the guided builder can reference, as friendly options. */
|
|
19842
|
+
this.fieldOptions = computed(() => this.allInputs().map((inp) => ({
|
|
19843
|
+
variable: inp.formControlName,
|
|
19844
|
+
label: inp.label || inp.formControlName,
|
|
19845
|
+
// `stepName` is attached at runtime by the form builder; it is not on the
|
|
19846
|
+
// static FormColumnInputs type, so read it defensively.
|
|
19847
|
+
stepName: inp.stepName ?? null,
|
|
19848
|
+
})), ...(ngDevMode ? [{ debugName: "fieldOptions" }] : /* istanbul ignore next */ []));
|
|
19849
|
+
/**
|
|
19850
|
+
* Field options grouped by their `stepName` for the dropdowns, preserving
|
|
19851
|
+
* first-seen order. Fields without a step collapse into a single ungrouped
|
|
19852
|
+
* bucket (rendered without an `<optgroup>`), so forms that don't carry step
|
|
19853
|
+
* names degrade to a plain flat list.
|
|
19854
|
+
*/
|
|
19855
|
+
this.fieldOptionGroups = computed(() => {
|
|
19856
|
+
const buckets = new Map();
|
|
19857
|
+
const order = [];
|
|
19858
|
+
for (const option of this.fieldOptions()) {
|
|
19859
|
+
const key = option.stepName ?? '';
|
|
19860
|
+
const existing = buckets.get(key);
|
|
19861
|
+
if (existing) {
|
|
19862
|
+
existing.push(option);
|
|
19863
|
+
}
|
|
19864
|
+
else {
|
|
19865
|
+
buckets.set(key, [option]);
|
|
19866
|
+
order.push(key);
|
|
19867
|
+
}
|
|
19868
|
+
}
|
|
19869
|
+
return order.map((key) => ({
|
|
19870
|
+
label: key === '' ? null : key,
|
|
19871
|
+
options: buckets.get(key) ?? [],
|
|
19872
|
+
}));
|
|
19873
|
+
}, ...(ngDevMode ? [{ debugName: "fieldOptionGroups" }] : /* istanbul ignore next */ []));
|
|
19874
|
+
/** Whether the current expression can be represented by the guided builder. */
|
|
19875
|
+
this.canUseGuided = computed(() => parseConditions(this.expressionText(), this.#fieldNameSet()) !== null, ...(ngDevMode ? [{ debugName: "canUseGuided" }] : /* istanbul ignore next */ []));
|
|
19130
19876
|
/** Local mutable mirror of incoming `valueAccessRules`. */
|
|
19131
19877
|
this.#valueAccessRules = {};
|
|
19132
19878
|
this.methods = [
|
|
@@ -19173,7 +19919,11 @@ class ValidationExpressioCreatorComponent {
|
|
|
19173
19919
|
value: '<=',
|
|
19174
19920
|
},
|
|
19175
19921
|
];
|
|
19176
|
-
/**
|
|
19922
|
+
/**
|
|
19923
|
+
* Bridge the `expression` input into the FormControl and seed the guided
|
|
19924
|
+
* builder. Reparsing is `untracked` so this only re-runs when the `expression`
|
|
19925
|
+
* input changes — never when the user edits inside either mode.
|
|
19926
|
+
*/
|
|
19177
19927
|
this.expressionBridge = effect(() => {
|
|
19178
19928
|
const value = this.expression();
|
|
19179
19929
|
if (this.expressionControl.value !== value) {
|
|
@@ -19181,6 +19931,10 @@ class ValidationExpressioCreatorComponent {
|
|
|
19181
19931
|
this.expressionControl.markAsPristine();
|
|
19182
19932
|
this.expressionControl.markAsUntouched();
|
|
19183
19933
|
}
|
|
19934
|
+
untracked(() => {
|
|
19935
|
+
this.#expressionText.set(value);
|
|
19936
|
+
this.#syncBuilderFromExpression(value);
|
|
19937
|
+
});
|
|
19184
19938
|
}, ...(ngDevMode ? [{ debugName: "expressionBridge" }] : /* istanbul ignore next */ []));
|
|
19185
19939
|
/** Mirror the `valueAccessRules` input into the local mutable copy. */
|
|
19186
19940
|
this.valueAccessRulesBridge = effect(() => {
|
|
@@ -19191,6 +19945,7 @@ class ValidationExpressioCreatorComponent {
|
|
|
19191
19945
|
this.#destroyRef = inject(DestroyRef);
|
|
19192
19946
|
this.expressionControl.valueChanges
|
|
19193
19947
|
.pipe(distinctUntilChanged((prev, curr) => prev === curr), tap((value) => {
|
|
19948
|
+
this.#expressionText.set(value || '');
|
|
19194
19949
|
this.onTextChange(value || '').then(() => {
|
|
19195
19950
|
this.expressionChange.emit({
|
|
19196
19951
|
expression: this.expressionControl.value,
|
|
@@ -19220,7 +19975,14 @@ class ValidationExpressioCreatorComponent {
|
|
|
19220
19975
|
return this.#valueAccessRules[key] ?? [];
|
|
19221
19976
|
}
|
|
19222
19977
|
async onTextChange(expression) {
|
|
19223
|
-
const textarea = this.textareaElementRef()
|
|
19978
|
+
const textarea = this.textareaElementRef()?.nativeElement;
|
|
19979
|
+
// Guided mode has no textarea: skip the `$`-suggestion handling and just
|
|
19980
|
+
// keep the derived value-access rules in sync with the expression.
|
|
19981
|
+
if (!textarea) {
|
|
19982
|
+
this.showSuggestions.set(false);
|
|
19983
|
+
this.cleanValueAccessRules();
|
|
19984
|
+
return;
|
|
19985
|
+
}
|
|
19224
19986
|
this.#cursorPosition = textarea.selectionStart || 0;
|
|
19225
19987
|
// Define the operators that should prevent suggestions from showing
|
|
19226
19988
|
const operators = this.methods.map((method) => method.value);
|
|
@@ -19280,7 +20042,9 @@ class ValidationExpressioCreatorComponent {
|
|
|
19280
20042
|
this.expressionControl.setValue(newValue);
|
|
19281
20043
|
this.expressionControl.markAsDirty();
|
|
19282
20044
|
this.showSuggestions.set(false);
|
|
19283
|
-
const textarea = this.textareaElementRef()
|
|
20045
|
+
const textarea = this.textareaElementRef()?.nativeElement;
|
|
20046
|
+
if (!textarea)
|
|
20047
|
+
return;
|
|
19284
20048
|
textarea.focus();
|
|
19285
20049
|
const newCursorPosition = (beforeDollar + suggestion + ' ').length;
|
|
19286
20050
|
setTimeout(() => {
|
|
@@ -19304,9 +20068,65 @@ class ValidationExpressioCreatorComponent {
|
|
|
19304
20068
|
}
|
|
19305
20069
|
}
|
|
19306
20070
|
onFocus() {
|
|
19307
|
-
const textarea = this.textareaElementRef()
|
|
20071
|
+
const textarea = this.textareaElementRef()?.nativeElement;
|
|
20072
|
+
if (!textarea)
|
|
20073
|
+
return;
|
|
19308
20074
|
this.#cursorPosition = textarea.selectionStart || 0;
|
|
19309
20075
|
}
|
|
20076
|
+
// ---- guided condition builder ------------------------------------------
|
|
20077
|
+
/** Read the value-event target as a string. */
|
|
20078
|
+
inputValue(event) {
|
|
20079
|
+
return event.target.value;
|
|
20080
|
+
}
|
|
20081
|
+
/** Switch the All/Any connector joining the conditions. */
|
|
20082
|
+
setConnector(connector) {
|
|
20083
|
+
this.#applyGroup({ ...this.#group(), connector });
|
|
20084
|
+
}
|
|
20085
|
+
/** Append a fresh condition defaulting its field to the first available one. */
|
|
20086
|
+
addCondition() {
|
|
20087
|
+
const fallback = this.fieldOptions()[0]?.variable ?? '';
|
|
20088
|
+
const group = this.#group();
|
|
20089
|
+
this.#applyGroup({
|
|
20090
|
+
...group,
|
|
20091
|
+
conditions: [...group.conditions, emptyCondition(fallback)],
|
|
20092
|
+
});
|
|
20093
|
+
}
|
|
20094
|
+
/** Apply a partial change to the condition at `index`. */
|
|
20095
|
+
updateCondition(index, patch) {
|
|
20096
|
+
const group = this.#group();
|
|
20097
|
+
const conditions = group.conditions.map((c, i) => (i === index ? { ...c, ...patch } : c));
|
|
20098
|
+
this.#applyGroup({ ...group, conditions });
|
|
20099
|
+
}
|
|
20100
|
+
/** Flip a condition between comparing to a typed value and another field. */
|
|
20101
|
+
toggleCompareTo(index) {
|
|
20102
|
+
const condition = this.#group().conditions[index];
|
|
20103
|
+
if (!condition)
|
|
20104
|
+
return;
|
|
20105
|
+
if (condition.compareTo === 'value') {
|
|
20106
|
+
const field = this.fieldOptions().find((f) => f.variable !== condition.field);
|
|
20107
|
+
this.updateCondition(index, { compareTo: 'field', value: field?.variable ?? '' });
|
|
20108
|
+
}
|
|
20109
|
+
else {
|
|
20110
|
+
this.updateCondition(index, { compareTo: 'value', value: '' });
|
|
20111
|
+
}
|
|
20112
|
+
}
|
|
20113
|
+
/** Remove the condition at `index`. */
|
|
20114
|
+
removeCondition(index) {
|
|
20115
|
+
const group = this.#group();
|
|
20116
|
+
this.#applyGroup({ ...group, conditions: group.conditions.filter((_, i) => i !== index) });
|
|
20117
|
+
}
|
|
20118
|
+
/** Switch to the raw expression editor (the escape hatch for power users). */
|
|
20119
|
+
useAdvanced() {
|
|
20120
|
+
this.#mode.set('advanced');
|
|
20121
|
+
}
|
|
20122
|
+
/** Switch back to the guided builder, reparsing the current expression. */
|
|
20123
|
+
useGuided() {
|
|
20124
|
+
const parsed = parseConditions(this.expressionText(), this.#fieldNameSet());
|
|
20125
|
+
if (!parsed)
|
|
20126
|
+
return;
|
|
20127
|
+
this.#group.set(parsed);
|
|
20128
|
+
this.#mode.set('guided');
|
|
20129
|
+
}
|
|
19310
20130
|
toggleVariableInEdit(variable) {
|
|
19311
20131
|
this.variableInEdit.update((current) => (current === variable ? null : variable));
|
|
19312
20132
|
}
|
|
@@ -19319,8 +20139,35 @@ class ValidationExpressioCreatorComponent {
|
|
|
19319
20139
|
},
|
|
19320
20140
|
});
|
|
19321
20141
|
}
|
|
20142
|
+
// ---- internal ----------------------------------------------------------
|
|
20143
|
+
/** Set of field variable names the builder recognises (for parsing). */
|
|
20144
|
+
#fieldNameSet() {
|
|
20145
|
+
return new Set(this.fieldOptions().map((f) => f.variable));
|
|
20146
|
+
}
|
|
20147
|
+
/**
|
|
20148
|
+
* Store a builder change: update the model, then serialise it into the
|
|
20149
|
+
* control. Writing the control drives the existing valueChanges pipeline
|
|
20150
|
+
* (value-access rule sync + `expressionChange` emit), so the guided and raw
|
|
20151
|
+
* paths share one source of truth.
|
|
20152
|
+
*/
|
|
20153
|
+
#applyGroup(next) {
|
|
20154
|
+
this.#group.set(next);
|
|
20155
|
+
this.expressionControl.setValue(serializeConditions(next));
|
|
20156
|
+
this.expressionControl.markAsDirty();
|
|
20157
|
+
}
|
|
20158
|
+
/** Seed the builder from an expression: guided when parseable, else raw. */
|
|
20159
|
+
#syncBuilderFromExpression(expression) {
|
|
20160
|
+
const parsed = parseConditions(expression, this.#fieldNameSet());
|
|
20161
|
+
if (parsed) {
|
|
20162
|
+
this.#group.set(parsed);
|
|
20163
|
+
this.#mode.set('guided');
|
|
20164
|
+
}
|
|
20165
|
+
else {
|
|
20166
|
+
this.#mode.set('advanced');
|
|
20167
|
+
}
|
|
20168
|
+
}
|
|
19322
20169
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: ValidationExpressioCreatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
19323
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: ValidationExpressioCreatorComponent, isStandalone: true, selector: "lib-validation-expressio-creator", inputs: { hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, formInputs: { classPropertyName: "formInputs", publicName: "formInputs", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, expression: { classPropertyName: "expression", publicName: "expression", isSignal: true, isRequired: false, transformFunction: null }, valueAccessRules: { classPropertyName: "valueAccessRules", publicName: "valueAccessRules", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { expressionChange: "expressionChange" }, host: { classAttribute: "lib-validation-expressio-creator" }, viewQueries: [{ propertyName: "textareaElementRef", first: true, predicate: ["textarea"], descendants: true, isSignal: true }], ngImport: i0, template: "<mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" style=\"width: 100%;\" floatLabel=\"always\"\r\n id=\"validationExpressionCreator\">\r\n <mat-label>Condition expression</mat-label>\r\n <textarea [formControl]=\"expressionControl\" matInput #textarea (focus)=\"onFocus()\"\r\n placeholder=\"Enter a validation string for the function\"></textarea>\r\n\r\n\r\n <mat-hint\r\n [style.color]=\"expressionControl.invalid && !showSuggestions() ? 'var(--mat-form-field-error-text-color, var(--mat-sys-error))' : ''\">\r\n @if (expressionControl.invalid && errorMessage !== null && !showSuggestions()) {\r\n {{ errorMessage }}\r\n } @else {\r\n {{ showSuggestions() ? 'Click a suggestion to apply it' : 'Enter a filter condition. Type $ for options' }}\r\n @if (showSuggestions()) {\r\n <section class=\"showSuggestionContainer\">\r\n <mat-divider></mat-divider>\r\n <div style=\"padding: 0px;margin-top:8px\" class=\"\">\r\n <div class=\"suggestion-container\">\r\n <div class=\"suggestion-column\">\r\n <div class=\"suggestion-heading\">\r\n Logical Operators\r\n </div>\r\n <div class=\"button-container\">\r\n @for (method of getMethods() | searchList:optionsSearch(); track method.value) {\r\n <button matTooltipPosition=\"left\" [matTooltip]=\"method.hint\" color=\"primary\" mat-button\r\n (click)=\"selectSuggestionInput(method.value)\" class=\"suggestion-button\">\r\n {{ method.label | titlecase }}\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"suggestion-column\">\r\n <div class=\"suggestion-heading\">\r\n Add Input as a Variable\r\n </div>\r\n <div class=\"button-container\">\r\n @for (inp of allInputs() | searchList:optionsSearch(); track inp.formControlName) {\r\n <button mat-button matTooltipPosition=\"right\"\r\n [matTooltip]=\"'Add Variable - ' + inp.label\"\r\n (click)=\"selectSuggestionInput(inp.formControlName)\" class=\"suggestion-button\">\r\n {{ inp.label | titlecase }}\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </section>\r\n }\r\n }\r\n </mat-hint>\r\n</mat-form-field>\r\n\r\n@if (valueAccessOptions().length > 0) {\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" style=\"width: 100%;margin-top:12px\"\r\n floatLabel=\"always\" id=\"Value access options\">\r\n <mat-label>\r\n Form Fields for expression\r\n </mat-label>\r\n <mat-chip-grid #chipGrid aria-label=\"value access options\">\r\n @for (variable of valueAccessOptions(); track variable) {\r\n <mat-chip-option\r\n [selected]=\"variableInEdit() === variable\"\r\n (click)=\"toggleVariableInEdit(variable)\"\r\n [aria-description]=\"'press enter to edit ' + variable\">\r\n {{ variable }}\r\n </mat-chip-option>\r\n }\r\n <input placeholder=\"\" style=\"display: none;\" [matChipInputFor]=\"chipGrid\" />\r\n </mat-chip-grid>\r\n @if (variableInEdit(); as activeVariable) {\r\n <lib-api-value-access-rules\r\n [value]=\"getValueAccessRule(activeVariable)\"\r\n [errors]=\"[]\"\r\n [formInputs]=\"formInputs() || []\"\r\n [mapToData]=\"data()\"\r\n (valueChanged)=\"activeVariableChanged($event)\">\r\n </lib-api-value-access-rules>\r\n }\r\n <mat-hint>\r\n Click a field to define how to process its value. You can filter a list, count its items, or access specific\r\n data within a complex object.\r\n </mat-hint>\r\n </mat-form-field>\r\n}\r\n", styles: [".suggestion-container{display:flex;width:100%;gap:8px}.suggestion-column{flex:1;min-width:0}.button-container{display:flex;flex-wrap:wrap}.suggestion-button{height:auto;text-align:left;font-size:10.5px;border-radius:4px;margin-bottom:4px;line-height:normal;padding:4px;white-space:nowrap;overflow:hidden;display:inline-block;text-overflow:ellipsis}.suggestion-heading{margin-bottom:8px;font-size:.6875em;font-weight:500}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { 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.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i1$6.MatChipGrid, selector: "mat-chip-grid", inputs: ["disabled", "placeholder", "required", "value", "errorStateMatcher"], outputs: ["change", "valueChange"] }, { kind: "directive", type: i1$6.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputFor", "matChipInputAddOnBlur", "matChipInputSeparatorKeyCodes", "placeholder", "id", "disabled", "readonly", "matChipInputDisabledInteractive"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { kind: "component", type: i1$6.MatChipOption, selector: "mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]", inputs: ["selectable", "selected"], outputs: ["selectionChange"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i4.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i2$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: ApiValueAccessRulesComponent, selector: "lib-api-value-access-rules", inputs: ["disabled", "multipleBind", "errors", "value", "formInputs", "mapToData", "postmanCollectionConfig"], outputs: ["valueChanged", "reload"] }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }, { kind: "pipe", type: SearchListPipe, name: "searchList" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
20170
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: ValidationExpressioCreatorComponent, isStandalone: true, selector: "lib-validation-expressio-creator", inputs: { hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, formInputs: { classPropertyName: "formInputs", publicName: "formInputs", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, expression: { classPropertyName: "expression", publicName: "expression", isSignal: true, isRequired: false, transformFunction: null }, valueAccessRules: { classPropertyName: "valueAccessRules", publicName: "valueAccessRules", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { expressionChange: "expressionChange" }, host: { classAttribute: "lib-validation-expressio-creator" }, viewQueries: [{ propertyName: "textareaElementRef", first: true, predicate: ["textarea"], descendants: true, isSignal: true }], ngImport: i0, template: "<section class=\"lib-vec\">\n <div class=\"lib-vec__head\">\n <div class=\"lib-vec__heading\">\n <span class=\"lib-vec__f-label\">Condition expression</span>\n <p class=\"lib-vec__sub-hint\">{{ hint() }}</p>\n </div>\n\n @if (mode() === 'advanced') {\n <button type=\"button\" class=\"lib-vec__link\" [disabled]=\"!canUseGuided()\"\n [matTooltip]=\"canUseGuided() ? 'Build this with guided rows' : 'This expression is too advanced for the guided builder'\"\n (click)=\"useGuided()\">\n <mat-icon>view_module</mat-icon> Guided\n </button>\n } @else {\n <button type=\"button\" class=\"lib-vec__link\" matTooltip=\"Type the expression yourself\"\n (click)=\"useAdvanced()\">\n <mat-icon>code</mat-icon> Advanced\n </button>\n }\n </div>\n\n @if (mode() === 'guided') {\n @if (fieldOptions().length === 0) {\n <p class=\"lib-vec__sub-hint\">\n No fields available yet \u2014 switch to Advanced to type an expression.\n </p>\n } @else if (group().conditions.length === 0) {\n <p class=\"lib-vec__sub-hint lib-vec__sub-hint--lead\">\n <mat-icon class=\"lib-vec__lead-icon\">lightbulb</mat-icon>\n <span>Add a check below \u2014 this passes when it\u2019s true.</span>\n </p>\n } @else if (group().conditions.length > 1) {\n <div class=\"lib-vec__match\">\n <span class=\"lib-vec__muted\">Match</span>\n <mat-button-toggle-group class=\"lib-vec__seg\" [value]=\"group().connector\"\n hideSingleSelectionIndicator (change)=\"setConnector($event.value)\"\n aria-label=\"Combine conditions\">\n <mat-button-toggle value=\"&&\">All</mat-button-toggle>\n <mat-button-toggle value=\"||\">Any</mat-button-toggle>\n </mat-button-toggle-group>\n <span class=\"lib-vec__muted\">of the checks</span>\n </div>\n }\n\n @for (cond of group().conditions; track $index; let first = $first) {\n @if (!first) {\n <div class=\"lib-vec__connector\" aria-hidden=\"true\">\n <span>{{ group().connector === '&&' ? 'AND' : 'OR' }}</span>\n </div>\n }\n <div class=\"lib-vec__cond\" [class.lib-vec__cond--incomplete]=\"!cond.field || !cond.value\">\n <div class=\"lib-vec__cond-row\">\n <select class=\"lib-vec__control lib-vec__control--field\"\n [class.lib-vec__control--invalid]=\"!cond.field\"\n (change)=\"updateCondition($index, { field: inputValue($event) })\">\n <option value=\"\" disabled [selected]=\"!cond.field\">Choose a field</option>\n @for (group of fieldOptionGroups(); track $index) {\n @if (group.label) {\n <optgroup [label]=\"group.label\">\n @for (f of group.options; track f.variable) {\n <option [value]=\"f.variable\" [selected]=\"f.variable === cond.field\">\n {{ f.label }}\n </option>\n }\n </optgroup>\n } @else {\n @for (f of group.options; track f.variable) {\n <option [value]=\"f.variable\" [selected]=\"f.variable === cond.field\">\n {{ f.label }}\n </option>\n }\n }\n }\n </select>\n <button type=\"button\" class=\"lib-vec__icon-btn\"\n (click)=\"removeCondition($index)\" matTooltip=\"Remove check\" aria-label=\"Remove check\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n\n <div class=\"lib-vec__cond-row lib-vec__cond-row--ops\">\n <select class=\"lib-vec__control\"\n (change)=\"updateCondition($index, { operator: inputValue($event) })\">\n @for (op of operators; track op.value) {\n <option [value]=\"op.value\" [selected]=\"op.value === cond.operator\">\n {{ op.label }}\n </option>\n }\n </select>\n\n @if (cond.compareTo === 'field') {\n <select class=\"lib-vec__control\"\n [class.lib-vec__control--invalid]=\"!cond.value\"\n (change)=\"updateCondition($index, { value: inputValue($event) })\">\n <option value=\"\" disabled [selected]=\"!cond.value\">Choose a field</option>\n @for (group of fieldOptionGroups(); track $index) {\n @if (group.label) {\n <optgroup [label]=\"group.label\">\n @for (f of group.options; track f.variable) {\n <option [value]=\"f.variable\" [selected]=\"f.variable === cond.value\">\n {{ f.label }}\n </option>\n }\n </optgroup>\n } @else {\n @for (f of group.options; track f.variable) {\n <option [value]=\"f.variable\" [selected]=\"f.variable === cond.value\">\n {{ f.label }}\n </option>\n }\n }\n }\n </select>\n } @else {\n <input class=\"lib-vec__control\"\n [class.lib-vec__control--invalid]=\"!cond.value\"\n [value]=\"cond.value\"\n (input)=\"updateCondition($index, { value: inputValue($event) })\"\n [placeholder]=\"'a value'\" />\n }\n\n <button type=\"button\" class=\"lib-vec__icon-btn\"\n [class.lib-vec__icon-btn--on]=\"cond.compareTo === 'field'\"\n (click)=\"toggleCompareTo($index)\"\n [attr.aria-label]=\"cond.compareTo === 'field' ? 'Compare to a typed value' : 'Compare to another field'\"\n [matTooltip]=\"cond.compareTo === 'field' ? 'Comparing to a field \u2014 switch to a typed value' : 'Compare to another field instead'\">\n <mat-icon>{{ cond.compareTo === 'field' ? 'link' : 'link_off' }}</mat-icon>\n </button>\n </div>\n </div>\n }\n\n <div class=\"lib-vec__foot\">\n <button type=\"button\" class=\"lib-vec__link\" [disabled]=\"fieldOptions().length === 0\"\n (click)=\"addCondition()\">\n <mat-icon>add</mat-icon> Add check\n </button>\n\n @if (expressionText()) {\n <span class=\"lib-vec__valid\" matTooltip=\"Generated expression: {{ expressionText() }}\">\n <mat-icon>check_circle</mat-icon> Ready\n </span>\n }\n </div>\n } @else {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" style=\"width: 100%;\"\n floatLabel=\"always\" id=\"validationExpressionCreator\">\n <mat-label>Expression</mat-label>\n <textarea [formControl]=\"expressionControl\" matInput #textarea (focus)=\"onFocus()\"\n class=\"lib-vec__mono\"\n placeholder=\"Enter a validation string for the function\"></textarea>\n\n <mat-hint\n [style.color]=\"expressionControl.invalid && !showSuggestions() ? 'var(--mat-form-field-error-text-color, var(--mat-sys-error))' : ''\">\n @if (expressionControl.invalid && errorMessage !== null && !showSuggestions()) {\n {{ errorMessage }}\n } @else {\n {{ showSuggestions() ? 'Click a suggestion to apply it' : 'Enter a filter condition. Type $ for options' }}\n @if (showSuggestions()) {\n <section class=\"showSuggestionContainer\">\n <mat-divider></mat-divider>\n <div style=\"padding: 0px;margin-top:8px\" class=\"\">\n <div class=\"suggestion-container\">\n <div class=\"suggestion-column\">\n <div class=\"suggestion-heading\">\n Logical Operators\n </div>\n <div class=\"button-container\">\n @for (method of getMethods() | searchList:optionsSearch(); track method.value) {\n <button matTooltipPosition=\"left\" [matTooltip]=\"method.hint\" color=\"primary\" mat-button\n (click)=\"selectSuggestionInput(method.value)\" class=\"suggestion-button\">\n {{ method.label | titlecase }}\n </button>\n }\n </div>\n </div>\n <div class=\"suggestion-column\">\n <div class=\"suggestion-heading\">\n Add Input as a Variable\n </div>\n <div class=\"button-container\">\n @for (inp of allInputs() | searchList:optionsSearch(); track inp.formControlName) {\n <button mat-button matTooltipPosition=\"right\"\n [matTooltip]=\"'Add Variable - ' + inp.label\"\n (click)=\"selectSuggestionInput(inp.formControlName)\" class=\"suggestion-button\">\n {{ inp.label | titlecase }}\n </button>\n }\n </div>\n </div>\n </div>\n </div>\n </section>\n }\n }\n </mat-hint>\n </mat-form-field>\n }\n</section>\n\n@if (valueAccessOptions().length > 0) {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" style=\"width: 100%;margin-top:12px\"\n floatLabel=\"always\" id=\"Value access options\">\n <mat-label>\n Form Fields for expression\n </mat-label>\n <mat-chip-grid #chipGrid aria-label=\"value access options\">\n @for (variable of valueAccessOptions(); track variable) {\n <mat-chip-option\n [selected]=\"variableInEdit() === variable\"\n (click)=\"toggleVariableInEdit(variable)\"\n [aria-description]=\"'press enter to edit ' + variable\">\n {{ variable }}\n </mat-chip-option>\n }\n <input placeholder=\"\" style=\"display: none;\" [matChipInputFor]=\"chipGrid\" />\n </mat-chip-grid>\n @if (variableInEdit(); as activeVariable) {\n <lib-api-value-access-rules\n [value]=\"getValueAccessRule(activeVariable)\"\n [errors]=\"[]\"\n [formInputs]=\"formInputs() || []\"\n [mapToData]=\"data()\"\n (valueChanged)=\"activeVariableChanged($event)\">\n </lib-api-value-access-rules>\n }\n <mat-hint>\n Click a field to define how to process its value. You can filter a list, count its items, or access specific\n data within a complex object.\n </mat-hint>\n </mat-form-field>\n}\n", styles: [".lib-vec{display:flex;flex-direction:column;gap:.625rem}.lib-vec__head{display:flex;align-items:flex-start;justify-content:space-between;gap:.75rem}.lib-vec__heading{display:flex;flex-direction:column;gap:.125rem;min-width:0}.lib-vec__f-label{font-size:.625rem;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--lib-forms-on-surface-variant)}.lib-vec__sub-hint{margin:0;font-size:.75rem;line-height:1.4;color:var(--lib-forms-on-surface-variant)}.lib-vec__sub-hint--lead{display:flex;align-items:center;gap:.375rem;padding:.4375rem .625rem;background:var(--lib-forms-surface-container-lowest);border:1px dashed var(--lib-forms-outline-variant);border-radius:var(--lib-forms-radius-sm, 8px)}.lib-vec__lead-icon{flex:none;font-size:1rem;width:1rem;height:1rem;color:var(--sem-info, var(--lib-forms-primary))}.lib-vec__match{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.lib-vec__muted{font-size:.75rem;color:var(--lib-forms-on-surface-variant)}.lib-vec__seg{--mat-standard-button-toggle-height: 28px;height:28px}.lib-vec__connector{display:flex;justify-content:center;margin:-.1875rem 0}.lib-vec__connector span{padding:.0625rem .5rem;font-size:.5625rem;font-weight:600;letter-spacing:.1em;color:var(--lib-forms-on-surface-variant);background:var(--lib-forms-surface-container-high);border-radius:var(--lib-forms-radius-pill, 999px)}.lib-vec__cond{display:flex;flex-direction:column;gap:.375rem;padding:.5rem .5rem .5625rem;background:var(--lib-forms-surface-container-lowest);border:1px solid var(--lib-forms-outline-variant);border-radius:var(--lib-forms-radius-md, 12px);transition:border-color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1))}.lib-vec__cond:hover{border-color:var(--lib-forms-outline)}.lib-vec__cond--incomplete{border-color:var(--sem-warning, var(--lib-forms-outline-variant))}.lib-vec__cond-row{display:grid;grid-template-columns:1fr auto;align-items:center;gap:.375rem;min-width:0}.lib-vec__cond-row--ops{grid-template-columns:minmax(0,1fr) minmax(0,1fr) auto}.lib-vec__control{box-sizing:border-box;width:100%;min-width:0;height:2rem;padding:.3125rem .5rem;font-family:inherit;font-size:.8125rem;line-height:1.2;color:var(--lib-forms-on-surface);background:var(--lib-forms-surface-container-lowest);border:1px solid var(--lib-forms-outline-variant);border-radius:var(--lib-forms-radius-sm, 8px);transition:border-color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1))}.lib-vec__control--field{font-weight:500}select.lib-vec__control{cursor:pointer}.lib-vec__control:hover{border-color:var(--lib-forms-outline)}.lib-vec__control:focus{outline:none;border-color:var(--lib-forms-primary);box-shadow:0 0 0 1px var(--lib-forms-primary)}.lib-vec__control--invalid:not(:focus){border-color:var(--sem-warning, var(--lib-forms-outline));background:var(--sem-warning-surface, var(--lib-forms-surface-container-lowest))}.lib-vec__icon-btn{display:inline-flex;align-items:center;justify-content:center;flex:none;width:1.875rem;height:1.875rem;padding:0;color:var(--lib-forms-on-surface-variant);background:transparent;border:1px solid transparent;border-radius:var(--lib-forms-radius-sm, 8px);cursor:pointer;transition:color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1)),background-color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1)),border-color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1))}.lib-vec__icon-btn:hover{color:var(--lib-forms-primary);background:var(--lib-forms-primary-container)}.lib-vec__icon-btn--on{color:var(--lib-forms-primary);border-color:var(--lib-forms-primary)}.lib-vec__icon-btn mat-icon{font-size:1.0625rem;width:1.0625rem;height:1.0625rem}.lib-vec__link{display:inline-flex;align-items:center;gap:.25rem;height:1.75rem;padding:0 .5rem;font:inherit;font-size:.8125rem;font-weight:500;color:var(--lib-forms-primary);background:transparent;border:0;border-radius:var(--lib-forms-radius-sm, 8px);cursor:pointer;transition:background-color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1))}.lib-vec__head .lib-vec__link{flex:none}.lib-vec__link:hover:not(:disabled){background:var(--lib-forms-primary-container)}.lib-vec__link:disabled{color:var(--lib-forms-on-surface-variant);cursor:default;opacity:.6}.lib-vec__link mat-icon{flex:none;font-size:1.0625rem;width:1.0625rem;height:1.0625rem}.lib-vec__foot{display:flex;align-items:center;justify-content:space-between;gap:.5rem}.lib-vec__valid{display:inline-flex;align-items:center;gap:.25rem;font-size:.6875rem;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--sem-success, var(--lib-forms-primary));cursor:default}.lib-vec__valid mat-icon{font-size:.9375rem;width:.9375rem;height:.9375rem}.lib-vec__mono{font-family:var(--lib-forms-font-mono, monospace)}:host ::ng-deep .mat-mdc-form-field-hint-wrapper{min-width:0}:host ::ng-deep .mat-mdc-form-field-hint{min-width:0;width:100%}.showSuggestionContainer{display:block;box-sizing:border-box;width:100%;max-width:100%;overflow:hidden}.suggestion-container{display:flex;flex-wrap:wrap;box-sizing:border-box;width:100%;gap:24px;max-height:220px;overflow-x:hidden;overflow-y:auto}.suggestion-column{flex:1 1 150px;min-width:0}.suggestion-heading{margin-bottom:12px;font-size:.625rem;font-weight:600;letter-spacing:.14em;text-transform:uppercase;opacity:.7}.button-container{display:flex;flex-wrap:wrap;gap:4px}.suggestion-button{height:auto;min-width:0;max-width:100%;text-align:left;font-size:11px;line-height:normal;padding:4px 8px;border-radius:4px;overflow:hidden}.suggestion-button ::ng-deep .mdc-button__label{display:block;max-width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { 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.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "directive", type: i3$5.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i3$5.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i4$3.MatChipGrid, selector: "mat-chip-grid", inputs: ["disabled", "placeholder", "required", "value", "errorStateMatcher"], outputs: ["change", "valueChange"] }, { kind: "directive", type: i4$3.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputFor", "matChipInputAddOnBlur", "matChipInputSeparatorKeyCodes", "placeholder", "id", "disabled", "readonly", "matChipInputDisabledInteractive"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { kind: "component", type: i4$3.MatChipOption, selector: "mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]", inputs: ["selectable", "selected"], outputs: ["selectionChange"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i4.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i2$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: ApiValueAccessRulesComponent, selector: "lib-api-value-access-rules", inputs: ["disabled", "multipleBind", "errors", "value", "formInputs", "mapToData", "postmanCollectionConfig"], outputs: ["valueChanged", "reload"] }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }, { kind: "pipe", type: SearchListPipe, name: "searchList" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
19324
20171
|
}
|
|
19325
20172
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: ValidationExpressioCreatorComponent, decorators: [{
|
|
19326
20173
|
type: Component,
|
|
@@ -19328,16 +20175,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
19328
20175
|
TitleCasePipe,
|
|
19329
20176
|
ReactiveFormsModule,
|
|
19330
20177
|
MatButtonModule,
|
|
20178
|
+
MatButtonToggleModule,
|
|
19331
20179
|
MatChipsModule,
|
|
19332
20180
|
MatDividerModule,
|
|
19333
20181
|
MatFormFieldModule,
|
|
20182
|
+
MatIconModule,
|
|
19334
20183
|
MatInputModule,
|
|
19335
20184
|
MatTooltipModule,
|
|
19336
20185
|
SearchListPipe,
|
|
19337
20186
|
ApiValueAccessRulesComponent,
|
|
19338
20187
|
], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, host: {
|
|
19339
20188
|
class: 'lib-validation-expressio-creator',
|
|
19340
|
-
}, template: "<mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" style=\"width: 100%;\" floatLabel=\"always\"\r\n id=\"validationExpressionCreator\">\r\n <mat-label>Condition expression</mat-label>\r\n <textarea [formControl]=\"expressionControl\" matInput #textarea (focus)=\"onFocus()\"\r\n placeholder=\"Enter a validation string for the function\"></textarea>\r\n\r\n\r\n <mat-hint\r\n [style.color]=\"expressionControl.invalid && !showSuggestions() ? 'var(--mat-form-field-error-text-color, var(--mat-sys-error))' : ''\">\r\n @if (expressionControl.invalid && errorMessage !== null && !showSuggestions()) {\r\n {{ errorMessage }}\r\n } @else {\r\n {{ showSuggestions() ? 'Click a suggestion to apply it' : 'Enter a filter condition. Type $ for options' }}\r\n @if (showSuggestions()) {\r\n <section class=\"showSuggestionContainer\">\r\n <mat-divider></mat-divider>\r\n <div style=\"padding: 0px;margin-top:8px\" class=\"\">\r\n <div class=\"suggestion-container\">\r\n <div class=\"suggestion-column\">\r\n <div class=\"suggestion-heading\">\r\n Logical Operators\r\n </div>\r\n <div class=\"button-container\">\r\n @for (method of getMethods() | searchList:optionsSearch(); track method.value) {\r\n <button matTooltipPosition=\"left\" [matTooltip]=\"method.hint\" color=\"primary\" mat-button\r\n (click)=\"selectSuggestionInput(method.value)\" class=\"suggestion-button\">\r\n {{ method.label | titlecase }}\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"suggestion-column\">\r\n <div class=\"suggestion-heading\">\r\n Add Input as a Variable\r\n </div>\r\n <div class=\"button-container\">\r\n @for (inp of allInputs() | searchList:optionsSearch(); track inp.formControlName) {\r\n <button mat-button matTooltipPosition=\"right\"\r\n [matTooltip]=\"'Add Variable - ' + inp.label\"\r\n (click)=\"selectSuggestionInput(inp.formControlName)\" class=\"suggestion-button\">\r\n {{ inp.label | titlecase }}\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </section>\r\n }\r\n }\r\n </mat-hint>\r\n</mat-form-field>\r\n\r\n@if (valueAccessOptions().length > 0) {\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" style=\"width: 100%;margin-top:12px\"\r\n floatLabel=\"always\" id=\"Value access options\">\r\n <mat-label>\r\n Form Fields for expression\r\n </mat-label>\r\n <mat-chip-grid #chipGrid aria-label=\"value access options\">\r\n @for (variable of valueAccessOptions(); track variable) {\r\n <mat-chip-option\r\n [selected]=\"variableInEdit() === variable\"\r\n (click)=\"toggleVariableInEdit(variable)\"\r\n [aria-description]=\"'press enter to edit ' + variable\">\r\n {{ variable }}\r\n </mat-chip-option>\r\n }\r\n <input placeholder=\"\" style=\"display: none;\" [matChipInputFor]=\"chipGrid\" />\r\n </mat-chip-grid>\r\n @if (variableInEdit(); as activeVariable) {\r\n <lib-api-value-access-rules\r\n [value]=\"getValueAccessRule(activeVariable)\"\r\n [errors]=\"[]\"\r\n [formInputs]=\"formInputs() || []\"\r\n [mapToData]=\"data()\"\r\n (valueChanged)=\"activeVariableChanged($event)\">\r\n </lib-api-value-access-rules>\r\n }\r\n <mat-hint>\r\n Click a field to define how to process its value. You can filter a list, count its items, or access specific\r\n data within a complex object.\r\n </mat-hint>\r\n </mat-form-field>\r\n}\r\n", styles: [".suggestion-container{display:flex;width:100%;gap:8px}.suggestion-column{flex:1;min-width:0}.button-container{display:flex;flex-wrap:wrap}.suggestion-button{height:auto;text-align:left;font-size:10.5px;border-radius:4px;margin-bottom:4px;line-height:normal;padding:4px;white-space:nowrap;overflow:hidden;display:inline-block;text-overflow:ellipsis}.suggestion-heading{margin-bottom:8px;font-size:.6875em;font-weight:500}\n"] }]
|
|
20189
|
+
}, template: "<section class=\"lib-vec\">\n <div class=\"lib-vec__head\">\n <div class=\"lib-vec__heading\">\n <span class=\"lib-vec__f-label\">Condition expression</span>\n <p class=\"lib-vec__sub-hint\">{{ hint() }}</p>\n </div>\n\n @if (mode() === 'advanced') {\n <button type=\"button\" class=\"lib-vec__link\" [disabled]=\"!canUseGuided()\"\n [matTooltip]=\"canUseGuided() ? 'Build this with guided rows' : 'This expression is too advanced for the guided builder'\"\n (click)=\"useGuided()\">\n <mat-icon>view_module</mat-icon> Guided\n </button>\n } @else {\n <button type=\"button\" class=\"lib-vec__link\" matTooltip=\"Type the expression yourself\"\n (click)=\"useAdvanced()\">\n <mat-icon>code</mat-icon> Advanced\n </button>\n }\n </div>\n\n @if (mode() === 'guided') {\n @if (fieldOptions().length === 0) {\n <p class=\"lib-vec__sub-hint\">\n No fields available yet \u2014 switch to Advanced to type an expression.\n </p>\n } @else if (group().conditions.length === 0) {\n <p class=\"lib-vec__sub-hint lib-vec__sub-hint--lead\">\n <mat-icon class=\"lib-vec__lead-icon\">lightbulb</mat-icon>\n <span>Add a check below \u2014 this passes when it\u2019s true.</span>\n </p>\n } @else if (group().conditions.length > 1) {\n <div class=\"lib-vec__match\">\n <span class=\"lib-vec__muted\">Match</span>\n <mat-button-toggle-group class=\"lib-vec__seg\" [value]=\"group().connector\"\n hideSingleSelectionIndicator (change)=\"setConnector($event.value)\"\n aria-label=\"Combine conditions\">\n <mat-button-toggle value=\"&&\">All</mat-button-toggle>\n <mat-button-toggle value=\"||\">Any</mat-button-toggle>\n </mat-button-toggle-group>\n <span class=\"lib-vec__muted\">of the checks</span>\n </div>\n }\n\n @for (cond of group().conditions; track $index; let first = $first) {\n @if (!first) {\n <div class=\"lib-vec__connector\" aria-hidden=\"true\">\n <span>{{ group().connector === '&&' ? 'AND' : 'OR' }}</span>\n </div>\n }\n <div class=\"lib-vec__cond\" [class.lib-vec__cond--incomplete]=\"!cond.field || !cond.value\">\n <div class=\"lib-vec__cond-row\">\n <select class=\"lib-vec__control lib-vec__control--field\"\n [class.lib-vec__control--invalid]=\"!cond.field\"\n (change)=\"updateCondition($index, { field: inputValue($event) })\">\n <option value=\"\" disabled [selected]=\"!cond.field\">Choose a field</option>\n @for (group of fieldOptionGroups(); track $index) {\n @if (group.label) {\n <optgroup [label]=\"group.label\">\n @for (f of group.options; track f.variable) {\n <option [value]=\"f.variable\" [selected]=\"f.variable === cond.field\">\n {{ f.label }}\n </option>\n }\n </optgroup>\n } @else {\n @for (f of group.options; track f.variable) {\n <option [value]=\"f.variable\" [selected]=\"f.variable === cond.field\">\n {{ f.label }}\n </option>\n }\n }\n }\n </select>\n <button type=\"button\" class=\"lib-vec__icon-btn\"\n (click)=\"removeCondition($index)\" matTooltip=\"Remove check\" aria-label=\"Remove check\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n\n <div class=\"lib-vec__cond-row lib-vec__cond-row--ops\">\n <select class=\"lib-vec__control\"\n (change)=\"updateCondition($index, { operator: inputValue($event) })\">\n @for (op of operators; track op.value) {\n <option [value]=\"op.value\" [selected]=\"op.value === cond.operator\">\n {{ op.label }}\n </option>\n }\n </select>\n\n @if (cond.compareTo === 'field') {\n <select class=\"lib-vec__control\"\n [class.lib-vec__control--invalid]=\"!cond.value\"\n (change)=\"updateCondition($index, { value: inputValue($event) })\">\n <option value=\"\" disabled [selected]=\"!cond.value\">Choose a field</option>\n @for (group of fieldOptionGroups(); track $index) {\n @if (group.label) {\n <optgroup [label]=\"group.label\">\n @for (f of group.options; track f.variable) {\n <option [value]=\"f.variable\" [selected]=\"f.variable === cond.value\">\n {{ f.label }}\n </option>\n }\n </optgroup>\n } @else {\n @for (f of group.options; track f.variable) {\n <option [value]=\"f.variable\" [selected]=\"f.variable === cond.value\">\n {{ f.label }}\n </option>\n }\n }\n }\n </select>\n } @else {\n <input class=\"lib-vec__control\"\n [class.lib-vec__control--invalid]=\"!cond.value\"\n [value]=\"cond.value\"\n (input)=\"updateCondition($index, { value: inputValue($event) })\"\n [placeholder]=\"'a value'\" />\n }\n\n <button type=\"button\" class=\"lib-vec__icon-btn\"\n [class.lib-vec__icon-btn--on]=\"cond.compareTo === 'field'\"\n (click)=\"toggleCompareTo($index)\"\n [attr.aria-label]=\"cond.compareTo === 'field' ? 'Compare to a typed value' : 'Compare to another field'\"\n [matTooltip]=\"cond.compareTo === 'field' ? 'Comparing to a field \u2014 switch to a typed value' : 'Compare to another field instead'\">\n <mat-icon>{{ cond.compareTo === 'field' ? 'link' : 'link_off' }}</mat-icon>\n </button>\n </div>\n </div>\n }\n\n <div class=\"lib-vec__foot\">\n <button type=\"button\" class=\"lib-vec__link\" [disabled]=\"fieldOptions().length === 0\"\n (click)=\"addCondition()\">\n <mat-icon>add</mat-icon> Add check\n </button>\n\n @if (expressionText()) {\n <span class=\"lib-vec__valid\" matTooltip=\"Generated expression: {{ expressionText() }}\">\n <mat-icon>check_circle</mat-icon> Ready\n </span>\n }\n </div>\n } @else {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" style=\"width: 100%;\"\n floatLabel=\"always\" id=\"validationExpressionCreator\">\n <mat-label>Expression</mat-label>\n <textarea [formControl]=\"expressionControl\" matInput #textarea (focus)=\"onFocus()\"\n class=\"lib-vec__mono\"\n placeholder=\"Enter a validation string for the function\"></textarea>\n\n <mat-hint\n [style.color]=\"expressionControl.invalid && !showSuggestions() ? 'var(--mat-form-field-error-text-color, var(--mat-sys-error))' : ''\">\n @if (expressionControl.invalid && errorMessage !== null && !showSuggestions()) {\n {{ errorMessage }}\n } @else {\n {{ showSuggestions() ? 'Click a suggestion to apply it' : 'Enter a filter condition. Type $ for options' }}\n @if (showSuggestions()) {\n <section class=\"showSuggestionContainer\">\n <mat-divider></mat-divider>\n <div style=\"padding: 0px;margin-top:8px\" class=\"\">\n <div class=\"suggestion-container\">\n <div class=\"suggestion-column\">\n <div class=\"suggestion-heading\">\n Logical Operators\n </div>\n <div class=\"button-container\">\n @for (method of getMethods() | searchList:optionsSearch(); track method.value) {\n <button matTooltipPosition=\"left\" [matTooltip]=\"method.hint\" color=\"primary\" mat-button\n (click)=\"selectSuggestionInput(method.value)\" class=\"suggestion-button\">\n {{ method.label | titlecase }}\n </button>\n }\n </div>\n </div>\n <div class=\"suggestion-column\">\n <div class=\"suggestion-heading\">\n Add Input as a Variable\n </div>\n <div class=\"button-container\">\n @for (inp of allInputs() | searchList:optionsSearch(); track inp.formControlName) {\n <button mat-button matTooltipPosition=\"right\"\n [matTooltip]=\"'Add Variable - ' + inp.label\"\n (click)=\"selectSuggestionInput(inp.formControlName)\" class=\"suggestion-button\">\n {{ inp.label | titlecase }}\n </button>\n }\n </div>\n </div>\n </div>\n </div>\n </section>\n }\n }\n </mat-hint>\n </mat-form-field>\n }\n</section>\n\n@if (valueAccessOptions().length > 0) {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" style=\"width: 100%;margin-top:12px\"\n floatLabel=\"always\" id=\"Value access options\">\n <mat-label>\n Form Fields for expression\n </mat-label>\n <mat-chip-grid #chipGrid aria-label=\"value access options\">\n @for (variable of valueAccessOptions(); track variable) {\n <mat-chip-option\n [selected]=\"variableInEdit() === variable\"\n (click)=\"toggleVariableInEdit(variable)\"\n [aria-description]=\"'press enter to edit ' + variable\">\n {{ variable }}\n </mat-chip-option>\n }\n <input placeholder=\"\" style=\"display: none;\" [matChipInputFor]=\"chipGrid\" />\n </mat-chip-grid>\n @if (variableInEdit(); as activeVariable) {\n <lib-api-value-access-rules\n [value]=\"getValueAccessRule(activeVariable)\"\n [errors]=\"[]\"\n [formInputs]=\"formInputs() || []\"\n [mapToData]=\"data()\"\n (valueChanged)=\"activeVariableChanged($event)\">\n </lib-api-value-access-rules>\n }\n <mat-hint>\n Click a field to define how to process its value. You can filter a list, count its items, or access specific\n data within a complex object.\n </mat-hint>\n </mat-form-field>\n}\n", styles: [".lib-vec{display:flex;flex-direction:column;gap:.625rem}.lib-vec__head{display:flex;align-items:flex-start;justify-content:space-between;gap:.75rem}.lib-vec__heading{display:flex;flex-direction:column;gap:.125rem;min-width:0}.lib-vec__f-label{font-size:.625rem;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--lib-forms-on-surface-variant)}.lib-vec__sub-hint{margin:0;font-size:.75rem;line-height:1.4;color:var(--lib-forms-on-surface-variant)}.lib-vec__sub-hint--lead{display:flex;align-items:center;gap:.375rem;padding:.4375rem .625rem;background:var(--lib-forms-surface-container-lowest);border:1px dashed var(--lib-forms-outline-variant);border-radius:var(--lib-forms-radius-sm, 8px)}.lib-vec__lead-icon{flex:none;font-size:1rem;width:1rem;height:1rem;color:var(--sem-info, var(--lib-forms-primary))}.lib-vec__match{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.lib-vec__muted{font-size:.75rem;color:var(--lib-forms-on-surface-variant)}.lib-vec__seg{--mat-standard-button-toggle-height: 28px;height:28px}.lib-vec__connector{display:flex;justify-content:center;margin:-.1875rem 0}.lib-vec__connector span{padding:.0625rem .5rem;font-size:.5625rem;font-weight:600;letter-spacing:.1em;color:var(--lib-forms-on-surface-variant);background:var(--lib-forms-surface-container-high);border-radius:var(--lib-forms-radius-pill, 999px)}.lib-vec__cond{display:flex;flex-direction:column;gap:.375rem;padding:.5rem .5rem .5625rem;background:var(--lib-forms-surface-container-lowest);border:1px solid var(--lib-forms-outline-variant);border-radius:var(--lib-forms-radius-md, 12px);transition:border-color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1))}.lib-vec__cond:hover{border-color:var(--lib-forms-outline)}.lib-vec__cond--incomplete{border-color:var(--sem-warning, var(--lib-forms-outline-variant))}.lib-vec__cond-row{display:grid;grid-template-columns:1fr auto;align-items:center;gap:.375rem;min-width:0}.lib-vec__cond-row--ops{grid-template-columns:minmax(0,1fr) minmax(0,1fr) auto}.lib-vec__control{box-sizing:border-box;width:100%;min-width:0;height:2rem;padding:.3125rem .5rem;font-family:inherit;font-size:.8125rem;line-height:1.2;color:var(--lib-forms-on-surface);background:var(--lib-forms-surface-container-lowest);border:1px solid var(--lib-forms-outline-variant);border-radius:var(--lib-forms-radius-sm, 8px);transition:border-color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1))}.lib-vec__control--field{font-weight:500}select.lib-vec__control{cursor:pointer}.lib-vec__control:hover{border-color:var(--lib-forms-outline)}.lib-vec__control:focus{outline:none;border-color:var(--lib-forms-primary);box-shadow:0 0 0 1px var(--lib-forms-primary)}.lib-vec__control--invalid:not(:focus){border-color:var(--sem-warning, var(--lib-forms-outline));background:var(--sem-warning-surface, var(--lib-forms-surface-container-lowest))}.lib-vec__icon-btn{display:inline-flex;align-items:center;justify-content:center;flex:none;width:1.875rem;height:1.875rem;padding:0;color:var(--lib-forms-on-surface-variant);background:transparent;border:1px solid transparent;border-radius:var(--lib-forms-radius-sm, 8px);cursor:pointer;transition:color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1)),background-color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1)),border-color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1))}.lib-vec__icon-btn:hover{color:var(--lib-forms-primary);background:var(--lib-forms-primary-container)}.lib-vec__icon-btn--on{color:var(--lib-forms-primary);border-color:var(--lib-forms-primary)}.lib-vec__icon-btn mat-icon{font-size:1.0625rem;width:1.0625rem;height:1.0625rem}.lib-vec__link{display:inline-flex;align-items:center;gap:.25rem;height:1.75rem;padding:0 .5rem;font:inherit;font-size:.8125rem;font-weight:500;color:var(--lib-forms-primary);background:transparent;border:0;border-radius:var(--lib-forms-radius-sm, 8px);cursor:pointer;transition:background-color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1))}.lib-vec__head .lib-vec__link{flex:none}.lib-vec__link:hover:not(:disabled){background:var(--lib-forms-primary-container)}.lib-vec__link:disabled{color:var(--lib-forms-on-surface-variant);cursor:default;opacity:.6}.lib-vec__link mat-icon{flex:none;font-size:1.0625rem;width:1.0625rem;height:1.0625rem}.lib-vec__foot{display:flex;align-items:center;justify-content:space-between;gap:.5rem}.lib-vec__valid{display:inline-flex;align-items:center;gap:.25rem;font-size:.6875rem;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--sem-success, var(--lib-forms-primary));cursor:default}.lib-vec__valid mat-icon{font-size:.9375rem;width:.9375rem;height:.9375rem}.lib-vec__mono{font-family:var(--lib-forms-font-mono, monospace)}:host ::ng-deep .mat-mdc-form-field-hint-wrapper{min-width:0}:host ::ng-deep .mat-mdc-form-field-hint{min-width:0;width:100%}.showSuggestionContainer{display:block;box-sizing:border-box;width:100%;max-width:100%;overflow:hidden}.suggestion-container{display:flex;flex-wrap:wrap;box-sizing:border-box;width:100%;gap:24px;max-height:220px;overflow-x:hidden;overflow-y:auto}.suggestion-column{flex:1 1 150px;min-width:0}.suggestion-heading{margin-bottom:12px;font-size:.625rem;font-weight:600;letter-spacing:.14em;text-transform:uppercase;opacity:.7}.button-container{display:flex;flex-wrap:wrap;gap:4px}.suggestion-button{height:auto;min-width:0;max-width:100%;text-align:left;font-size:11px;line-height:normal;padding:4px 8px;border-radius:4px;overflow:hidden}.suggestion-button ::ng-deep .mdc-button__label{display:block;max-width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}\n"] }]
|
|
19341
20190
|
}], ctorParameters: () => [], propDecorators: { hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], formInputs: [{ type: i0.Input, args: [{ isSignal: true, alias: "formInputs", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], expression: [{ type: i0.Input, args: [{ isSignal: true, alias: "expression", required: false }] }], valueAccessRules: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueAccessRules", required: false }] }], expressionChange: [{ type: i0.Output, args: ["expressionChange"] }], textareaElementRef: [{ type: i0.ViewChild, args: ['textarea', { isSignal: true }] }] } });
|
|
19342
20191
|
|
|
19343
20192
|
/**
|
|
@@ -19457,5 +20306,5 @@ const getSignatureImage = async (inputConfig, value, secret) => {
|
|
|
19457
20306
|
* Generated bundle index. Do not edit.
|
|
19458
20307
|
*/
|
|
19459
20308
|
|
|
19460
|
-
export {
|
|
19461
|
-
//# sourceMappingURL=ngx-t-forms-ngx-t-forms-
|
|
20309
|
+
export { HttpPipelineRepository as $, calculateListOveralFunctions as A, BaseCustomInput as B, returnMappedPathValue as C, DaysAgoPipe as D, EmptyStateComponent as E, FormsStoreService as F, FormatDataPipe as G, fuzzySearch as H, ACCOUNTING_BASIS as I, JsonEditorComponent as J, getToolbarColor as K, getToolbarBackground as L, MscoaFormInputComponent as M, NGX_T_FORMS_CONFIG_TOKEN as N, getToolbarIconColor as O, PREDICATE_OPERATORS as P, FORM_ACTIONS_TOKEN as Q, FORM_CONFIG_TOKEN as R, SignatureInputElementComponent as S, TDynamicDataEditComponent as T, UserFormStepperComponent as U, ValidationExpressioCreatorComponent as V, FORM_INPUTS_TOKEN as W, FORM_ROUTE_SOURCE as X, FORM_SLIDES_TOKEN as Y, FormTowerControllerService as Z, _isEqual as _, assignDeepPropertyToObject as a, IMPORT_TOWER_INSTANCE_ID as a0, INPUT_SECRET_TOKEN as a1, MSCOA_TREE_PROVIDER as a2, MULTIPLE_FORM_INPUT_TOKEN as a3, NgxTFormsComponent as a4, NgxTFormsService as a5, PIPELINE_REPOSITORY as a6, PipelineRepository as a7, PropertyAccessError as a8, TFormImportController as a9, UTILS_OBJECT_TOKEN as aa, createFileFromBase64 as ab, formGenerator as ac, getPipedValueFromDataType as ad, getSampleValueForInput as ae, getSectionElements as af, getUrl as ag, getValueFromValueAccessor as ah, initFormConfigToV2 as ai, provideNgxTForms as aj, returnDeepProperty as ak, sheetConsolodation as al, textIconsForUserHints as am, validateExpressionSyntax as an, validateObjectAgainstString as ao, withHttpPipeline as ap, withInputSecret as aq, withRouterFormId as ar, formatData_pipe as as, TDynamicDataViewComponent as b, TFormEngine as c, TourManagerService as d, getSubmissionStatusFn as e, evaluatePredicate as f, getAvatar as g, emptyCondition as h, deriveObservedInputs as i, TreeComponent as j, convertPostmanFolderItemsToTree as k, ErrorListComponent as l, NESTED_EDITOR_COMPONENT as m, safeReturnDeepProperty as n, DataTreeComponent as o, parseConditions as p, getInputErrorMessage as q, referencedTokens as r, serializeConditions as s, testAgainstItem as t, TFormInputStatusComponent as u, DialogTemplateComponent as v, FormBuilderComponent as w, FormsComponent as x, TFormInputComponent as y, getSignatureImage as z };
|
|
20310
|
+
//# sourceMappingURL=ngx-t-forms-ngx-t-forms-C2G8_WQk.mjs.map
|