@fuentis/phoenix-ui 0.0.9-alpha.657 → 0.0.9-alpha.659
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/fuentis-phoenix-ui.mjs +538 -1073
- package/fesm2022/fuentis-phoenix-ui.mjs.map +1 -1
- package/index.d.ts +96 -166
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Input, Component, EventEmitter, Output, ViewEncapsulation, signal, Injectable, inject, input, output, ViewChild, ChangeDetectionStrategy, ViewChildren, Pipe, DestroyRef, ChangeDetectorRef, HostBinding, ContentChild, Directive, forwardRef, HostListener, computed, InjectionToken, Optional, Inject } from '@angular/core';
|
|
2
|
+
import { Input, Component, EventEmitter, Output, ViewEncapsulation, signal, Injectable, inject, input, output, ViewChild, ChangeDetectionStrategy, ViewChildren, Pipe, DestroyRef, ChangeDetectorRef, HostBinding, ContentChild, Directive, forwardRef, HostListener, computed, InjectionToken, Optional, Inject, effect } from '@angular/core';
|
|
3
3
|
import * as i1$2 from '@angular/common';
|
|
4
4
|
import { CommonModule, DatePipe } from '@angular/common';
|
|
5
5
|
import * as i1 from 'primeng/tooltip';
|
|
@@ -37,7 +37,7 @@ import * as i5 from 'primeng/inputicon';
|
|
|
37
37
|
import { InputIconModule } from 'primeng/inputicon';
|
|
38
38
|
import * as i2$5 from 'primeng/message';
|
|
39
39
|
import { MessageModule } from 'primeng/message';
|
|
40
|
-
import { Subject, debounceTime, switchMap, of, catchError, map, BehaviorSubject, merge, distinctUntilChanged, combineLatest, firstValueFrom } from 'rxjs';
|
|
40
|
+
import { Subject, debounceTime, switchMap, of, catchError, map, BehaviorSubject, merge, distinctUntilChanged, combineLatest, EMPTY, startWith, firstValueFrom } from 'rxjs';
|
|
41
41
|
import * as i4$3 from '@angular/common/http';
|
|
42
42
|
import { HttpParams } from '@angular/common/http';
|
|
43
43
|
import * as i2$1 from '@angular/forms';
|
|
@@ -60,7 +60,7 @@ import { PanelModule } from 'primeng/panel';
|
|
|
60
60
|
import { SkeletonModule } from 'primeng/skeleton';
|
|
61
61
|
import * as i2$4 from 'primeng/table';
|
|
62
62
|
import { TableModule } from 'primeng/table';
|
|
63
|
-
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
63
|
+
import { takeUntilDestroyed, toSignal, toObservable } from '@angular/core/rxjs-interop';
|
|
64
64
|
import * as i3$4 from 'primeng/select';
|
|
65
65
|
import { SelectModule } from 'primeng/select';
|
|
66
66
|
import * as i5$2 from 'primeng/multiselect';
|
|
@@ -100,6 +100,7 @@ import { Schema } from 'prosemirror-model';
|
|
|
100
100
|
import * as i2$9 from 'primeng/fileupload';
|
|
101
101
|
import { FileUploadModule } from 'primeng/fileupload';
|
|
102
102
|
import * as i1$4 from '@angular/platform-browser';
|
|
103
|
+
import { switchMap as switchMap$1 } from 'rxjs/operators';
|
|
103
104
|
|
|
104
105
|
class InnerHeaderComponent {
|
|
105
106
|
title = '';
|
|
@@ -8669,6 +8670,102 @@ function clearPersistedTableState(userPrefix) {
|
|
|
8669
8670
|
store.removeItem(key);
|
|
8670
8671
|
}
|
|
8671
8672
|
|
|
8673
|
+
/**
|
|
8674
|
+
* V2 TIMEPERIOD field (signal-based, OnPush). A plain text input for a duration
|
|
8675
|
+
* string (e.g. `2w 4d 6h 45m`) with a calm, always-on format helper underneath.
|
|
8676
|
+
*
|
|
8677
|
+
* Unlike the legacy `phoenix-meta-timeperiod`, the format guidance is rendered as
|
|
8678
|
+
* neutral helper text — never a red validation error — because the pattern is
|
|
8679
|
+
* guidance, not a failure. The control still carries whatever validators the form
|
|
8680
|
+
* config attaches (for form-level validity on submit); this field just doesn't
|
|
8681
|
+
* shout at the user while they type. The label is owned by the field wrapper, as
|
|
8682
|
+
* with every other V2 field.
|
|
8683
|
+
*/
|
|
8684
|
+
class MetaTimeperiodV2Component {
|
|
8685
|
+
/** Field key, used for the input id / data-cy. */
|
|
8686
|
+
key = input(...(ngDevMode ? [undefined, { debugName: "key" }] : []));
|
|
8687
|
+
/** Field-level disable coming from the meta config (combined with the CVA state). */
|
|
8688
|
+
disable = input(false, ...(ngDevMode ? [{ debugName: "disable" }] : []));
|
|
8689
|
+
formDisabled = signal(false, ...(ngDevMode ? [{ debugName: "formDisabled" }] : []));
|
|
8690
|
+
/** The duration string shown in the input (the control value is this string). */
|
|
8691
|
+
value = signal('', ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
8692
|
+
disabled = computed(() => this.disable() || this.formDisabled(), ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
8693
|
+
onChange = () => { };
|
|
8694
|
+
onTouched = () => { };
|
|
8695
|
+
writeValue(v) {
|
|
8696
|
+
if (v === null || v === undefined || v === '') {
|
|
8697
|
+
this.value.set('');
|
|
8698
|
+
return;
|
|
8699
|
+
}
|
|
8700
|
+
this.value.set(typeof v === 'string' ? v : timePeriodFromMS(v));
|
|
8701
|
+
}
|
|
8702
|
+
registerOnChange(fn) {
|
|
8703
|
+
this.onChange = fn;
|
|
8704
|
+
}
|
|
8705
|
+
registerOnTouched(fn) {
|
|
8706
|
+
this.onTouched = fn;
|
|
8707
|
+
}
|
|
8708
|
+
setDisabledState(isDisabled) {
|
|
8709
|
+
this.formDisabled.set(isDisabled);
|
|
8710
|
+
}
|
|
8711
|
+
onInput(event) {
|
|
8712
|
+
const next = event.target?.value ?? '';
|
|
8713
|
+
this.value.set(next);
|
|
8714
|
+
this.onChange(next);
|
|
8715
|
+
}
|
|
8716
|
+
handleBlur() {
|
|
8717
|
+
this.onTouched();
|
|
8718
|
+
}
|
|
8719
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MetaTimeperiodV2Component, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8720
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.16", type: MetaTimeperiodV2Component, isStandalone: true, selector: "phoenix-meta-timeperiod-v2", inputs: { key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: false, transformFunction: null }, disable: { classPropertyName: "disable", publicName: "disable", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
8721
|
+
{
|
|
8722
|
+
provide: NG_VALUE_ACCESSOR,
|
|
8723
|
+
useExisting: forwardRef(() => MetaTimeperiodV2Component),
|
|
8724
|
+
multi: true,
|
|
8725
|
+
},
|
|
8726
|
+
], ngImport: i0, template: `
|
|
8727
|
+
<input
|
|
8728
|
+
pInputText
|
|
8729
|
+
type="text"
|
|
8730
|
+
class="w-full"
|
|
8731
|
+
[attr.id]="key() ?? null"
|
|
8732
|
+
[attr.data-cy]="'time-period-v2-' + (key() ?? '')"
|
|
8733
|
+
[value]="value()"
|
|
8734
|
+
[disabled]="disabled()"
|
|
8735
|
+
(input)="onInput($event)"
|
|
8736
|
+
(blur)="handleBlur()"
|
|
8737
|
+
/>
|
|
8738
|
+
<small class="block mt-1 timeperiod-v2-hint">
|
|
8739
|
+
<i class="pi pi-info-circle mr-1"></i>{{ 'VALIDATION_MESSAGE.VALUE_SHOULD_MATCH_TIMEPATTERN' | translate }}
|
|
8740
|
+
</small>
|
|
8741
|
+
`, isInline: true, styles: [".timeperiod-v2-hint{color:var(--p-text-muted-color, #6b7280);font-size:12px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3$3.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i4$2.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
8742
|
+
}
|
|
8743
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MetaTimeperiodV2Component, decorators: [{
|
|
8744
|
+
type: Component,
|
|
8745
|
+
args: [{ selector: 'phoenix-meta-timeperiod-v2', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, InputTextModule, TranslateModule], template: `
|
|
8746
|
+
<input
|
|
8747
|
+
pInputText
|
|
8748
|
+
type="text"
|
|
8749
|
+
class="w-full"
|
|
8750
|
+
[attr.id]="key() ?? null"
|
|
8751
|
+
[attr.data-cy]="'time-period-v2-' + (key() ?? '')"
|
|
8752
|
+
[value]="value()"
|
|
8753
|
+
[disabled]="disabled()"
|
|
8754
|
+
(input)="onInput($event)"
|
|
8755
|
+
(blur)="handleBlur()"
|
|
8756
|
+
/>
|
|
8757
|
+
<small class="block mt-1 timeperiod-v2-hint">
|
|
8758
|
+
<i class="pi pi-info-circle mr-1"></i>{{ 'VALIDATION_MESSAGE.VALUE_SHOULD_MATCH_TIMEPATTERN' | translate }}
|
|
8759
|
+
</small>
|
|
8760
|
+
`, providers: [
|
|
8761
|
+
{
|
|
8762
|
+
provide: NG_VALUE_ACCESSOR,
|
|
8763
|
+
useExisting: forwardRef(() => MetaTimeperiodV2Component),
|
|
8764
|
+
multi: true,
|
|
8765
|
+
},
|
|
8766
|
+
], styles: [".timeperiod-v2-hint{color:var(--p-text-muted-color, #6b7280);font-size:12px}\n"] }]
|
|
8767
|
+
}], propDecorators: { key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: false }] }], disable: [{ type: i0.Input, args: [{ isSignal: true, alias: "disable", required: false }] }] } });
|
|
8768
|
+
|
|
8672
8769
|
class StripHtmlSafePipe {
|
|
8673
8770
|
transform(value) {
|
|
8674
8771
|
if (value === null || value === undefined)
|
|
@@ -8933,120 +9030,67 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
8933
9030
|
args: [{ required: true }]
|
|
8934
9031
|
}] } });
|
|
8935
9032
|
|
|
9033
|
+
/**
|
|
9034
|
+
* V2 ASSIGN field — signal-based ControlValueAccessor (OnPush, no manual CD).
|
|
9035
|
+
* Holds the full selected assignee (downstream fields often need more than uuid);
|
|
9036
|
+
* a picker dialog returns the chosen row.
|
|
9037
|
+
*/
|
|
8936
9038
|
class MetaAssignResponsibleV2Component {
|
|
8937
|
-
/**
|
|
8938
|
-
|
|
8939
|
-
|
|
8940
|
-
|
|
8941
|
-
*/
|
|
8942
|
-
items = [];
|
|
8943
|
-
/**
|
|
8944
|
-
* Translation key for the dialog header title.
|
|
8945
|
-
* Kept as an input so different contexts can reuse this field with a custom title.
|
|
8946
|
-
*/
|
|
8947
|
-
dialogHeaderKey = 'LABELS.ASSIGN_RESPONSIBLE';
|
|
9039
|
+
/** Selectable assignees shown in the picker dialog. */
|
|
9040
|
+
items = input([], ...(ngDevMode ? [{ debugName: "items" }] : []));
|
|
9041
|
+
/** i18n key for the dialog header title. */
|
|
9042
|
+
dialogHeaderKey = input('LABELS.ASSIGN_RESPONSIBLE', ...(ngDevMode ? [{ debugName: "dialogHeaderKey" }] : []));
|
|
8948
9043
|
translate = inject(TranslateService);
|
|
8949
9044
|
dialog = inject(DialogService);
|
|
8950
|
-
/**
|
|
8951
|
-
|
|
8952
|
-
|
|
8953
|
-
|
|
8954
|
-
value = null;
|
|
8955
|
-
/**
|
|
8956
|
-
* Disabled state propagated from Angular forms via `setDisabledState`.
|
|
8957
|
-
* (If you later add a field-level `@Input() disable`, combine them like in other CVAs.)
|
|
8958
|
-
*/
|
|
8959
|
-
disabled = false;
|
|
8960
|
-
/**
|
|
8961
|
-
* CVA callback invoked when the value changes (selection/clear).
|
|
8962
|
-
*/
|
|
9045
|
+
/** The full selected assignee bound to the parent control. */
|
|
9046
|
+
value = signal(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
9047
|
+
/** Disabled state from Angular Forms (this field has no separate field-level disable). */
|
|
9048
|
+
disabled = signal(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
8963
9049
|
onChange = () => { };
|
|
8964
|
-
/**
|
|
8965
|
-
* CVA callback invoked when the control is marked as touched (user interaction).
|
|
8966
|
-
* Standard: call on meaningful interactions (open dialog, select, clear).
|
|
8967
|
-
*/
|
|
8968
9050
|
onTouched = () => { };
|
|
8969
|
-
/**
|
|
8970
|
-
* Called by Angular forms when the model value changes programmatically.
|
|
8971
|
-
* Keep it side-effect free: do not call `onChange`/`onTouched` from here.
|
|
8972
|
-
*/
|
|
8973
9051
|
writeValue(value) {
|
|
8974
|
-
this.value
|
|
9052
|
+
this.value.set(value ?? null);
|
|
8975
9053
|
}
|
|
8976
|
-
/**
|
|
8977
|
-
* Registers the callback that should be called when the component updates the value.
|
|
8978
|
-
*/
|
|
8979
9054
|
registerOnChange(fn) {
|
|
8980
9055
|
this.onChange = fn;
|
|
8981
9056
|
}
|
|
8982
|
-
/**
|
|
8983
|
-
* Registers the callback that should be called when the control becomes "touched".
|
|
8984
|
-
*/
|
|
8985
9057
|
registerOnTouched(fn) {
|
|
8986
9058
|
this.onTouched = fn;
|
|
8987
9059
|
}
|
|
8988
|
-
/**
|
|
8989
|
-
* Receives disabled state from Angular forms and updates local state.
|
|
8990
|
-
*/
|
|
8991
9060
|
setDisabledState(isDisabled) {
|
|
8992
|
-
this.disabled
|
|
9061
|
+
this.disabled.set(isDisabled);
|
|
8993
9062
|
}
|
|
8994
|
-
/**
|
|
8995
|
-
* Clears current assignee value.
|
|
8996
|
-
* - emits `null`
|
|
8997
|
-
* - marks as touched (user action)
|
|
8998
|
-
*/
|
|
9063
|
+
/** Clears the assignee (emits null + touched). */
|
|
8999
9064
|
clear() {
|
|
9000
|
-
if (this.disabled)
|
|
9065
|
+
if (this.disabled())
|
|
9001
9066
|
return;
|
|
9002
|
-
|
|
9003
|
-
if (this.value === null) {
|
|
9067
|
+
if (this.value() === null) {
|
|
9004
9068
|
this.onTouched();
|
|
9005
9069
|
return;
|
|
9006
9070
|
}
|
|
9007
|
-
this.value
|
|
9071
|
+
this.value.set(null);
|
|
9008
9072
|
this.onChange(null);
|
|
9009
9073
|
this.onTouched();
|
|
9010
9074
|
}
|
|
9011
9075
|
/**
|
|
9012
|
-
* Opens
|
|
9013
|
-
*
|
|
9014
|
-
*
|
|
9015
|
-
* Standard for CVA:
|
|
9016
|
-
* - mark as touched when user opens the picker (interaction started)
|
|
9017
|
-
* - emit onChange only when a row is actually selected
|
|
9076
|
+
* Opens the picker dialog and applies the selected row. Touched on open
|
|
9077
|
+
* (interaction started); onChange only when a row is actually selected.
|
|
9018
9078
|
*/
|
|
9019
9079
|
openDialog() {
|
|
9020
|
-
if (this.disabled)
|
|
9080
|
+
if (this.disabled())
|
|
9021
9081
|
return;
|
|
9022
9082
|
this.onTouched();
|
|
9023
9083
|
const ref = this.dialog.open(ObjectItemDialogComponent, {
|
|
9024
|
-
header: this.translate.instant(this.dialogHeaderKey),
|
|
9084
|
+
header: this.translate.instant(this.dialogHeaderKey()),
|
|
9025
9085
|
width: '700px',
|
|
9026
9086
|
modal: true,
|
|
9027
9087
|
data: {
|
|
9028
|
-
tableData: this.items,
|
|
9088
|
+
tableData: this.items(),
|
|
9029
9089
|
columns: [
|
|
9030
|
-
{
|
|
9031
|
-
|
|
9032
|
-
|
|
9033
|
-
|
|
9034
|
-
},
|
|
9035
|
-
{
|
|
9036
|
-
field: 'function',
|
|
9037
|
-
header: 'LABELS.FUNCTION',
|
|
9038
|
-
columnType: tableColumnType.TEXT,
|
|
9039
|
-
},
|
|
9040
|
-
{
|
|
9041
|
-
field: 'phone',
|
|
9042
|
-
header: 'LABELS.PHONE',
|
|
9043
|
-
columnType: tableColumnType.TEXT,
|
|
9044
|
-
},
|
|
9045
|
-
{
|
|
9046
|
-
field: 'email',
|
|
9047
|
-
header: 'LABELS.EMAIL',
|
|
9048
|
-
columnType: tableColumnType.TEXT,
|
|
9049
|
-
},
|
|
9090
|
+
{ field: 'name', header: 'LABELS.NAME', columnType: tableColumnType.TEXT },
|
|
9091
|
+
{ field: 'function', header: 'LABELS.FUNCTION', columnType: tableColumnType.TEXT },
|
|
9092
|
+
{ field: 'phone', header: 'LABELS.PHONE', columnType: tableColumnType.TEXT },
|
|
9093
|
+
{ field: 'email', header: 'LABELS.EMAIL', columnType: tableColumnType.TEXT },
|
|
9050
9094
|
],
|
|
9051
9095
|
},
|
|
9052
9096
|
contentStyle: { overflow: 'auto' },
|
|
@@ -9056,47 +9100,46 @@ class MetaAssignResponsibleV2Component {
|
|
|
9056
9100
|
ref?.onClose.subscribe((response) => {
|
|
9057
9101
|
if (!response)
|
|
9058
9102
|
return;
|
|
9059
|
-
|
|
9060
|
-
const same = (
|
|
9061
|
-
JSON.stringify(
|
|
9062
|
-
this.value
|
|
9063
|
-
if (!same)
|
|
9103
|
+
const current = this.value();
|
|
9104
|
+
const same = (current?.uuid ?? null) === (response?.uuid ?? null) &&
|
|
9105
|
+
JSON.stringify(current ?? null) === JSON.stringify(response ?? null);
|
|
9106
|
+
this.value.set(response);
|
|
9107
|
+
if (!same)
|
|
9064
9108
|
this.onChange(response);
|
|
9065
|
-
}
|
|
9066
9109
|
this.onTouched();
|
|
9067
9110
|
});
|
|
9068
9111
|
}
|
|
9069
9112
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MetaAssignResponsibleV2Component, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9070
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: MetaAssignResponsibleV2Component, isStandalone: true, selector: "phoenix-meta-assign-responsible-v2", inputs: { items: "items", dialogHeaderKey: "dialogHeaderKey" }, providers: [
|
|
9113
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: MetaAssignResponsibleV2Component, isStandalone: true, selector: "phoenix-meta-assign-responsible-v2", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, dialogHeaderKey: { classPropertyName: "dialogHeaderKey", publicName: "dialogHeaderKey", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
9071
9114
|
{
|
|
9072
9115
|
provide: NG_VALUE_ACCESSOR,
|
|
9073
9116
|
useExisting: forwardRef(() => MetaAssignResponsibleV2Component),
|
|
9074
9117
|
multi: true,
|
|
9075
9118
|
},
|
|
9076
9119
|
], ngImport: i0, template: `
|
|
9077
|
-
@if (value?.uuid) {
|
|
9120
|
+
@if (value()?.uuid) {
|
|
9078
9121
|
<div class="flex align-items-center">
|
|
9079
9122
|
<div>
|
|
9080
9123
|
<p-button
|
|
9081
9124
|
[rounded]="true"
|
|
9082
9125
|
[text]="true"
|
|
9083
9126
|
(onClick)="op.toggle($event)"
|
|
9084
|
-
[disabled]="disabled"
|
|
9127
|
+
[disabled]="disabled()"
|
|
9085
9128
|
>
|
|
9086
9129
|
<div class="person-wrap">
|
|
9087
9130
|
<div class="person-avatar">
|
|
9088
|
-
{{ (value?.name ?? '').toUpperCase().charAt(0) }}
|
|
9131
|
+
{{ (value()?.name ?? '').toUpperCase().charAt(0) }}
|
|
9089
9132
|
</div>
|
|
9090
9133
|
<div>
|
|
9091
9134
|
<p
|
|
9092
9135
|
class="white-space-nowrap overflow-hidden text-overflow-ellipsis"
|
|
9093
9136
|
>
|
|
9094
|
-
{{ value?.name ?? '--' }}
|
|
9137
|
+
{{ value()?.name ?? '--' }}
|
|
9095
9138
|
</p>
|
|
9096
9139
|
<p
|
|
9097
9140
|
class="white-space-nowrap overflow-hidden text-overflow-ellipsis"
|
|
9098
9141
|
>
|
|
9099
|
-
{{ value?.function ?? '--' }}
|
|
9142
|
+
{{ value()?.function ?? '--' }}
|
|
9100
9143
|
</p>
|
|
9101
9144
|
</div>
|
|
9102
9145
|
</div>
|
|
@@ -9107,28 +9150,28 @@ class MetaAssignResponsibleV2Component {
|
|
|
9107
9150
|
<span
|
|
9108
9151
|
class="block mb-2"
|
|
9109
9152
|
pTooltip="{{
|
|
9110
|
-
(value?.email?.length ?? 0) > 25 ? value?.email : ''
|
|
9153
|
+
(value()?.email?.length ?? 0) > 25 ? value()?.email : ''
|
|
9111
9154
|
}}"
|
|
9112
9155
|
tooltipPosition="right"
|
|
9113
9156
|
>
|
|
9114
9157
|
<i class="pi pi-envelope mr-1 text-500"></i>
|
|
9115
9158
|
{{
|
|
9116
|
-
(value?.email?.length ?? 0) > 25
|
|
9117
|
-
? value?.email?.slice(0, 25) + '...'
|
|
9118
|
-
: (value?.email ?? '--')
|
|
9159
|
+
(value()?.email?.length ?? 0) > 25
|
|
9160
|
+
? value()?.email?.slice(0, 25) + '...'
|
|
9161
|
+
: (value()?.email ?? '--')
|
|
9119
9162
|
}}
|
|
9120
9163
|
</span>
|
|
9121
9164
|
<p
|
|
9122
9165
|
pTooltip="{{
|
|
9123
|
-
(value?.phone?.length ?? 0) > 25 ? value?.phone : ''
|
|
9166
|
+
(value()?.phone?.length ?? 0) > 25 ? value()?.phone : ''
|
|
9124
9167
|
}}"
|
|
9125
9168
|
tooltipPosition="right"
|
|
9126
9169
|
>
|
|
9127
9170
|
<i class="pi pi-phone mr-1 text-500"></i>
|
|
9128
9171
|
{{
|
|
9129
|
-
(value?.phone?.length ?? 0) > 25
|
|
9130
|
-
? value?.phone?.slice(0, 25) + '...'
|
|
9131
|
-
: (value?.phone ?? '--')
|
|
9172
|
+
(value()?.phone?.length ?? 0) > 25
|
|
9173
|
+
? value()?.phone?.slice(0, 25) + '...'
|
|
9174
|
+
: (value()?.phone ?? '--')
|
|
9132
9175
|
}}
|
|
9133
9176
|
</p>
|
|
9134
9177
|
</div>
|
|
@@ -9140,7 +9183,7 @@ class MetaAssignResponsibleV2Component {
|
|
|
9140
9183
|
styleClass="p-button-sm mt-1"
|
|
9141
9184
|
type="button"
|
|
9142
9185
|
[text]="true"
|
|
9143
|
-
[disabled]="disabled"
|
|
9186
|
+
[disabled]="disabled()"
|
|
9144
9187
|
[label]="'ACTION.REASSIGN' | translate"
|
|
9145
9188
|
(click)="op.hide(); openDialog()"
|
|
9146
9189
|
></p-button>
|
|
@@ -9148,7 +9191,7 @@ class MetaAssignResponsibleV2Component {
|
|
|
9148
9191
|
<p-button
|
|
9149
9192
|
type="button"
|
|
9150
9193
|
icon="pi pi-times"
|
|
9151
|
-
[disabled]="disabled"
|
|
9194
|
+
[disabled]="disabled()"
|
|
9152
9195
|
(click)="op.hide(); clear()"
|
|
9153
9196
|
[text]="true"
|
|
9154
9197
|
styleClass="p-button-danger p-button-sm mt-1 ml-2"
|
|
@@ -9163,14 +9206,14 @@ class MetaAssignResponsibleV2Component {
|
|
|
9163
9206
|
[label]="'ACTION.ASSIGN' | translate"
|
|
9164
9207
|
(click)="openDialog()"
|
|
9165
9208
|
[text]="true"
|
|
9166
|
-
[disabled]="disabled"
|
|
9209
|
+
[disabled]="disabled()"
|
|
9167
9210
|
></p-button>
|
|
9168
9211
|
}
|
|
9169
|
-
`, isInline: true, styles: ["::ng-deep .p-popover-content{padding:0!important}.person-wrap{display:flex;align-items:center;margin-left:-6px}.person-wrap p{margin:0}.person-avatar{display:flex;justify-content:center;align-items:center;width:28px;height:28px;min-width:28px;min-height:28px;margin-right:5px;background-color:#e94260;color:#fff;border-radius:50%;font-size:1rem}.person-details{border-top:1px solid #e0e0e0;padding:10px;width:200px}.person-details p{margin:0;display:flex;align-items:center}.person-details i{color:#e94260;padding-right:5px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i3.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i3$2.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "pipe", type: i4$2.TranslatePipe, name: "translate" }] });
|
|
9212
|
+
`, isInline: true, styles: ["::ng-deep .p-popover-content{padding:0!important}.person-wrap{display:flex;align-items:center;margin-left:-6px}.person-wrap p{margin:0}.person-avatar{display:flex;justify-content:center;align-items:center;width:28px;height:28px;min-width:28px;min-height:28px;margin-right:5px;background-color:#e94260;color:#fff;border-radius:50%;font-size:1rem}.person-details{border-top:1px solid #e0e0e0;padding:10px;width:200px}.person-details p{margin:0;display:flex;align-items:center}.person-details i{color:#e94260;padding-right:5px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i3.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i3$2.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "pipe", type: i4$2.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
9170
9213
|
}
|
|
9171
9214
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MetaAssignResponsibleV2Component, decorators: [{
|
|
9172
9215
|
type: Component,
|
|
9173
|
-
args: [{ selector: 'phoenix-meta-assign-responsible-v2', standalone: true, imports: [
|
|
9216
|
+
args: [{ selector: 'phoenix-meta-assign-responsible-v2', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
9174
9217
|
CommonModule,
|
|
9175
9218
|
ButtonModule,
|
|
9176
9219
|
PopoverModule,
|
|
@@ -9183,29 +9226,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
9183
9226
|
multi: true,
|
|
9184
9227
|
},
|
|
9185
9228
|
], template: `
|
|
9186
|
-
@if (value?.uuid) {
|
|
9229
|
+
@if (value()?.uuid) {
|
|
9187
9230
|
<div class="flex align-items-center">
|
|
9188
9231
|
<div>
|
|
9189
9232
|
<p-button
|
|
9190
9233
|
[rounded]="true"
|
|
9191
9234
|
[text]="true"
|
|
9192
9235
|
(onClick)="op.toggle($event)"
|
|
9193
|
-
[disabled]="disabled"
|
|
9236
|
+
[disabled]="disabled()"
|
|
9194
9237
|
>
|
|
9195
9238
|
<div class="person-wrap">
|
|
9196
9239
|
<div class="person-avatar">
|
|
9197
|
-
{{ (value?.name ?? '').toUpperCase().charAt(0) }}
|
|
9240
|
+
{{ (value()?.name ?? '').toUpperCase().charAt(0) }}
|
|
9198
9241
|
</div>
|
|
9199
9242
|
<div>
|
|
9200
9243
|
<p
|
|
9201
9244
|
class="white-space-nowrap overflow-hidden text-overflow-ellipsis"
|
|
9202
9245
|
>
|
|
9203
|
-
{{ value?.name ?? '--' }}
|
|
9246
|
+
{{ value()?.name ?? '--' }}
|
|
9204
9247
|
</p>
|
|
9205
9248
|
<p
|
|
9206
9249
|
class="white-space-nowrap overflow-hidden text-overflow-ellipsis"
|
|
9207
9250
|
>
|
|
9208
|
-
{{ value?.function ?? '--' }}
|
|
9251
|
+
{{ value()?.function ?? '--' }}
|
|
9209
9252
|
</p>
|
|
9210
9253
|
</div>
|
|
9211
9254
|
</div>
|
|
@@ -9216,28 +9259,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
9216
9259
|
<span
|
|
9217
9260
|
class="block mb-2"
|
|
9218
9261
|
pTooltip="{{
|
|
9219
|
-
(value?.email?.length ?? 0) > 25 ? value?.email : ''
|
|
9262
|
+
(value()?.email?.length ?? 0) > 25 ? value()?.email : ''
|
|
9220
9263
|
}}"
|
|
9221
9264
|
tooltipPosition="right"
|
|
9222
9265
|
>
|
|
9223
9266
|
<i class="pi pi-envelope mr-1 text-500"></i>
|
|
9224
9267
|
{{
|
|
9225
|
-
(value?.email?.length ?? 0) > 25
|
|
9226
|
-
? value?.email?.slice(0, 25) + '...'
|
|
9227
|
-
: (value?.email ?? '--')
|
|
9268
|
+
(value()?.email?.length ?? 0) > 25
|
|
9269
|
+
? value()?.email?.slice(0, 25) + '...'
|
|
9270
|
+
: (value()?.email ?? '--')
|
|
9228
9271
|
}}
|
|
9229
9272
|
</span>
|
|
9230
9273
|
<p
|
|
9231
9274
|
pTooltip="{{
|
|
9232
|
-
(value?.phone?.length ?? 0) > 25 ? value?.phone : ''
|
|
9275
|
+
(value()?.phone?.length ?? 0) > 25 ? value()?.phone : ''
|
|
9233
9276
|
}}"
|
|
9234
9277
|
tooltipPosition="right"
|
|
9235
9278
|
>
|
|
9236
9279
|
<i class="pi pi-phone mr-1 text-500"></i>
|
|
9237
9280
|
{{
|
|
9238
|
-
(value?.phone?.length ?? 0) > 25
|
|
9239
|
-
? value?.phone?.slice(0, 25) + '...'
|
|
9240
|
-
: (value?.phone ?? '--')
|
|
9281
|
+
(value()?.phone?.length ?? 0) > 25
|
|
9282
|
+
? value()?.phone?.slice(0, 25) + '...'
|
|
9283
|
+
: (value()?.phone ?? '--')
|
|
9241
9284
|
}}
|
|
9242
9285
|
</p>
|
|
9243
9286
|
</div>
|
|
@@ -9249,7 +9292,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
9249
9292
|
styleClass="p-button-sm mt-1"
|
|
9250
9293
|
type="button"
|
|
9251
9294
|
[text]="true"
|
|
9252
|
-
[disabled]="disabled"
|
|
9295
|
+
[disabled]="disabled()"
|
|
9253
9296
|
[label]="'ACTION.REASSIGN' | translate"
|
|
9254
9297
|
(click)="op.hide(); openDialog()"
|
|
9255
9298
|
></p-button>
|
|
@@ -9257,7 +9300,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
9257
9300
|
<p-button
|
|
9258
9301
|
type="button"
|
|
9259
9302
|
icon="pi pi-times"
|
|
9260
|
-
[disabled]="disabled"
|
|
9303
|
+
[disabled]="disabled()"
|
|
9261
9304
|
(click)="op.hide(); clear()"
|
|
9262
9305
|
[text]="true"
|
|
9263
9306
|
styleClass="p-button-danger p-button-sm mt-1 ml-2"
|
|
@@ -9272,109 +9315,51 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
9272
9315
|
[label]="'ACTION.ASSIGN' | translate"
|
|
9273
9316
|
(click)="openDialog()"
|
|
9274
9317
|
[text]="true"
|
|
9275
|
-
[disabled]="disabled"
|
|
9318
|
+
[disabled]="disabled()"
|
|
9276
9319
|
></p-button>
|
|
9277
9320
|
}
|
|
9278
9321
|
`, styles: ["::ng-deep .p-popover-content{padding:0!important}.person-wrap{display:flex;align-items:center;margin-left:-6px}.person-wrap p{margin:0}.person-avatar{display:flex;justify-content:center;align-items:center;width:28px;height:28px;min-width:28px;min-height:28px;margin-right:5px;background-color:#e94260;color:#fff;border-radius:50%;font-size:1rem}.person-details{border-top:1px solid #e0e0e0;padding:10px;width:200px}.person-details p{margin:0;display:flex;align-items:center}.person-details i{color:#e94260;padding-right:5px}\n"] }]
|
|
9279
|
-
}], propDecorators: { items: [{
|
|
9280
|
-
type: Input
|
|
9281
|
-
}], dialogHeaderKey: [{
|
|
9282
|
-
type: Input
|
|
9283
|
-
}] } });
|
|
9322
|
+
}], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], dialogHeaderKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "dialogHeaderKey", required: false }] }] } });
|
|
9284
9323
|
|
|
9324
|
+
/**
|
|
9325
|
+
* V2 COLOR field — signal-based ControlValueAccessor (OnPush, no manual CD).
|
|
9326
|
+
* Stores a HEX string (or null); the template reads the value/disabled signals.
|
|
9327
|
+
*/
|
|
9285
9328
|
class MetaColorPickerV2Component {
|
|
9286
|
-
/**
|
|
9287
|
-
|
|
9288
|
-
|
|
9289
|
-
|
|
9290
|
-
|
|
9291
|
-
|
|
9292
|
-
/**
|
|
9293
|
-
* Currently selected color value.
|
|
9294
|
-
* Expected format: HEX string (e.g. "#ff00aa") or null.
|
|
9295
|
-
*/
|
|
9296
|
-
value = null;
|
|
9297
|
-
/**
|
|
9298
|
-
* CVA callback invoked when the value changes.
|
|
9299
|
-
*/
|
|
9329
|
+
/** Field-level disable (meta config), combined with the Angular Forms state. */
|
|
9330
|
+
disable = input(false, ...(ngDevMode ? [{ debugName: "disable" }] : []));
|
|
9331
|
+
/** Selected colour: HEX string (e.g. "#ff00aa") or null. */
|
|
9332
|
+
value = signal(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
9333
|
+
formDisabled = signal(false, ...(ngDevMode ? [{ debugName: "formDisabled" }] : []));
|
|
9334
|
+
disabled = computed(() => this.disable() || this.formDisabled(), ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
9300
9335
|
onChange = () => { };
|
|
9301
|
-
/**
|
|
9302
|
-
* CVA callback invoked when the control is marked as touched.
|
|
9303
|
-
* Standard: call on blur / close, not on every value change.
|
|
9304
|
-
*/
|
|
9305
9336
|
onTouched = () => { };
|
|
9306
|
-
/**
|
|
9307
|
-
* Disabled state coming from Angular Forms (ControlValueAccessor).
|
|
9308
|
-
*/
|
|
9309
|
-
isDisabled = false;
|
|
9310
|
-
/**
|
|
9311
|
-
* Final disabled state combining:
|
|
9312
|
-
* - form-level disabled state (CVA)
|
|
9313
|
-
* - field-level disable flag (input)
|
|
9314
|
-
*/
|
|
9315
|
-
get disabled() {
|
|
9316
|
-
return this.disable || this.isDisabled;
|
|
9317
|
-
}
|
|
9318
|
-
/**
|
|
9319
|
-
* Writes a new value from the parent form control into the component.
|
|
9320
|
-
* Keep it idempotent and UI-safe.
|
|
9321
|
-
*/
|
|
9322
9337
|
writeValue(v) {
|
|
9323
|
-
this.value
|
|
9324
|
-
this.cdr.markForCheck();
|
|
9338
|
+
this.value.set(this.normalizeHex(v));
|
|
9325
9339
|
}
|
|
9326
|
-
/**
|
|
9327
|
-
* Registers callback that is triggered when the value changes.
|
|
9328
|
-
*/
|
|
9329
9340
|
registerOnChange(fn) {
|
|
9330
9341
|
this.onChange = fn;
|
|
9331
9342
|
}
|
|
9332
|
-
/**
|
|
9333
|
-
* Registers callback that is triggered when the control is touched.
|
|
9334
|
-
*/
|
|
9335
9343
|
registerOnTouched(fn) {
|
|
9336
9344
|
this.onTouched = fn;
|
|
9337
9345
|
}
|
|
9338
|
-
/**
|
|
9339
|
-
* Receives disabled state from Angular Forms and updates local state.
|
|
9340
|
-
*/
|
|
9341
9346
|
setDisabledState(isDisabled) {
|
|
9342
|
-
this.isDisabled
|
|
9343
|
-
this.cdr.markForCheck();
|
|
9347
|
+
this.formDisabled.set(isDisabled);
|
|
9344
9348
|
}
|
|
9345
|
-
/**
|
|
9346
|
-
|
|
9347
|
-
|
|
9348
|
-
*
|
|
9349
|
-
* Note: we intentionally do NOT call onTouched here (our standard is: touched on blur).
|
|
9350
|
-
*/
|
|
9351
|
-
onPickerChange() {
|
|
9352
|
-
if (this.disabled)
|
|
9349
|
+
/** Touched is emitted on blur (not on value change). */
|
|
9350
|
+
onPickerChange(next) {
|
|
9351
|
+
if (this.disabled())
|
|
9353
9352
|
return;
|
|
9354
|
-
const
|
|
9355
|
-
|
|
9356
|
-
|
|
9357
|
-
this.cdr.markForCheck();
|
|
9358
|
-
return;
|
|
9359
|
-
}
|
|
9360
|
-
this.value = next;
|
|
9361
|
-
this.onChange(next);
|
|
9362
|
-
this.cdr.markForCheck();
|
|
9353
|
+
const normalized = this.normalizeHex(next);
|
|
9354
|
+
this.value.set(normalized);
|
|
9355
|
+
this.onChange(normalized);
|
|
9363
9356
|
}
|
|
9364
|
-
/**
|
|
9365
|
-
* Marks control as touched when user leaves the component.
|
|
9366
|
-
* (Matches "touched on blur" CVA guideline.)
|
|
9367
|
-
*/
|
|
9368
9357
|
handleBlur() {
|
|
9369
|
-
if (this.disabled)
|
|
9358
|
+
if (this.disabled())
|
|
9370
9359
|
return;
|
|
9371
9360
|
this.onTouched();
|
|
9372
9361
|
}
|
|
9373
|
-
/**
|
|
9374
|
-
* Normalizes incoming values to a safe HEX string or null.
|
|
9375
|
-
* - accepts "#RRGGBB" / "#RGB" / "RRGGBB"
|
|
9376
|
-
* - returns null for empty/invalid inputs
|
|
9377
|
-
*/
|
|
9362
|
+
/** Normalizes to "#rrggbb"/"#rgb" (adds '#', lowercases) or null. */
|
|
9378
9363
|
normalizeHex(v) {
|
|
9379
9364
|
if (v === null || v === undefined)
|
|
9380
9365
|
return null;
|
|
@@ -9386,7 +9371,7 @@ class MetaColorPickerV2Component {
|
|
|
9386
9371
|
return ok ? withHash.toLowerCase() : null;
|
|
9387
9372
|
}
|
|
9388
9373
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MetaColorPickerV2Component, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9389
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
9374
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.16", type: MetaColorPickerV2Component, isStandalone: true, selector: "phoenix-meta-color-picker-v2", inputs: { disable: { classPropertyName: "disable", publicName: "disable", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
9390
9375
|
{
|
|
9391
9376
|
provide: NG_VALUE_ACCESSOR,
|
|
9392
9377
|
useExisting: forwardRef(() => MetaColorPickerV2Component),
|
|
@@ -9395,10 +9380,10 @@ class MetaColorPickerV2Component {
|
|
|
9395
9380
|
], ngImport: i0, template: `
|
|
9396
9381
|
<p-colorPicker
|
|
9397
9382
|
class="color-swatch"
|
|
9398
|
-
[
|
|
9399
|
-
(
|
|
9383
|
+
[ngModel]="value()"
|
|
9384
|
+
(ngModelChange)="onPickerChange($event)"
|
|
9400
9385
|
(onBlur)="handleBlur()"
|
|
9401
|
-
[disabled]="disabled"
|
|
9386
|
+
[disabled]="disabled()"
|
|
9402
9387
|
[appendTo]="'body'"
|
|
9403
9388
|
></p-colorPicker>
|
|
9404
9389
|
`, isInline: true, styles: [":host ::ng-deep .color-swatch.p-colorpicker{width:35px;height:35px;padding:0!important;border:none!important;background:transparent!important;box-shadow:none!important}:host ::ng-deep .color-swatch .p-colorpicker-preview{width:35px!important;height:35px!important;border:none!important;border-radius:6px!important;box-shadow:none!important}:host ::ng-deep .color-swatch .p-colorpicker-preview:focus,:host ::ng-deep .color-swatch .p-colorpicker-preview:focus-visible{outline:none!important;box-shadow:none!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ColorPickerModule }, { kind: "component", type: i2$7.ColorPicker, selector: "p-colorPicker, p-colorpicker, p-color-picker", inputs: ["styleClass", "inline", "format", "tabindex", "inputId", "autoZIndex", "showTransitionOptions", "hideTransitionOptions", "autofocus", "defaultColor", "appendTo"], outputs: ["onChange", "onShow", "onHide"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
@@ -9408,10 +9393,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
9408
9393
|
args: [{ selector: 'phoenix-meta-color-picker-v2', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, FormsModule, ColorPickerModule], template: `
|
|
9409
9394
|
<p-colorPicker
|
|
9410
9395
|
class="color-swatch"
|
|
9411
|
-
[
|
|
9412
|
-
(
|
|
9396
|
+
[ngModel]="value()"
|
|
9397
|
+
(ngModelChange)="onPickerChange($event)"
|
|
9413
9398
|
(onBlur)="handleBlur()"
|
|
9414
|
-
[disabled]="disabled"
|
|
9399
|
+
[disabled]="disabled()"
|
|
9415
9400
|
[appendTo]="'body'"
|
|
9416
9401
|
></p-colorPicker>
|
|
9417
9402
|
`, providers: [
|
|
@@ -9421,128 +9406,61 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
9421
9406
|
multi: true,
|
|
9422
9407
|
},
|
|
9423
9408
|
], styles: [":host ::ng-deep .color-swatch.p-colorpicker{width:35px;height:35px;padding:0!important;border:none!important;background:transparent!important;box-shadow:none!important}:host ::ng-deep .color-swatch .p-colorpicker-preview{width:35px!important;height:35px!important;border:none!important;border-radius:6px!important;box-shadow:none!important}:host ::ng-deep .color-swatch .p-colorpicker-preview:focus,:host ::ng-deep .color-swatch .p-colorpicker-preview:focus-visible{outline:none!important;box-shadow:none!important}\n"] }]
|
|
9424
|
-
}], propDecorators: { disable: [{
|
|
9425
|
-
type: Input
|
|
9426
|
-
}] } });
|
|
9409
|
+
}], propDecorators: { disable: [{ type: i0.Input, args: [{ isSignal: true, alias: "disable", required: false }] }] } });
|
|
9427
9410
|
|
|
9411
|
+
/**
|
|
9412
|
+
* V2 CHECKBOX_COLOR field — signal-based ControlValueAccessor (OnPush, no manual
|
|
9413
|
+
* CD). A colour swatch that opens a grid popover; value + focus highlight live in
|
|
9414
|
+
* signals.
|
|
9415
|
+
*/
|
|
9428
9416
|
class MetaCheckboxColorPickerV2Component {
|
|
9429
|
-
/**
|
|
9430
|
-
|
|
9431
|
-
|
|
9432
|
-
|
|
9433
|
-
|
|
9434
|
-
|
|
9435
|
-
|
|
9436
|
-
|
|
9437
|
-
|
|
9438
|
-
|
|
9439
|
-
* External disable flag (e.g. meta-form field-level disable).
|
|
9440
|
-
* This is combined with CVA disabled state.
|
|
9441
|
-
*/
|
|
9442
|
-
disable = false;
|
|
9443
|
-
cdr = inject(ChangeDetectorRef);
|
|
9444
|
-
/**
|
|
9445
|
-
* Currently selected color value bound to the parent form control.
|
|
9446
|
-
*/
|
|
9447
|
-
value = null;
|
|
9448
|
-
/**
|
|
9449
|
-
* Color currently focused/hovered in the UI.
|
|
9450
|
-
* Used only for visual outline highlight in the picker grid.
|
|
9451
|
-
*/
|
|
9452
|
-
focusedColor = null;
|
|
9453
|
-
/**
|
|
9454
|
-
* Disabled state coming from Angular Forms (ControlValueAccessor).
|
|
9455
|
-
*/
|
|
9456
|
-
isDisabled = false;
|
|
9457
|
-
/**
|
|
9458
|
-
* CVA callback invoked when the value changes.
|
|
9459
|
-
*/
|
|
9417
|
+
/** 2D grid of colours rendered in the popover. */
|
|
9418
|
+
options = input([], ...(ngDevMode ? [{ debugName: "options" }] : []));
|
|
9419
|
+
/** Field-level disable (meta config), combined with the Angular Forms state. */
|
|
9420
|
+
disable = input(false, ...(ngDevMode ? [{ debugName: "disable" }] : []));
|
|
9421
|
+
/** Selected colour bound to the parent control. */
|
|
9422
|
+
value = signal(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
9423
|
+
/** Colour currently focused/hovered in the grid (visual outline only). */
|
|
9424
|
+
focusedColor = signal(null, ...(ngDevMode ? [{ debugName: "focusedColor" }] : []));
|
|
9425
|
+
formDisabled = signal(false, ...(ngDevMode ? [{ debugName: "formDisabled" }] : []));
|
|
9426
|
+
disabled = computed(() => this.disable() || this.formDisabled(), ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
9460
9427
|
onChange = () => { };
|
|
9461
|
-
/**
|
|
9462
|
-
* CVA callback invoked when the control is marked as touched.
|
|
9463
|
-
* Standard: touched on "open/blur/close" actions, not necessarily on hover.
|
|
9464
|
-
*/
|
|
9465
9428
|
onTouched = () => { };
|
|
9466
|
-
/**
|
|
9467
|
-
* Final disabled state combining:
|
|
9468
|
-
* - form-level disabled state (CVA)
|
|
9469
|
-
* - field-level disable flag (input)
|
|
9470
|
-
*/
|
|
9471
|
-
get disabled() {
|
|
9472
|
-
return this.disable || this.isDisabled;
|
|
9473
|
-
}
|
|
9474
|
-
// ----- ControlValueAccessor implementation -----
|
|
9475
|
-
/**
|
|
9476
|
-
* Writes a new value from the parent form into the component.
|
|
9477
|
-
* Keeps internal value and focusedColor in sync for correct UI outline.
|
|
9478
|
-
*/
|
|
9479
9429
|
writeValue(v) {
|
|
9480
|
-
|
|
9481
|
-
this.
|
|
9482
|
-
this.
|
|
9430
|
+
const next = this.normalizeColor(v);
|
|
9431
|
+
this.value.set(next);
|
|
9432
|
+
this.focusedColor.set(next);
|
|
9483
9433
|
}
|
|
9484
|
-
/**
|
|
9485
|
-
* Registers callback that is triggered when the value changes.
|
|
9486
|
-
*/
|
|
9487
9434
|
registerOnChange(fn) {
|
|
9488
9435
|
this.onChange = fn;
|
|
9489
9436
|
}
|
|
9490
|
-
/**
|
|
9491
|
-
* Registers callback that is triggered when the control is touched.
|
|
9492
|
-
*/
|
|
9493
9437
|
registerOnTouched(fn) {
|
|
9494
9438
|
this.onTouched = fn;
|
|
9495
9439
|
}
|
|
9496
|
-
/**
|
|
9497
|
-
* Receives disabled state from Angular Forms and updates local state.
|
|
9498
|
-
*/
|
|
9499
9440
|
setDisabledState(isDisabled) {
|
|
9500
|
-
this.isDisabled
|
|
9501
|
-
this.cdr.markForCheck();
|
|
9441
|
+
this.formDisabled.set(isDisabled);
|
|
9502
9442
|
}
|
|
9503
|
-
// ----- UI handlers -----
|
|
9504
|
-
/**
|
|
9505
|
-
* Toggles the popover visibility when the selected-color button is clicked.
|
|
9506
|
-
* We mark as touched because user interacted with the control.
|
|
9507
|
-
*/
|
|
9508
9443
|
toggle(popover, ev) {
|
|
9509
|
-
if (this.disabled)
|
|
9444
|
+
if (this.disabled())
|
|
9510
9445
|
return;
|
|
9511
9446
|
this.onTouched();
|
|
9512
9447
|
popover.toggle(ev);
|
|
9513
9448
|
}
|
|
9514
|
-
/**
|
|
9515
|
-
* Handles color selection from the grid:
|
|
9516
|
-
* - updates internal value
|
|
9517
|
-
* - propagates value to parent form (onChange)
|
|
9518
|
-
* - marks control as touched (selection is a meaningful interaction)
|
|
9519
|
-
* - closes the popover
|
|
9520
|
-
*/
|
|
9521
9449
|
select(color, popover) {
|
|
9522
|
-
if (this.disabled)
|
|
9450
|
+
if (this.disabled())
|
|
9523
9451
|
return;
|
|
9524
9452
|
const next = this.normalizeColor(color);
|
|
9525
|
-
|
|
9526
|
-
if (next
|
|
9527
|
-
this.
|
|
9528
|
-
this.
|
|
9529
|
-
this.cdr.markForCheck();
|
|
9530
|
-
popover.hide();
|
|
9531
|
-
return;
|
|
9453
|
+
this.focusedColor.set(next);
|
|
9454
|
+
if (next !== this.value()) {
|
|
9455
|
+
this.value.set(next);
|
|
9456
|
+
this.onChange(next);
|
|
9532
9457
|
}
|
|
9533
|
-
this.focusedColor = next;
|
|
9534
|
-
this.value = next;
|
|
9535
|
-
this.onChange(next);
|
|
9536
9458
|
this.onTouched();
|
|
9537
|
-
this.cdr.markForCheck();
|
|
9538
9459
|
popover.hide();
|
|
9539
9460
|
}
|
|
9540
9461
|
/**
|
|
9541
|
-
* Normalizes
|
|
9542
|
-
*
|
|
9543
|
-
* - accepts "#RRGGBB" / "#RGB"
|
|
9544
|
-
* - also allows any non-empty string (in case someone passes "red" or "var(--x)")
|
|
9545
|
-
* - returns null for empty values
|
|
9462
|
+
* Normalizes hex ("#rgb"/"#rrggbb", with/without '#') and passes through other
|
|
9463
|
+
* CSS colours ("red", "var(--x)"); empty → null.
|
|
9546
9464
|
*/
|
|
9547
9465
|
normalizeColor(v) {
|
|
9548
9466
|
if (v === null || v === undefined)
|
|
@@ -9550,15 +9468,13 @@ class MetaCheckboxColorPickerV2Component {
|
|
|
9550
9468
|
const s = String(v).trim();
|
|
9551
9469
|
if (!s)
|
|
9552
9470
|
return null;
|
|
9553
|
-
// normalize common hex values (with/without '#')
|
|
9554
9471
|
const withHash = s.startsWith('#') ? s : `#${s}`;
|
|
9555
9472
|
if (/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(withHash))
|
|
9556
9473
|
return withHash.toLowerCase();
|
|
9557
|
-
// fallback: allow CSS colors (e.g. "red") or CSS vars
|
|
9558
9474
|
return s;
|
|
9559
9475
|
}
|
|
9560
9476
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MetaCheckboxColorPickerV2Component, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9561
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: MetaCheckboxColorPickerV2Component, isStandalone: true, selector: "phoenix-meta-checkbox-color-picker-v2", inputs: { options: "options", disable: "disable" }, providers: [
|
|
9477
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: MetaCheckboxColorPickerV2Component, isStandalone: true, selector: "phoenix-meta-checkbox-color-picker-v2", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, disable: { classPropertyName: "disable", publicName: "disable", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
9562
9478
|
{
|
|
9563
9479
|
provide: NG_VALUE_ACCESSOR,
|
|
9564
9480
|
useExisting: forwardRef(() => MetaCheckboxColorPickerV2Component),
|
|
@@ -9567,18 +9483,18 @@ class MetaCheckboxColorPickerV2Component {
|
|
|
9567
9483
|
], ngImport: i0, template: `
|
|
9568
9484
|
<p-popover #popover>
|
|
9569
9485
|
<div class="color-picker">
|
|
9570
|
-
@for (row of options; track $index; let last = $last) {
|
|
9486
|
+
@for (row of options(); track $index; let last = $last) {
|
|
9571
9487
|
<div class="color-row" [class.mb-2]="!last">
|
|
9572
9488
|
@for (color of row; track color) {
|
|
9573
9489
|
<button
|
|
9574
9490
|
type="button"
|
|
9575
9491
|
class="color-box"
|
|
9576
|
-
[disabled]="disabled"
|
|
9492
|
+
[disabled]="disabled()"
|
|
9577
9493
|
[style.backgroundColor]="color"
|
|
9578
|
-
[style.outline]="focusedColor === color ? '3px solid ' + color : 'none'"
|
|
9579
|
-
[style.outlineOffset]="focusedColor === color ? '3px' : '0'"
|
|
9494
|
+
[style.outline]="focusedColor() === color ? '3px solid ' + color : 'none'"
|
|
9495
|
+
[style.outlineOffset]="focusedColor() === color ? '3px' : '0'"
|
|
9580
9496
|
(click)="select(color, popover)"
|
|
9581
|
-
(mouseenter)="focusedColor
|
|
9497
|
+
(mouseenter)="focusedColor.set(color)"
|
|
9582
9498
|
></button>
|
|
9583
9499
|
}
|
|
9584
9500
|
</div>
|
|
@@ -9589,8 +9505,8 @@ class MetaCheckboxColorPickerV2Component {
|
|
|
9589
9505
|
<button
|
|
9590
9506
|
type="button"
|
|
9591
9507
|
class="selected-color"
|
|
9592
|
-
[disabled]="disabled"
|
|
9593
|
-
[style.backgroundColor]="value || 'transparent'"
|
|
9508
|
+
[disabled]="disabled()"
|
|
9509
|
+
[style.backgroundColor]="value() || 'transparent'"
|
|
9594
9510
|
(click)="toggle(popover, $event)"
|
|
9595
9511
|
aria-label="Select color"
|
|
9596
9512
|
></button>
|
|
@@ -9607,18 +9523,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
9607
9523
|
], template: `
|
|
9608
9524
|
<p-popover #popover>
|
|
9609
9525
|
<div class="color-picker">
|
|
9610
|
-
@for (row of options; track $index; let last = $last) {
|
|
9526
|
+
@for (row of options(); track $index; let last = $last) {
|
|
9611
9527
|
<div class="color-row" [class.mb-2]="!last">
|
|
9612
9528
|
@for (color of row; track color) {
|
|
9613
9529
|
<button
|
|
9614
9530
|
type="button"
|
|
9615
9531
|
class="color-box"
|
|
9616
|
-
[disabled]="disabled"
|
|
9532
|
+
[disabled]="disabled()"
|
|
9617
9533
|
[style.backgroundColor]="color"
|
|
9618
|
-
[style.outline]="focusedColor === color ? '3px solid ' + color : 'none'"
|
|
9619
|
-
[style.outlineOffset]="focusedColor === color ? '3px' : '0'"
|
|
9534
|
+
[style.outline]="focusedColor() === color ? '3px solid ' + color : 'none'"
|
|
9535
|
+
[style.outlineOffset]="focusedColor() === color ? '3px' : '0'"
|
|
9620
9536
|
(click)="select(color, popover)"
|
|
9621
|
-
(mouseenter)="focusedColor
|
|
9537
|
+
(mouseenter)="focusedColor.set(color)"
|
|
9622
9538
|
></button>
|
|
9623
9539
|
}
|
|
9624
9540
|
</div>
|
|
@@ -9629,174 +9545,97 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
9629
9545
|
<button
|
|
9630
9546
|
type="button"
|
|
9631
9547
|
class="selected-color"
|
|
9632
|
-
[disabled]="disabled"
|
|
9633
|
-
[style.backgroundColor]="value || 'transparent'"
|
|
9548
|
+
[disabled]="disabled()"
|
|
9549
|
+
[style.backgroundColor]="value() || 'transparent'"
|
|
9634
9550
|
(click)="toggle(popover, $event)"
|
|
9635
9551
|
aria-label="Select color"
|
|
9636
9552
|
></button>
|
|
9637
9553
|
`, styles: [":host ::ng-deep .p-popover-content{padding:0!important}.color-picker{display:flex;flex-direction:column;padding:10px}.color-row{display:flex;justify-content:center;gap:8px}.mb-2{margin-bottom:8px}.color-box{margin:2px;width:30px;height:30px;cursor:pointer;border-radius:4px;border:0;padding:0;background:transparent}.color-box:hover:not(:disabled){transform:scale(1.1);opacity:.9;box-shadow:0 0 5px #0003}.color-box:disabled{cursor:not-allowed;opacity:.6}.selected-color{width:35px;height:35px;border:2px solid #ccc;cursor:pointer;border-radius:6px;padding:0;background:transparent}.selected-color:disabled{cursor:not-allowed;opacity:.6}\n"] }]
|
|
9638
|
-
}], propDecorators: { options: [{
|
|
9639
|
-
type: Input
|
|
9640
|
-
}], disable: [{
|
|
9641
|
-
type: Input
|
|
9642
|
-
}] } });
|
|
9554
|
+
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], disable: [{ type: i0.Input, args: [{ isSignal: true, alias: "disable", required: false }] }] } });
|
|
9643
9555
|
|
|
9556
|
+
/**
|
|
9557
|
+
* V2 START_DUE_DATE field — signal-based ControlValueAccessor (OnPush, no manual
|
|
9558
|
+
* CD). Two date pickers whose composite value is propagated through CVA.
|
|
9559
|
+
*/
|
|
9644
9560
|
class MetaStartDueDateV2Component {
|
|
9645
|
-
/**
|
|
9646
|
-
|
|
9647
|
-
|
|
9648
|
-
|
|
9649
|
-
|
|
9650
|
-
|
|
9651
|
-
|
|
9652
|
-
|
|
9653
|
-
|
|
9654
|
-
disable = false;
|
|
9655
|
-
cdr = inject(ChangeDetectorRef);
|
|
9656
|
-
/**
|
|
9657
|
-
* Disabled state coming from Angular Forms (ControlValueAccessor).
|
|
9658
|
-
* When true, both date pickers are non-interactive.
|
|
9659
|
-
*/
|
|
9660
|
-
isDisabled = false;
|
|
9661
|
-
/**
|
|
9662
|
-
* Local UI state for the selected start date.
|
|
9663
|
-
* Normalized to Date or null for PrimeNG DatePicker compatibility.
|
|
9664
|
-
*/
|
|
9665
|
-
startDate = null;
|
|
9666
|
-
/**
|
|
9667
|
-
* Local UI state for the selected end date.
|
|
9668
|
-
* Normalized to Date or null for PrimeNG DatePicker compatibility.
|
|
9669
|
-
*/
|
|
9670
|
-
endDate = null;
|
|
9671
|
-
/**
|
|
9672
|
-
* CVA callback invoked when the composite value changes.
|
|
9673
|
-
*/
|
|
9561
|
+
/** Optional data-cy prefix for e2e tests. */
|
|
9562
|
+
dataCy = input(...(ngDevMode ? [undefined, { debugName: "dataCy" }] : []));
|
|
9563
|
+
/** Field-level disable (meta config), combined with the Angular Forms state. */
|
|
9564
|
+
disable = input(false, ...(ngDevMode ? [{ debugName: "disable" }] : []));
|
|
9565
|
+
/** Selected start/end dates (Date or null) for the pickers. */
|
|
9566
|
+
startDate = signal(null, ...(ngDevMode ? [{ debugName: "startDate" }] : []));
|
|
9567
|
+
endDate = signal(null, ...(ngDevMode ? [{ debugName: "endDate" }] : []));
|
|
9568
|
+
formDisabled = signal(false, ...(ngDevMode ? [{ debugName: "formDisabled" }] : []));
|
|
9569
|
+
disabled = computed(() => this.disable() || this.formDisabled(), ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
9674
9570
|
onChange = () => { };
|
|
9675
|
-
/**
|
|
9676
|
-
* CVA callback invoked when the control is marked as touched.
|
|
9677
|
-
* IMPORTANT: We call this on blur (not on every change) to match standard CVA behavior.
|
|
9678
|
-
*/
|
|
9679
9571
|
onTouched = () => { };
|
|
9680
|
-
/**
|
|
9681
|
-
* Effective disabled state used by the template.
|
|
9682
|
-
* Combines reactive form disable + parent-level disable.
|
|
9683
|
-
*/
|
|
9684
|
-
get disabled() {
|
|
9685
|
-
return this.disable || this.isDisabled;
|
|
9686
|
-
}
|
|
9687
|
-
/**
|
|
9688
|
-
* Writes a new value from the parent form control into the component.
|
|
9689
|
-
* Incoming values are normalized to Date instances for the UI layer.
|
|
9690
|
-
*
|
|
9691
|
-
* NOTE: "YYYY-MM-DD" strings are parsed as local dates to avoid timezone day-shifts.
|
|
9692
|
-
*/
|
|
9693
9572
|
writeValue(v) {
|
|
9694
|
-
this.startDate
|
|
9695
|
-
this.endDate
|
|
9696
|
-
// OnPush: ensure UI reflects external value writes (patchValue/setValue)
|
|
9697
|
-
this.cdr.markForCheck();
|
|
9573
|
+
this.startDate.set(this.normalizeDateOnly(this.parseToDate(v?.startDate ?? null)));
|
|
9574
|
+
this.endDate.set(this.normalizeDateOnly(this.parseToDate(v?.endDate ?? null)));
|
|
9698
9575
|
}
|
|
9699
|
-
/**
|
|
9700
|
-
* Registers the callback that should be called when the value changes.
|
|
9701
|
-
*/
|
|
9702
9576
|
registerOnChange(fn) {
|
|
9703
9577
|
this.onChange = fn;
|
|
9704
9578
|
}
|
|
9705
|
-
/**
|
|
9706
|
-
* Registers the callback that should be called when the control is touched.
|
|
9707
|
-
*/
|
|
9708
9579
|
registerOnTouched(fn) {
|
|
9709
9580
|
this.onTouched = fn;
|
|
9710
9581
|
}
|
|
9711
|
-
/**
|
|
9712
|
-
* Receives disabled state from Angular Forms and updates local state.
|
|
9713
|
-
*/
|
|
9714
9582
|
setDisabledState(isDisabled) {
|
|
9715
|
-
this.isDisabled
|
|
9716
|
-
// OnPush: reflect disabled state changes immediately
|
|
9717
|
-
this.cdr.markForCheck();
|
|
9583
|
+
this.formDisabled.set(isDisabled);
|
|
9718
9584
|
}
|
|
9719
|
-
/**
|
|
9720
|
-
* Handler used by PrimeNG DatePicker blur events.
|
|
9721
|
-
* Marks the control as touched without emitting a value change.
|
|
9722
|
-
*/
|
|
9723
9585
|
handleBlur() {
|
|
9724
|
-
if (this.disabled)
|
|
9586
|
+
if (this.disabled())
|
|
9725
9587
|
return;
|
|
9726
9588
|
this.onTouched();
|
|
9727
9589
|
}
|
|
9728
|
-
/**
|
|
9729
|
-
* Handler for start date change coming from the DatePicker.
|
|
9730
|
-
* Updates local state and propagates the composite value.
|
|
9731
|
-
*/
|
|
9732
9590
|
onStartChange(d) {
|
|
9733
|
-
if (this.disabled)
|
|
9591
|
+
if (this.disabled())
|
|
9734
9592
|
return;
|
|
9735
|
-
this.startDate
|
|
9593
|
+
this.startDate.set(this.normalizeDateOnly(d ?? null));
|
|
9736
9594
|
this.emitChange();
|
|
9737
9595
|
}
|
|
9738
|
-
/**
|
|
9739
|
-
* Handler for end date change coming from the DatePicker.
|
|
9740
|
-
* Updates local state and propagates the composite value.
|
|
9741
|
-
*/
|
|
9742
9596
|
onEndChange(d) {
|
|
9743
|
-
if (this.disabled)
|
|
9597
|
+
if (this.disabled())
|
|
9744
9598
|
return;
|
|
9745
|
-
this.endDate
|
|
9599
|
+
this.endDate.set(this.normalizeDateOnly(d ?? null));
|
|
9746
9600
|
this.emitChange();
|
|
9747
9601
|
}
|
|
9748
|
-
/**
|
|
9749
|
-
* Emits the composite value to the parent form control.
|
|
9750
|
-
* - Emits `null` when both dates are empty (cleaner semantics for required/bothDates validators).
|
|
9751
|
-
* - Otherwise emits the `{ startDate, endDate }` object (partial values allowed; validator decides).
|
|
9752
|
-
*/
|
|
9602
|
+
/** Emits `null` when both dates are empty, otherwise the range object. */
|
|
9753
9603
|
emitChange() {
|
|
9754
|
-
|
|
9604
|
+
const start = this.startDate();
|
|
9605
|
+
const end = this.endDate();
|
|
9606
|
+
if (!start && !end) {
|
|
9755
9607
|
this.onChange(null);
|
|
9756
|
-
this.cdr.markForCheck();
|
|
9757
9608
|
return;
|
|
9758
9609
|
}
|
|
9759
|
-
this.onChange({
|
|
9760
|
-
startDate: this.startDate,
|
|
9761
|
-
endDate: this.endDate,
|
|
9762
|
-
});
|
|
9763
|
-
this.cdr.markForCheck();
|
|
9610
|
+
this.onChange({ startDate: start, endDate: end });
|
|
9764
9611
|
}
|
|
9765
9612
|
/**
|
|
9766
|
-
* Parses Date | string
|
|
9767
|
-
*
|
|
9613
|
+
* Parses Date | string to a Date. "YYYY-MM-DD" is treated as a LOCAL date to
|
|
9614
|
+
* avoid timezone day-shifts.
|
|
9768
9615
|
*/
|
|
9769
9616
|
parseToDate(v) {
|
|
9770
9617
|
if (!v)
|
|
9771
9618
|
return null;
|
|
9772
|
-
if (v instanceof Date)
|
|
9619
|
+
if (v instanceof Date)
|
|
9773
9620
|
return isNaN(v.getTime()) ? null : v;
|
|
9774
|
-
}
|
|
9775
9621
|
const s = String(v).trim();
|
|
9776
9622
|
if (!s)
|
|
9777
9623
|
return null;
|
|
9778
|
-
// Date-only string -> create LOCAL date (avoid UTC shifting)
|
|
9779
9624
|
const m = s.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
9780
9625
|
if (m) {
|
|
9781
|
-
const
|
|
9782
|
-
const mo = Number(m[2]) - 1;
|
|
9783
|
-
const d = Number(m[3]);
|
|
9784
|
-
const local = new Date(y, mo, d, 12, 0, 0, 0);
|
|
9626
|
+
const local = new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]), 12, 0, 0, 0);
|
|
9785
9627
|
return isNaN(local.getTime()) ? null : local;
|
|
9786
9628
|
}
|
|
9787
|
-
// ISO / other -> fallback
|
|
9788
9629
|
const dt = new Date(s);
|
|
9789
9630
|
return isNaN(dt.getTime()) ? null : dt;
|
|
9790
9631
|
}
|
|
9791
9632
|
normalizeDateOnly(d) {
|
|
9792
|
-
if (!d)
|
|
9793
|
-
return null;
|
|
9794
|
-
if (isNaN(d.getTime()))
|
|
9633
|
+
if (!d || isNaN(d.getTime()))
|
|
9795
9634
|
return null;
|
|
9796
9635
|
return new Date(d.getFullYear(), d.getMonth(), d.getDate(), 12, 0, 0, 0);
|
|
9797
9636
|
}
|
|
9798
9637
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MetaStartDueDateV2Component, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9799
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
9638
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.16", type: MetaStartDueDateV2Component, isStandalone: true, selector: "phoenix-meta-start-due-date-v2", inputs: { dataCy: { classPropertyName: "dataCy", publicName: "dataCy", isSignal: true, isRequired: false, transformFunction: null }, disable: { classPropertyName: "disable", publicName: "disable", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
9800
9639
|
{
|
|
9801
9640
|
provide: NG_VALUE_ACCESSOR,
|
|
9802
9641
|
useExisting: forwardRef(() => MetaStartDueDateV2Component),
|
|
@@ -9812,8 +9651,8 @@ class MetaStartDueDateV2Component {
|
|
|
9812
9651
|
[showButtonBar]="true"
|
|
9813
9652
|
[showIcon]="true"
|
|
9814
9653
|
[placeholder]="'LABELS.PLANNED_START' | translate"
|
|
9815
|
-
[disabled]="disabled"
|
|
9816
|
-
[ngModel]="startDate"
|
|
9654
|
+
[disabled]="disabled()"
|
|
9655
|
+
[ngModel]="startDate()"
|
|
9817
9656
|
(ngModelChange)="onStartChange($event)"
|
|
9818
9657
|
(onBlur)="handleBlur()"
|
|
9819
9658
|
appendTo="body"
|
|
@@ -9831,8 +9670,8 @@ class MetaStartDueDateV2Component {
|
|
|
9831
9670
|
[showButtonBar]="true"
|
|
9832
9671
|
[showIcon]="true"
|
|
9833
9672
|
[placeholder]="'LABELS.PLANNED_END' | translate"
|
|
9834
|
-
[disabled]="disabled"
|
|
9835
|
-
[ngModel]="endDate"
|
|
9673
|
+
[disabled]="disabled()"
|
|
9674
|
+
[ngModel]="endDate()"
|
|
9836
9675
|
(ngModelChange)="onEndChange($event)"
|
|
9837
9676
|
(onBlur)="handleBlur()"
|
|
9838
9677
|
appendTo="body"
|
|
@@ -9860,8 +9699,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
9860
9699
|
[showButtonBar]="true"
|
|
9861
9700
|
[showIcon]="true"
|
|
9862
9701
|
[placeholder]="'LABELS.PLANNED_START' | translate"
|
|
9863
|
-
[disabled]="disabled"
|
|
9864
|
-
[ngModel]="startDate"
|
|
9702
|
+
[disabled]="disabled()"
|
|
9703
|
+
[ngModel]="startDate()"
|
|
9865
9704
|
(ngModelChange)="onStartChange($event)"
|
|
9866
9705
|
(onBlur)="handleBlur()"
|
|
9867
9706
|
appendTo="body"
|
|
@@ -9879,8 +9718,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
9879
9718
|
[showButtonBar]="true"
|
|
9880
9719
|
[showIcon]="true"
|
|
9881
9720
|
[placeholder]="'LABELS.PLANNED_END' | translate"
|
|
9882
|
-
[disabled]="disabled"
|
|
9883
|
-
[ngModel]="endDate"
|
|
9721
|
+
[disabled]="disabled()"
|
|
9722
|
+
[ngModel]="endDate()"
|
|
9884
9723
|
(ngModelChange)="onEndChange($event)"
|
|
9885
9724
|
(onBlur)="handleBlur()"
|
|
9886
9725
|
appendTo="body"
|
|
@@ -9889,116 +9728,55 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
9889
9728
|
</div>
|
|
9890
9729
|
</div>
|
|
9891
9730
|
`, styles: [":host{display:block}\n"] }]
|
|
9892
|
-
}], propDecorators: { dataCy: [{
|
|
9893
|
-
type: Input
|
|
9894
|
-
}], disable: [{
|
|
9895
|
-
type: Input
|
|
9896
|
-
}] } });
|
|
9731
|
+
}], propDecorators: { dataCy: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataCy", required: false }] }], disable: [{ type: i0.Input, args: [{ isSignal: true, alias: "disable", required: false }] }] } });
|
|
9897
9732
|
|
|
9733
|
+
/**
|
|
9734
|
+
* V2 SWITCH field — signal-based ControlValueAccessor (OnPush, no manual CD).
|
|
9735
|
+
* Value + disabled live in signals; the template reads them as functions.
|
|
9736
|
+
*/
|
|
9898
9737
|
class MetaSwitchV2Component {
|
|
9899
|
-
/**
|
|
9900
|
-
|
|
9901
|
-
|
|
9902
|
-
|
|
9903
|
-
|
|
9904
|
-
|
|
9905
|
-
|
|
9906
|
-
|
|
9907
|
-
|
|
9908
|
-
|
|
9909
|
-
|
|
9910
|
-
* Optional data-cy attribute for e2e tests (e.g. "switch-singleEntity").
|
|
9911
|
-
*/
|
|
9912
|
-
dataCy;
|
|
9913
|
-
cdr = inject(ChangeDetectorRef);
|
|
9914
|
-
/**
|
|
9915
|
-
* Current boolean value stored inside the component.
|
|
9916
|
-
* This value is synchronized with the parent FormControl through CVA.
|
|
9917
|
-
*/
|
|
9918
|
-
value = false;
|
|
9919
|
-
/**
|
|
9920
|
-
* CVA callback invoked when the value changes.
|
|
9921
|
-
*/
|
|
9738
|
+
/** Field-level disable (meta config), combined with the Angular Forms state. */
|
|
9739
|
+
disable = input(false, ...(ngDevMode ? [{ debugName: "disable" }] : []));
|
|
9740
|
+
/** Hide the switch (meta hidden). Does not disable it. */
|
|
9741
|
+
hidden = input(false, ...(ngDevMode ? [{ debugName: "hidden" }] : []));
|
|
9742
|
+
/** Optional data-cy for e2e tests. */
|
|
9743
|
+
dataCy = input(...(ngDevMode ? [undefined, { debugName: "dataCy" }] : []));
|
|
9744
|
+
/** Current boolean value, synced with the parent control through CVA. */
|
|
9745
|
+
value = signal(false, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
9746
|
+
formDisabled = signal(false, ...(ngDevMode ? [{ debugName: "formDisabled" }] : []));
|
|
9747
|
+
/** Final disabled = field-level disable OR the Forms disabled state. */
|
|
9748
|
+
disabled = computed(() => this.disable() || this.formDisabled(), ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
9922
9749
|
onChange = () => { };
|
|
9923
|
-
/**
|
|
9924
|
-
* CVA callback invoked when the control is marked as touched.
|
|
9925
|
-
* Standard: call on blur, not on every change.
|
|
9926
|
-
*/
|
|
9927
9750
|
onTouched = () => { };
|
|
9928
|
-
/**
|
|
9929
|
-
* Disabled state coming from Angular Forms (ControlValueAccessor).
|
|
9930
|
-
*/
|
|
9931
|
-
isDisabled = false;
|
|
9932
|
-
/**
|
|
9933
|
-
* Final disabled state combining:
|
|
9934
|
-
* - form-level disabled state (CVA)
|
|
9935
|
-
* - field-level disable flag (input)
|
|
9936
|
-
*/
|
|
9937
|
-
get disabled() {
|
|
9938
|
-
return this.disable || this.isDisabled;
|
|
9939
|
-
}
|
|
9940
|
-
/**
|
|
9941
|
-
* Writes a new value from the parent form control into the component.
|
|
9942
|
-
* Keep it idempotent and UI-safe.
|
|
9943
|
-
*/
|
|
9944
9751
|
writeValue(v) {
|
|
9945
|
-
this.value
|
|
9946
|
-
this.cdr.markForCheck();
|
|
9752
|
+
this.value.set(this.normalizeBool(v));
|
|
9947
9753
|
}
|
|
9948
|
-
/**
|
|
9949
|
-
* Registers callback that is triggered when the value changes.
|
|
9950
|
-
*/
|
|
9951
9754
|
registerOnChange(fn) {
|
|
9952
9755
|
this.onChange = fn;
|
|
9953
9756
|
}
|
|
9954
|
-
/**
|
|
9955
|
-
* Registers callback that is triggered when the control is touched.
|
|
9956
|
-
*/
|
|
9957
9757
|
registerOnTouched(fn) {
|
|
9958
9758
|
this.onTouched = fn;
|
|
9959
9759
|
}
|
|
9960
|
-
/**
|
|
9961
|
-
* Receives disabled state from Angular Forms and updates local state.
|
|
9962
|
-
*/
|
|
9963
9760
|
setDisabledState(isDisabled) {
|
|
9964
|
-
this.isDisabled
|
|
9965
|
-
this.cdr.markForCheck();
|
|
9761
|
+
this.formDisabled.set(isDisabled);
|
|
9966
9762
|
}
|
|
9967
9763
|
/**
|
|
9968
|
-
*
|
|
9969
|
-
*
|
|
9970
|
-
*
|
|
9971
|
-
* Important note:
|
|
9972
|
-
* We intentionally use [ngModel] instead of [(ngModel)] in the template.
|
|
9973
|
-
* Two-way binding would update the local value BEFORE this handler runs,
|
|
9974
|
-
* which would prevent correct change detection and CVA propagation.
|
|
9764
|
+
* We use one-way [ngModel] + (ngModelChange) on purpose: two-way binding would
|
|
9765
|
+
* mutate the value before this handler runs and break CVA propagation.
|
|
9975
9766
|
*/
|
|
9976
9767
|
onSwitchChange(next) {
|
|
9977
|
-
if (this.disabled)
|
|
9768
|
+
if (this.disabled())
|
|
9978
9769
|
return;
|
|
9979
9770
|
const normalized = this.normalizeBool(next);
|
|
9980
|
-
|
|
9981
|
-
this.value = normalized;
|
|
9982
|
-
this.onChange(normalized);
|
|
9983
|
-
this.cdr.markForCheck();
|
|
9984
|
-
return;
|
|
9985
|
-
}
|
|
9986
|
-
// ensure the form control still receives the value
|
|
9771
|
+
this.value.set(normalized);
|
|
9987
9772
|
this.onChange(normalized);
|
|
9988
|
-
this.cdr.markForCheck();
|
|
9989
9773
|
}
|
|
9990
|
-
/**
|
|
9991
|
-
* Marks control as touched when user leaves the component.
|
|
9992
|
-
*/
|
|
9993
9774
|
handleBlur() {
|
|
9994
|
-
if (this.disabled)
|
|
9775
|
+
if (this.disabled())
|
|
9995
9776
|
return;
|
|
9996
9777
|
this.onTouched();
|
|
9997
9778
|
}
|
|
9998
|
-
/**
|
|
9999
|
-
* Normalizes incoming values to strict boolean.
|
|
10000
|
-
* Supports: boolean, "true"/"false", 1/0, "1"/"0".
|
|
10001
|
-
*/
|
|
9779
|
+
/** Normalizes boolean-ish values (boolean, "true"/"false", 1/0, "1"/"0"). */
|
|
10002
9780
|
normalizeBool(v) {
|
|
10003
9781
|
if (v === true || v === false)
|
|
10004
9782
|
return v;
|
|
@@ -10016,7 +9794,7 @@ class MetaSwitchV2Component {
|
|
|
10016
9794
|
return !!v;
|
|
10017
9795
|
}
|
|
10018
9796
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MetaSwitchV2Component, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10019
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
9797
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.16", type: MetaSwitchV2Component, isStandalone: true, selector: "phoenix-meta-switch-v2", inputs: { disable: { classPropertyName: "disable", publicName: "disable", isSignal: true, isRequired: false, transformFunction: null }, hidden: { classPropertyName: "hidden", publicName: "hidden", isSignal: true, isRequired: false, transformFunction: null }, dataCy: { classPropertyName: "dataCy", publicName: "dataCy", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
10020
9798
|
{
|
|
10021
9799
|
provide: NG_VALUE_ACCESSOR,
|
|
10022
9800
|
useExisting: forwardRef(() => MetaSwitchV2Component),
|
|
@@ -10025,12 +9803,12 @@ class MetaSwitchV2Component {
|
|
|
10025
9803
|
], ngImport: i0, template: `
|
|
10026
9804
|
<p-toggleSwitch
|
|
10027
9805
|
class="phoenix-switch-v2"
|
|
10028
|
-
[ngModel]="value"
|
|
9806
|
+
[ngModel]="value()"
|
|
10029
9807
|
(ngModelChange)="onSwitchChange($event)"
|
|
10030
9808
|
(onBlur)="handleBlur()"
|
|
10031
|
-
[disabled]="disabled"
|
|
10032
|
-
[hidden]="hidden"
|
|
10033
|
-
[attr.data-cy]="dataCy ?? null"
|
|
9809
|
+
[disabled]="disabled()"
|
|
9810
|
+
[hidden]="hidden()"
|
|
9811
|
+
[attr.data-cy]="dataCy() ?? null"
|
|
10034
9812
|
></p-toggleSwitch>
|
|
10035
9813
|
`, isInline: true, styles: [":host ::ng-deep .p-toggleswitch{margin-top:12px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ToggleSwitchModule }, { kind: "component", type: i3$6.ToggleSwitch, selector: "p-toggleswitch, p-toggleSwitch, p-toggle-switch", inputs: ["styleClass", "tabindex", "inputId", "readonly", "trueValue", "falseValue", "ariaLabel", "size", "ariaLabelledBy", "autofocus"], outputs: ["onChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
10036
9814
|
}
|
|
@@ -10039,12 +9817,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
10039
9817
|
args: [{ selector: 'phoenix-meta-switch-v2', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, FormsModule, ToggleSwitchModule], template: `
|
|
10040
9818
|
<p-toggleSwitch
|
|
10041
9819
|
class="phoenix-switch-v2"
|
|
10042
|
-
[ngModel]="value"
|
|
9820
|
+
[ngModel]="value()"
|
|
10043
9821
|
(ngModelChange)="onSwitchChange($event)"
|
|
10044
9822
|
(onBlur)="handleBlur()"
|
|
10045
|
-
[disabled]="disabled"
|
|
10046
|
-
[hidden]="hidden"
|
|
10047
|
-
[attr.data-cy]="dataCy ?? null"
|
|
9823
|
+
[disabled]="disabled()"
|
|
9824
|
+
[hidden]="hidden()"
|
|
9825
|
+
[attr.data-cy]="dataCy() ?? null"
|
|
10048
9826
|
></p-toggleSwitch>
|
|
10049
9827
|
`, providers: [
|
|
10050
9828
|
{
|
|
@@ -10053,178 +9831,70 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
10053
9831
|
multi: true,
|
|
10054
9832
|
},
|
|
10055
9833
|
], styles: [":host ::ng-deep .p-toggleswitch{margin-top:12px}\n"] }]
|
|
10056
|
-
}], propDecorators: { disable: [{
|
|
10057
|
-
type: Input
|
|
10058
|
-
}], hidden: [{
|
|
10059
|
-
type: Input
|
|
10060
|
-
}], dataCy: [{
|
|
10061
|
-
type: Input
|
|
10062
|
-
}] } });
|
|
9834
|
+
}], propDecorators: { disable: [{ type: i0.Input, args: [{ isSignal: true, alias: "disable", required: false }] }], hidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "hidden", required: false }] }], dataCy: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataCy", required: false }] }] } });
|
|
10063
9835
|
|
|
10064
9836
|
/**
|
|
10065
|
-
* V2
|
|
10066
|
-
*
|
|
10067
|
-
*
|
|
10068
|
-
* - Uses a clean ControlValueAccessor implementation (no BaseMetaField inheritance).
|
|
10069
|
-
* - OnPush + explicit markForCheck() for predictable rendering in large dynamic forms.
|
|
10070
|
-
* - Supports "disable" (meta-level) + Angular Forms disabled state (CVA) combined.
|
|
10071
|
-
* - Emits touched on blur (standard), not on every input.
|
|
10072
|
-
* - Keeps value as string and normalizes null/undefined to ''.
|
|
10073
|
-
*
|
|
10074
|
-
* Notes:
|
|
10075
|
-
* - PrimeNG <p-password> supports toggleMask, feedback, strength meter, etc.
|
|
10076
|
-
* - We keep [feedback]="false" to match old behavior.
|
|
9837
|
+
* V2 PASSWORD field — signal-based ControlValueAccessor (OnPush, no manual CD).
|
|
9838
|
+
* Value + disabled live in signals; touched is emitted on blur, value kept as a
|
|
9839
|
+
* string (null/undefined normalized to '').
|
|
10077
9840
|
*/
|
|
10078
9841
|
class MetaPasswordFieldV2Component {
|
|
10079
|
-
/**
|
|
10080
|
-
|
|
10081
|
-
|
|
10082
|
-
|
|
10083
|
-
|
|
10084
|
-
|
|
10085
|
-
control
|
|
10086
|
-
|
|
10087
|
-
|
|
10088
|
-
|
|
10089
|
-
|
|
10090
|
-
|
|
10091
|
-
|
|
10092
|
-
|
|
10093
|
-
/**
|
|
10094
|
-
|
|
10095
|
-
|
|
10096
|
-
|
|
10097
|
-
disable = false;
|
|
10098
|
-
/**
|
|
10099
|
-
* Optional flag to hide the control from UI (meta hidden).
|
|
10100
|
-
* Keep in mind: hidden does not automatically disable the control.
|
|
10101
|
-
*/
|
|
10102
|
-
hidden = false;
|
|
10103
|
-
/**
|
|
10104
|
-
* Optional data-cy attribute for e2e tests (e.g. "password-admin").
|
|
10105
|
-
* If not provided, you can still generate it from control.id in template usage.
|
|
10106
|
-
*/
|
|
10107
|
-
dataCy;
|
|
10108
|
-
/**
|
|
10109
|
-
* PrimeNG feedback (strength meter / hints). Disabled by default to match v1.
|
|
10110
|
-
*/
|
|
10111
|
-
feedback = false;
|
|
10112
|
-
/**
|
|
10113
|
-
* Autocomplete attribute: by default we set to "off" (match old component).
|
|
10114
|
-
* For login forms you might want "current-password" or "new-password".
|
|
10115
|
-
*/
|
|
10116
|
-
autocomplete = 'off';
|
|
10117
|
-
cdr = inject(ChangeDetectorRef);
|
|
10118
|
-
/**
|
|
10119
|
-
* Current password value.
|
|
10120
|
-
* Always keep as string to avoid null/undefined edge cases with ngModel.
|
|
10121
|
-
*/
|
|
10122
|
-
value = '';
|
|
10123
|
-
/**
|
|
10124
|
-
* CVA callback invoked when the value changes.
|
|
10125
|
-
*/
|
|
9842
|
+
/** Meta control configuration (kept for API compatibility). */
|
|
9843
|
+
control = input(...(ngDevMode ? [undefined, { debugName: "control" }] : []));
|
|
9844
|
+
/** Underlying control reference (kept for API compatibility). */
|
|
9845
|
+
ctrl = input(...(ngDevMode ? [undefined, { debugName: "ctrl" }] : []));
|
|
9846
|
+
/** Field-level disable (meta config), combined with the Angular Forms state. */
|
|
9847
|
+
disable = input(false, ...(ngDevMode ? [{ debugName: "disable" }] : []));
|
|
9848
|
+
/** Hide the control (meta hidden). Does not disable it. */
|
|
9849
|
+
hidden = input(false, ...(ngDevMode ? [{ debugName: "hidden" }] : []));
|
|
9850
|
+
/** Optional data-cy for e2e tests. */
|
|
9851
|
+
dataCy = input(...(ngDevMode ? [undefined, { debugName: "dataCy" }] : []));
|
|
9852
|
+
/** PrimeNG strength meter; off by default to match v1. */
|
|
9853
|
+
feedback = input(false, ...(ngDevMode ? [{ debugName: "feedback" }] : []));
|
|
9854
|
+
/** Autocomplete attribute (default "off"). */
|
|
9855
|
+
autocomplete = input('off', ...(ngDevMode ? [{ debugName: "autocomplete" }] : []));
|
|
9856
|
+
/** Current password value (always a string). */
|
|
9857
|
+
value = signal('', ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
9858
|
+
formDisabled = signal(false, ...(ngDevMode ? [{ debugName: "formDisabled" }] : []));
|
|
9859
|
+
disabled = computed(() => this.disable() || this.formDisabled(), ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
10126
9860
|
onChange = () => { };
|
|
10127
|
-
/**
|
|
10128
|
-
* CVA callback invoked when the control is marked as touched.
|
|
10129
|
-
* Standard: call on blur, not on every change.
|
|
10130
|
-
*/
|
|
10131
9861
|
onTouched = () => { };
|
|
10132
|
-
/**
|
|
10133
|
-
* Disabled state coming from Angular Forms (ControlValueAccessor).
|
|
10134
|
-
*/
|
|
10135
|
-
isDisabled = false;
|
|
10136
|
-
/**
|
|
10137
|
-
* Final disabled state combining:
|
|
10138
|
-
* - form-level disabled state (CVA)
|
|
10139
|
-
* - field-level disable flag (input)
|
|
10140
|
-
*/
|
|
10141
|
-
get disabled() {
|
|
10142
|
-
return this.disable || this.isDisabled;
|
|
10143
|
-
}
|
|
10144
|
-
/**
|
|
10145
|
-
* Writes a new value from the parent form control into the component.
|
|
10146
|
-
* Keep it idempotent and UI-safe.
|
|
10147
|
-
*/
|
|
10148
9862
|
writeValue(v) {
|
|
10149
|
-
|
|
10150
|
-
// Prevent redundant UI updates.
|
|
10151
|
-
if (next === this.value) {
|
|
10152
|
-
this.cdr.markForCheck();
|
|
10153
|
-
return;
|
|
10154
|
-
}
|
|
10155
|
-
this.value = next;
|
|
10156
|
-
this.cdr.markForCheck();
|
|
9863
|
+
this.value.set(this.normalizeString(v));
|
|
10157
9864
|
}
|
|
10158
|
-
/**
|
|
10159
|
-
* Registers callback that is triggered when the value changes.
|
|
10160
|
-
*/
|
|
10161
9865
|
registerOnChange(fn) {
|
|
10162
9866
|
this.onChange = fn;
|
|
10163
9867
|
}
|
|
10164
|
-
/**
|
|
10165
|
-
* Registers callback that is triggered when the control is touched.
|
|
10166
|
-
*/
|
|
10167
9868
|
registerOnTouched(fn) {
|
|
10168
9869
|
this.onTouched = fn;
|
|
10169
9870
|
}
|
|
10170
|
-
/**
|
|
10171
|
-
* Receives disabled state from Angular Forms and updates local state.
|
|
10172
|
-
*/
|
|
10173
9871
|
setDisabledState(isDisabled) {
|
|
10174
|
-
this.isDisabled
|
|
10175
|
-
this.cdr.markForCheck();
|
|
9872
|
+
this.formDisabled.set(isDisabled);
|
|
10176
9873
|
}
|
|
10177
|
-
/**
|
|
10178
|
-
* Handler for user typing into the password input.
|
|
10179
|
-
* Propagates current value to the parent form control.
|
|
10180
|
-
*
|
|
10181
|
-
* Note:
|
|
10182
|
-
* - PrimeNG (input) gives us an event; we can also just use this.value directly.
|
|
10183
|
-
* - We intentionally do NOT call onTouched here (touched on blur).
|
|
10184
|
-
*/
|
|
9874
|
+
/** Propagates every keystroke; touched is emitted on blur. */
|
|
10185
9875
|
onPasswordInput(event) {
|
|
10186
|
-
if (this.disabled)
|
|
9876
|
+
if (this.disabled())
|
|
10187
9877
|
return;
|
|
10188
9878
|
const next = this.getInputValue(event);
|
|
10189
|
-
|
|
10190
|
-
// if (next === this.value) {
|
|
10191
|
-
// this.cdr.markForCheck();
|
|
10192
|
-
// return;
|
|
10193
|
-
// }
|
|
10194
|
-
this.value = next;
|
|
9879
|
+
this.value.set(next);
|
|
10195
9880
|
this.onChange(next);
|
|
10196
|
-
this.cdr.markForCheck();
|
|
10197
9881
|
}
|
|
10198
|
-
/**
|
|
10199
|
-
* Marks control as touched when user leaves the component.
|
|
10200
|
-
*/
|
|
10201
9882
|
handleBlur() {
|
|
10202
|
-
if (this.disabled)
|
|
9883
|
+
if (this.disabled())
|
|
10203
9884
|
return;
|
|
10204
9885
|
this.onTouched();
|
|
10205
9886
|
}
|
|
10206
|
-
/**
|
|
10207
|
-
* PrimeNG input event -> string value.
|
|
10208
|
-
* Supports:
|
|
10209
|
-
* - native input event: event.target.value
|
|
10210
|
-
* - direct string (some wrappers)
|
|
10211
|
-
*/
|
|
10212
9887
|
getInputValue(event) {
|
|
10213
9888
|
const v = event?.target?.value ?? event;
|
|
10214
9889
|
return this.normalizeString(v);
|
|
10215
9890
|
}
|
|
10216
|
-
/**
|
|
10217
|
-
* Normalizes incoming values to a string.
|
|
10218
|
-
* - null/undefined -> ''
|
|
10219
|
-
* - other -> String(v)
|
|
10220
|
-
*/
|
|
10221
9891
|
normalizeString(v) {
|
|
10222
9892
|
if (v === null || v === undefined)
|
|
10223
9893
|
return '';
|
|
10224
9894
|
return String(v);
|
|
10225
9895
|
}
|
|
10226
9896
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MetaPasswordFieldV2Component, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10227
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
9897
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.16", type: MetaPasswordFieldV2Component, isStandalone: true, selector: "phoenix-meta-password-field-v2", inputs: { control: { classPropertyName: "control", publicName: "control", isSignal: true, isRequired: false, transformFunction: null }, ctrl: { classPropertyName: "ctrl", publicName: "ctrl", isSignal: true, isRequired: false, transformFunction: null }, disable: { classPropertyName: "disable", publicName: "disable", isSignal: true, isRequired: false, transformFunction: null }, hidden: { classPropertyName: "hidden", publicName: "hidden", isSignal: true, isRequired: false, transformFunction: null }, dataCy: { classPropertyName: "dataCy", publicName: "dataCy", isSignal: true, isRequired: false, transformFunction: null }, feedback: { classPropertyName: "feedback", publicName: "feedback", isSignal: true, isRequired: false, transformFunction: null }, autocomplete: { classPropertyName: "autocomplete", publicName: "autocomplete", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
10228
9898
|
{
|
|
10229
9899
|
provide: NG_VALUE_ACCESSOR,
|
|
10230
9900
|
useExisting: forwardRef(() => MetaPasswordFieldV2Component),
|
|
@@ -10232,22 +9902,16 @@ class MetaPasswordFieldV2Component {
|
|
|
10232
9902
|
},
|
|
10233
9903
|
], ngImport: i0, template: `
|
|
10234
9904
|
<div>
|
|
10235
|
-
<!--
|
|
10236
|
-
PrimeNG Password:
|
|
10237
|
-
- We use ngModel for simple CVA integration (same pattern as other meta v2 fields).
|
|
10238
|
-
- We handle change via (input) to propagate every keystroke to the parent form.
|
|
10239
|
-
- We mark touched on blur to match standard UX (touched != changed).
|
|
10240
|
-
-->
|
|
10241
9905
|
<p-password
|
|
10242
9906
|
class="phoenix-password-v2"
|
|
10243
|
-
[
|
|
9907
|
+
[ngModel]="value()"
|
|
10244
9908
|
(ngModelChange)="onPasswordInput($event)"
|
|
10245
9909
|
(onBlur)="handleBlur()"
|
|
10246
|
-
[disabled]="disabled"
|
|
10247
|
-
[hidden]="hidden"
|
|
10248
|
-
[feedback]="feedback"
|
|
10249
|
-
[attr.autocomplete]="autocomplete"
|
|
10250
|
-
[attr.data-cy]="dataCy ?? null"
|
|
9910
|
+
[disabled]="disabled()"
|
|
9911
|
+
[hidden]="hidden()"
|
|
9912
|
+
[feedback]="feedback()"
|
|
9913
|
+
[attr.autocomplete]="autocomplete()"
|
|
9914
|
+
[attr.data-cy]="dataCy() ?? null"
|
|
10251
9915
|
></p-password>
|
|
10252
9916
|
</div>
|
|
10253
9917
|
`, isInline: true, styles: [":host ::ng-deep .p-component{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "ngmodule", type: PasswordModule }, { kind: "component", type: i2$8.Password, selector: "p-password", inputs: ["ariaLabel", "ariaLabelledBy", "label", "promptLabel", "mediumRegex", "strongRegex", "weakLabel", "mediumLabel", "maxLength", "strongLabel", "inputId", "feedback", "toggleMask", "inputStyleClass", "styleClass", "inputStyle", "showTransitionOptions", "hideTransitionOptions", "autocomplete", "placeholder", "showClear", "autofocus", "tabindex", "appendTo"], outputs: ["onFocus", "onBlur", "onClear"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
@@ -10256,22 +9920,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
10256
9920
|
type: Component,
|
|
10257
9921
|
args: [{ selector: 'phoenix-meta-password-field-v2', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, FormsModule, TranslateModule, PasswordModule], template: `
|
|
10258
9922
|
<div>
|
|
10259
|
-
<!--
|
|
10260
|
-
PrimeNG Password:
|
|
10261
|
-
- We use ngModel for simple CVA integration (same pattern as other meta v2 fields).
|
|
10262
|
-
- We handle change via (input) to propagate every keystroke to the parent form.
|
|
10263
|
-
- We mark touched on blur to match standard UX (touched != changed).
|
|
10264
|
-
-->
|
|
10265
9923
|
<p-password
|
|
10266
9924
|
class="phoenix-password-v2"
|
|
10267
|
-
[
|
|
9925
|
+
[ngModel]="value()"
|
|
10268
9926
|
(ngModelChange)="onPasswordInput($event)"
|
|
10269
9927
|
(onBlur)="handleBlur()"
|
|
10270
|
-
[disabled]="disabled"
|
|
10271
|
-
[hidden]="hidden"
|
|
10272
|
-
[feedback]="feedback"
|
|
10273
|
-
[attr.autocomplete]="autocomplete"
|
|
10274
|
-
[attr.data-cy]="dataCy ?? null"
|
|
9928
|
+
[disabled]="disabled()"
|
|
9929
|
+
[hidden]="hidden()"
|
|
9930
|
+
[feedback]="feedback()"
|
|
9931
|
+
[attr.autocomplete]="autocomplete()"
|
|
9932
|
+
[attr.data-cy]="dataCy() ?? null"
|
|
10275
9933
|
></p-password>
|
|
10276
9934
|
</div>
|
|
10277
9935
|
`, providers: [
|
|
@@ -10281,47 +9939,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
10281
9939
|
multi: true,
|
|
10282
9940
|
},
|
|
10283
9941
|
], styles: [":host ::ng-deep .p-component{width:100%}\n"] }]
|
|
10284
|
-
}], propDecorators: { control: [{
|
|
10285
|
-
type: Input
|
|
10286
|
-
}], ctrl: [{
|
|
10287
|
-
type: Input
|
|
10288
|
-
}], disable: [{
|
|
10289
|
-
type: Input
|
|
10290
|
-
}], hidden: [{
|
|
10291
|
-
type: Input
|
|
10292
|
-
}], dataCy: [{
|
|
10293
|
-
type: Input
|
|
10294
|
-
}], feedback: [{
|
|
10295
|
-
type: Input
|
|
10296
|
-
}], autocomplete: [{
|
|
10297
|
-
type: Input
|
|
10298
|
-
}] } });
|
|
9942
|
+
}], propDecorators: { control: [{ type: i0.Input, args: [{ isSignal: true, alias: "control", required: false }] }], ctrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "ctrl", required: false }] }], disable: [{ type: i0.Input, args: [{ isSignal: true, alias: "disable", required: false }] }], hidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "hidden", required: false }] }], dataCy: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataCy", required: false }] }], feedback: [{ type: i0.Input, args: [{ isSignal: true, alias: "feedback", required: false }] }], autocomplete: [{ type: i0.Input, args: [{ isSignal: true, alias: "autocomplete", required: false }] }] } });
|
|
10299
9943
|
|
|
9944
|
+
/**
|
|
9945
|
+
* Renders one meta field. Signal-based (OnPush): every template-facing value is a
|
|
9946
|
+
* `computed()` so it is memoized and recomputed only when its inputs actually
|
|
9947
|
+
* change — instead of a plain method re-running on every change-detection pass.
|
|
9948
|
+
* Control state (value/status) is bridged into a signal (`controlTick`), so the
|
|
9949
|
+
* error helpers stay reactive without a manual `markForCheck()`.
|
|
9950
|
+
*/
|
|
10300
9951
|
class MetaFormFieldV2Component {
|
|
10301
9952
|
/** Metadata definition of the field (type, key, options, styles, flags, etc.) */
|
|
10302
|
-
field;
|
|
10303
|
-
/** Parent FormGroup that contains the FormControl for this field */
|
|
10304
|
-
form;
|
|
10305
|
-
/**
|
|
10306
|
-
|
|
10307
|
-
|
|
10308
|
-
|
|
10309
|
-
readOnly = false;
|
|
10310
|
-
/**
|
|
10311
|
-
* Global disable flag (e.g. parent dialog toggles entire form disabled).
|
|
10312
|
-
* This is merged with field-level disable configuration.
|
|
10313
|
-
*/
|
|
10314
|
-
disableForm = false;
|
|
10315
|
-
/** Used to manually trigger change detection for OnPush strategy */
|
|
10316
|
-
cdr = inject(ChangeDetectorRef);
|
|
10317
|
-
/** Used to automatically unsubscribe from value/status streams on destroy */
|
|
10318
|
-
dr = inject(DestroyRef);
|
|
10319
|
-
/** Translation service for validation and display labels */
|
|
9953
|
+
field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
|
|
9954
|
+
/** Parent FormGroup that contains the FormControl for this field. */
|
|
9955
|
+
form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
9956
|
+
/** Page-level read-only flag (renders the read-only view). */
|
|
9957
|
+
readOnly = input(false, ...(ngDevMode ? [{ debugName: "readOnly" }] : []));
|
|
9958
|
+
/** Global disable flag (merged with the field-level disable config). */
|
|
9959
|
+
disableForm = input(false, ...(ngDevMode ? [{ debugName: "disableForm" }] : []));
|
|
10320
9960
|
translate = inject(TranslateService);
|
|
10321
|
-
/**
|
|
10322
|
-
* Exposed enum-like mapping of MetaFieldType for template usage.
|
|
10323
|
-
* Keeps templates readable and avoids magic strings.
|
|
10324
|
-
*/
|
|
9961
|
+
/** Enum-like map for the template `@switch`. */
|
|
10325
9962
|
MetaFieldType = Object.freeze({
|
|
10326
9963
|
TEXT: 'TEXT',
|
|
10327
9964
|
URL: 'URL',
|
|
@@ -10348,95 +9985,41 @@ class MetaFormFieldV2Component {
|
|
|
10348
9985
|
LINKS_DATA: 'LINKS_DATA',
|
|
10349
9986
|
SLOT: 'SLOT',
|
|
10350
9987
|
});
|
|
10351
|
-
|
|
10352
|
-
|
|
10353
|
-
|
|
10354
|
-
}
|
|
10355
|
-
|
|
10356
|
-
|
|
10357
|
-
|
|
10358
|
-
}
|
|
10359
|
-
|
|
10360
|
-
|
|
10361
|
-
|
|
10362
|
-
|
|
10363
|
-
|
|
10364
|
-
|
|
10365
|
-
|
|
10366
|
-
|
|
10367
|
-
|
|
10368
|
-
|
|
10369
|
-
|
|
10370
|
-
|
|
10371
|
-
|
|
10372
|
-
|
|
10373
|
-
|
|
10374
|
-
|
|
10375
|
-
|
|
10376
|
-
.subscribe(() => this.cdr.markForCheck());
|
|
10377
|
-
}
|
|
10378
|
-
/** Human-friendly label defined in metadata (already localized key) */
|
|
10379
|
-
userFriendlyMessage() {
|
|
10380
|
-
return this.field?.userFriendlyMessage ?? null;
|
|
10381
|
-
}
|
|
10382
|
-
/** Optional placeholder i18n key defined in metadata */
|
|
10383
|
-
placeholderKey() {
|
|
10384
|
-
return this.field?.configuration?.placeholderKey ?? null;
|
|
10385
|
-
}
|
|
10386
|
-
/**
|
|
10387
|
-
* Resolves final read-only state for this field:
|
|
10388
|
-
* - page-level readOnly OR field-level readOnly
|
|
10389
|
-
*/
|
|
10390
|
-
isReadOnly() {
|
|
10391
|
-
return !!this.readOnly || !!this.field?.readOnly;
|
|
10392
|
-
}
|
|
10393
|
-
/**
|
|
10394
|
-
* Resolves final disabled state for this field:
|
|
10395
|
-
* - page-level disable OR field-level disable
|
|
10396
|
-
*/
|
|
10397
|
-
isDisabled() {
|
|
10398
|
-
return !!this.disableForm || !!this.field?.disable;
|
|
10399
|
-
}
|
|
10400
|
-
/** Shortcut to underlying FormControl */
|
|
10401
|
-
ctrl() {
|
|
10402
|
-
return this.form.get(this.key);
|
|
10403
|
-
}
|
|
10404
|
-
/**
|
|
10405
|
-
* Minimal value formatter for legacy read-only rendering.
|
|
10406
|
-
* Kept intentionally simple to match V1 behavior.
|
|
10407
|
-
*/
|
|
10408
|
-
displayValue() {
|
|
10409
|
-
const v = this.ctrl()?.value;
|
|
10410
|
-
if (v === null || v === undefined)
|
|
10411
|
-
return '';
|
|
10412
|
-
if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean')
|
|
10413
|
-
return v;
|
|
10414
|
-
// Common DTO shapes (assign, option objects, uploads, etc.)
|
|
10415
|
-
if (typeof v === 'object') {
|
|
10416
|
-
return v.label ?? v.name ?? v.fileName ?? JSON.stringify(v);
|
|
10417
|
-
}
|
|
10418
|
-
return String(v);
|
|
10419
|
-
}
|
|
10420
|
-
/**
|
|
10421
|
-
* Determines whether validation error should be displayed.
|
|
10422
|
-
* Errors are shown only after user interaction (touched or dirty).
|
|
10423
|
-
*/
|
|
10424
|
-
showError() {
|
|
9988
|
+
// ---- Pure, input-derived views (memoized) ----
|
|
9989
|
+
key = computed(() => this.field()?.configuration?.key ?? '', ...(ngDevMode ? [{ debugName: "key" }] : []));
|
|
9990
|
+
type = computed(() => this.field()?.configuration?.type ?? 'TEXT', ...(ngDevMode ? [{ debugName: "type" }] : []));
|
|
9991
|
+
colClass = computed(() => this.field()?.hidden ? 'p-0' : (this.field()?.style.colWidth ?? 'col-12 md:col-6'), ...(ngDevMode ? [{ debugName: "colClass" }] : []));
|
|
9992
|
+
userFriendlyMessage = computed(() => this.field()?.userFriendlyMessage ?? null, ...(ngDevMode ? [{ debugName: "userFriendlyMessage" }] : []));
|
|
9993
|
+
placeholderKey = computed(() => this.field()?.configuration?.placeholderKey ?? null, ...(ngDevMode ? [{ debugName: "placeholderKey" }] : []));
|
|
9994
|
+
isReadOnly = computed(() => !!this.readOnly() || !!this.field()?.readOnly, ...(ngDevMode ? [{ debugName: "isReadOnly" }] : []));
|
|
9995
|
+
isDisabled = computed(() => !!this.disableForm() || !!this.field()?.disable, ...(ngDevMode ? [{ debugName: "isDisabled" }] : []));
|
|
9996
|
+
isCheckbox = computed(() => this.type() === this.MetaFieldType.CHECKBOX, ...(ngDevMode ? [{ debugName: "isCheckbox" }] : []));
|
|
9997
|
+
/** The underlying FormControl for this field (recomputed if form/key change). */
|
|
9998
|
+
ctrl = computed(() => this.form().get(this.key()) ?? null, ...(ngDevMode ? [{ debugName: "ctrl" }] : []));
|
|
9999
|
+
/**
|
|
10000
|
+
* Bridge the current control's value/status stream into a signal so the error
|
|
10001
|
+
* helpers below recompute reactively (reactive forms aren't signal-native yet).
|
|
10002
|
+
* Re-subscribes when the control identity changes.
|
|
10003
|
+
*/
|
|
10004
|
+
controlTick = toSignal(toObservable(this.ctrl).pipe(switchMap$1((c) => c ? merge(c.valueChanges, c.statusChanges).pipe(startWith(null)) : EMPTY)), { initialValue: null });
|
|
10005
|
+
/** Bumped for silent (emitEvent:false) programmatic writes, e.g. the date field. */
|
|
10006
|
+
manualTick = signal(0, ...(ngDevMode ? [{ debugName: "manualTick" }] : []));
|
|
10007
|
+
/** Track the active language so translated error text refreshes on lang change. */
|
|
10008
|
+
lang = toSignal(this.translate.onLangChange.pipe(startWith(null)), { initialValue: null });
|
|
10009
|
+
/** Show validation only after interaction (touched/dirty). */
|
|
10010
|
+
showError = computed(() => {
|
|
10011
|
+
this.controlTick();
|
|
10012
|
+
this.manualTick();
|
|
10425
10013
|
const c = this.ctrl();
|
|
10426
10014
|
return !!c && (c.touched || c.dirty) && !!c.errors;
|
|
10427
|
-
}
|
|
10428
|
-
/**
|
|
10429
|
-
|
|
10430
|
-
|
|
10431
|
-
|
|
10432
|
-
* - Phoenix custom validators
|
|
10433
|
-
* - Submit-only async validators
|
|
10434
|
-
*/
|
|
10435
|
-
errorKey() {
|
|
10015
|
+
}, ...(ngDevMode ? [{ debugName: "showError" }] : []));
|
|
10016
|
+
/** Normalized error key for the current control. */
|
|
10017
|
+
errorKey = computed(() => {
|
|
10018
|
+
this.controlTick();
|
|
10019
|
+
this.manualTick();
|
|
10436
10020
|
const c = this.ctrl();
|
|
10437
10021
|
if (!c?.errors)
|
|
10438
10022
|
return null;
|
|
10439
|
-
// Angular built-in validators
|
|
10440
10023
|
if (c.errors['required'])
|
|
10441
10024
|
return 'required';
|
|
10442
10025
|
if (c.errors['minlength'])
|
|
@@ -10451,7 +10034,6 @@ class MetaFormFieldV2Component {
|
|
|
10451
10034
|
return 'min';
|
|
10452
10035
|
if (c.errors['max'])
|
|
10453
10036
|
return 'max';
|
|
10454
|
-
// Phoenix custom validators
|
|
10455
10037
|
if (c.errors['dangerousChars'])
|
|
10456
10038
|
return 'dangerousChars';
|
|
10457
10039
|
if (c.errors['timeperiod'])
|
|
@@ -10462,21 +10044,17 @@ class MetaFormFieldV2Component {
|
|
|
10462
10044
|
return 'dueDate';
|
|
10463
10045
|
if (c.errors['bothDates'])
|
|
10464
10046
|
return 'bothDates';
|
|
10465
|
-
// Submit-only async validators
|
|
10466
10047
|
if (c.errors['unique'])
|
|
10467
10048
|
return 'unique';
|
|
10468
10049
|
if (c.errors['uniqueEntry'])
|
|
10469
10050
|
return 'uniqueEntry';
|
|
10470
10051
|
if (c.errors['custom'])
|
|
10471
10052
|
return 'custom';
|
|
10472
|
-
// Fallback: return first error key
|
|
10473
10053
|
return Object.keys(c.errors)[0] ?? null;
|
|
10474
|
-
}
|
|
10475
|
-
/**
|
|
10476
|
-
|
|
10477
|
-
|
|
10478
|
-
*/
|
|
10479
|
-
errorText() {
|
|
10054
|
+
}, ...(ngDevMode ? [{ debugName: "errorKey" }] : []));
|
|
10055
|
+
/** Translated validation message (the single place that owns error UX text). */
|
|
10056
|
+
errorText = computed(() => {
|
|
10057
|
+
this.lang();
|
|
10480
10058
|
const c = this.ctrl();
|
|
10481
10059
|
const k = this.errorKey();
|
|
10482
10060
|
if (!c || !k)
|
|
@@ -10497,10 +10075,8 @@ class MetaFormFieldV2Component {
|
|
|
10497
10075
|
case 'dangerousChars':
|
|
10498
10076
|
return this.translate.instant('VALIDATION_MESSAGE.NO_SPECIAL_CHARS_ALLOWED');
|
|
10499
10077
|
case 'custom':
|
|
10500
|
-
// Legacy behavior: custom error can already be a translation key
|
|
10501
10078
|
return this.translate.instant(c.errors?.['custom']);
|
|
10502
10079
|
case 'uniqueEntry':
|
|
10503
|
-
// Legacy behavior: uniqueEntry may already be a translated string
|
|
10504
10080
|
return (c.errors?.['uniqueEntry'] ??
|
|
10505
10081
|
this.translate.instant('VALIDATION_MESSAGE.VALUE_IS_ALREADY_IN_USE'));
|
|
10506
10082
|
case 'unique':
|
|
@@ -10517,7 +10093,6 @@ class MetaFormFieldV2Component {
|
|
|
10517
10093
|
upperValue: c.errors?.['max']?.max,
|
|
10518
10094
|
});
|
|
10519
10095
|
case 'pattern': {
|
|
10520
|
-
// Special-case URL pattern handling (legacy InlineFieldError behavior)
|
|
10521
10096
|
const re = '^(https?://)?([\\da-z.-]+)\\.([a-z.]{2,6})[/\\w .-]*/?$';
|
|
10522
10097
|
const requiredPattern = c.errors?.['pattern']?.requiredPattern;
|
|
10523
10098
|
if (requiredPattern === re) {
|
|
@@ -10528,54 +10103,54 @@ class MetaFormFieldV2Component {
|
|
|
10528
10103
|
default:
|
|
10529
10104
|
return this.translate.instant('VALIDATION_MESSAGE.INVALID_VALUE');
|
|
10530
10105
|
}
|
|
10106
|
+
}, ...(ngDevMode ? [{ debugName: "errorText" }] : []));
|
|
10107
|
+
/** Minimal value formatter for legacy read-only rendering (not used in template). */
|
|
10108
|
+
displayValue() {
|
|
10109
|
+
const v = this.ctrl()?.value;
|
|
10110
|
+
if (v === null || v === undefined)
|
|
10111
|
+
return '';
|
|
10112
|
+
if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean')
|
|
10113
|
+
return v;
|
|
10114
|
+
if (typeof v === 'object') {
|
|
10115
|
+
return v.label ?? v.name ?? v.fileName ?? JSON.stringify(v);
|
|
10116
|
+
}
|
|
10117
|
+
return String(v);
|
|
10531
10118
|
}
|
|
10532
|
-
/**
|
|
10533
|
-
* Lightweight text formatter for simple read-only display use cases.
|
|
10534
|
-
* This is used mainly for inline displays and summary UIs.
|
|
10535
|
-
*/
|
|
10119
|
+
/** Lightweight text formatter for simple read-only/summary display. */
|
|
10536
10120
|
valueText() {
|
|
10537
10121
|
const c = this.ctrl();
|
|
10538
10122
|
const v = c?.value;
|
|
10539
10123
|
if (v === null || v === undefined || v === '')
|
|
10540
10124
|
return '--';
|
|
10541
|
-
|
|
10542
|
-
|
|
10543
|
-
const opts = this.field?.configuration?.options ?? [];
|
|
10125
|
+
if (this.type() === 'SS_OPTION') {
|
|
10126
|
+
const opts = this.field()?.configuration?.options ?? [];
|
|
10544
10127
|
if (typeof v !== 'object') {
|
|
10545
10128
|
const hit = opts.find((o) => o?.value === v);
|
|
10546
|
-
|
|
10547
|
-
return this.translate.instant(label);
|
|
10129
|
+
return this.translate.instant(hit?.label ?? v);
|
|
10548
10130
|
}
|
|
10549
|
-
|
|
10550
|
-
const label = v.label ?? v.value;
|
|
10551
|
-
return this.translate.instant(label);
|
|
10131
|
+
return this.translate.instant(v.label ?? v.value);
|
|
10552
10132
|
}
|
|
10553
|
-
|
|
10554
|
-
if (this.type === 'DATE' && v instanceof Date) {
|
|
10133
|
+
if (this.type() === 'DATE' && v instanceof Date) {
|
|
10555
10134
|
return v.toLocaleDateString();
|
|
10556
10135
|
}
|
|
10557
|
-
|
|
10558
|
-
if (this.type === 'TEXT_EDITOR' || this.type === 'TEXT_AREA') {
|
|
10136
|
+
if (this.type() === 'TEXT_EDITOR' || this.type() === 'TEXT_AREA') {
|
|
10559
10137
|
return String(v).replace(/<[^>]*>/g, '').trim() || '--';
|
|
10560
10138
|
}
|
|
10561
10139
|
return String(v);
|
|
10562
10140
|
}
|
|
10563
|
-
isCheckbox() {
|
|
10564
|
-
return this.type === this.MetaFieldType.CHECKBOX;
|
|
10565
|
-
}
|
|
10566
10141
|
onDateSelected(val) {
|
|
10567
10142
|
const ctrl = this.ctrl();
|
|
10568
10143
|
if (!ctrl)
|
|
10569
10144
|
return;
|
|
10570
|
-
const d = val instanceof Date ? val :
|
|
10145
|
+
const d = val instanceof Date ? val : val ? new Date(val) : null;
|
|
10571
10146
|
if (!d || isNaN(d.getTime()))
|
|
10572
10147
|
return;
|
|
10573
10148
|
const normalized = new Date(d.getFullYear(), d.getMonth(), d.getDate(), 12, 0, 0, 0);
|
|
10574
|
-
//
|
|
10149
|
+
// Silent write (no loops); bump the tick so error helpers re-evaluate.
|
|
10575
10150
|
ctrl.setValue(normalized, { emitEvent: false });
|
|
10576
10151
|
ctrl.markAsDirty();
|
|
10577
10152
|
ctrl.markAsTouched();
|
|
10578
|
-
this.
|
|
10153
|
+
this.manualTick.update((v) => v + 1);
|
|
10579
10154
|
}
|
|
10580
10155
|
onDateCleared() {
|
|
10581
10156
|
const ctrl = this.ctrl();
|
|
@@ -10584,16 +10159,14 @@ class MetaFormFieldV2Component {
|
|
|
10584
10159
|
ctrl.setValue(null, { emitEvent: false });
|
|
10585
10160
|
ctrl.markAsDirty();
|
|
10586
10161
|
ctrl.markAsTouched();
|
|
10587
|
-
this.
|
|
10162
|
+
this.manualTick.update((v) => v + 1);
|
|
10588
10163
|
}
|
|
10589
10164
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MetaFormFieldV2Component, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10590
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: MetaFormFieldV2Component, isStandalone: true, selector: "phoenix-meta-form-field-v2", inputs: { field: "field", form: "form", readOnly: "readOnly", disableForm: "disableForm" }, ngImport: i0, template: "<div [formGroup]=\"form\">\n @if (!field.hidden) {\n <div\n class=\"meta-field flex gap-2\"\n [class.flex-column]=\"!(isCheckbox() && !isReadOnly())\"\n [class.align-items-center]=\"isCheckbox() && !isReadOnly()\"\n [style.order]=\"field.order ?? null\"\n [attr.data-cy]=\"'meta-field-' + key\"\n >\n\n <!-- Skip the wrapper label only where the control supplies its own:\n - an editable checkbox renders an inline label beside the box;\n - an editable TIMEPERIOD self-labels (phoenix-meta-timeperiod).\n The read-only view has no inline/self label, so it keeps the wrapper\n label (otherwise a read-only checkbox shows a bare \"Yes\" with no field\n name). -->\n @if (userFriendlyMessage() && !(isCheckbox() && !isReadOnly()) && !(type === MetaFieldType.TIMEPERIOD && !isReadOnly())) {\n <label class=\"meta-label\" [attr.for]=\"key\">\n {{ userFriendlyMessage()! | translate }}\n @if (field.mandatory) { <span class=\"meta-required\">*</span> }\n </label>\n }\n\n <!-- READ ONLY (page-level ili field-level) -->\n @if (isReadOnly()) {\n <phoenix-read-only-input-v2 [field]=\"field\" [form]=\"form\"></phoenix-read-only-input-v2>\n } @else {\n @switch (type) {\n\n @case (MetaFieldType.TEXT) {\n <input pInputText [id]=\"key\" [formControlName]=\"key\"\n [attr.placeholder]=\"placeholderKey() ? (placeholderKey()! | translate) : null\" [readonly]=\"isReadOnly()\">\n }\n\n @case (MetaFieldType.URL) {\n <input pInputText [id]=\"key\" [formControlName]=\"key\"\n [attr.placeholder]=\"placeholderKey() ? (placeholderKey()! | translate) : null\" [readonly]=\"isReadOnly()\">\n }\n\n @case (MetaFieldType.PASSWORD) {\n <phoenix-meta-password-field-v2 [disable]=\"isDisabled()\" [formControlName]=\"key\" [control]=\"field\">\n </phoenix-meta-password-field-v2>\n }\n\n @case (MetaFieldType.TEXT_AREA) {\n <textarea pTextarea class=\"meta-textarea\" [id]=\"key\" [formControlName]=\"key\" fluid [autoResize]=\"false\" rows=\"5\"\n [readonly]=\"isReadOnly()\" [attr.placeholder]=\"placeholderKey() ? (placeholderKey()! | translate) : null\">\n </textarea>\n }\n\n @case (MetaFieldType.NUMBER) {\n <p-inputNumber [inputId]=\"key\" [formControlName]=\"key\">\n </p-inputNumber>\n }\n\n @case (MetaFieldType.DATE) {\n <p-datepicker\n [inputId]=\"key\"\n [formControlName]=\"key\"\n [showIcon]=\"true\"\n [readonlyInput]=\"true\"\n [showButtonBar]=\"true\"\n appendTo=\"body\"\n (onSelect)=\"onDateSelected($event)\"\n (onClearClick)=\"onDateCleared()\"\n ></p-datepicker>\n }\n\n @case (MetaFieldType.SS_OPTION) {\n <p-select [inputId]=\"key\" [options]=\"field.configuration.options ?? []\" optionLabel=\"label\" optionValue=\"value\"\n [formControlName]=\"key\" [showClear]=\"false\">\n </p-select>\n }\n\n @case (MetaFieldType.SS_OPTION_OBJECT_BASED) {\n <p-select [inputId]=\"key\" [options]=\"field.configuration.options ?? []\" optionLabel=\"label\" [formControlName]=\"key\"\n [showClear]=\"true\">\n </p-select>\n }\n\n @case (MetaFieldType.MS_OPTION) {\n <p-multiselect [inputId]=\"key\" [options]=\"field.configuration.options ?? []\" optionLabel=\"label\" optionValue=\"value\"\n [formControlName]=\"key\" [showClear]=\"false\" display=\"chip\">\n </p-multiselect>\n }\n\n @case (MetaFieldType.CHECKBOX) {\n <p-checkbox\n [inputId]=\"key\"\n [binary]=\"true\"\n [formControlName]=\"key\"\n [disabled]=\"isDisabled()\"\n ></p-checkbox>\n\n <label class=\"meta-inline-label\" [attr.for]=\"key\">\n {{ (userFriendlyMessage() ?? placeholderKey() ?? '') | translate }}\n @if (field.mandatory) { <span class=\"meta-required\">*</span> }\n </label>\n }\n\n <!-- advanced: preko postoje\u0107ih komponenti -->\n @case (MetaFieldType.TIMEPERIOD) {\n <phoenix-meta-timeperiod [formControlName]=\"key\" [control]=\"field\" [parentForm]=\"form\"></phoenix-meta-timeperiod>\n }\n\n @case (MetaFieldType.CURRENCY) {\n <phoenix-meta-currency [disable]=\"isDisabled()\" [formControlName]=\"key\" [control]=\"field\"\n [parentForm]=\"form\"></phoenix-meta-currency>\n }\n\n @case (MetaFieldType.START_DUE_DATE) {\n <phoenix-meta-start-due-date-v2\n [formControlName]=\"key\"\n [attr.data-cy]=\"'start-due-' + key\">\n </phoenix-meta-start-due-date-v2>\n }\n\n @case (MetaFieldType.TEXT_EDITOR) {\n <phoenix-meta-text-editor [disable]=\"isDisabled()\" [formControlName]=\"key\" [control]=\"field\"\n [parentForm]=\"form\"></phoenix-meta-text-editor>\n }\n\n @case (MetaFieldType.CHECKBOX_COLOR) {\n <phoenix-meta-checkbox-color-picker-v2\n [formControlName]=\"key\"\n [options]=\"(field.configuration.extra?.['colorGrid'] ?? [])\"\n [disable]=\"isDisabled()\">\n </phoenix-meta-checkbox-color-picker-v2>\n }\n\n @case (MetaFieldType.SWITCH) {\n <phoenix-meta-switch-v2 [disable]=\"isDisabled()\" [formControlName]=\"key\" [hidden]=\"field.hidden ?? false\"\n [dataCy]=\"'switch-' + key\"></phoenix-meta-switch-v2>\n }\n\n @case (MetaFieldType.SELECT_BUTTON) {\n <phoenix-meta-select-button [disable]=\"isDisabled()\" [formControlName]=\"key\" [control]=\"field\"\n [parentForm]=\"form\"></phoenix-meta-select-button>\n }\n\n @case (MetaFieldType.ASSIGN) {\n <phoenix-meta-assign-responsible-v2\n [formControlName]=\"key\"\n [items]=\"(field.configuration.extra?.['items'] ?? [])\"\n [dialogHeaderKey]=\"(field.configuration.extra?.['dialogHeaderKey'] ?? 'LABELS.ASSIGN_RESPONSIBLE')\"\n ></phoenix-meta-assign-responsible-v2>\n }\n\n <!-- @case (MetaFieldType.ASSIGN_ASSET) {\n <phoenix-meta-assign-asset [disable]=\"isDisabled()\" [formControlName]=\"key\" [control]=\"field\"\n [parentForm]=\"form\"></phoenix-meta-assign-asset>\n } -->\n\n @case (MetaFieldType.COLOR) {\n <phoenix-meta-color-picker-v2\n [formControlName]=\"key\"\n [disable]=\"isDisabled()\">\n </phoenix-meta-color-picker-v2>\n }\n\n @case (MetaFieldType.UPLOAD) {\n <phoenix-meta-upload [disable]=\"isDisabled()\" [formControlName]=\"key\" [control]=\"field\"\n [parentForm]=\"form\"></phoenix-meta-upload>\n }\n\n @case (MetaFieldType.UPLOAD_DRAG_DROP) {\n <phoenix-meta-upload-dragdrop [disable]=\"isDisabled()\" [formControlName]=\"key\" [control]=\"field\"\n [parentForm]=\"form\"></phoenix-meta-upload-dragdrop>\n }\n\n @case (MetaFieldType.LINKS_DATA) {\n <!-- <input pInputText [id]=\"key\" [formControlName]=\"key\" [readonly]=\"true\"> -->\n }\n\n @case (MetaFieldType.SLOT) { }\n\n @default {\n <input pInputText [id]=\"key\" [formControlName]=\"key\">\n }\n }\n\n @if (field.configuration.extra?.['dividerAfter']) {\n <div\n class=\"meta-divider\"\n [style.margin]=\"field.configuration.extra?.['dividerMargin'] ?? '12px 0'\"\n ></div>\n }\n }\n\n\n @if (!readOnly && showError()) {\n <small class=\"p-error block mt-1\">\n <i class=\"pi pi-info-circle mr-1\"></i>{{ errorText() }}\n </small>\n }\n </div>\n }\n</div>", styles: [".meta-field{width:100%}.meta-required{margin-left:4px;color:#ef4444}.meta-textarea{resize:none!important}.meta-inline-label{opacity:.9;margin:0;cursor:pointer}.p-inputtext.ng-invalid.ng-dirty{border-color:var(--p-inputtext-border-color)!important}.p-select.ng-invalid.ng-dirty{border-color:var(--p-select-border-color)!important}.meta-divider{width:100%;height:1px;background:#0000001f}:host-context(.dark-theme) .meta-divider{background:#ffffff26}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$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: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "ngmodule", type:
|
|
10165
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: MetaFormFieldV2Component, isStandalone: true, selector: "phoenix-meta-form-field-v2", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, disableForm: { classPropertyName: "disableForm", publicName: "disableForm", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div [formGroup]=\"form()\">\n @if (!field().hidden) {\n <div\n class=\"meta-field flex gap-2\"\n [class.flex-column]=\"!(isCheckbox() && !isReadOnly())\"\n [class.align-items-center]=\"isCheckbox() && !isReadOnly()\"\n [style.order]=\"field().order ?? null\"\n [attr.data-cy]=\"'meta-field-' + key()\"\n >\n\n <!-- Skip the wrapper label only where the control supplies its own:\n - an editable checkbox renders an inline label beside the box;\n - an editable TIMEPERIOD self-labels (phoenix-meta-timeperiod).\n The read-only view has no inline/self label, so it keeps the wrapper\n label (otherwise a read-only checkbox shows a bare \"Yes\" with no field\n name). -->\n @if (userFriendlyMessage() && !(isCheckbox() && !isReadOnly())) {\n <label class=\"meta-label\" [attr.for]=\"key()\">\n {{ userFriendlyMessage()! | translate }}\n @if (field().mandatory) { <span class=\"meta-required\">*</span> }\n </label>\n }\n\n <!-- READ ONLY (page-level ili field-level) -->\n @if (isReadOnly()) {\n <phoenix-read-only-input-v2 [field]=\"field()\" [form]=\"form()\"></phoenix-read-only-input-v2>\n } @else {\n @switch (type()) {\n\n @case (MetaFieldType.TEXT) {\n <input pInputText [id]=\"key()\" [formControlName]=\"key()\"\n [attr.placeholder]=\"placeholderKey() ? (placeholderKey()! | translate) : null\" [readonly]=\"isReadOnly()\">\n }\n\n @case (MetaFieldType.URL) {\n <input pInputText [id]=\"key()\" [formControlName]=\"key()\"\n [attr.placeholder]=\"placeholderKey() ? (placeholderKey()! | translate) : null\" [readonly]=\"isReadOnly()\">\n }\n\n @case (MetaFieldType.PASSWORD) {\n <phoenix-meta-password-field-v2 [disable]=\"isDisabled()\" [formControlName]=\"key()\" [control]=\"field()\">\n </phoenix-meta-password-field-v2>\n }\n\n @case (MetaFieldType.TEXT_AREA) {\n <textarea pTextarea class=\"meta-textarea\" [id]=\"key()\" [formControlName]=\"key()\" fluid [autoResize]=\"false\" rows=\"5\"\n [readonly]=\"isReadOnly()\" [attr.placeholder]=\"placeholderKey() ? (placeholderKey()! | translate) : null\">\n </textarea>\n }\n\n @case (MetaFieldType.NUMBER) {\n <p-inputNumber [inputId]=\"key()\" [formControlName]=\"key()\">\n </p-inputNumber>\n }\n\n @case (MetaFieldType.DATE) {\n <p-datepicker\n [inputId]=\"key()\"\n [formControlName]=\"key()\"\n [showIcon]=\"true\"\n [readonlyInput]=\"true\"\n [showButtonBar]=\"true\"\n appendTo=\"body\"\n (onSelect)=\"onDateSelected($event)\"\n (onClearClick)=\"onDateCleared()\"\n ></p-datepicker>\n }\n\n @case (MetaFieldType.SS_OPTION) {\n <p-select [inputId]=\"key()\" [options]=\"field().configuration.options ?? []\" optionLabel=\"label\" optionValue=\"value\"\n [formControlName]=\"key()\" [showClear]=\"false\" appendTo=\"body\">\n </p-select>\n }\n\n @case (MetaFieldType.SS_OPTION_OBJECT_BASED) {\n <p-select [inputId]=\"key()\" [options]=\"field().configuration.options ?? []\" optionLabel=\"label\" [formControlName]=\"key()\"\n [showClear]=\"true\" appendTo=\"body\">\n </p-select>\n }\n\n @case (MetaFieldType.MS_OPTION) {\n <p-multiselect [inputId]=\"key()\" [options]=\"field().configuration.options ?? []\" optionLabel=\"label\" optionValue=\"value\"\n [formControlName]=\"key()\" [showClear]=\"false\" display=\"chip\" appendTo=\"body\">\n </p-multiselect>\n }\n\n @case (MetaFieldType.CHECKBOX) {\n <p-checkbox\n [inputId]=\"key()\"\n [binary]=\"true\"\n [formControlName]=\"key()\"\n [disabled]=\"isDisabled()\"\n ></p-checkbox>\n\n <label class=\"meta-inline-label\" [attr.for]=\"key()\">\n {{ (userFriendlyMessage() ?? placeholderKey() ?? '') | translate }}\n @if (field().mandatory) { <span class=\"meta-required\">*</span> }\n </label>\n }\n\n <!-- advanced: preko postoje\u0107ih komponenti -->\n @case (MetaFieldType.TIMEPERIOD) {\n <phoenix-meta-timeperiod-v2 [formControlName]=\"key()\" [key]=\"key()\" [disable]=\"isDisabled()\"></phoenix-meta-timeperiod-v2>\n }\n\n @case (MetaFieldType.CURRENCY) {\n <phoenix-meta-currency [disable]=\"isDisabled()\" [formControlName]=\"key()\" [control]=\"field()\"\n [parentForm]=\"form()\"></phoenix-meta-currency>\n }\n\n @case (MetaFieldType.START_DUE_DATE) {\n <phoenix-meta-start-due-date-v2\n [formControlName]=\"key()\"\n [attr.data-cy]=\"'start-due-' + key()\">\n </phoenix-meta-start-due-date-v2>\n }\n\n @case (MetaFieldType.TEXT_EDITOR) {\n <phoenix-meta-text-editor [disable]=\"isDisabled()\" [formControlName]=\"key()\" [control]=\"field()\"\n [parentForm]=\"form()\"></phoenix-meta-text-editor>\n }\n\n @case (MetaFieldType.CHECKBOX_COLOR) {\n <phoenix-meta-checkbox-color-picker-v2\n [formControlName]=\"key()\"\n [options]=\"(field().configuration.extra?.['colorGrid'] ?? [])\"\n [disable]=\"isDisabled()\">\n </phoenix-meta-checkbox-color-picker-v2>\n }\n\n @case (MetaFieldType.SWITCH) {\n <phoenix-meta-switch-v2 [disable]=\"isDisabled()\" [formControlName]=\"key()\" [hidden]=\"field().hidden ?? false\"\n [dataCy]=\"'switch-' + key()\"></phoenix-meta-switch-v2>\n }\n\n @case (MetaFieldType.SELECT_BUTTON) {\n <phoenix-meta-select-button [disable]=\"isDisabled()\" [formControlName]=\"key()\" [control]=\"field()\"\n [parentForm]=\"form()\"></phoenix-meta-select-button>\n }\n\n @case (MetaFieldType.ASSIGN) {\n <phoenix-meta-assign-responsible-v2\n [formControlName]=\"key()\"\n [items]=\"(field().configuration.extra?.['items'] ?? [])\"\n [dialogHeaderKey]=\"(field().configuration.extra?.['dialogHeaderKey'] ?? 'LABELS.ASSIGN_RESPONSIBLE')\"\n ></phoenix-meta-assign-responsible-v2>\n }\n\n <!-- @case (MetaFieldType.ASSIGN_ASSET) {\n <phoenix-meta-assign-asset [disable]=\"isDisabled()\" [formControlName]=\"key()\" [control]=\"field()\"\n [parentForm]=\"form()\"></phoenix-meta-assign-asset>\n } -->\n\n @case (MetaFieldType.COLOR) {\n <phoenix-meta-color-picker-v2\n [formControlName]=\"key()\"\n [disable]=\"isDisabled()\">\n </phoenix-meta-color-picker-v2>\n }\n\n @case (MetaFieldType.UPLOAD) {\n <phoenix-meta-upload [disable]=\"isDisabled()\" [formControlName]=\"key()\" [control]=\"field()\"\n [parentForm]=\"form()\"></phoenix-meta-upload>\n }\n\n @case (MetaFieldType.UPLOAD_DRAG_DROP) {\n <phoenix-meta-upload-dragdrop [disable]=\"isDisabled()\" [formControlName]=\"key()\" [control]=\"field()\"\n [parentForm]=\"form()\"></phoenix-meta-upload-dragdrop>\n }\n\n @case (MetaFieldType.LINKS_DATA) {\n <!-- <input pInputText [id]=\"key()\" [formControlName]=\"key()\" [readonly]=\"true\"> -->\n }\n\n @case (MetaFieldType.SLOT) { }\n\n @default {\n <input pInputText [id]=\"key()\" [formControlName]=\"key()\">\n }\n }\n\n @if (field().configuration.extra?.['dividerAfter']) {\n <div\n class=\"meta-divider\"\n [style.margin]=\"field().configuration.extra?.['dividerMargin'] ?? '12px 0'\"\n ></div>\n }\n }\n\n\n <!-- TIMEPERIOD carries its own calm format helper; don't duplicate a red error here. -->\n @if (!readOnly() && showError() && type() !== MetaFieldType.TIMEPERIOD) {\n <small class=\"p-error block mt-1\">\n <i class=\"pi pi-info-circle mr-1\"></i>{{ errorText() }}\n </small>\n }\n </div>\n }\n</div>\n", styles: [".meta-field{width:100%}.meta-required{margin-left:4px;color:#ef4444}.meta-textarea{resize:none!important}.meta-inline-label{opacity:.9;margin:0;cursor:pointer}.p-inputtext.ng-invalid.ng-dirty{border-color:var(--p-inputtext-border-color)!important}.p-select.ng-invalid.ng-dirty{border-color:var(--p-select-border-color)!important}.meta-divider{width:100%;height:1px;background:#0000001f}:host-context(.dark-theme) .meta-divider{background:#ffffff26}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$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: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "ngmodule", type:
|
|
10591
10166
|
// PrimeNG 20 base inputs
|
|
10592
10167
|
InputTextModule }, { kind: "directive", type: i3$3.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: TextareaModule }, { kind: "directive", type: i3$7.Textarea, selector: "[pTextarea], [pInputTextarea]", inputs: ["autoResize", "pSize", "variant", "fluid", "invalid"], outputs: ["onResize"] }, { kind: "ngmodule", type: InputNumberModule }, { kind: "component", type: i3$5.InputNumber, selector: "p-inputNumber, p-inputnumber, p-input-number", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "placeholder", "tabindex", "title", "ariaLabelledBy", "ariaDescribedBy", "ariaLabel", "ariaRequired", "autocomplete", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i4$4.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["hostName", "value", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "inputStyle", "styleClass", "inputClass", "indeterminate", "formControl", "checkboxIcon", "readonly", "autofocus", "trueValue", "falseValue", "variant", "size"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i5$2.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "styleClass", "panelStyle", "panelStyleClass", "inputId", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "dataKey", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "placeholder", "options", "filterValue", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect", "size", "variant", "fluid", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i3$4.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i2$6.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: MessageModule }, { kind: "component", type:
|
|
10593
10168
|
// Advanced / custom Phoenix fields
|
|
10594
|
-
|
|
10595
|
-
// MetaAssignAssetComponent,
|
|
10596
|
-
MetaPasswordFieldV2Component, selector: "phoenix-meta-password-field-v2", inputs: ["control", "ctrl", "disable", "hidden", "dataCy", "feedback", "autocomplete"] }, { kind: "component", type: MetaColorPickerV2Component, selector: "phoenix-meta-color-picker-v2", inputs: ["disable"] }, { kind: "component", type: MetaUploadComponent, selector: "phoenix-meta-upload" }, { kind: "component", type: MetaUploadComponentDragDrop, selector: "phoenix-meta-upload-dragdrop" }, { kind: "component", type:
|
|
10169
|
+
MetaTimeperiodV2Component, selector: "phoenix-meta-timeperiod-v2", inputs: ["key", "disable"] }, { kind: "component", type: MetaCurrencyComponent, selector: "phoenix-meta-currency" }, { kind: "component", type: MetaStartDueDateV2Component, selector: "phoenix-meta-start-due-date-v2", inputs: ["dataCy", "disable"] }, { kind: "component", type: MetaTextEditorComponent, selector: "phoenix-meta-text-editor", inputs: ["previewMode", "hideLabel"] }, { kind: "component", type: MetaCheckboxColorPickerV2Component, selector: "phoenix-meta-checkbox-color-picker-v2", inputs: ["options", "disable"] }, { kind: "component", type: MetaSwitchV2Component, selector: "phoenix-meta-switch-v2", inputs: ["disable", "hidden", "dataCy"] }, { kind: "component", type: MetaSelectButtonComponent, selector: "phoenix-meta-select-button" }, { kind: "component", type: MetaAssignResponsibleV2Component, selector: "phoenix-meta-assign-responsible-v2", inputs: ["items", "dialogHeaderKey"] }, { kind: "component", type: MetaPasswordFieldV2Component, selector: "phoenix-meta-password-field-v2", inputs: ["control", "ctrl", "disable", "hidden", "dataCy", "feedback", "autocomplete"] }, { kind: "component", type: MetaColorPickerV2Component, selector: "phoenix-meta-color-picker-v2", inputs: ["disable"] }, { kind: "component", type: MetaUploadComponent, selector: "phoenix-meta-upload" }, { kind: "component", type: MetaUploadComponentDragDrop, selector: "phoenix-meta-upload-dragdrop" }, { kind: "component", type:
|
|
10597
10170
|
// Read-only renderer used when page or field is in read-only mode
|
|
10598
10171
|
ReadOnlyInputV2Component, selector: "phoenix-read-only-input-v2", inputs: ["field", "form"] }, { kind: "pipe", type: i4$2.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
10599
10172
|
}
|
|
@@ -10613,7 +10186,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
10613
10186
|
DatePickerModule,
|
|
10614
10187
|
MessageModule,
|
|
10615
10188
|
// Advanced / custom Phoenix fields
|
|
10616
|
-
|
|
10189
|
+
MetaTimeperiodV2Component,
|
|
10617
10190
|
MetaCurrencyComponent,
|
|
10618
10191
|
MetaStartDueDateV2Component,
|
|
10619
10192
|
MetaTextEditorComponent,
|
|
@@ -10621,25 +10194,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
10621
10194
|
MetaSwitchV2Component,
|
|
10622
10195
|
MetaSelectButtonComponent,
|
|
10623
10196
|
MetaAssignResponsibleV2Component,
|
|
10624
|
-
// MetaAssignAssetComponent,
|
|
10625
10197
|
MetaPasswordFieldV2Component,
|
|
10626
10198
|
MetaColorPickerV2Component,
|
|
10627
10199
|
MetaUploadComponent,
|
|
10628
10200
|
MetaUploadComponentDragDrop,
|
|
10629
10201
|
// Read-only renderer used when page or field is in read-only mode
|
|
10630
10202
|
ReadOnlyInputV2Component,
|
|
10631
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [formGroup]=\"form\">\n @if (!field.hidden) {\n <div\n class=\"meta-field flex gap-2\"\n [class.flex-column]=\"!(isCheckbox() && !isReadOnly())\"\n [class.align-items-center]=\"isCheckbox() && !isReadOnly()\"\n [style.order]=\"field.order ?? null\"\n [attr.data-cy]=\"'meta-field-' + key\"\n >\n\n <!-- Skip the wrapper label only where the control supplies its own:\n - an editable checkbox renders an inline label beside the box;\n - an editable TIMEPERIOD self-labels (phoenix-meta-timeperiod).\n The read-only view has no inline/self label, so it keeps the wrapper\n label (otherwise a read-only checkbox shows a bare \"Yes\" with no field\n name). -->\n @if (userFriendlyMessage() && !(isCheckbox() && !isReadOnly())
|
|
10632
|
-
}], propDecorators: { field: [{
|
|
10633
|
-
type: Input,
|
|
10634
|
-
args: [{ required: true }]
|
|
10635
|
-
}], form: [{
|
|
10636
|
-
type: Input,
|
|
10637
|
-
args: [{ required: true }]
|
|
10638
|
-
}], readOnly: [{
|
|
10639
|
-
type: Input
|
|
10640
|
-
}], disableForm: [{
|
|
10641
|
-
type: Input
|
|
10642
|
-
}] } });
|
|
10203
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [formGroup]=\"form()\">\n @if (!field().hidden) {\n <div\n class=\"meta-field flex gap-2\"\n [class.flex-column]=\"!(isCheckbox() && !isReadOnly())\"\n [class.align-items-center]=\"isCheckbox() && !isReadOnly()\"\n [style.order]=\"field().order ?? null\"\n [attr.data-cy]=\"'meta-field-' + key()\"\n >\n\n <!-- Skip the wrapper label only where the control supplies its own:\n - an editable checkbox renders an inline label beside the box;\n - an editable TIMEPERIOD self-labels (phoenix-meta-timeperiod).\n The read-only view has no inline/self label, so it keeps the wrapper\n label (otherwise a read-only checkbox shows a bare \"Yes\" with no field\n name). -->\n @if (userFriendlyMessage() && !(isCheckbox() && !isReadOnly())) {\n <label class=\"meta-label\" [attr.for]=\"key()\">\n {{ userFriendlyMessage()! | translate }}\n @if (field().mandatory) { <span class=\"meta-required\">*</span> }\n </label>\n }\n\n <!-- READ ONLY (page-level ili field-level) -->\n @if (isReadOnly()) {\n <phoenix-read-only-input-v2 [field]=\"field()\" [form]=\"form()\"></phoenix-read-only-input-v2>\n } @else {\n @switch (type()) {\n\n @case (MetaFieldType.TEXT) {\n <input pInputText [id]=\"key()\" [formControlName]=\"key()\"\n [attr.placeholder]=\"placeholderKey() ? (placeholderKey()! | translate) : null\" [readonly]=\"isReadOnly()\">\n }\n\n @case (MetaFieldType.URL) {\n <input pInputText [id]=\"key()\" [formControlName]=\"key()\"\n [attr.placeholder]=\"placeholderKey() ? (placeholderKey()! | translate) : null\" [readonly]=\"isReadOnly()\">\n }\n\n @case (MetaFieldType.PASSWORD) {\n <phoenix-meta-password-field-v2 [disable]=\"isDisabled()\" [formControlName]=\"key()\" [control]=\"field()\">\n </phoenix-meta-password-field-v2>\n }\n\n @case (MetaFieldType.TEXT_AREA) {\n <textarea pTextarea class=\"meta-textarea\" [id]=\"key()\" [formControlName]=\"key()\" fluid [autoResize]=\"false\" rows=\"5\"\n [readonly]=\"isReadOnly()\" [attr.placeholder]=\"placeholderKey() ? (placeholderKey()! | translate) : null\">\n </textarea>\n }\n\n @case (MetaFieldType.NUMBER) {\n <p-inputNumber [inputId]=\"key()\" [formControlName]=\"key()\">\n </p-inputNumber>\n }\n\n @case (MetaFieldType.DATE) {\n <p-datepicker\n [inputId]=\"key()\"\n [formControlName]=\"key()\"\n [showIcon]=\"true\"\n [readonlyInput]=\"true\"\n [showButtonBar]=\"true\"\n appendTo=\"body\"\n (onSelect)=\"onDateSelected($event)\"\n (onClearClick)=\"onDateCleared()\"\n ></p-datepicker>\n }\n\n @case (MetaFieldType.SS_OPTION) {\n <p-select [inputId]=\"key()\" [options]=\"field().configuration.options ?? []\" optionLabel=\"label\" optionValue=\"value\"\n [formControlName]=\"key()\" [showClear]=\"false\" appendTo=\"body\">\n </p-select>\n }\n\n @case (MetaFieldType.SS_OPTION_OBJECT_BASED) {\n <p-select [inputId]=\"key()\" [options]=\"field().configuration.options ?? []\" optionLabel=\"label\" [formControlName]=\"key()\"\n [showClear]=\"true\" appendTo=\"body\">\n </p-select>\n }\n\n @case (MetaFieldType.MS_OPTION) {\n <p-multiselect [inputId]=\"key()\" [options]=\"field().configuration.options ?? []\" optionLabel=\"label\" optionValue=\"value\"\n [formControlName]=\"key()\" [showClear]=\"false\" display=\"chip\" appendTo=\"body\">\n </p-multiselect>\n }\n\n @case (MetaFieldType.CHECKBOX) {\n <p-checkbox\n [inputId]=\"key()\"\n [binary]=\"true\"\n [formControlName]=\"key()\"\n [disabled]=\"isDisabled()\"\n ></p-checkbox>\n\n <label class=\"meta-inline-label\" [attr.for]=\"key()\">\n {{ (userFriendlyMessage() ?? placeholderKey() ?? '') | translate }}\n @if (field().mandatory) { <span class=\"meta-required\">*</span> }\n </label>\n }\n\n <!-- advanced: preko postoje\u0107ih komponenti -->\n @case (MetaFieldType.TIMEPERIOD) {\n <phoenix-meta-timeperiod-v2 [formControlName]=\"key()\" [key]=\"key()\" [disable]=\"isDisabled()\"></phoenix-meta-timeperiod-v2>\n }\n\n @case (MetaFieldType.CURRENCY) {\n <phoenix-meta-currency [disable]=\"isDisabled()\" [formControlName]=\"key()\" [control]=\"field()\"\n [parentForm]=\"form()\"></phoenix-meta-currency>\n }\n\n @case (MetaFieldType.START_DUE_DATE) {\n <phoenix-meta-start-due-date-v2\n [formControlName]=\"key()\"\n [attr.data-cy]=\"'start-due-' + key()\">\n </phoenix-meta-start-due-date-v2>\n }\n\n @case (MetaFieldType.TEXT_EDITOR) {\n <phoenix-meta-text-editor [disable]=\"isDisabled()\" [formControlName]=\"key()\" [control]=\"field()\"\n [parentForm]=\"form()\"></phoenix-meta-text-editor>\n }\n\n @case (MetaFieldType.CHECKBOX_COLOR) {\n <phoenix-meta-checkbox-color-picker-v2\n [formControlName]=\"key()\"\n [options]=\"(field().configuration.extra?.['colorGrid'] ?? [])\"\n [disable]=\"isDisabled()\">\n </phoenix-meta-checkbox-color-picker-v2>\n }\n\n @case (MetaFieldType.SWITCH) {\n <phoenix-meta-switch-v2 [disable]=\"isDisabled()\" [formControlName]=\"key()\" [hidden]=\"field().hidden ?? false\"\n [dataCy]=\"'switch-' + key()\"></phoenix-meta-switch-v2>\n }\n\n @case (MetaFieldType.SELECT_BUTTON) {\n <phoenix-meta-select-button [disable]=\"isDisabled()\" [formControlName]=\"key()\" [control]=\"field()\"\n [parentForm]=\"form()\"></phoenix-meta-select-button>\n }\n\n @case (MetaFieldType.ASSIGN) {\n <phoenix-meta-assign-responsible-v2\n [formControlName]=\"key()\"\n [items]=\"(field().configuration.extra?.['items'] ?? [])\"\n [dialogHeaderKey]=\"(field().configuration.extra?.['dialogHeaderKey'] ?? 'LABELS.ASSIGN_RESPONSIBLE')\"\n ></phoenix-meta-assign-responsible-v2>\n }\n\n <!-- @case (MetaFieldType.ASSIGN_ASSET) {\n <phoenix-meta-assign-asset [disable]=\"isDisabled()\" [formControlName]=\"key()\" [control]=\"field()\"\n [parentForm]=\"form()\"></phoenix-meta-assign-asset>\n } -->\n\n @case (MetaFieldType.COLOR) {\n <phoenix-meta-color-picker-v2\n [formControlName]=\"key()\"\n [disable]=\"isDisabled()\">\n </phoenix-meta-color-picker-v2>\n }\n\n @case (MetaFieldType.UPLOAD) {\n <phoenix-meta-upload [disable]=\"isDisabled()\" [formControlName]=\"key()\" [control]=\"field()\"\n [parentForm]=\"form()\"></phoenix-meta-upload>\n }\n\n @case (MetaFieldType.UPLOAD_DRAG_DROP) {\n <phoenix-meta-upload-dragdrop [disable]=\"isDisabled()\" [formControlName]=\"key()\" [control]=\"field()\"\n [parentForm]=\"form()\"></phoenix-meta-upload-dragdrop>\n }\n\n @case (MetaFieldType.LINKS_DATA) {\n <!-- <input pInputText [id]=\"key()\" [formControlName]=\"key()\" [readonly]=\"true\"> -->\n }\n\n @case (MetaFieldType.SLOT) { }\n\n @default {\n <input pInputText [id]=\"key()\" [formControlName]=\"key()\">\n }\n }\n\n @if (field().configuration.extra?.['dividerAfter']) {\n <div\n class=\"meta-divider\"\n [style.margin]=\"field().configuration.extra?.['dividerMargin'] ?? '12px 0'\"\n ></div>\n }\n }\n\n\n <!-- TIMEPERIOD carries its own calm format helper; don't duplicate a red error here. -->\n @if (!readOnly() && showError() && type() !== MetaFieldType.TIMEPERIOD) {\n <small class=\"p-error block mt-1\">\n <i class=\"pi pi-info-circle mr-1\"></i>{{ errorText() }}\n </small>\n }\n </div>\n }\n</div>\n", styles: [".meta-field{width:100%}.meta-required{margin-left:4px;color:#ef4444}.meta-textarea{resize:none!important}.meta-inline-label{opacity:.9;margin:0;cursor:pointer}.p-inputtext.ng-invalid.ng-dirty{border-color:var(--p-inputtext-border-color)!important}.p-select.ng-invalid.ng-dirty{border-color:var(--p-select-border-color)!important}.meta-divider{width:100%;height:1px;background:#0000001f}:host-context(.dark-theme) .meta-divider{background:#ffffff26}\n"] }]
|
|
10204
|
+
}], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }], readOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnly", required: false }] }], disableForm: [{ type: i0.Input, args: [{ isSignal: true, alias: "disableForm", required: false }] }] } });
|
|
10643
10205
|
|
|
10644
10206
|
/**
|
|
10645
10207
|
* Splits a flat list of fields into row chunks for grid rendering.
|
|
@@ -11108,161 +10670,135 @@ function flattenControls(input) {
|
|
|
11108
10670
|
.filter((x) => !!x?.configuration?.key);
|
|
11109
10671
|
}
|
|
11110
10672
|
|
|
10673
|
+
/**
|
|
10674
|
+
* V2 form host. Signal-based (OnPush): inputs are `input()` signals, the
|
|
10675
|
+
* template-facing structure (`hasControls`/`isGrouped`/`groupedControls`/
|
|
10676
|
+
* `controlRows`) is `computed()` (so `splitControlsIntoRows` runs only when the
|
|
10677
|
+
* config changes, not on every CD pass), and `expandedGroupIds` is a signal.
|
|
10678
|
+
*
|
|
10679
|
+
* Reactive forms aren't signal-native, so control building stays imperative: the
|
|
10680
|
+
* first build runs synchronously in `ngOnInit` (controls exist before first
|
|
10681
|
+
* paint), and an `effect()` re-runs the same build when `config`/`form`/`readOnly`
|
|
10682
|
+
* change — with the same change-detection semantics the old `ngOnChanges` had.
|
|
10683
|
+
*/
|
|
11111
10684
|
class MetaFormV2Component {
|
|
11112
|
-
/** Form instance created/owned by the parent (dialog/page) */
|
|
11113
|
-
form;
|
|
11114
|
-
/**
|
|
11115
|
-
|
|
11116
|
-
|
|
11117
|
-
|
|
11118
|
-
|
|
11119
|
-
|
|
11120
|
-
|
|
11121
|
-
|
|
11122
|
-
/**
|
|
11123
|
-
* Page-level readOnly state controlled by parent.
|
|
11124
|
-
* Used both for rendering and for "enter edit mode" behavior.
|
|
11125
|
-
*/
|
|
11126
|
-
readOnly = false;
|
|
11127
|
-
/** Optional layout customization for inner content wrapper */
|
|
11128
|
-
contentStyle = null;
|
|
11129
|
-
/** Optional class name(s) applied to inner content wrapper */
|
|
11130
|
-
contentClass = null;
|
|
11131
|
-
/** Builds/ensures controls exist (ensures validators & default values are wired) */
|
|
10685
|
+
/** Form instance created/owned by the parent (dialog/page). */
|
|
10686
|
+
form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
10687
|
+
/** V2 metadata/config (controls, initialValues, submitValidators, setupDependencies). */
|
|
10688
|
+
config = input.required(...(ngDevMode ? [{ debugName: "config" }] : []));
|
|
10689
|
+
/** Page-level readOnly state (rendering + "enter edit mode" behavior). */
|
|
10690
|
+
readOnly = input(false, ...(ngDevMode ? [{ debugName: "readOnly" }] : []));
|
|
10691
|
+
/** Optional layout customization for the inner content wrapper. */
|
|
10692
|
+
contentStyle = input(null, ...(ngDevMode ? [{ debugName: "contentStyle" }] : []));
|
|
10693
|
+
/** Optional class name(s) for the inner content wrapper. */
|
|
10694
|
+
contentClass = input(null, ...(ngDevMode ? [{ debugName: "contentClass" }] : []));
|
|
11132
10695
|
fb = inject(FormBuilder);
|
|
11133
|
-
/** Registers and executes submit-only validators (async validation on submit) */
|
|
11134
10696
|
submitValidator = inject(MetaSubmitValidatorService);
|
|
11135
|
-
/** Used for validator localization (lang-dependent validators / messages) */
|
|
11136
10697
|
translate = inject(TranslateService);
|
|
11137
|
-
/**
|
|
11138
|
-
* A lightweight signature of the current metadata structure.
|
|
11139
|
-
* Used to detect when the form schema changes (and avoid unnecessary resets).
|
|
11140
|
-
*/
|
|
10698
|
+
/** Signature of the current schema (key+type only) to detect real schema changes. */
|
|
11141
10699
|
lastSignature = '';
|
|
11142
|
-
/**
|
|
11143
|
-
* Cleanup function returned by setupDependencies (if any).
|
|
11144
|
-
* Called only when metadata structure changes or on destroy.
|
|
11145
|
-
*/
|
|
10700
|
+
/** Cleanup from setupDependencies; called on schema change or destroy. */
|
|
11146
10701
|
depCleanup;
|
|
10702
|
+
/** Previous input references, to reproduce the old SimpleChanges semantics. */
|
|
10703
|
+
prevConfig = null;
|
|
10704
|
+
prevForm = null;
|
|
10705
|
+
prevReadOnly = false;
|
|
10706
|
+
initialized = false;
|
|
10707
|
+
/** PrimeNG Accordion opened-panel ids. */
|
|
10708
|
+
expandedGroupIds = signal([], ...(ngDevMode ? [{ debugName: "expandedGroupIds" }] : []));
|
|
10709
|
+
// ---- Memoized, config-derived structure for the template ----
|
|
10710
|
+
hasControls = computed(() => Array.isArray(this.config()?.controls) && this.config().controls.length > 0, ...(ngDevMode ? [{ debugName: "hasControls" }] : []));
|
|
10711
|
+
/** Heuristic: grouped config has "ctrl" on the first element. */
|
|
10712
|
+
isGrouped = computed(() => {
|
|
10713
|
+
const c = this.config()?.controls ?? [];
|
|
10714
|
+
return !!c[0]?.ctrl;
|
|
10715
|
+
}, ...(ngDevMode ? [{ debugName: "isGrouped" }] : []));
|
|
10716
|
+
groupedControls = computed(() => this.config()?.controls ?? [], ...(ngDevMode ? [{ debugName: "groupedControls" }] : []));
|
|
10717
|
+
flatControls = computed(() => this.config()?.controls ?? [], ...(ngDevMode ? [{ debugName: "flatControls" }] : []));
|
|
10718
|
+
/** Flat schema split into rows, honoring `style.newRow` hard breaks. */
|
|
10719
|
+
controlRows = computed(() => splitControlsIntoRows(this.flatControls()), ...(ngDevMode ? [{ debugName: "controlRows" }] : []));
|
|
10720
|
+
constructor() {
|
|
10721
|
+
// Reactive updates on input changes. The first run happens during the first
|
|
10722
|
+
// CD (after ngOnInit's synchronous build), and no-ops via the change guard.
|
|
10723
|
+
effect(() => this.rebuild());
|
|
10724
|
+
}
|
|
10725
|
+
ngOnInit() {
|
|
10726
|
+
// First build runs synchronously so controls exist before the first paint.
|
|
10727
|
+
this.rebuild();
|
|
10728
|
+
}
|
|
11147
10729
|
/**
|
|
11148
|
-
*
|
|
11149
|
-
*
|
|
10730
|
+
* Ensures controls, patches initial values, wires validators/dependencies and
|
|
10731
|
+
* initializes accordion state — only when config/form/readOnly actually change
|
|
10732
|
+
* (same early-exit the old ngOnChanges had).
|
|
11150
10733
|
*/
|
|
11151
|
-
|
|
11152
|
-
|
|
11153
|
-
|
|
10734
|
+
rebuild() {
|
|
10735
|
+
const form = this.form();
|
|
10736
|
+
const config = this.config();
|
|
10737
|
+
const readOnly = this.readOnly();
|
|
10738
|
+
if (!form || !config)
|
|
11154
10739
|
return;
|
|
11155
|
-
|
|
11156
|
-
|
|
11157
|
-
|
|
11158
|
-
|
|
11159
|
-
|
|
11160
|
-
|
|
11161
|
-
const flat = flattenControls(this.config.controls);
|
|
11162
|
-
/**
|
|
11163
|
-
* Signature is used to detect real schema changes.
|
|
11164
|
-
* We intentionally ignore labels/props and track key+type only.
|
|
11165
|
-
*/
|
|
11166
|
-
const signature = flat.map((f) => `${f.configuration.key}:${f.configuration.type}`).join('|');
|
|
11167
|
-
/** "config changed" includes initialValues, validators, dependencies, etc. */
|
|
11168
|
-
const configChanged = !!changes['config'];
|
|
11169
|
-
/** "form changed" means parent passed a different FormGroup instance */
|
|
11170
|
-
const formChanged = !!changes['form'];
|
|
11171
|
-
/** schema changed if the signature differs from the last one */
|
|
10740
|
+
const flat = flattenControls(config.controls);
|
|
10741
|
+
const signature = flat
|
|
10742
|
+
.map((f) => `${f.configuration.key}:${f.configuration.type}`)
|
|
10743
|
+
.join('|');
|
|
10744
|
+
const configChanged = config !== this.prevConfig;
|
|
10745
|
+
const formChanged = form !== this.prevForm;
|
|
11172
10746
|
const metaChanged = signature !== this.lastSignature;
|
|
11173
|
-
|
|
11174
|
-
|
|
11175
|
-
|
|
11176
|
-
|
|
11177
|
-
|
|
11178
|
-
|
|
11179
|
-
changes['readOnly'].currentValue === false;
|
|
11180
|
-
// If nothing relevant changed, exit early to avoid unnecessary work.
|
|
10747
|
+
const enteringEdit = this.initialized && this.prevReadOnly === true && readOnly === false;
|
|
10748
|
+
// Record inputs seen this run (before the early-exit, so the guard is stable).
|
|
10749
|
+
this.prevConfig = config;
|
|
10750
|
+
this.prevForm = form;
|
|
10751
|
+
this.prevReadOnly = readOnly;
|
|
10752
|
+
this.initialized = true;
|
|
11181
10753
|
if (!configChanged && !formChanged && !metaChanged && !enteringEdit)
|
|
11182
10754
|
return;
|
|
11183
|
-
/**
|
|
11184
|
-
* Dependencies are tied to the metadata structure.
|
|
11185
|
-
* If schema changed, cleanup old subscriptions/bindings first.
|
|
11186
|
-
*/
|
|
11187
10755
|
if (configChanged || metaChanged) {
|
|
11188
10756
|
this.depCleanup?.();
|
|
11189
10757
|
this.depCleanup = undefined;
|
|
11190
10758
|
}
|
|
11191
|
-
|
|
11192
|
-
|
|
11193
|
-
|
|
11194
|
-
|
|
11195
|
-
|
|
11196
|
-
|
|
11197
|
-
|
|
11198
|
-
* Patch initial values without emitting changes:
|
|
11199
|
-
* - prevents loops
|
|
11200
|
-
* - keeps create/edit initialization silent
|
|
11201
|
-
*/
|
|
11202
|
-
this.form.patchValue(initial, { emitEvent: false });
|
|
11203
|
-
this.form.updateValueAndValidity({ emitEvent: false });
|
|
11204
|
-
/**
|
|
11205
|
-
* Initialize accordion open panels ONLY when schema changes.
|
|
11206
|
-
* IMPORTANT: do NOT do this on readOnly toggle, otherwise user-collapsed state resets.
|
|
11207
|
-
*/
|
|
10759
|
+
const initial = config.initialValues ?? {};
|
|
10760
|
+
ensureControlsV2(this.fb, form, flat, initial, { lang: this.translate.currentLang });
|
|
10761
|
+
// Patch initial values silently (no loops, silent create/edit init).
|
|
10762
|
+
form.patchValue(initial, { emitEvent: false });
|
|
10763
|
+
form.updateValueAndValidity({ emitEvent: false });
|
|
10764
|
+
// Initialize accordion open panels ONLY on schema change (don't reset the
|
|
10765
|
+
// user-collapsed state on a readOnly toggle).
|
|
11208
10766
|
if (metaChanged) {
|
|
11209
|
-
if (this.isGrouped) {
|
|
11210
|
-
const groups = this.groupedControls ?? [];
|
|
11211
|
-
this.expandedGroupIds
|
|
10767
|
+
if (this.isGrouped()) {
|
|
10768
|
+
const groups = this.groupedControls() ?? [];
|
|
10769
|
+
this.expandedGroupIds.set(groups
|
|
11212
10770
|
.filter((g) => !g?.collapsed)
|
|
11213
10771
|
.map((g) => this.panelValue(g))
|
|
11214
|
-
.filter(Boolean);
|
|
10772
|
+
.filter(Boolean));
|
|
11215
10773
|
}
|
|
11216
10774
|
else {
|
|
11217
|
-
this.expandedGroupIds
|
|
10775
|
+
this.expandedGroupIds.set([]);
|
|
11218
10776
|
}
|
|
11219
10777
|
}
|
|
11220
|
-
|
|
11221
|
-
|
|
11222
|
-
|
|
11223
|
-
|
|
11224
|
-
this.submitValidator.register(this.form, this.config.submitValidators);
|
|
11225
|
-
/**
|
|
11226
|
-
* Bind dependencies ONLY when schema changes.
|
|
11227
|
-
* setupDependencies can subscribe to valueChanges, set options, reset fields, etc.
|
|
11228
|
-
* If it returns a function, we store it for cleanup.
|
|
11229
|
-
*/
|
|
11230
|
-
if ((configChanged || metaChanged) && this.config.setupDependencies) {
|
|
11231
|
-
const maybeCleanup = this.config.setupDependencies({
|
|
11232
|
-
form: this.form,
|
|
10778
|
+
this.submitValidator.register(form, config.submitValidators);
|
|
10779
|
+
if ((configChanged || metaChanged) && config.setupDependencies) {
|
|
10780
|
+
const maybeCleanup = config.setupDependencies({
|
|
10781
|
+
form,
|
|
11233
10782
|
flatControls: flat,
|
|
11234
10783
|
initialValues: initial,
|
|
11235
|
-
getControl: (k) =>
|
|
10784
|
+
getControl: (k) => form.get(k),
|
|
11236
10785
|
findField: (k) => flat.find((f) => f.configuration.key === k) ?? null,
|
|
11237
10786
|
});
|
|
11238
10787
|
if (typeof maybeCleanup === 'function')
|
|
11239
10788
|
this.depCleanup = maybeCleanup;
|
|
11240
10789
|
}
|
|
11241
|
-
/**
|
|
11242
|
-
* Entering edit mode:
|
|
11243
|
-
* - mark controls as touched ONLY if they already have a meaningful value
|
|
11244
|
-
* - expand groups that contain "visible invalid" controls (invalid + touched/dirty)
|
|
11245
|
-
* This prevents CREATE dialogs from showing "required" errors immediately.
|
|
11246
|
-
*/
|
|
11247
10790
|
if (enteringEdit) {
|
|
11248
10791
|
queueMicrotask(() => {
|
|
11249
10792
|
this.touchAndValidateOnlyFilledControls();
|
|
11250
10793
|
this.expandVisibleInvalidGroupsUnion();
|
|
11251
10794
|
});
|
|
11252
10795
|
}
|
|
11253
|
-
// Store signature for the next change detection pass
|
|
11254
10796
|
this.lastSignature = signature;
|
|
11255
10797
|
}
|
|
11256
|
-
/**
|
|
11257
|
-
* PrimeNG Accordion emits value as:
|
|
11258
|
-
* - single id (string/number)
|
|
11259
|
-
* - array of ids
|
|
11260
|
-
* We normalize everything into string[] for stable internal state.
|
|
11261
|
-
*/
|
|
10798
|
+
/** Normalizes PrimeNG Accordion value into a stable string[]. */
|
|
11262
10799
|
onAccordionValueChange(v) {
|
|
11263
|
-
this.expandedGroupIds
|
|
10800
|
+
this.expandedGroupIds.set(this.normalizeAccordionValue(v));
|
|
11264
10801
|
}
|
|
11265
|
-
/** Normalizes Accordion value into a stable string[] representation */
|
|
11266
10802
|
normalizeAccordionValue(v) {
|
|
11267
10803
|
if (Array.isArray(v))
|
|
11268
10804
|
return v.map((x) => `${x}`);
|
|
@@ -11271,74 +10807,30 @@ class MetaFormV2Component {
|
|
|
11271
10807
|
return [`${v}`];
|
|
11272
10808
|
}
|
|
11273
10809
|
// ---------------- template helpers ----------------
|
|
11274
|
-
/**
|
|
11275
|
-
get hasControls() {
|
|
11276
|
-
return Array.isArray(this.config?.controls) && this.config.controls.length > 0;
|
|
11277
|
-
}
|
|
11278
|
-
/**
|
|
11279
|
-
* Heuristic: grouped config has "ctrl" on first element.
|
|
11280
|
-
* (Keeps template simple and avoids extra schema fields.)
|
|
11281
|
-
*/
|
|
11282
|
-
get isGrouped() {
|
|
11283
|
-
const c = this.config?.controls ?? [];
|
|
11284
|
-
return !!c[0]?.ctrl;
|
|
11285
|
-
}
|
|
11286
|
-
/** Returns grouped schema structure (accordion groups) */
|
|
11287
|
-
get groupedControls() {
|
|
11288
|
-
return this.config?.controls ?? [];
|
|
11289
|
-
}
|
|
11290
|
-
/** Returns flat schema structure (grid mode) */
|
|
11291
|
-
get flatControls() {
|
|
11292
|
-
return this.config?.controls ?? [];
|
|
11293
|
-
}
|
|
11294
|
-
/**
|
|
11295
|
-
* Flat schema split into row chunks, honoring `style.newRow` hard breaks.
|
|
11296
|
-
* Used by the non-grouped grid template.
|
|
11297
|
-
*/
|
|
11298
|
-
get controlRows() {
|
|
11299
|
-
return splitControlsIntoRows(this.flatControls);
|
|
11300
|
-
}
|
|
11301
|
-
/** TrackBy for group rendering */
|
|
10810
|
+
/** TrackBy for group rendering. */
|
|
11302
10811
|
groupTrack(g, idx) {
|
|
11303
10812
|
return g?.id ?? idx;
|
|
11304
10813
|
}
|
|
11305
|
-
/**
|
|
11306
|
-
* PrimeNG accordion panel `value` must match accordion `value` type.
|
|
11307
|
-
* We always convert group id to string for consistent behavior.
|
|
11308
|
-
*/
|
|
10814
|
+
/** Group id as a string (matches the accordion `value` type). */
|
|
11309
10815
|
panelValue(g) {
|
|
11310
10816
|
const id = g?.id;
|
|
11311
10817
|
return id === null || id === undefined ? '' : `${id}`;
|
|
11312
10818
|
}
|
|
11313
10819
|
// ---------------- core behavior ----------------
|
|
11314
|
-
/**
|
|
11315
|
-
* Marks & validates ONLY controls that already have meaningful values.
|
|
11316
|
-
* This is used when switching from readOnly -> edit mode to avoid:
|
|
11317
|
-
* - triggering "required" errors for empty fields
|
|
11318
|
-
* - expanding groups based on empty mandatory fields on CREATE dialogs
|
|
11319
|
-
*/
|
|
10820
|
+
/** Marks & validates ONLY controls that already have meaningful values. */
|
|
11320
10821
|
touchAndValidateOnlyFilledControls() {
|
|
11321
|
-
const controls = this.form?.controls ?? {};
|
|
11322
|
-
for (const [
|
|
10822
|
+
const controls = this.form()?.controls ?? {};
|
|
10823
|
+
for (const [, ctrl] of Object.entries(controls)) {
|
|
11323
10824
|
if (!ctrl)
|
|
11324
10825
|
continue;
|
|
11325
|
-
|
|
11326
|
-
// Touch only if this field is already populated (edit case) or prefilled.
|
|
11327
|
-
if (this.hasMeaningfulValue(value)) {
|
|
10826
|
+
if (this.hasMeaningfulValue(ctrl.value)) {
|
|
11328
10827
|
ctrl.markAsTouched();
|
|
11329
10828
|
ctrl.updateValueAndValidity({ emitEvent: true });
|
|
11330
10829
|
}
|
|
11331
10830
|
}
|
|
11332
|
-
|
|
11333
|
-
this.form.updateValueAndValidity({ emitEvent: true });
|
|
10831
|
+
this.form().updateValueAndValidity({ emitEvent: true });
|
|
11334
10832
|
}
|
|
11335
|
-
/**
|
|
11336
|
-
* Defines what counts as a "meaningful" value:
|
|
11337
|
-
* - non-empty strings
|
|
11338
|
-
* - numbers / booleans
|
|
11339
|
-
* - non-empty arrays
|
|
11340
|
-
* - objects with common identifiers (key/uuid/id) or any own keys
|
|
11341
|
-
*/
|
|
10833
|
+
/** What counts as a "meaningful" value (non-empty string/number/boolean/array/object). */
|
|
11342
10834
|
hasMeaningfulValue(v) {
|
|
11343
10835
|
if (v === null || v === undefined)
|
|
11344
10836
|
return false;
|
|
@@ -11351,61 +10843,46 @@ class MetaFormV2Component {
|
|
|
11351
10843
|
if (Array.isArray(v))
|
|
11352
10844
|
return v.length > 0;
|
|
11353
10845
|
if (typeof v === 'object') {
|
|
11354
|
-
// Common selection shapes: { key }, { uuid }, { id }, etc.
|
|
11355
10846
|
if ('key' in v && v.key != null && `${v.key}`.trim() !== '')
|
|
11356
10847
|
return true;
|
|
11357
10848
|
if ('uuid' in v && v.uuid != null && `${v.uuid}`.trim() !== '')
|
|
11358
10849
|
return true;
|
|
11359
10850
|
if ('id' in v && v.id != null && `${v.id}`.trim() !== '')
|
|
11360
10851
|
return true;
|
|
11361
|
-
// Fallback: any own keys
|
|
11362
10852
|
return Object.keys(v).length > 0;
|
|
11363
10853
|
}
|
|
11364
10854
|
return false;
|
|
11365
10855
|
}
|
|
11366
|
-
/**
|
|
11367
|
-
* "Visible invalid" means:
|
|
11368
|
-
* - invalid
|
|
11369
|
-
* - AND user has interacted with it (touched or dirty)
|
|
11370
|
-
* This matches typical UI behavior: show errors only after interaction.
|
|
11371
|
-
*/
|
|
10856
|
+
/** "Visible invalid" = invalid AND interacted with (touched/dirty). */
|
|
11372
10857
|
isVisibleInvalid(ctrl) {
|
|
11373
10858
|
if (!ctrl)
|
|
11374
10859
|
return false;
|
|
11375
10860
|
return ctrl.invalid && (ctrl.touched || ctrl.dirty);
|
|
11376
10861
|
}
|
|
11377
|
-
/**
|
|
11378
|
-
* Checks if a group contains at least one visible invalid control.
|
|
11379
|
-
* Used to auto-expand groups when entering edit mode.
|
|
11380
|
-
*/
|
|
11381
10862
|
groupHasVisibleInvalid(g) {
|
|
11382
10863
|
const keys = (g?.ctrl ?? [])
|
|
11383
10864
|
.map((f) => f?.configuration?.key)
|
|
11384
10865
|
.filter(Boolean);
|
|
11385
|
-
return keys.some((k) => this.isVisibleInvalid(this.form.get(k)));
|
|
10866
|
+
return keys.some((k) => this.isVisibleInvalid(this.form().get(k)));
|
|
11386
10867
|
}
|
|
11387
|
-
/**
|
|
11388
|
-
* Expands all groups that contain visible invalid controls,
|
|
11389
|
-
* while preserving any groups already expanded by the user.
|
|
11390
|
-
*/
|
|
10868
|
+
/** Expands groups with visible-invalid controls, preserving user-expanded ones. */
|
|
11391
10869
|
expandVisibleInvalidGroupsUnion() {
|
|
11392
|
-
if (!this.isGrouped)
|
|
10870
|
+
if (!this.isGrouped())
|
|
11393
10871
|
return;
|
|
11394
|
-
const groups = this.groupedControls ?? [];
|
|
10872
|
+
const groups = this.groupedControls() ?? [];
|
|
11395
10873
|
const invalidIds = groups
|
|
11396
10874
|
.filter((g) => this.groupHasVisibleInvalid(g))
|
|
11397
10875
|
.map((g) => this.panelValue(g))
|
|
11398
10876
|
.filter(Boolean);
|
|
11399
10877
|
if (!invalidIds.length)
|
|
11400
10878
|
return;
|
|
11401
|
-
this.expandedGroupIds
|
|
10879
|
+
this.expandedGroupIds.set(Array.from(new Set([...this.expandedGroupIds(), ...invalidIds])));
|
|
11402
10880
|
}
|
|
11403
|
-
/** Cleanup dependency subscriptions when component is destroyed */
|
|
11404
10881
|
ngOnDestroy() {
|
|
11405
10882
|
this.depCleanup?.();
|
|
11406
10883
|
}
|
|
11407
10884
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MetaFormV2Component, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11408
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: MetaFormV2Component, isStandalone: true, selector: "phoenix-meta-form-v2", inputs: { form: "form", config: "config", readOnly: "readOnly", contentStyle: "contentStyle", contentClass: "contentClass"
|
|
10885
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: MetaFormV2Component, isStandalone: true, selector: "phoenix-meta-form-v2", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, contentStyle: { classPropertyName: "contentStyle", publicName: "contentStyle", isSignal: true, isRequired: false, transformFunction: null }, contentClass: { classPropertyName: "contentClass", publicName: "contentClass", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div [formGroup]=\"form()\">\n @if (hasControls()) {\n\n @if (isGrouped()) {\n <p-accordion\n [multiple]=\"true\"\n [value]=\"expandedGroupIds()\"\n (valueChange)=\"onAccordionValueChange($event)\"\n >\n @for (g of groupedControls(); track groupTrack(g, $index)) {\n <p-accordion-panel [value]=\"panelValue(g)\">\n <p-accordion-header>\n\n <!-- plus/minus toggle icon -->\n <ng-template #toggleicon let-active=\"active\">\n @if (active) {\n <i class=\"pi pi-minus-circle\"></i>\n } @else {\n <i class=\"pi pi-plus-circle\"></i>\n }\n </ng-template>\n\n {{ g?.groupName | translate }}\n </p-accordion-header>\n\n <p-accordion-content>\n <div [ngStyle]=\"contentStyle()\" [ngClass]=\"contentClass()\">\n <phoenix-meta-form-group-v2 [group]=\"g\" [form]=\"form()\" [readOnly]=\"readOnly()\"></phoenix-meta-form-group-v2>\n </div>\n </p-accordion-content>\n </p-accordion-panel>\n }\n </p-accordion>\n\n } @else {\n @for (row of controlRows(); track $index) {\n <div class=\"grid\">\n @for (f of row; track f.configuration.key) {\n <div [ngClass]=\"f.style.colWidth ?? 'col-12 md:col-6'\">\n <phoenix-meta-form-field-v2 [field]=\"f\" [form]=\"form()\" [readOnly]=\"readOnly()\"></phoenix-meta-form-field-v2>\n </div>\n }\n </div>\n }\n }\n\n }\n</div>\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: AccordionModule }, { kind: "component", type: i3$1.Accordion, selector: "p-accordion", inputs: ["value", "multiple", "styleClass", "expandIcon", "collapseIcon", "selectOnFocus", "transitionOptions"], outputs: ["valueChange", "onClose", "onOpen"] }, { kind: "component", type: i3$1.AccordionPanel, selector: "p-accordion-panel, p-accordionpanel", inputs: ["value", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: i3$1.AccordionHeader, selector: "p-accordion-header, p-accordionheader" }, { kind: "component", type: i3$1.AccordionContent, selector: "p-accordion-content, p-accordioncontent" }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: MetaFormFieldV2Component, selector: "phoenix-meta-form-field-v2", inputs: ["field", "form", "readOnly", "disableForm"] }, { kind: "component", type: MetaFormGroupV2Component, selector: "phoenix-meta-form-group-v2", inputs: ["group", "form", "readOnly"] }, { kind: "pipe", type: i4$2.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
11409
10886
|
}
|
|
11410
10887
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MetaFormV2Component, decorators: [{
|
|
11411
10888
|
type: Component,
|
|
@@ -11416,20 +10893,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
11416
10893
|
TranslateModule,
|
|
11417
10894
|
MetaFormFieldV2Component,
|
|
11418
10895
|
MetaFormGroupV2Component,
|
|
11419
|
-
], template: "<div [formGroup]=\"form\">\n @if (hasControls) {\n\n @if (isGrouped) {\n <p-accordion\n [multiple]=\"true\"\n [value]=\"expandedGroupIds\"\n (valueChange)=\"onAccordionValueChange($event)\"\n >\n @for (g of groupedControls; track groupTrack(g, $index)) {\n <p-accordion-panel [value]=\"panelValue(g)\">\n <p-accordion-header>\n\n <!-- plus/minus toggle icon -->\n <ng-template #toggleicon let-active=\"active\">\n @if (active) {\n <i class=\"pi pi-minus-circle\"></i>\n } @else {\n <i class=\"pi pi-plus-circle\"></i>\n }\n </ng-template>\n\n {{ g?.groupName | translate }}\n </p-accordion-header>\n
|
|
11420
|
-
}], propDecorators: { form: [{
|
|
11421
|
-
type: Input,
|
|
11422
|
-
args: [{ required: true }]
|
|
11423
|
-
}], config: [{
|
|
11424
|
-
type: Input,
|
|
11425
|
-
args: [{ required: true }]
|
|
11426
|
-
}], readOnly: [{
|
|
11427
|
-
type: Input
|
|
11428
|
-
}], contentStyle: [{
|
|
11429
|
-
type: Input
|
|
11430
|
-
}], contentClass: [{
|
|
11431
|
-
type: Input
|
|
11432
|
-
}] } });
|
|
10896
|
+
], template: "<div [formGroup]=\"form()\">\n @if (hasControls()) {\n\n @if (isGrouped()) {\n <p-accordion\n [multiple]=\"true\"\n [value]=\"expandedGroupIds()\"\n (valueChange)=\"onAccordionValueChange($event)\"\n >\n @for (g of groupedControls(); track groupTrack(g, $index)) {\n <p-accordion-panel [value]=\"panelValue(g)\">\n <p-accordion-header>\n\n <!-- plus/minus toggle icon -->\n <ng-template #toggleicon let-active=\"active\">\n @if (active) {\n <i class=\"pi pi-minus-circle\"></i>\n } @else {\n <i class=\"pi pi-plus-circle\"></i>\n }\n </ng-template>\n\n {{ g?.groupName | translate }}\n </p-accordion-header>\n\n <p-accordion-content>\n <div [ngStyle]=\"contentStyle()\" [ngClass]=\"contentClass()\">\n <phoenix-meta-form-group-v2 [group]=\"g\" [form]=\"form()\" [readOnly]=\"readOnly()\"></phoenix-meta-form-group-v2>\n </div>\n </p-accordion-content>\n </p-accordion-panel>\n }\n </p-accordion>\n\n } @else {\n @for (row of controlRows(); track $index) {\n <div class=\"grid\">\n @for (f of row; track f.configuration.key) {\n <div [ngClass]=\"f.style.colWidth ?? 'col-12 md:col-6'\">\n <phoenix-meta-form-field-v2 [field]=\"f\" [form]=\"form()\" [readOnly]=\"readOnly()\"></phoenix-meta-form-field-v2>\n </div>\n }\n </div>\n }\n }\n\n }\n</div>\n", styles: [":host{display:block}\n"] }]
|
|
10897
|
+
}], ctorParameters: () => [], propDecorators: { form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: true }] }], readOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnly", required: false }] }], contentStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentStyle", required: false }] }], contentClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentClass", required: false }] }] } });
|
|
11433
10898
|
|
|
11434
10899
|
class MetaFormButtonsV2Component {
|
|
11435
10900
|
/**
|