@meshmakers/octo-ui 3.5.430 → 3.5.450
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_SECRET_STATUS_LABELS, secretStateFromAttribute, isSecretValueType, isSecretStateObject, toSecretState, isSecretAttributeCandidate, TENANT_ID_PROVIDER, SearchFilterTypesDto, FieldFilterOperatorsDto, OCTO_SILENT_ERRORS, isSecretPresent, DeleteStrategiesDto, AssociationModOptionsDto, GraphDirectionDto, formatSecretStatus, SortOrdersDto, GraphQL } from '@meshmakers/octo-services';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
|
-
import { InjectionToken, Injectable, inject, provideEnvironmentInitializer, LOCALE_ID, input, computed, ChangeDetectionStrategy, Component, signal, effect, forwardRef, untracked, viewChild, output,
|
|
3
|
+
import { InjectionToken, Injectable, inject, provideEnvironmentInitializer, makeEnvironmentProviders, LOCALE_ID, input, computed, ChangeDetectionStrategy, Component, signal, effect, forwardRef, untracked, viewChild, output, ElementRef, afterRenderEffect, DestroyRef, Injector, afterNextRender, Directive, Input, TemplateRef, contentChild } from '@angular/core';
|
|
4
4
|
import { firstValueFrom, from, map, isObservable, of } from 'rxjs';
|
|
5
5
|
import * as i1 from 'apollo-angular';
|
|
6
6
|
import { gql } from 'apollo-angular';
|
|
@@ -1717,6 +1717,7 @@ function resolveEntityForm(type, forms, opts = {}) {
|
|
|
1717
1717
|
const result = {
|
|
1718
1718
|
source: picked ? picked.source : 'builtIn',
|
|
1719
1719
|
rtCkTypeId: type.rtCkTypeId,
|
|
1720
|
+
ckTypeAncestors: [...type.ancestors],
|
|
1720
1721
|
formTargetCkTypeId: form.targetCkTypeId,
|
|
1721
1722
|
isAbstract: type.isAbstract,
|
|
1722
1723
|
includeDerivedTypes: form.includeDerivedTypes,
|
|
@@ -3452,6 +3453,76 @@ _secretPresence = {}, options = {}) {
|
|
|
3452
3453
|
return changeSet;
|
|
3453
3454
|
}
|
|
3454
3455
|
|
|
3456
|
+
/**
|
|
3457
|
+
* Multi token of host validators (root or lazy route). Prefer {@link provideEntityFormCrossFieldValidators}.
|
|
3458
|
+
* The `crossFieldValidators` input of `mm-entity-form` is applied in addition to these.
|
|
3459
|
+
*/
|
|
3460
|
+
const ENTITY_FORM_CROSS_FIELD_VALIDATORS = new InjectionToken('ENTITY_FORM_CROSS_FIELD_VALIDATORS');
|
|
3461
|
+
/** Registers validators on a route or at root; several registrations add up. */
|
|
3462
|
+
function provideEntityFormCrossFieldValidators(...validators) {
|
|
3463
|
+
return makeEnvironmentProviders([{ provide: ENTITY_FORM_CROSS_FIELD_VALIDATORS, multi: true, useValue: validators }]);
|
|
3464
|
+
}
|
|
3465
|
+
/** Flattens the injected multi-provider value (`null` / single / list entries). */
|
|
3466
|
+
function flattenCrossFieldValidators(provided) {
|
|
3467
|
+
if (!provided) {
|
|
3468
|
+
return [];
|
|
3469
|
+
}
|
|
3470
|
+
const out = [];
|
|
3471
|
+
const visit = (entry) => {
|
|
3472
|
+
if (Array.isArray(entry)) {
|
|
3473
|
+
entry.forEach(visit);
|
|
3474
|
+
}
|
|
3475
|
+
else if (entry && typeof entry.validate === 'function') {
|
|
3476
|
+
out.push(entry);
|
|
3477
|
+
}
|
|
3478
|
+
};
|
|
3479
|
+
visit(provided);
|
|
3480
|
+
return out;
|
|
3481
|
+
}
|
|
3482
|
+
const norm = (value) => (value ?? '').trim().toLowerCase();
|
|
3483
|
+
/** True when the validator applies to the form's concrete type or one of its ancestors. */
|
|
3484
|
+
function crossFieldValidatorApplies(validator, form) {
|
|
3485
|
+
const types = new Set([norm(form.rtCkTypeId), ...(form.ckTypeAncestors ?? []).map(norm)]);
|
|
3486
|
+
return validator.ckTypeIds.some((id) => types.has(norm(id)));
|
|
3487
|
+
}
|
|
3488
|
+
/**
|
|
3489
|
+
* Runs every applicable validator and maps the answer to field keys. The first message per field
|
|
3490
|
+
* wins (validators run in registration order). Names that match no field are dropped.
|
|
3491
|
+
*/
|
|
3492
|
+
function runCrossFieldValidators(validators, form, fields, values, mode) {
|
|
3493
|
+
const result = {};
|
|
3494
|
+
if (validators.length === 0) {
|
|
3495
|
+
return result;
|
|
3496
|
+
}
|
|
3497
|
+
const byName = new Map();
|
|
3498
|
+
for (const f of fields) {
|
|
3499
|
+
byName.set(norm(f.key), f.key);
|
|
3500
|
+
if (f.attributeName) {
|
|
3501
|
+
byName.set(norm(f.attributeName), f.key);
|
|
3502
|
+
}
|
|
3503
|
+
}
|
|
3504
|
+
for (const validator of validators) {
|
|
3505
|
+
if (!crossFieldValidatorApplies(validator, form)) {
|
|
3506
|
+
continue;
|
|
3507
|
+
}
|
|
3508
|
+
let answer;
|
|
3509
|
+
try {
|
|
3510
|
+
answer = validator.validate({ values, form, mode });
|
|
3511
|
+
}
|
|
3512
|
+
catch (error) {
|
|
3513
|
+
console.error('mm-entity-form: a cross-field validator failed and was ignored', error);
|
|
3514
|
+
continue;
|
|
3515
|
+
}
|
|
3516
|
+
for (const [name, message] of Object.entries(answer ?? {})) {
|
|
3517
|
+
const key = byName.get(norm(name));
|
|
3518
|
+
if (key && message && !(key in result)) {
|
|
3519
|
+
result[key] = message;
|
|
3520
|
+
}
|
|
3521
|
+
}
|
|
3522
|
+
}
|
|
3523
|
+
return result;
|
|
3524
|
+
}
|
|
3525
|
+
|
|
3455
3526
|
/**
|
|
3456
3527
|
* App-wide {@link EntityFormLabelResolver} for `mm-entity-form`, `mm-entity-list` and
|
|
3457
3528
|
* `mm-entity-page`. Their `labelResolver` input wins over this token. Not provided = the texts of
|
|
@@ -5352,7 +5423,7 @@ function firstErrorKey(errors) {
|
|
|
5352
5423
|
if (!errors) {
|
|
5353
5424
|
return null;
|
|
5354
5425
|
}
|
|
5355
|
-
const order = ['required', 'min', 'max', 'pattern', 'email', 'url', 'json'];
|
|
5426
|
+
const order = ['required', 'crossField', 'min', 'max', 'pattern', 'email', 'url', 'json'];
|
|
5356
5427
|
return order.find((k) => k in errors) ?? Object.keys(errors)[0] ?? null;
|
|
5357
5428
|
}
|
|
5358
5429
|
/** Deep copy of plain form values (arrays, plain objects, Dates). */
|
|
@@ -5396,10 +5467,55 @@ class EntityFormFieldComponent {
|
|
|
5396
5467
|
/** Whether the field is required in the current mode (secrets: only when not set). */
|
|
5397
5468
|
required = input(false, /* @ts-ignore */
|
|
5398
5469
|
...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
|
|
5470
|
+
/**
|
|
5471
|
+
* Host mark (AB#7422): text shown under a pristine, otherwise valid field, e.g. the field named
|
|
5472
|
+
* by the last failed deployment. Informational; never affects validity.
|
|
5473
|
+
*/
|
|
5474
|
+
externalError = input(null, /* @ts-ignore */
|
|
5475
|
+
...(ngDevMode ? [{ debugName: "externalError" }] : /* istanbul ignore next */ []));
|
|
5476
|
+
/** Host hint (AB#7423): informational text with an optional action link under the field. */
|
|
5477
|
+
hint = input(null, /* @ts-ignore */
|
|
5478
|
+
...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
|
|
5479
|
+
/** The hint's action link was activated; carries the hint's `actionId`. */
|
|
5480
|
+
hintAction = output();
|
|
5399
5481
|
/** Change counter from the parent form; read so `errorText` recomputes on every form event. */
|
|
5400
5482
|
revision = input(0, /* @ts-ignore */
|
|
5401
5483
|
...(ngDevMode ? [{ debugName: "revision" }] : /* istanbul ignore next */ []));
|
|
5402
5484
|
locale = inject(LOCALE_ID);
|
|
5485
|
+
host = inject(ElementRef);
|
|
5486
|
+
errorId = computed(() => `mm-ef-error-${this.field().key}`, /* @ts-ignore */
|
|
5487
|
+
...(ngDevMode ? [{ debugName: "errorId" }] : /* istanbul ignore next */ []));
|
|
5488
|
+
helpId = computed(() => `mm-ef-help-${this.field().key}`, /* @ts-ignore */
|
|
5489
|
+
...(ngDevMode ? [{ debugName: "helpId" }] : /* istanbul ignore next */ []));
|
|
5490
|
+
hintId = computed(() => `mm-ef-hint-${this.field().key}`, /* @ts-ignore */
|
|
5491
|
+
...(ngDevMode ? [{ debugName: "hintId" }] : /* istanbul ignore next */ []));
|
|
5492
|
+
constructor() {
|
|
5493
|
+
// The error text (or, without one, the help text) describes the projected editor control, so a
|
|
5494
|
+
// screen reader announces it with the field (AB#7422). The editors are projected, therefore the
|
|
5495
|
+
// attributes are set on the first native input of the shell after every render.
|
|
5496
|
+
afterRenderEffect(() => {
|
|
5497
|
+
const error = this.errorText();
|
|
5498
|
+
const hasHelp = !!this.field().help;
|
|
5499
|
+
// Kendo switch and dropdown list expose their accessible element as `.k-switch` / `.k-dropdownlist`.
|
|
5500
|
+
const input = this.host.nativeElement.querySelector('.mm-ef-field__editor .k-switch, .mm-ef-field__editor .k-dropdownlist, .mm-ef-field__editor input, .mm-ef-field__editor textarea');
|
|
5501
|
+
if (!input) {
|
|
5502
|
+
return;
|
|
5503
|
+
}
|
|
5504
|
+
const ids = [error ? this.errorId() : hasHelp ? this.helpId() : null, this.hint() ? this.hintId() : null].filter((id) => !!id);
|
|
5505
|
+
if (ids.length > 0) {
|
|
5506
|
+
input.setAttribute('aria-describedby', ids.join(' '));
|
|
5507
|
+
}
|
|
5508
|
+
else {
|
|
5509
|
+
input.removeAttribute('aria-describedby');
|
|
5510
|
+
}
|
|
5511
|
+
if (error) {
|
|
5512
|
+
input.setAttribute('aria-invalid', 'true');
|
|
5513
|
+
}
|
|
5514
|
+
else {
|
|
5515
|
+
input.removeAttribute('aria-invalid');
|
|
5516
|
+
}
|
|
5517
|
+
});
|
|
5518
|
+
}
|
|
5403
5519
|
showRequired = computed(() => this.required() && !this.readOnly(), /* @ts-ignore */
|
|
5404
5520
|
...(ngDevMode ? [{ debugName: "showRequired" }] : /* istanbul ignore next */ []));
|
|
5405
5521
|
/**
|
|
@@ -5426,7 +5542,17 @@ class EntityFormFieldComponent {
|
|
|
5426
5542
|
errorText = computed(() => {
|
|
5427
5543
|
this.revision();
|
|
5428
5544
|
const control = this.control();
|
|
5429
|
-
if (!control || control.disabled
|
|
5545
|
+
if (!control || control.disabled) {
|
|
5546
|
+
return null;
|
|
5547
|
+
}
|
|
5548
|
+
// A host-marked field that is still untouched (AB#7422): informational text, no validity impact.
|
|
5549
|
+
const mark = this.externalError();
|
|
5550
|
+
if (!control.invalid && mark && !control.dirty) {
|
|
5551
|
+
return mark;
|
|
5552
|
+
}
|
|
5553
|
+
const crossField = control.errors?.['crossField']?.message;
|
|
5554
|
+
// A cross-field error is shown at once: the partner field the user edits is not this one.
|
|
5555
|
+
if (!control.invalid || !(control.touched || control.dirty || crossField)) {
|
|
5430
5556
|
return null;
|
|
5431
5557
|
}
|
|
5432
5558
|
const key = firstErrorKey(control.errors);
|
|
@@ -5449,13 +5575,15 @@ class EntityFormFieldComponent {
|
|
|
5449
5575
|
return m.validationUrl;
|
|
5450
5576
|
case 'json':
|
|
5451
5577
|
return m.validationJson;
|
|
5578
|
+
case 'crossField':
|
|
5579
|
+
return crossField ?? m.formInvalid;
|
|
5452
5580
|
default:
|
|
5453
5581
|
return m.formInvalid;
|
|
5454
5582
|
}
|
|
5455
5583
|
}, /* @ts-ignore */
|
|
5456
5584
|
...(ngDevMode ? [{ debugName: "errorText" }] : /* istanbul ignore next */ []));
|
|
5457
5585
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: EntityFormFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5458
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: EntityFormFieldComponent, isStandalone: true, selector: "mm-entity-form-field", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, control: { classPropertyName: "control", publicName: "control", isSignal: true, isRequired: false, transformFunction: null }, messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: true, transformFunction: null }, secretState: { classPropertyName: "secretState", publicName: "secretState", isSignal: true, isRequired: false, transformFunction: null }, secretSetAt: { classPropertyName: "secretSetAt", publicName: "secretSetAt", isSignal: true, isRequired: false, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, revision: { classPropertyName: "revision", publicName: "revision", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.mm-ef-field--full": "field().width === 'full'", "class.mm-ef-field--half": "field().width === 'half'", "class.mm-ef-field--invalid": "errorText() !== null", "class.mm-ef-field--readonly": "readOnly()", "attr.data-field-key": "field().key" }, classAttribute: "mm-ef-field" }, ngImport: i0, template: `
|
|
5586
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: EntityFormFieldComponent, isStandalone: true, selector: "mm-entity-form-field", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, control: { classPropertyName: "control", publicName: "control", isSignal: true, isRequired: false, transformFunction: null }, messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: true, transformFunction: null }, secretState: { classPropertyName: "secretState", publicName: "secretState", isSignal: true, isRequired: false, transformFunction: null }, secretSetAt: { classPropertyName: "secretSetAt", publicName: "secretSetAt", isSignal: true, isRequired: false, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, externalError: { classPropertyName: "externalError", publicName: "externalError", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, revision: { classPropertyName: "revision", publicName: "revision", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { hintAction: "hintAction" }, host: { properties: { "class.mm-ef-field--full": "field().width === 'full'", "class.mm-ef-field--half": "field().width === 'half'", "class.mm-ef-field--invalid": "errorText() !== null", "class.mm-ef-field--readonly": "readOnly()", "attr.data-field-key": "field().key" }, classAttribute: "mm-ef-field" }, ngImport: i0, template: `
|
|
5459
5587
|
<div class="mm-ef-field__label-row">
|
|
5460
5588
|
<label class="mm-ef-field__label">
|
|
5461
5589
|
{{ field().label }}
|
|
@@ -5479,9 +5607,17 @@ class EntityFormFieldComponent {
|
|
|
5479
5607
|
<ng-content></ng-content>
|
|
5480
5608
|
</div>
|
|
5481
5609
|
@if (errorText(); as err) {
|
|
5482
|
-
<div class="mm-ef-field__error" role="alert">{{ err }}</div>
|
|
5610
|
+
<div class="mm-ef-field__error" role="alert" [id]="errorId()">{{ err }}</div>
|
|
5483
5611
|
} @else if (field().help) {
|
|
5484
|
-
<div class="mm-ef-field__help">{{ field().help }}</div>
|
|
5612
|
+
<div class="mm-ef-field__help" [id]="helpId()">{{ field().help }}</div>
|
|
5613
|
+
}
|
|
5614
|
+
@if (hint(); as h) {
|
|
5615
|
+
<div class="mm-ef-field__hint" role="note" [id]="hintId()" data-field-hint>
|
|
5616
|
+
{{ h.text }}
|
|
5617
|
+
@if (h.actionLabel) {
|
|
5618
|
+
<button type="button" class="mm-ef-field__hint-action" (click)="hintAction.emit(h.actionId ?? '')">{{ h.actionLabel }}</button>
|
|
5619
|
+
}
|
|
5620
|
+
</div>
|
|
5485
5621
|
}
|
|
5486
5622
|
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
5487
5623
|
}
|
|
@@ -5523,13 +5659,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
5523
5659
|
<ng-content></ng-content>
|
|
5524
5660
|
</div>
|
|
5525
5661
|
@if (errorText(); as err) {
|
|
5526
|
-
<div class="mm-ef-field__error" role="alert">{{ err }}</div>
|
|
5662
|
+
<div class="mm-ef-field__error" role="alert" [id]="errorId()">{{ err }}</div>
|
|
5527
5663
|
} @else if (field().help) {
|
|
5528
|
-
<div class="mm-ef-field__help">{{ field().help }}</div>
|
|
5664
|
+
<div class="mm-ef-field__help" [id]="helpId()">{{ field().help }}</div>
|
|
5665
|
+
}
|
|
5666
|
+
@if (hint(); as h) {
|
|
5667
|
+
<div class="mm-ef-field__hint" role="note" [id]="hintId()" data-field-hint>
|
|
5668
|
+
{{ h.text }}
|
|
5669
|
+
@if (h.actionLabel) {
|
|
5670
|
+
<button type="button" class="mm-ef-field__hint-action" (click)="hintAction.emit(h.actionId ?? '')">{{ h.actionLabel }}</button>
|
|
5671
|
+
}
|
|
5672
|
+
</div>
|
|
5529
5673
|
}
|
|
5530
5674
|
`,
|
|
5531
5675
|
}]
|
|
5532
|
-
}], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], control: [{ type: i0.Input, args: [{ isSignal: true, alias: "control", required: false }] }], messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: true }] }], secretState: [{ type: i0.Input, args: [{ isSignal: true, alias: "secretState", required: false }] }], secretSetAt: [{ type: i0.Input, args: [{ isSignal: true, alias: "secretSetAt", required: false }] }], readOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], revision: [{ type: i0.Input, args: [{ isSignal: true, alias: "revision", required: false }] }] } });
|
|
5676
|
+
}], ctorParameters: () => [], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], control: [{ type: i0.Input, args: [{ isSignal: true, alias: "control", required: false }] }], messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: true }] }], secretState: [{ type: i0.Input, args: [{ isSignal: true, alias: "secretState", required: false }] }], secretSetAt: [{ type: i0.Input, args: [{ isSignal: true, alias: "secretSetAt", required: false }] }], readOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], externalError: [{ type: i0.Input, args: [{ isSignal: true, alias: "externalError", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], hintAction: [{ type: i0.Output, args: ["hintAction"] }], revision: [{ type: i0.Input, args: [{ isSignal: true, alias: "revision", required: false }] }] } });
|
|
5533
5677
|
|
|
5534
5678
|
/** Integer value types: the number editor uses 0 decimals for these. */
|
|
5535
5679
|
const INTEGER_TYPES = ['INT', 'INTEGER', 'INT_64', 'INTEGER_64'];
|
|
@@ -5567,6 +5711,9 @@ class EntityFormComponent {
|
|
|
5567
5711
|
keyRingConfigured = inject(ENTITY_FORM_SECRET_KEY_RING_CONFIGURED, { optional: true });
|
|
5568
5712
|
injectedLabelResolver = inject(ENTITY_FORM_LABEL_RESOLVER, { optional: true });
|
|
5569
5713
|
injectedBeforeSave = inject(ENTITY_FORM_BEFORE_SAVE, { optional: true });
|
|
5714
|
+
injectedCrossFieldValidators = flattenCrossFieldValidators(inject(ENTITY_FORM_CROSS_FIELD_VALIDATORS, { optional: true }));
|
|
5715
|
+
host = inject(ElementRef);
|
|
5716
|
+
injector = inject(Injector);
|
|
5570
5717
|
unsetPlaceholders = entityFormUnsetPlaceholderLookup(inject(ENTITY_FORM_UNSET_PLACEHOLDER_VALUES, { optional: true }));
|
|
5571
5718
|
// --- Inputs ---
|
|
5572
5719
|
model = input.required(/* @ts-ignore */
|
|
@@ -5603,7 +5750,30 @@ class EntityFormComponent {
|
|
|
5603
5750
|
*/
|
|
5604
5751
|
beforeSave = input(undefined, /* @ts-ignore */
|
|
5605
5752
|
...(ngDevMode ? [{ debugName: "beforeSave" }] : /* istanbul ignore next */ []));
|
|
5753
|
+
/**
|
|
5754
|
+
* Host cross-field validators (AB#7422), applied in addition to the ones registered with
|
|
5755
|
+
* `provideEntityFormCrossFieldValidators` / `ENTITY_FORM_CROSS_FIELD_VALIDATORS`. A validator
|
|
5756
|
+
* names the fields that break a rule over several fields; those fields are invalid (message
|
|
5757
|
+
* shown immediately) and the form cannot be saved until the rule holds.
|
|
5758
|
+
*/
|
|
5759
|
+
crossFieldValidators = input(undefined, /* @ts-ignore */
|
|
5760
|
+
...(ngDevMode ? [{ debugName: "crossFieldValidators" }] : /* istanbul ignore next */ []));
|
|
5761
|
+
/**
|
|
5762
|
+
* Host marks on fields (AB#7422), e.g. the field named by the last failed deployment: key = field
|
|
5763
|
+
* key or attribute name (any casing), value = the text shown under the field. A mark is
|
|
5764
|
+
* informational — it never blocks saving — and disappears as soon as the user edits that field.
|
|
5765
|
+
*/
|
|
5766
|
+
fieldErrors = input(undefined, /* @ts-ignore */
|
|
5767
|
+
...(ngDevMode ? [{ debugName: "fieldErrors" }] : /* istanbul ignore next */ []));
|
|
5768
|
+
/**
|
|
5769
|
+
* Host hints under fields (AB#7423): called with the current values of the form on every change; the
|
|
5770
|
+
* returned hints (text and an optional action link) are shown under their fields. Informational only.
|
|
5771
|
+
*/
|
|
5772
|
+
fieldHints = input(undefined, /* @ts-ignore */
|
|
5773
|
+
...(ngDevMode ? [{ debugName: "fieldHints" }] : /* istanbul ignore next */ []));
|
|
5606
5774
|
// --- Outputs ---
|
|
5775
|
+
/** The action link of a field hint was activated (`actionId` as given by the host, `key` = field key). */
|
|
5776
|
+
fieldHintAction = output();
|
|
5607
5777
|
changeSetChange = output();
|
|
5608
5778
|
validChange = output();
|
|
5609
5779
|
dirtyChange = output();
|
|
@@ -5635,6 +5805,63 @@ class EntityFormComponent {
|
|
|
5635
5805
|
...(ngDevMode ? [{ debugName: "rawValues" }] : /* istanbul ignore next */ []));
|
|
5636
5806
|
collapsed = signal(new Set(), /* @ts-ignore */
|
|
5637
5807
|
...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
|
|
5808
|
+
/** Current cross-field errors by field key (the control validators read it; see {@link refreshCrossFieldErrors}). */
|
|
5809
|
+
crossFieldErrorMap = {};
|
|
5810
|
+
/** Host field marks by field key. */
|
|
5811
|
+
hostFieldMarks = computed(() => {
|
|
5812
|
+
const marks = this.fieldErrors();
|
|
5813
|
+
if (!marks) {
|
|
5814
|
+
return {};
|
|
5815
|
+
}
|
|
5816
|
+
const byName = new Map();
|
|
5817
|
+
for (const f of allFields(this.model())) {
|
|
5818
|
+
byName.set(f.key.toLowerCase(), f.key);
|
|
5819
|
+
if (f.attributeName) {
|
|
5820
|
+
byName.set(f.attributeName.toLowerCase(), f.key);
|
|
5821
|
+
}
|
|
5822
|
+
}
|
|
5823
|
+
const out = {};
|
|
5824
|
+
for (const [name, message] of Object.entries(marks)) {
|
|
5825
|
+
const key = byName.get(name.toLowerCase());
|
|
5826
|
+
if (key && message) {
|
|
5827
|
+
out[key] = message;
|
|
5828
|
+
}
|
|
5829
|
+
}
|
|
5830
|
+
return out;
|
|
5831
|
+
}, /* @ts-ignore */
|
|
5832
|
+
...(ngDevMode ? [{ debugName: "hostFieldMarks" }] : /* istanbul ignore next */ []));
|
|
5833
|
+
/** Host hints by field key, re-evaluated when the values change. */
|
|
5834
|
+
hostHints = computed(() => {
|
|
5835
|
+
const provider = this.fieldHints();
|
|
5836
|
+
if (!provider) {
|
|
5837
|
+
return {};
|
|
5838
|
+
}
|
|
5839
|
+
const model = this.model();
|
|
5840
|
+
let answer;
|
|
5841
|
+
try {
|
|
5842
|
+
answer = provider({ values: this.rawValues(), form: model, mode: this.mode() });
|
|
5843
|
+
}
|
|
5844
|
+
catch (error) {
|
|
5845
|
+
console.error('mm-entity-form: a field hints provider failed and was ignored', error);
|
|
5846
|
+
return {};
|
|
5847
|
+
}
|
|
5848
|
+
const byName = new Map();
|
|
5849
|
+
for (const f of allFields(model)) {
|
|
5850
|
+
byName.set(f.key.toLowerCase(), f.key);
|
|
5851
|
+
if (f.attributeName) {
|
|
5852
|
+
byName.set(f.attributeName.toLowerCase(), f.key);
|
|
5853
|
+
}
|
|
5854
|
+
}
|
|
5855
|
+
const out = {};
|
|
5856
|
+
for (const [name, hint] of Object.entries(answer ?? {})) {
|
|
5857
|
+
const key = byName.get(name.toLowerCase());
|
|
5858
|
+
if (key && hint?.text) {
|
|
5859
|
+
out[key] = hint;
|
|
5860
|
+
}
|
|
5861
|
+
}
|
|
5862
|
+
return out;
|
|
5863
|
+
}, /* @ts-ignore */
|
|
5864
|
+
...(ngDevMode ? [{ debugName: "hostHints" }] : /* istanbul ignore next */ []));
|
|
5638
5865
|
/** Keys of the fields whose stored value was an unset placeholder (AB#5623); they start empty. */
|
|
5639
5866
|
unsetPlaceholderFields = signal(new Set(), /* @ts-ignore */
|
|
5640
5867
|
...(ngDevMode ? [{ debugName: "unsetPlaceholderFields" }] : /* istanbul ignore next */ []));
|
|
@@ -5706,6 +5933,16 @@ class EntityFormComponent {
|
|
|
5706
5933
|
const initialValues = this.initialValues();
|
|
5707
5934
|
untracked(() => this.rebuild(model, mode, this.withPrefill(model, mode, state ?? null, initialValues), readOnly));
|
|
5708
5935
|
});
|
|
5936
|
+
// Validators that arrive or change after the form was built (async source, conditional binding): re-validate.
|
|
5937
|
+
effect(() => {
|
|
5938
|
+
this.crossFieldValidators();
|
|
5939
|
+
untracked(() => {
|
|
5940
|
+
if (this.refreshCrossFieldErrors()) {
|
|
5941
|
+
this.bump();
|
|
5942
|
+
this.emitState();
|
|
5943
|
+
}
|
|
5944
|
+
});
|
|
5945
|
+
});
|
|
5709
5946
|
// The key ring status arrives asynchronously (and may change): re-apply the enabled state of
|
|
5710
5947
|
// the secret controls whenever it flips after the form was built.
|
|
5711
5948
|
effect(() => {
|
|
@@ -5770,10 +6007,58 @@ class EntityFormComponent {
|
|
|
5770
6007
|
const form = this.form();
|
|
5771
6008
|
return (form.valid || form.disabled) && this.saveBlockedReason() === null;
|
|
5772
6009
|
}
|
|
5773
|
-
/**
|
|
6010
|
+
/**
|
|
6011
|
+
* Marks every control as touched so validation errors become visible and moves the focus to the
|
|
6012
|
+
* first invalid field (AB#7422), expanding its section when it is collapsed.
|
|
6013
|
+
*/
|
|
5774
6014
|
markAllAsTouched() {
|
|
5775
6015
|
this.form().markAllAsTouched();
|
|
5776
6016
|
this.bump();
|
|
6017
|
+
this.focusFirstInvalid();
|
|
6018
|
+
}
|
|
6019
|
+
/** Focuses the first invalid, visible field in reading order. Returns its key, or `null`. */
|
|
6020
|
+
focusFirstInvalid() {
|
|
6021
|
+
const controls = this.form().controls;
|
|
6022
|
+
const vis = this.visibility();
|
|
6023
|
+
for (const section of this.view().sections) {
|
|
6024
|
+
for (const field of section.fields) {
|
|
6025
|
+
const control = controls[field.key];
|
|
6026
|
+
if (!control || control.disabled || !control.invalid || vis[field.key] === false) {
|
|
6027
|
+
continue;
|
|
6028
|
+
}
|
|
6029
|
+
return this.focusField(field.key);
|
|
6030
|
+
}
|
|
6031
|
+
}
|
|
6032
|
+
return null;
|
|
6033
|
+
}
|
|
6034
|
+
/**
|
|
6035
|
+
* Focuses the editor of a visible field (key or attribute name, any casing), expanding its section when it
|
|
6036
|
+
* is collapsed (AB#7423, e.g. a hint's action link that leads to another field). Returns the field key, or
|
|
6037
|
+
* `null` when there is no such visible field.
|
|
6038
|
+
*/
|
|
6039
|
+
focusField(name) {
|
|
6040
|
+
const wanted = name.toLowerCase();
|
|
6041
|
+
const vis = this.visibility();
|
|
6042
|
+
for (const section of this.view().sections) {
|
|
6043
|
+
for (const field of section.fields) {
|
|
6044
|
+
if (field.key.toLowerCase() !== wanted && field.attributeName?.toLowerCase() !== wanted) {
|
|
6045
|
+
continue;
|
|
6046
|
+
}
|
|
6047
|
+
if (vis[field.key] === false) {
|
|
6048
|
+
return null;
|
|
6049
|
+
}
|
|
6050
|
+
if (this.isCollapsed(section)) {
|
|
6051
|
+
this.toggleSection(section);
|
|
6052
|
+
}
|
|
6053
|
+
afterNextRender(() => {
|
|
6054
|
+
const root = `[data-field-key="${CSS.escape(field.key)}"]`;
|
|
6055
|
+
const target = this.host.nativeElement.querySelector(`${root} input, ${root} textarea, ${root} [tabindex]`);
|
|
6056
|
+
target?.focus();
|
|
6057
|
+
}, { injector: this.injector });
|
|
6058
|
+
return field.key;
|
|
6059
|
+
}
|
|
6060
|
+
}
|
|
6061
|
+
return null;
|
|
5777
6062
|
}
|
|
5778
6063
|
/** Rebuilds the form from the current inputs, discarding user edits. */
|
|
5779
6064
|
reset() {
|
|
@@ -5811,6 +6096,16 @@ class EntityFormComponent {
|
|
|
5811
6096
|
control(key) {
|
|
5812
6097
|
return this.form().controls[key];
|
|
5813
6098
|
}
|
|
6099
|
+
/** Host mark of the field (shown while the field is pristine), or `null`. */
|
|
6100
|
+
hostMark(field) {
|
|
6101
|
+
return this.hostFieldMarks()[field.key] ?? null;
|
|
6102
|
+
}
|
|
6103
|
+
hintOf(field) {
|
|
6104
|
+
return this.hostHints()[field.key] ?? null;
|
|
6105
|
+
}
|
|
6106
|
+
onHintAction(field, actionId) {
|
|
6107
|
+
this.fieldHintAction.emit({ key: field.key, actionId });
|
|
6108
|
+
}
|
|
5814
6109
|
isFieldVisible(field) {
|
|
5815
6110
|
return this.visibility()[field.key] !== false;
|
|
5816
6111
|
}
|
|
@@ -5945,10 +6240,13 @@ class EntityFormComponent {
|
|
|
5945
6240
|
const form = buildFormGroup(model, mode, { state, readOnly });
|
|
5946
6241
|
this.normaliseAttributeReferences(model, form);
|
|
5947
6242
|
this.clearUnsetPlaceholders(model, form);
|
|
6243
|
+
this.installCrossFieldValidators(form);
|
|
5948
6244
|
this.form.set(form);
|
|
5949
6245
|
this.collapsed.set(new Set(model.sections.filter((s) => s.collapsed && s.title).map((s) => s.key)));
|
|
5950
6246
|
this.rawValues.set(form.getRawValue());
|
|
5951
6247
|
this.applyVisibility();
|
|
6248
|
+
this.crossFieldErrorMap = {};
|
|
6249
|
+
this.refreshCrossFieldErrors();
|
|
5952
6250
|
this.baselineValues = cloneValue(form.getRawValue());
|
|
5953
6251
|
this.lastValid = undefined;
|
|
5954
6252
|
this.lastDirty = undefined;
|
|
@@ -5991,6 +6289,7 @@ class EntityFormComponent {
|
|
|
5991
6289
|
if (!formValuesEqual(raw, this.rawValues())) {
|
|
5992
6290
|
this.rawValues.set(raw);
|
|
5993
6291
|
this.applyVisibility();
|
|
6292
|
+
this.refreshCrossFieldErrors();
|
|
5994
6293
|
}
|
|
5995
6294
|
this.bump();
|
|
5996
6295
|
this.emitState();
|
|
@@ -6023,6 +6322,39 @@ class EntityFormComponent {
|
|
|
6023
6322
|
}
|
|
6024
6323
|
}
|
|
6025
6324
|
}
|
|
6325
|
+
/** One validator per control that reports the current cross-field error of its field. */
|
|
6326
|
+
installCrossFieldValidators(form) {
|
|
6327
|
+
for (const [key, control] of Object.entries(form.controls)) {
|
|
6328
|
+
const validator = (_control) => {
|
|
6329
|
+
const message = this.crossFieldErrorMap[key];
|
|
6330
|
+
return message ? { crossField: { message } } : null;
|
|
6331
|
+
};
|
|
6332
|
+
control.addValidators(validator);
|
|
6333
|
+
}
|
|
6334
|
+
}
|
|
6335
|
+
/**
|
|
6336
|
+
* Re-runs the cross-field validators on the enabled values and re-validates exactly the
|
|
6337
|
+
* controls whose error changed (`emitEvent: false`: no event loop; the caller bumps / emits).
|
|
6338
|
+
*/
|
|
6339
|
+
refreshCrossFieldErrors() {
|
|
6340
|
+
const validators = [...this.injectedCrossFieldValidators, ...(this.crossFieldValidators() ?? [])];
|
|
6341
|
+
const form = this.form();
|
|
6342
|
+
const next = validators.length === 0
|
|
6343
|
+
? {}
|
|
6344
|
+
: runCrossFieldValidators(validators, this.model(), allFields(this.model()), this.enabledValues(), this.mode());
|
|
6345
|
+
const previous = this.crossFieldErrorMap;
|
|
6346
|
+
const keys = new Set([...Object.keys(previous), ...Object.keys(next)]);
|
|
6347
|
+
const changed = [...keys].filter((k) => previous[k] !== next[k]);
|
|
6348
|
+
if (changed.length === 0) {
|
|
6349
|
+
return false;
|
|
6350
|
+
}
|
|
6351
|
+
this.crossFieldErrorMap = next;
|
|
6352
|
+
for (const key of changed) {
|
|
6353
|
+
form.controls[key]?.updateValueAndValidity({ emitEvent: false, onlySelf: true });
|
|
6354
|
+
}
|
|
6355
|
+
form.updateValueAndValidity({ emitEvent: false });
|
|
6356
|
+
return true;
|
|
6357
|
+
}
|
|
6026
6358
|
/** Values of enabled controls only (hidden and read-only fields are absent). */
|
|
6027
6359
|
enabledValues() {
|
|
6028
6360
|
const form = this.form();
|
|
@@ -6051,7 +6383,7 @@ class EntityFormComponent {
|
|
|
6051
6383
|
this.revision.update((r) => r + 1);
|
|
6052
6384
|
}
|
|
6053
6385
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: EntityFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6054
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: EntityFormComponent, isStandalone: true, selector: "mm-entity-form", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: false, transformFunction: null }, records: { classPropertyName: "records", publicName: "records", isSignal: true, isRequired: false, transformFunction: null }, labelResolver: { classPropertyName: "labelResolver", publicName: "labelResolver", isSignal: true, isRequired: false, transformFunction: null }, initialValues: { classPropertyName: "initialValues", publicName: "initialValues", isSignal: true, isRequired: false, transformFunction: null }, beforeSave: { classPropertyName: "beforeSave", publicName: "beforeSave", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changeSetChange: "changeSetChange", validChange: "validChange", dirtyChange: "dirtyChange" }, ngImport: i0, template: "@let m = resolvedMessages();\n@let rev = revision();\n<form class=\"mm-entity-form\" [formGroup]=\"form()\" (submit)=\"$event.preventDefault()\" novalidate>\n @if (saveBlockedReason(); as reason) {\n <p class=\"mm-ef-blocked\" role=\"status\" data-save-blocked>{{ reason }}</p>\n }\n @for (section of view().sections; track section.key) {\n @if (visibleFieldCount(section) > 0) {\n <section\n class=\"mm-ef-section\"\n [class.mm-ef-section--generated]=\"section.generated\"\n [class.mm-ef-section--collapsed]=\"isCollapsed(section)\"\n [attr.data-section-key]=\"section.key\"\n >\n @if (section.title) {\n <button\n type=\"button\"\n class=\"mm-ef-section__header\"\n [attr.aria-expanded]=\"!isCollapsed(section)\"\n (click)=\"toggleSection(section)\"\n >\n <kendo-svgicon [icon]=\"isCollapsed(section) ? chevronRightIcon : chevronDownIcon\"></kendo-svgicon>\n <span class=\"mm-ef-section__title\">{{ section.title }}</span>\n </button>\n }\n @if (!isCollapsed(section)) {\n @if (section.description) {\n <p class=\"mm-ef-section__description\">{{ section.description }}</p>\n }\n <div class=\"mm-ef-section__grid\" [class.mm-ef-section__grid--two]=\"section.columns === 2\">\n @for (field of section.fields; track field.key) {\n @if (isFieldVisible(field)) {\n @let ctrl = control(field.key);\n @let ro = isReadOnly(field);\n <mm-entity-form-field\n [field]=\"field\"\n [control]=\"ctrl\"\n [messages]=\"m\"\n [secretState]=\"secretState(field)\"\n [secretSetAt]=\"secretSetAt(field)\"\n [readOnly]=\"ro\"\n [required]=\"isRequired(field)\"\n [revision]=\"rev\"\n >\n @if (field.secret && field.kind === 'attribute' && (field.editor === 'password' || field.editor === 'multiline' || field.editor === 'text')) {\n <mm-entity-form-secret-editor\n [control]=\"ctrl\"\n [messages]=\"m\"\n [placeholder]=\"placeholder(field)\"\n [multiline]=\"field.editor === 'multiline'\"\n [readOnly]=\"ro\"\n [canClear]=\"canClearSecret(field)\"\n [clearStaged]=\"isSecretClearStaged(field)\"\n [writesDisabled]=\"isSecretWriteBlocked(field)\"\n [revision]=\"rev\"\n (clearStagedChange)=\"setSecretClearStaged(field, $event)\"\n ></mm-entity-form-secret-editor>\n } @else {\n @switch (field.editor) {\n @case ('multiline') {\n <kendo-textarea\n [formControl]=\"ctrl\"\n [rows]=\"4\"\n resizable=\"vertical\"\n [placeholder]=\"placeholder(field)\"\n [readonly]=\"ro\"\n ></kendo-textarea>\n }\n @case ('json') {\n <kendo-textarea\n class=\"mm-ef-mono\"\n [formControl]=\"ctrl\"\n [rows]=\"8\"\n resizable=\"vertical\"\n [placeholder]=\"placeholder(field)\"\n [readonly]=\"ro\"\n ></kendo-textarea>\n }\n @case ('yaml') {\n <kendo-textarea\n class=\"mm-ef-mono\"\n [formControl]=\"ctrl\"\n [rows]=\"8\"\n resizable=\"vertical\"\n [placeholder]=\"placeholder(field)\"\n [readonly]=\"ro\"\n ></kendo-textarea>\n }\n @case ('number') {\n <kendo-numerictextbox\n [formControl]=\"ctrl\"\n [decimals]=\"isIntegerField(field) ? 0 : 6\"\n [format]=\"isIntegerField(field) ? 'n0' : 'n'\"\n [placeholder]=\"placeholder(field)\"\n [readonly]=\"ro\"\n ></kendo-numerictextbox>\n }\n @case ('toggle') {\n <kendo-switch\n [formControl]=\"ctrl\"\n [onLabel]=\"m.toggleOn\"\n [offLabel]=\"m.toggleOff\"\n ></kendo-switch>\n }\n @case ('enum') {\n <kendo-dropdownlist\n [formControl]=\"ctrl\"\n [data]=\"field.enumOptions ?? []\"\n textField=\"name\"\n valueField=\"key\"\n [valuePrimitive]=\"true\"\n [defaultItem]=\"enumDefaultItem()\"\n ></kendo-dropdownlist>\n }\n @case ('datetime') {\n <kendo-datetimepicker\n [formControl]=\"ctrl\"\n [placeholder]=\"placeholder(field)\"\n [readOnlyInput]=\"ro\"\n ></kendo-datetimepicker>\n }\n @case ('cron') {\n <mm-cron-builder [formControl]=\"ctrl\"></mm-cron-builder>\n }\n @case ('chips') {\n <mm-entity-form-chips-editor\n [formControl]=\"ctrl\"\n [numeric]=\"isIntArray(field)\"\n [placeholder]=\"field.placeholder ?? m.chipsPlaceholder\"\n [invalidMessage]=\"m.validationNumber\"\n ></mm-entity-form-chips-editor>\n }\n @case ('reference') {\n <mm-entity-form-reference-field\n [formControl]=\"ctrl\"\n [targetCkTypeId]=\"field.reference?.targetCkTypeId ?? ''\"\n [multiple]=\"field.reference?.multiple ?? false\"\n [displayAttributes]=\"field.reference?.displayAttributes ?? noDisplayAttributes\"\n [displayAttributeInfo]=\"field.reference?.displayAttributeInfo ?? noDisplayAttributeInfo\"\n [messages]=\"messages()\"\n [placeholder]=\"field.placeholder ?? m.referencePlaceholder\"\n [readOnly]=\"ro\"\n ></mm-entity-form-reference-field>\n }\n @case ('records') {\n <mm-entity-form-records-field\n [formControl]=\"ctrl\"\n [ckRecordId]=\"field.record?.ckRecordId ?? ''\"\n [columns]=\"field.record?.columns ?? []\"\n [single]=\"field.record?.single ?? false\"\n [readOnly]=\"ro\"\n [secretWritesDisabled]=\"secretWritesDisabled()\"\n [messages]=\"messages()\"\n ></mm-entity-form-records-field>\n }\n @case ('unsupported') {\n <div class=\"mm-ef-unsupported\" [attr.title]=\"m.unsupportedEditor\">\n <span class=\"mm-ef-mono\">{{ displayUnsupported(field) }}</span>\n </div>\n }\n @default {\n <!-- text, password, url, email -->\n <kendo-textbox\n [formControl]=\"ctrl\"\n [type]=\"field.secret || field.editor === 'password' ? 'password' : 'text'\"\n [inputAttributes]=\"field.secret || field.editor === 'password' ? { autocomplete: 'new-password' } : {}\"\n [placeholder]=\"placeholder(field)\"\n [readonly]=\"ro\"\n ></kendo-textbox>\n }\n }\n }\n </mm-entity-form-field>\n }\n }\n </div>\n }\n </section>\n }\n } @empty {\n <p class=\"mm-ef-empty\">{{ m.noFieldsToShow }}</p>\n }\n</form>\n", styles: [":host{display:block}.mm-entity-form{display:flex;flex-direction:column;gap:16px}.mm-ef-section{border:1px solid var(--theme-border-subtle, rgba(0, 0, 0, .12));border-radius:6px;background:var(--theme-ink-02, transparent);padding:12px 16px 16px}.mm-ef-section__header{display:flex;align-items:center;gap:6px;width:100%;margin:0 0 12px;padding:0;border:none;background:none;color:var(--theme-text-primary, inherit);font:inherit;font-weight:600;text-align:left;cursor:pointer}.mm-ef-section__header:focus-visible{outline:2px solid var(--theme-text-accent, currentColor);outline-offset:2px}.mm-ef-section--collapsed .mm-ef-section__header{margin-bottom:0}.mm-ef-section__description{margin:-6px 0 12px;color:var(--theme-text-secondary, inherit);font-size:.9em}.mm-ef-section__grid{display:grid;grid-template-columns:minmax(0,1fr);gap:12px 16px}.mm-ef-section__grid--two{grid-template-columns:repeat(2,minmax(0,1fr))}:host ::ng-deep .mm-ef-field{display:flex;flex-direction:column;gap:4px;min-width:0;grid-column:1/-1}:host ::ng-deep .mm-ef-field--half{grid-column:auto}:host ::ng-deep .mm-ef-field .mm-ef-field__label-row{display:flex;align-items:center;gap:8px}:host ::ng-deep .mm-ef-field .mm-ef-field__label{color:var(--theme-text-secondary, inherit);font-size:.875em;font-weight:500}:host ::ng-deep .mm-ef-field .mm-ef-field__required{color:var(--theme-status-error, currentColor);margin-left:2px}:host ::ng-deep .mm-ef-field .mm-ef-field__badge{padding:0 6px;border-radius:999px;border:1px solid var(--theme-border-strong, currentColor);color:var(--theme-text-muted, inherit);font-size:.75em;line-height:1.6}:host ::ng-deep .mm-ef-field .mm-ef-field__badge--set{border-color:var(--theme-status-success, currentColor);color:var(--theme-status-success, inherit)}:host ::ng-deep .mm-ef-field .mm-ef-field__badge--not-set{border-style:dashed}:host ::ng-deep .mm-ef-field .mm-ef-field__badge--key-missing{border-color:var(--theme-status-warning, currentColor);color:var(--theme-status-warning, inherit)}:host ::ng-deep .mm-ef-field .mm-ef-field__badge--clear-staged{border-style:dashed;border-color:var(--theme-status-error, currentColor);color:var(--theme-status-error, inherit)}:host ::ng-deep .mm-ef-field .mm-ef-field__help{color:var(--theme-text-muted, inherit);font-size:.8em}:host ::ng-deep .mm-ef-field .mm-ef-field__error{color:var(--theme-status-error, inherit);font-size:.8em}:host ::ng-deep .mm-ef-field--readonly .mm-ef-field__editor{opacity:.85}:host ::ng-deep .mm-ef-mono,:host ::ng-deep .mm-ef-mono textarea{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.875em}.mm-ef-unsupported{padding:6px 8px;border-radius:4px;background:var(--theme-ink-04, transparent);color:var(--theme-text-secondary, inherit);overflow-wrap:anywhere}.mm-ef-empty{color:var(--theme-text-muted, inherit)}@media(max-width:720px){.mm-ef-section__grid--two{grid-template-columns:minmax(0,1fr)}:host ::ng-deep .mm-ef-field--half{grid-column:1/-1}}.mm-ef-blocked{margin:0 0 12px;padding:8px 12px;border-left:3px solid var(--theme-status-warning, currentColor);background:color-mix(in srgb,var(--theme-status-warning, #f0ad4e) 10%,transparent);font-size:.875em}:host ::ng-deep .mm-ef-secret{display:flex;flex-direction:column;gap:4px}:host ::ng-deep .mm-ef-secret .mm-ef-secret__row{display:flex;align-items:flex-start;gap:4px}:host ::ng-deep .mm-ef-secret .mm-ef-secret__input{flex:1 1 auto;min-width:0}:host ::ng-deep .mm-ef-secret .mm-ef-secret__input--masked textarea{color:transparent;-webkit-text-fill-color:transparent;text-shadow:none;caret-color:var(--theme-text-primary, CanvasText)}:host ::ng-deep .mm-ef-secret .mm-ef-secret__input--masked textarea::selection{color:transparent;-webkit-text-fill-color:transparent}:host ::ng-deep .mm-ef-secret .mm-ef-secret__input--masked textarea::placeholder{color:var(--theme-text-muted, GrayText);-webkit-text-fill-color:var(--theme-text-muted, GrayText);opacity:1}:host ::ng-deep .mm-ef-secret [data-secret-show]:disabled,:host ::ng-deep .mm-ef-secret [data-secret-clear]:disabled{opacity:.4;cursor:not-allowed}:host ::ng-deep .mm-ef-secret .mm-ef-secret__masked{color:var(--theme-text-muted, inherit);font-size:.8em}:host ::ng-deep .mm-ef-secret .mm-ef-secret__staged{display:flex;align-items:center;gap:8px;color:var(--theme-text-muted, inherit);font-size:.875em}:host ::ng-deep .mm-ef-secret .mm-ef-secret__hint{color:var(--theme-status-warning, inherit);font-size:.8em}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i2$1.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: i2$1.TextAreaComponent, selector: "kendo-textarea", inputs: ["focusableId", "flow", "inputAttributes", "adornmentsOrientation", "rows", "cols", "maxlength", "maxResizableRows", "tabindex", "tabIndex", "resizable", "size", "rounded", "fillMode", "showPrefixSeparator", "showSuffixSeparator"], outputs: ["focus", "blur", "valueChange"], exportAs: ["kendoTextArea"] }, { kind: "component", type: i2$1.NumericTextBoxComponent, selector: "kendo-numerictextbox", inputs: ["focusableId", "disabled", "readonly", "title", "autoCorrect", "format", "max", "min", "decimals", "placeholder", "step", "spinners", "rangeValidation", "tabindex", "tabIndex", "changeValueOnScroll", "selectOnFocus", "value", "maxlength", "size", "rounded", "fillMode", "inputAttributes"], outputs: ["valueChange", "focus", "blur", "inputFocus", "inputBlur"], exportAs: ["kendoNumericTextBox"] }, { kind: "component", type: i2$1.SwitchComponent, selector: "kendo-switch", inputs: ["focusableId", "onLabel", "offLabel", "checked", "disabled", "readonly", "tabindex", "size", "thumbRounded", "trackRounded", "tabIndex"], outputs: ["focus", "blur", "valueChange"], exportAs: ["kendoSwitch"] }, { kind: "component", type: i5.DropDownListComponent, selector: "kendo-dropdownlist", inputs: ["customIconClass", "showStickyHeader", "icon", "svgIcon", "loading", "data", "value", "textField", "valueField", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "defaultItem", "disabled", "itemDisabled", "readonly", "filterable", "virtual", "ignoreCase", "delay", "valuePrimitive", "tabindex", "tabIndex", "size", "rounded", "fillMode", "leftRightArrowsNavigation", "id"], outputs: ["valueChange", "filterChange", "selectionChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoDropDownList"] }, { kind: "component", type: i4.DateTimePickerComponent, selector: "kendo-datetimepicker", inputs: ["focusableId", "weekDaysFormat", "showOtherMonthDays", "value", "format", "twoDigitYearMax", "tabindex", "disabledDates", "popupSettings", "adaptiveTitle", "adaptiveSubtitle", "disabled", "readonly", "readOnlyInput", "cancelButton", "formatPlaceholder", "placeholder", "steps", "focusedDate", "calendarType", "animateCalendarNavigation", "weekNumber", "min", "max", "rangeValidation", "disabledDatesValidation", "incompleteDateValidation", "autoCorrectParts", "autoSwitchParts", "autoSwitchKeys", "enableMouseWheel", "allowCaretMode", "clearButton", "autoFill", "adaptiveMode", "inputAttributes", "defaultTab", "size", "rounded", "fillMode", "headerTemplate", "footerTemplate", "footer"], outputs: ["valueChange", "open", "close", "focus", "blur", "escape"], exportAs: ["kendo-datetimepicker"] }, { kind: "component", type: i5$1.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon", "variant"], exportAs: ["kendoSVGIcon"] }, { kind: "component", type: CronBuilderComponent, selector: "mm-cron-builder", inputs: ["config"] }, { kind: "component", type: EntityFormFieldComponent, selector: "mm-entity-form-field", inputs: ["field", "control", "messages", "secretState", "secretSetAt", "readOnly", "required", "revision"] }, { kind: "component", type: EntityFormChipsEditorComponent, selector: "mm-entity-form-chips-editor", inputs: ["numeric", "placeholder", "invalidMessage"] }, { kind: "component", type: EntityFormSecretEditorComponent, selector: "mm-entity-form-secret-editor", inputs: ["control", "messages", "placeholder", "multiline", "readOnly", "canClear", "clearStaged", "writesDisabled", "revision"], outputs: ["clearStagedChange"] }, { kind: "component", type: EntityFormReferenceFieldComponent, selector: "mm-entity-form-reference-field", inputs: ["targetCkTypeId", "multiple", "displayAttributes", "displayAttributeInfo", "placeholder", "readOnly", "messages"] }, { kind: "component", type: EntityFormRecordsFieldComponent, selector: "mm-entity-form-records-field", inputs: ["ckRecordId", "columns", "single", "readOnly", "messages", "secretWritesDisabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
6386
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: EntityFormComponent, isStandalone: true, selector: "mm-entity-form", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: false, transformFunction: null }, records: { classPropertyName: "records", publicName: "records", isSignal: true, isRequired: false, transformFunction: null }, labelResolver: { classPropertyName: "labelResolver", publicName: "labelResolver", isSignal: true, isRequired: false, transformFunction: null }, initialValues: { classPropertyName: "initialValues", publicName: "initialValues", isSignal: true, isRequired: false, transformFunction: null }, beforeSave: { classPropertyName: "beforeSave", publicName: "beforeSave", isSignal: true, isRequired: false, transformFunction: null }, crossFieldValidators: { classPropertyName: "crossFieldValidators", publicName: "crossFieldValidators", isSignal: true, isRequired: false, transformFunction: null }, fieldErrors: { classPropertyName: "fieldErrors", publicName: "fieldErrors", isSignal: true, isRequired: false, transformFunction: null }, fieldHints: { classPropertyName: "fieldHints", publicName: "fieldHints", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { fieldHintAction: "fieldHintAction", changeSetChange: "changeSetChange", validChange: "validChange", dirtyChange: "dirtyChange" }, ngImport: i0, template: "@let m = resolvedMessages();\n@let rev = revision();\n<form class=\"mm-entity-form\" [formGroup]=\"form()\" (submit)=\"$event.preventDefault()\" novalidate>\n @if (saveBlockedReason(); as reason) {\n <p class=\"mm-ef-blocked\" role=\"status\" data-save-blocked>{{ reason }}</p>\n }\n @for (section of view().sections; track section.key) {\n @if (visibleFieldCount(section) > 0) {\n <section\n class=\"mm-ef-section\"\n [class.mm-ef-section--generated]=\"section.generated\"\n [class.mm-ef-section--collapsed]=\"isCollapsed(section)\"\n [attr.data-section-key]=\"section.key\"\n >\n @if (section.title) {\n <button\n type=\"button\"\n class=\"mm-ef-section__header\"\n [attr.aria-expanded]=\"!isCollapsed(section)\"\n (click)=\"toggleSection(section)\"\n >\n <kendo-svgicon [icon]=\"isCollapsed(section) ? chevronRightIcon : chevronDownIcon\"></kendo-svgicon>\n <span class=\"mm-ef-section__title\">{{ section.title }}</span>\n </button>\n }\n @if (!isCollapsed(section)) {\n @if (section.description) {\n <p class=\"mm-ef-section__description\">{{ section.description }}</p>\n }\n <div class=\"mm-ef-section__grid\" [class.mm-ef-section__grid--two]=\"section.columns === 2\">\n @for (field of section.fields; track field.key) {\n @if (isFieldVisible(field)) {\n @let ctrl = control(field.key);\n @let ro = isReadOnly(field);\n <mm-entity-form-field\n [field]=\"field\"\n [control]=\"ctrl\"\n [messages]=\"m\"\n [secretState]=\"secretState(field)\"\n [secretSetAt]=\"secretSetAt(field)\"\n [readOnly]=\"ro\"\n [required]=\"isRequired(field)\"\n [externalError]=\"hostMark(field)\"\n [hint]=\"hintOf(field)\"\n (hintAction)=\"onHintAction(field, $event)\"\n [revision]=\"rev\"\n >\n @if (field.secret && field.kind === 'attribute' && (field.editor === 'password' || field.editor === 'multiline' || field.editor === 'text')) {\n <mm-entity-form-secret-editor\n [control]=\"ctrl\"\n [messages]=\"m\"\n [placeholder]=\"placeholder(field)\"\n [multiline]=\"field.editor === 'multiline'\"\n [readOnly]=\"ro\"\n [canClear]=\"canClearSecret(field)\"\n [clearStaged]=\"isSecretClearStaged(field)\"\n [writesDisabled]=\"isSecretWriteBlocked(field)\"\n [revision]=\"rev\"\n (clearStagedChange)=\"setSecretClearStaged(field, $event)\"\n ></mm-entity-form-secret-editor>\n } @else {\n @switch (field.editor) {\n @case ('multiline') {\n <kendo-textarea\n [formControl]=\"ctrl\"\n [rows]=\"4\"\n resizable=\"vertical\"\n [placeholder]=\"placeholder(field)\"\n [readonly]=\"ro\"\n ></kendo-textarea>\n }\n @case ('json') {\n <kendo-textarea\n class=\"mm-ef-mono\"\n [formControl]=\"ctrl\"\n [rows]=\"8\"\n resizable=\"vertical\"\n [placeholder]=\"placeholder(field)\"\n [readonly]=\"ro\"\n ></kendo-textarea>\n }\n @case ('yaml') {\n <kendo-textarea\n class=\"mm-ef-mono\"\n [formControl]=\"ctrl\"\n [rows]=\"8\"\n resizable=\"vertical\"\n [placeholder]=\"placeholder(field)\"\n [readonly]=\"ro\"\n ></kendo-textarea>\n }\n @case ('number') {\n <kendo-numerictextbox\n [formControl]=\"ctrl\"\n [decimals]=\"isIntegerField(field) ? 0 : 6\"\n [format]=\"isIntegerField(field) ? 'n0' : 'n'\"\n [placeholder]=\"placeholder(field)\"\n [readonly]=\"ro\"\n ></kendo-numerictextbox>\n }\n @case ('toggle') {\n <kendo-switch\n [formControl]=\"ctrl\"\n [onLabel]=\"m.toggleOn\"\n [offLabel]=\"m.toggleOff\"\n ></kendo-switch>\n }\n @case ('enum') {\n <kendo-dropdownlist\n [formControl]=\"ctrl\"\n [data]=\"field.enumOptions ?? []\"\n textField=\"name\"\n valueField=\"key\"\n [valuePrimitive]=\"true\"\n [defaultItem]=\"enumDefaultItem()\"\n ></kendo-dropdownlist>\n }\n @case ('datetime') {\n <kendo-datetimepicker\n [formControl]=\"ctrl\"\n [placeholder]=\"placeholder(field)\"\n [readOnlyInput]=\"ro\"\n ></kendo-datetimepicker>\n }\n @case ('cron') {\n <mm-cron-builder [formControl]=\"ctrl\"></mm-cron-builder>\n }\n @case ('chips') {\n <mm-entity-form-chips-editor\n [formControl]=\"ctrl\"\n [numeric]=\"isIntArray(field)\"\n [placeholder]=\"field.placeholder ?? m.chipsPlaceholder\"\n [invalidMessage]=\"m.validationNumber\"\n ></mm-entity-form-chips-editor>\n }\n @case ('reference') {\n <mm-entity-form-reference-field\n [formControl]=\"ctrl\"\n [targetCkTypeId]=\"field.reference?.targetCkTypeId ?? ''\"\n [multiple]=\"field.reference?.multiple ?? false\"\n [displayAttributes]=\"field.reference?.displayAttributes ?? noDisplayAttributes\"\n [displayAttributeInfo]=\"field.reference?.displayAttributeInfo ?? noDisplayAttributeInfo\"\n [messages]=\"messages()\"\n [placeholder]=\"field.placeholder ?? m.referencePlaceholder\"\n [readOnly]=\"ro\"\n ></mm-entity-form-reference-field>\n }\n @case ('records') {\n <mm-entity-form-records-field\n [formControl]=\"ctrl\"\n [ckRecordId]=\"field.record?.ckRecordId ?? ''\"\n [columns]=\"field.record?.columns ?? []\"\n [single]=\"field.record?.single ?? false\"\n [readOnly]=\"ro\"\n [secretWritesDisabled]=\"secretWritesDisabled()\"\n [messages]=\"messages()\"\n ></mm-entity-form-records-field>\n }\n @case ('unsupported') {\n <div class=\"mm-ef-unsupported\" [attr.title]=\"m.unsupportedEditor\">\n <span class=\"mm-ef-mono\">{{ displayUnsupported(field) }}</span>\n </div>\n }\n @default {\n <!-- text, password, url, email -->\n <kendo-textbox\n [formControl]=\"ctrl\"\n [type]=\"field.secret || field.editor === 'password' ? 'password' : 'text'\"\n [inputAttributes]=\"field.secret || field.editor === 'password' ? { autocomplete: 'new-password' } : {}\"\n [placeholder]=\"placeholder(field)\"\n [readonly]=\"ro\"\n ></kendo-textbox>\n }\n }\n }\n </mm-entity-form-field>\n }\n }\n </div>\n }\n </section>\n }\n } @empty {\n <p class=\"mm-ef-empty\">{{ m.noFieldsToShow }}</p>\n }\n</form>\n", styles: [":host{display:block}.mm-entity-form{display:flex;flex-direction:column;gap:16px}.mm-ef-section{border:1px solid var(--theme-border-subtle, rgba(0, 0, 0, .12));border-radius:6px;background:var(--theme-ink-02, transparent);padding:12px 16px 16px}.mm-ef-section__header{display:flex;align-items:center;gap:6px;width:100%;margin:0 0 12px;padding:0;border:none;background:none;color:var(--theme-text-primary, inherit);font:inherit;font-weight:600;text-align:left;cursor:pointer}.mm-ef-section__header:focus-visible{outline:2px solid var(--theme-text-accent, currentColor);outline-offset:2px}.mm-ef-section--collapsed .mm-ef-section__header{margin-bottom:0}.mm-ef-section__description{margin:-6px 0 12px;color:var(--theme-text-secondary, inherit);font-size:.9em}.mm-ef-section__grid{display:grid;grid-template-columns:minmax(0,1fr);gap:12px 16px}.mm-ef-section__grid--two{grid-template-columns:repeat(2,minmax(0,1fr))}:host ::ng-deep .mm-ef-field{display:flex;flex-direction:column;gap:4px;min-width:0;grid-column:1/-1}:host ::ng-deep .mm-ef-field--half{grid-column:auto}:host ::ng-deep .mm-ef-field .mm-ef-field__label-row{display:flex;align-items:center;gap:8px}:host ::ng-deep .mm-ef-field .mm-ef-field__label{color:var(--theme-text-secondary, inherit);font-size:.875em;font-weight:500}:host ::ng-deep .mm-ef-field .mm-ef-field__required{color:var(--theme-status-error, currentColor);margin-left:2px}:host ::ng-deep .mm-ef-field .mm-ef-field__badge{padding:0 6px;border-radius:999px;border:1px solid var(--theme-border-strong, currentColor);color:var(--theme-text-muted, inherit);font-size:.75em;line-height:1.6}:host ::ng-deep .mm-ef-field .mm-ef-field__badge--set{border-color:var(--theme-status-success, currentColor);color:var(--theme-status-success, inherit)}:host ::ng-deep .mm-ef-field .mm-ef-field__badge--not-set{border-style:dashed}:host ::ng-deep .mm-ef-field .mm-ef-field__badge--key-missing{border-color:var(--theme-status-warning, currentColor);color:var(--theme-status-warning, inherit)}:host ::ng-deep .mm-ef-field .mm-ef-field__badge--clear-staged{border-style:dashed;border-color:var(--theme-status-error, currentColor);color:var(--theme-status-error, inherit)}:host ::ng-deep .mm-ef-field .mm-ef-field__help{color:var(--theme-text-muted, inherit);font-size:.8em}:host ::ng-deep .mm-ef-field .mm-ef-field__error{color:var(--theme-status-error, inherit);font-size:.8em}:host ::ng-deep .mm-ef-field .mm-ef-field__hint{color:var(--theme-status-warning, inherit);font-size:.8em}:host ::ng-deep .mm-ef-field .mm-ef-field__hint-action{background:none;border:0;padding:0;margin-left:.4em;color:var(--theme-text-accent, inherit);font:inherit;text-decoration:underline;cursor:pointer}:host ::ng-deep .mm-ef-field--readonly .mm-ef-field__editor{opacity:.85}:host ::ng-deep .mm-ef-mono,:host ::ng-deep .mm-ef-mono textarea{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.875em}.mm-ef-unsupported{padding:6px 8px;border-radius:4px;background:var(--theme-ink-04, transparent);color:var(--theme-text-secondary, inherit);overflow-wrap:anywhere}.mm-ef-empty{color:var(--theme-text-muted, inherit)}@media(max-width:720px){.mm-ef-section__grid--two{grid-template-columns:minmax(0,1fr)}:host ::ng-deep .mm-ef-field--half{grid-column:1/-1}}.mm-ef-blocked{margin:0 0 12px;padding:8px 12px;border-left:3px solid var(--theme-status-warning, currentColor);background:color-mix(in srgb,var(--theme-status-warning, #f0ad4e) 10%,transparent);font-size:.875em}:host ::ng-deep .mm-ef-secret{display:flex;flex-direction:column;gap:4px}:host ::ng-deep .mm-ef-secret .mm-ef-secret__row{display:flex;align-items:flex-start;gap:4px}:host ::ng-deep .mm-ef-secret .mm-ef-secret__input{flex:1 1 auto;min-width:0}:host ::ng-deep .mm-ef-secret .mm-ef-secret__input--masked textarea{color:transparent;-webkit-text-fill-color:transparent;text-shadow:none;caret-color:var(--theme-text-primary, CanvasText)}:host ::ng-deep .mm-ef-secret .mm-ef-secret__input--masked textarea::selection{color:transparent;-webkit-text-fill-color:transparent}:host ::ng-deep .mm-ef-secret .mm-ef-secret__input--masked textarea::placeholder{color:var(--theme-text-muted, GrayText);-webkit-text-fill-color:var(--theme-text-muted, GrayText);opacity:1}:host ::ng-deep .mm-ef-secret [data-secret-show]:disabled,:host ::ng-deep .mm-ef-secret [data-secret-clear]:disabled{opacity:.4;cursor:not-allowed}:host ::ng-deep .mm-ef-secret .mm-ef-secret__masked{color:var(--theme-text-muted, inherit);font-size:.8em}:host ::ng-deep .mm-ef-secret .mm-ef-secret__staged{display:flex;align-items:center;gap:8px;color:var(--theme-text-muted, inherit);font-size:.875em}:host ::ng-deep .mm-ef-secret .mm-ef-secret__hint{color:var(--theme-status-warning, inherit);font-size:.8em}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i2$1.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: i2$1.TextAreaComponent, selector: "kendo-textarea", inputs: ["focusableId", "flow", "inputAttributes", "adornmentsOrientation", "rows", "cols", "maxlength", "maxResizableRows", "tabindex", "tabIndex", "resizable", "size", "rounded", "fillMode", "showPrefixSeparator", "showSuffixSeparator"], outputs: ["focus", "blur", "valueChange"], exportAs: ["kendoTextArea"] }, { kind: "component", type: i2$1.NumericTextBoxComponent, selector: "kendo-numerictextbox", inputs: ["focusableId", "disabled", "readonly", "title", "autoCorrect", "format", "max", "min", "decimals", "placeholder", "step", "spinners", "rangeValidation", "tabindex", "tabIndex", "changeValueOnScroll", "selectOnFocus", "value", "maxlength", "size", "rounded", "fillMode", "inputAttributes"], outputs: ["valueChange", "focus", "blur", "inputFocus", "inputBlur"], exportAs: ["kendoNumericTextBox"] }, { kind: "component", type: i2$1.SwitchComponent, selector: "kendo-switch", inputs: ["focusableId", "onLabel", "offLabel", "checked", "disabled", "readonly", "tabindex", "size", "thumbRounded", "trackRounded", "tabIndex"], outputs: ["focus", "blur", "valueChange"], exportAs: ["kendoSwitch"] }, { kind: "component", type: i5.DropDownListComponent, selector: "kendo-dropdownlist", inputs: ["customIconClass", "showStickyHeader", "icon", "svgIcon", "loading", "data", "value", "textField", "valueField", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "defaultItem", "disabled", "itemDisabled", "readonly", "filterable", "virtual", "ignoreCase", "delay", "valuePrimitive", "tabindex", "tabIndex", "size", "rounded", "fillMode", "leftRightArrowsNavigation", "id"], outputs: ["valueChange", "filterChange", "selectionChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoDropDownList"] }, { kind: "component", type: i4.DateTimePickerComponent, selector: "kendo-datetimepicker", inputs: ["focusableId", "weekDaysFormat", "showOtherMonthDays", "value", "format", "twoDigitYearMax", "tabindex", "disabledDates", "popupSettings", "adaptiveTitle", "adaptiveSubtitle", "disabled", "readonly", "readOnlyInput", "cancelButton", "formatPlaceholder", "placeholder", "steps", "focusedDate", "calendarType", "animateCalendarNavigation", "weekNumber", "min", "max", "rangeValidation", "disabledDatesValidation", "incompleteDateValidation", "autoCorrectParts", "autoSwitchParts", "autoSwitchKeys", "enableMouseWheel", "allowCaretMode", "clearButton", "autoFill", "adaptiveMode", "inputAttributes", "defaultTab", "size", "rounded", "fillMode", "headerTemplate", "footerTemplate", "footer"], outputs: ["valueChange", "open", "close", "focus", "blur", "escape"], exportAs: ["kendo-datetimepicker"] }, { kind: "component", type: i5$1.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon", "variant"], exportAs: ["kendoSVGIcon"] }, { kind: "component", type: CronBuilderComponent, selector: "mm-cron-builder", inputs: ["config"] }, { kind: "component", type: EntityFormFieldComponent, selector: "mm-entity-form-field", inputs: ["field", "control", "messages", "secretState", "secretSetAt", "readOnly", "required", "externalError", "hint", "revision"], outputs: ["hintAction"] }, { kind: "component", type: EntityFormChipsEditorComponent, selector: "mm-entity-form-chips-editor", inputs: ["numeric", "placeholder", "invalidMessage"] }, { kind: "component", type: EntityFormSecretEditorComponent, selector: "mm-entity-form-secret-editor", inputs: ["control", "messages", "placeholder", "multiline", "readOnly", "canClear", "clearStaged", "writesDisabled", "revision"], outputs: ["clearStagedChange"] }, { kind: "component", type: EntityFormReferenceFieldComponent, selector: "mm-entity-form-reference-field", inputs: ["targetCkTypeId", "multiple", "displayAttributes", "displayAttributeInfo", "placeholder", "readOnly", "messages"] }, { kind: "component", type: EntityFormRecordsFieldComponent, selector: "mm-entity-form-records-field", inputs: ["ckRecordId", "columns", "single", "readOnly", "messages", "secretWritesDisabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
6055
6387
|
}
|
|
6056
6388
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: EntityFormComponent, decorators: [{
|
|
6057
6389
|
type: Component,
|
|
@@ -6070,8 +6402,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
6070
6402
|
EntityFormSecretEditorComponent,
|
|
6071
6403
|
EntityFormReferenceFieldComponent,
|
|
6072
6404
|
EntityFormRecordsFieldComponent,
|
|
6073
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let m = resolvedMessages();\n@let rev = revision();\n<form class=\"mm-entity-form\" [formGroup]=\"form()\" (submit)=\"$event.preventDefault()\" novalidate>\n @if (saveBlockedReason(); as reason) {\n <p class=\"mm-ef-blocked\" role=\"status\" data-save-blocked>{{ reason }}</p>\n }\n @for (section of view().sections; track section.key) {\n @if (visibleFieldCount(section) > 0) {\n <section\n class=\"mm-ef-section\"\n [class.mm-ef-section--generated]=\"section.generated\"\n [class.mm-ef-section--collapsed]=\"isCollapsed(section)\"\n [attr.data-section-key]=\"section.key\"\n >\n @if (section.title) {\n <button\n type=\"button\"\n class=\"mm-ef-section__header\"\n [attr.aria-expanded]=\"!isCollapsed(section)\"\n (click)=\"toggleSection(section)\"\n >\n <kendo-svgicon [icon]=\"isCollapsed(section) ? chevronRightIcon : chevronDownIcon\"></kendo-svgicon>\n <span class=\"mm-ef-section__title\">{{ section.title }}</span>\n </button>\n }\n @if (!isCollapsed(section)) {\n @if (section.description) {\n <p class=\"mm-ef-section__description\">{{ section.description }}</p>\n }\n <div class=\"mm-ef-section__grid\" [class.mm-ef-section__grid--two]=\"section.columns === 2\">\n @for (field of section.fields; track field.key) {\n @if (isFieldVisible(field)) {\n @let ctrl = control(field.key);\n @let ro = isReadOnly(field);\n <mm-entity-form-field\n [field]=\"field\"\n [control]=\"ctrl\"\n [messages]=\"m\"\n [secretState]=\"secretState(field)\"\n [secretSetAt]=\"secretSetAt(field)\"\n [readOnly]=\"ro\"\n [required]=\"isRequired(field)\"\n [revision]=\"rev\"\n >\n @if (field.secret && field.kind === 'attribute' && (field.editor === 'password' || field.editor === 'multiline' || field.editor === 'text')) {\n <mm-entity-form-secret-editor\n [control]=\"ctrl\"\n [messages]=\"m\"\n [placeholder]=\"placeholder(field)\"\n [multiline]=\"field.editor === 'multiline'\"\n [readOnly]=\"ro\"\n [canClear]=\"canClearSecret(field)\"\n [clearStaged]=\"isSecretClearStaged(field)\"\n [writesDisabled]=\"isSecretWriteBlocked(field)\"\n [revision]=\"rev\"\n (clearStagedChange)=\"setSecretClearStaged(field, $event)\"\n ></mm-entity-form-secret-editor>\n } @else {\n @switch (field.editor) {\n @case ('multiline') {\n <kendo-textarea\n [formControl]=\"ctrl\"\n [rows]=\"4\"\n resizable=\"vertical\"\n [placeholder]=\"placeholder(field)\"\n [readonly]=\"ro\"\n ></kendo-textarea>\n }\n @case ('json') {\n <kendo-textarea\n class=\"mm-ef-mono\"\n [formControl]=\"ctrl\"\n [rows]=\"8\"\n resizable=\"vertical\"\n [placeholder]=\"placeholder(field)\"\n [readonly]=\"ro\"\n ></kendo-textarea>\n }\n @case ('yaml') {\n <kendo-textarea\n class=\"mm-ef-mono\"\n [formControl]=\"ctrl\"\n [rows]=\"8\"\n resizable=\"vertical\"\n [placeholder]=\"placeholder(field)\"\n [readonly]=\"ro\"\n ></kendo-textarea>\n }\n @case ('number') {\n <kendo-numerictextbox\n [formControl]=\"ctrl\"\n [decimals]=\"isIntegerField(field) ? 0 : 6\"\n [format]=\"isIntegerField(field) ? 'n0' : 'n'\"\n [placeholder]=\"placeholder(field)\"\n [readonly]=\"ro\"\n ></kendo-numerictextbox>\n }\n @case ('toggle') {\n <kendo-switch\n [formControl]=\"ctrl\"\n [onLabel]=\"m.toggleOn\"\n [offLabel]=\"m.toggleOff\"\n ></kendo-switch>\n }\n @case ('enum') {\n <kendo-dropdownlist\n [formControl]=\"ctrl\"\n [data]=\"field.enumOptions ?? []\"\n textField=\"name\"\n valueField=\"key\"\n [valuePrimitive]=\"true\"\n [defaultItem]=\"enumDefaultItem()\"\n ></kendo-dropdownlist>\n }\n @case ('datetime') {\n <kendo-datetimepicker\n [formControl]=\"ctrl\"\n [placeholder]=\"placeholder(field)\"\n [readOnlyInput]=\"ro\"\n ></kendo-datetimepicker>\n }\n @case ('cron') {\n <mm-cron-builder [formControl]=\"ctrl\"></mm-cron-builder>\n }\n @case ('chips') {\n <mm-entity-form-chips-editor\n [formControl]=\"ctrl\"\n [numeric]=\"isIntArray(field)\"\n [placeholder]=\"field.placeholder ?? m.chipsPlaceholder\"\n [invalidMessage]=\"m.validationNumber\"\n ></mm-entity-form-chips-editor>\n }\n @case ('reference') {\n <mm-entity-form-reference-field\n [formControl]=\"ctrl\"\n [targetCkTypeId]=\"field.reference?.targetCkTypeId ?? ''\"\n [multiple]=\"field.reference?.multiple ?? false\"\n [displayAttributes]=\"field.reference?.displayAttributes ?? noDisplayAttributes\"\n [displayAttributeInfo]=\"field.reference?.displayAttributeInfo ?? noDisplayAttributeInfo\"\n [messages]=\"messages()\"\n [placeholder]=\"field.placeholder ?? m.referencePlaceholder\"\n [readOnly]=\"ro\"\n ></mm-entity-form-reference-field>\n }\n @case ('records') {\n <mm-entity-form-records-field\n [formControl]=\"ctrl\"\n [ckRecordId]=\"field.record?.ckRecordId ?? ''\"\n [columns]=\"field.record?.columns ?? []\"\n [single]=\"field.record?.single ?? false\"\n [readOnly]=\"ro\"\n [secretWritesDisabled]=\"secretWritesDisabled()\"\n [messages]=\"messages()\"\n ></mm-entity-form-records-field>\n }\n @case ('unsupported') {\n <div class=\"mm-ef-unsupported\" [attr.title]=\"m.unsupportedEditor\">\n <span class=\"mm-ef-mono\">{{ displayUnsupported(field) }}</span>\n </div>\n }\n @default {\n <!-- text, password, url, email -->\n <kendo-textbox\n [formControl]=\"ctrl\"\n [type]=\"field.secret || field.editor === 'password' ? 'password' : 'text'\"\n [inputAttributes]=\"field.secret || field.editor === 'password' ? { autocomplete: 'new-password' } : {}\"\n [placeholder]=\"placeholder(field)\"\n [readonly]=\"ro\"\n ></kendo-textbox>\n }\n }\n }\n </mm-entity-form-field>\n }\n }\n </div>\n }\n </section>\n }\n } @empty {\n <p class=\"mm-ef-empty\">{{ m.noFieldsToShow }}</p>\n }\n</form>\n", styles: [":host{display:block}.mm-entity-form{display:flex;flex-direction:column;gap:16px}.mm-ef-section{border:1px solid var(--theme-border-subtle, rgba(0, 0, 0, .12));border-radius:6px;background:var(--theme-ink-02, transparent);padding:12px 16px 16px}.mm-ef-section__header{display:flex;align-items:center;gap:6px;width:100%;margin:0 0 12px;padding:0;border:none;background:none;color:var(--theme-text-primary, inherit);font:inherit;font-weight:600;text-align:left;cursor:pointer}.mm-ef-section__header:focus-visible{outline:2px solid var(--theme-text-accent, currentColor);outline-offset:2px}.mm-ef-section--collapsed .mm-ef-section__header{margin-bottom:0}.mm-ef-section__description{margin:-6px 0 12px;color:var(--theme-text-secondary, inherit);font-size:.9em}.mm-ef-section__grid{display:grid;grid-template-columns:minmax(0,1fr);gap:12px 16px}.mm-ef-section__grid--two{grid-template-columns:repeat(2,minmax(0,1fr))}:host ::ng-deep .mm-ef-field{display:flex;flex-direction:column;gap:4px;min-width:0;grid-column:1/-1}:host ::ng-deep .mm-ef-field--half{grid-column:auto}:host ::ng-deep .mm-ef-field .mm-ef-field__label-row{display:flex;align-items:center;gap:8px}:host ::ng-deep .mm-ef-field .mm-ef-field__label{color:var(--theme-text-secondary, inherit);font-size:.875em;font-weight:500}:host ::ng-deep .mm-ef-field .mm-ef-field__required{color:var(--theme-status-error, currentColor);margin-left:2px}:host ::ng-deep .mm-ef-field .mm-ef-field__badge{padding:0 6px;border-radius:999px;border:1px solid var(--theme-border-strong, currentColor);color:var(--theme-text-muted, inherit);font-size:.75em;line-height:1.6}:host ::ng-deep .mm-ef-field .mm-ef-field__badge--set{border-color:var(--theme-status-success, currentColor);color:var(--theme-status-success, inherit)}:host ::ng-deep .mm-ef-field .mm-ef-field__badge--not-set{border-style:dashed}:host ::ng-deep .mm-ef-field .mm-ef-field__badge--key-missing{border-color:var(--theme-status-warning, currentColor);color:var(--theme-status-warning, inherit)}:host ::ng-deep .mm-ef-field .mm-ef-field__badge--clear-staged{border-style:dashed;border-color:var(--theme-status-error, currentColor);color:var(--theme-status-error, inherit)}:host ::ng-deep .mm-ef-field .mm-ef-field__help{color:var(--theme-text-muted, inherit);font-size:.8em}:host ::ng-deep .mm-ef-field .mm-ef-field__error{color:var(--theme-status-error, inherit);font-size:.8em}:host ::ng-deep .mm-ef-field--readonly .mm-ef-field__editor{opacity:.85}:host ::ng-deep .mm-ef-mono,:host ::ng-deep .mm-ef-mono textarea{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.875em}.mm-ef-unsupported{padding:6px 8px;border-radius:4px;background:var(--theme-ink-04, transparent);color:var(--theme-text-secondary, inherit);overflow-wrap:anywhere}.mm-ef-empty{color:var(--theme-text-muted, inherit)}@media(max-width:720px){.mm-ef-section__grid--two{grid-template-columns:minmax(0,1fr)}:host ::ng-deep .mm-ef-field--half{grid-column:1/-1}}.mm-ef-blocked{margin:0 0 12px;padding:8px 12px;border-left:3px solid var(--theme-status-warning, currentColor);background:color-mix(in srgb,var(--theme-status-warning, #f0ad4e) 10%,transparent);font-size:.875em}:host ::ng-deep .mm-ef-secret{display:flex;flex-direction:column;gap:4px}:host ::ng-deep .mm-ef-secret .mm-ef-secret__row{display:flex;align-items:flex-start;gap:4px}:host ::ng-deep .mm-ef-secret .mm-ef-secret__input{flex:1 1 auto;min-width:0}:host ::ng-deep .mm-ef-secret .mm-ef-secret__input--masked textarea{color:transparent;-webkit-text-fill-color:transparent;text-shadow:none;caret-color:var(--theme-text-primary, CanvasText)}:host ::ng-deep .mm-ef-secret .mm-ef-secret__input--masked textarea::selection{color:transparent;-webkit-text-fill-color:transparent}:host ::ng-deep .mm-ef-secret .mm-ef-secret__input--masked textarea::placeholder{color:var(--theme-text-muted, GrayText);-webkit-text-fill-color:var(--theme-text-muted, GrayText);opacity:1}:host ::ng-deep .mm-ef-secret [data-secret-show]:disabled,:host ::ng-deep .mm-ef-secret [data-secret-clear]:disabled{opacity:.4;cursor:not-allowed}:host ::ng-deep .mm-ef-secret .mm-ef-secret__masked{color:var(--theme-text-muted, inherit);font-size:.8em}:host ::ng-deep .mm-ef-secret .mm-ef-secret__staged{display:flex;align-items:center;gap:8px;color:var(--theme-text-muted, inherit);font-size:.875em}:host ::ng-deep .mm-ef-secret .mm-ef-secret__hint{color:var(--theme-status-warning, inherit);font-size:.8em}\n"] }]
|
|
6074
|
-
}], ctorParameters: () => [], propDecorators: { model: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: true }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], readOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnly", required: false }] }], messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: false }] }], records: [{ type: i0.Input, args: [{ isSignal: true, alias: "records", required: false }] }], labelResolver: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelResolver", required: false }] }], initialValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialValues", required: false }] }], beforeSave: [{ type: i0.Input, args: [{ isSignal: true, alias: "beforeSave", required: false }] }], changeSetChange: [{ type: i0.Output, args: ["changeSetChange"] }], validChange: [{ type: i0.Output, args: ["validChange"] }], dirtyChange: [{ type: i0.Output, args: ["dirtyChange"] }] } });
|
|
6405
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let m = resolvedMessages();\n@let rev = revision();\n<form class=\"mm-entity-form\" [formGroup]=\"form()\" (submit)=\"$event.preventDefault()\" novalidate>\n @if (saveBlockedReason(); as reason) {\n <p class=\"mm-ef-blocked\" role=\"status\" data-save-blocked>{{ reason }}</p>\n }\n @for (section of view().sections; track section.key) {\n @if (visibleFieldCount(section) > 0) {\n <section\n class=\"mm-ef-section\"\n [class.mm-ef-section--generated]=\"section.generated\"\n [class.mm-ef-section--collapsed]=\"isCollapsed(section)\"\n [attr.data-section-key]=\"section.key\"\n >\n @if (section.title) {\n <button\n type=\"button\"\n class=\"mm-ef-section__header\"\n [attr.aria-expanded]=\"!isCollapsed(section)\"\n (click)=\"toggleSection(section)\"\n >\n <kendo-svgicon [icon]=\"isCollapsed(section) ? chevronRightIcon : chevronDownIcon\"></kendo-svgicon>\n <span class=\"mm-ef-section__title\">{{ section.title }}</span>\n </button>\n }\n @if (!isCollapsed(section)) {\n @if (section.description) {\n <p class=\"mm-ef-section__description\">{{ section.description }}</p>\n }\n <div class=\"mm-ef-section__grid\" [class.mm-ef-section__grid--two]=\"section.columns === 2\">\n @for (field of section.fields; track field.key) {\n @if (isFieldVisible(field)) {\n @let ctrl = control(field.key);\n @let ro = isReadOnly(field);\n <mm-entity-form-field\n [field]=\"field\"\n [control]=\"ctrl\"\n [messages]=\"m\"\n [secretState]=\"secretState(field)\"\n [secretSetAt]=\"secretSetAt(field)\"\n [readOnly]=\"ro\"\n [required]=\"isRequired(field)\"\n [externalError]=\"hostMark(field)\"\n [hint]=\"hintOf(field)\"\n (hintAction)=\"onHintAction(field, $event)\"\n [revision]=\"rev\"\n >\n @if (field.secret && field.kind === 'attribute' && (field.editor === 'password' || field.editor === 'multiline' || field.editor === 'text')) {\n <mm-entity-form-secret-editor\n [control]=\"ctrl\"\n [messages]=\"m\"\n [placeholder]=\"placeholder(field)\"\n [multiline]=\"field.editor === 'multiline'\"\n [readOnly]=\"ro\"\n [canClear]=\"canClearSecret(field)\"\n [clearStaged]=\"isSecretClearStaged(field)\"\n [writesDisabled]=\"isSecretWriteBlocked(field)\"\n [revision]=\"rev\"\n (clearStagedChange)=\"setSecretClearStaged(field, $event)\"\n ></mm-entity-form-secret-editor>\n } @else {\n @switch (field.editor) {\n @case ('multiline') {\n <kendo-textarea\n [formControl]=\"ctrl\"\n [rows]=\"4\"\n resizable=\"vertical\"\n [placeholder]=\"placeholder(field)\"\n [readonly]=\"ro\"\n ></kendo-textarea>\n }\n @case ('json') {\n <kendo-textarea\n class=\"mm-ef-mono\"\n [formControl]=\"ctrl\"\n [rows]=\"8\"\n resizable=\"vertical\"\n [placeholder]=\"placeholder(field)\"\n [readonly]=\"ro\"\n ></kendo-textarea>\n }\n @case ('yaml') {\n <kendo-textarea\n class=\"mm-ef-mono\"\n [formControl]=\"ctrl\"\n [rows]=\"8\"\n resizable=\"vertical\"\n [placeholder]=\"placeholder(field)\"\n [readonly]=\"ro\"\n ></kendo-textarea>\n }\n @case ('number') {\n <kendo-numerictextbox\n [formControl]=\"ctrl\"\n [decimals]=\"isIntegerField(field) ? 0 : 6\"\n [format]=\"isIntegerField(field) ? 'n0' : 'n'\"\n [placeholder]=\"placeholder(field)\"\n [readonly]=\"ro\"\n ></kendo-numerictextbox>\n }\n @case ('toggle') {\n <kendo-switch\n [formControl]=\"ctrl\"\n [onLabel]=\"m.toggleOn\"\n [offLabel]=\"m.toggleOff\"\n ></kendo-switch>\n }\n @case ('enum') {\n <kendo-dropdownlist\n [formControl]=\"ctrl\"\n [data]=\"field.enumOptions ?? []\"\n textField=\"name\"\n valueField=\"key\"\n [valuePrimitive]=\"true\"\n [defaultItem]=\"enumDefaultItem()\"\n ></kendo-dropdownlist>\n }\n @case ('datetime') {\n <kendo-datetimepicker\n [formControl]=\"ctrl\"\n [placeholder]=\"placeholder(field)\"\n [readOnlyInput]=\"ro\"\n ></kendo-datetimepicker>\n }\n @case ('cron') {\n <mm-cron-builder [formControl]=\"ctrl\"></mm-cron-builder>\n }\n @case ('chips') {\n <mm-entity-form-chips-editor\n [formControl]=\"ctrl\"\n [numeric]=\"isIntArray(field)\"\n [placeholder]=\"field.placeholder ?? m.chipsPlaceholder\"\n [invalidMessage]=\"m.validationNumber\"\n ></mm-entity-form-chips-editor>\n }\n @case ('reference') {\n <mm-entity-form-reference-field\n [formControl]=\"ctrl\"\n [targetCkTypeId]=\"field.reference?.targetCkTypeId ?? ''\"\n [multiple]=\"field.reference?.multiple ?? false\"\n [displayAttributes]=\"field.reference?.displayAttributes ?? noDisplayAttributes\"\n [displayAttributeInfo]=\"field.reference?.displayAttributeInfo ?? noDisplayAttributeInfo\"\n [messages]=\"messages()\"\n [placeholder]=\"field.placeholder ?? m.referencePlaceholder\"\n [readOnly]=\"ro\"\n ></mm-entity-form-reference-field>\n }\n @case ('records') {\n <mm-entity-form-records-field\n [formControl]=\"ctrl\"\n [ckRecordId]=\"field.record?.ckRecordId ?? ''\"\n [columns]=\"field.record?.columns ?? []\"\n [single]=\"field.record?.single ?? false\"\n [readOnly]=\"ro\"\n [secretWritesDisabled]=\"secretWritesDisabled()\"\n [messages]=\"messages()\"\n ></mm-entity-form-records-field>\n }\n @case ('unsupported') {\n <div class=\"mm-ef-unsupported\" [attr.title]=\"m.unsupportedEditor\">\n <span class=\"mm-ef-mono\">{{ displayUnsupported(field) }}</span>\n </div>\n }\n @default {\n <!-- text, password, url, email -->\n <kendo-textbox\n [formControl]=\"ctrl\"\n [type]=\"field.secret || field.editor === 'password' ? 'password' : 'text'\"\n [inputAttributes]=\"field.secret || field.editor === 'password' ? { autocomplete: 'new-password' } : {}\"\n [placeholder]=\"placeholder(field)\"\n [readonly]=\"ro\"\n ></kendo-textbox>\n }\n }\n }\n </mm-entity-form-field>\n }\n }\n </div>\n }\n </section>\n }\n } @empty {\n <p class=\"mm-ef-empty\">{{ m.noFieldsToShow }}</p>\n }\n</form>\n", styles: [":host{display:block}.mm-entity-form{display:flex;flex-direction:column;gap:16px}.mm-ef-section{border:1px solid var(--theme-border-subtle, rgba(0, 0, 0, .12));border-radius:6px;background:var(--theme-ink-02, transparent);padding:12px 16px 16px}.mm-ef-section__header{display:flex;align-items:center;gap:6px;width:100%;margin:0 0 12px;padding:0;border:none;background:none;color:var(--theme-text-primary, inherit);font:inherit;font-weight:600;text-align:left;cursor:pointer}.mm-ef-section__header:focus-visible{outline:2px solid var(--theme-text-accent, currentColor);outline-offset:2px}.mm-ef-section--collapsed .mm-ef-section__header{margin-bottom:0}.mm-ef-section__description{margin:-6px 0 12px;color:var(--theme-text-secondary, inherit);font-size:.9em}.mm-ef-section__grid{display:grid;grid-template-columns:minmax(0,1fr);gap:12px 16px}.mm-ef-section__grid--two{grid-template-columns:repeat(2,minmax(0,1fr))}:host ::ng-deep .mm-ef-field{display:flex;flex-direction:column;gap:4px;min-width:0;grid-column:1/-1}:host ::ng-deep .mm-ef-field--half{grid-column:auto}:host ::ng-deep .mm-ef-field .mm-ef-field__label-row{display:flex;align-items:center;gap:8px}:host ::ng-deep .mm-ef-field .mm-ef-field__label{color:var(--theme-text-secondary, inherit);font-size:.875em;font-weight:500}:host ::ng-deep .mm-ef-field .mm-ef-field__required{color:var(--theme-status-error, currentColor);margin-left:2px}:host ::ng-deep .mm-ef-field .mm-ef-field__badge{padding:0 6px;border-radius:999px;border:1px solid var(--theme-border-strong, currentColor);color:var(--theme-text-muted, inherit);font-size:.75em;line-height:1.6}:host ::ng-deep .mm-ef-field .mm-ef-field__badge--set{border-color:var(--theme-status-success, currentColor);color:var(--theme-status-success, inherit)}:host ::ng-deep .mm-ef-field .mm-ef-field__badge--not-set{border-style:dashed}:host ::ng-deep .mm-ef-field .mm-ef-field__badge--key-missing{border-color:var(--theme-status-warning, currentColor);color:var(--theme-status-warning, inherit)}:host ::ng-deep .mm-ef-field .mm-ef-field__badge--clear-staged{border-style:dashed;border-color:var(--theme-status-error, currentColor);color:var(--theme-status-error, inherit)}:host ::ng-deep .mm-ef-field .mm-ef-field__help{color:var(--theme-text-muted, inherit);font-size:.8em}:host ::ng-deep .mm-ef-field .mm-ef-field__error{color:var(--theme-status-error, inherit);font-size:.8em}:host ::ng-deep .mm-ef-field .mm-ef-field__hint{color:var(--theme-status-warning, inherit);font-size:.8em}:host ::ng-deep .mm-ef-field .mm-ef-field__hint-action{background:none;border:0;padding:0;margin-left:.4em;color:var(--theme-text-accent, inherit);font:inherit;text-decoration:underline;cursor:pointer}:host ::ng-deep .mm-ef-field--readonly .mm-ef-field__editor{opacity:.85}:host ::ng-deep .mm-ef-mono,:host ::ng-deep .mm-ef-mono textarea{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.875em}.mm-ef-unsupported{padding:6px 8px;border-radius:4px;background:var(--theme-ink-04, transparent);color:var(--theme-text-secondary, inherit);overflow-wrap:anywhere}.mm-ef-empty{color:var(--theme-text-muted, inherit)}@media(max-width:720px){.mm-ef-section__grid--two{grid-template-columns:minmax(0,1fr)}:host ::ng-deep .mm-ef-field--half{grid-column:1/-1}}.mm-ef-blocked{margin:0 0 12px;padding:8px 12px;border-left:3px solid var(--theme-status-warning, currentColor);background:color-mix(in srgb,var(--theme-status-warning, #f0ad4e) 10%,transparent);font-size:.875em}:host ::ng-deep .mm-ef-secret{display:flex;flex-direction:column;gap:4px}:host ::ng-deep .mm-ef-secret .mm-ef-secret__row{display:flex;align-items:flex-start;gap:4px}:host ::ng-deep .mm-ef-secret .mm-ef-secret__input{flex:1 1 auto;min-width:0}:host ::ng-deep .mm-ef-secret .mm-ef-secret__input--masked textarea{color:transparent;-webkit-text-fill-color:transparent;text-shadow:none;caret-color:var(--theme-text-primary, CanvasText)}:host ::ng-deep .mm-ef-secret .mm-ef-secret__input--masked textarea::selection{color:transparent;-webkit-text-fill-color:transparent}:host ::ng-deep .mm-ef-secret .mm-ef-secret__input--masked textarea::placeholder{color:var(--theme-text-muted, GrayText);-webkit-text-fill-color:var(--theme-text-muted, GrayText);opacity:1}:host ::ng-deep .mm-ef-secret [data-secret-show]:disabled,:host ::ng-deep .mm-ef-secret [data-secret-clear]:disabled{opacity:.4;cursor:not-allowed}:host ::ng-deep .mm-ef-secret .mm-ef-secret__masked{color:var(--theme-text-muted, inherit);font-size:.8em}:host ::ng-deep .mm-ef-secret .mm-ef-secret__staged{display:flex;align-items:center;gap:8px;color:var(--theme-text-muted, inherit);font-size:.875em}:host ::ng-deep .mm-ef-secret .mm-ef-secret__hint{color:var(--theme-status-warning, inherit);font-size:.8em}\n"] }]
|
|
6406
|
+
}], ctorParameters: () => [], propDecorators: { model: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: true }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], readOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnly", required: false }] }], messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: false }] }], records: [{ type: i0.Input, args: [{ isSignal: true, alias: "records", required: false }] }], labelResolver: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelResolver", required: false }] }], initialValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialValues", required: false }] }], beforeSave: [{ type: i0.Input, args: [{ isSignal: true, alias: "beforeSave", required: false }] }], crossFieldValidators: [{ type: i0.Input, args: [{ isSignal: true, alias: "crossFieldValidators", required: false }] }], fieldErrors: [{ type: i0.Input, args: [{ isSignal: true, alias: "fieldErrors", required: false }] }], fieldHints: [{ type: i0.Input, args: [{ isSignal: true, alias: "fieldHints", required: false }] }], fieldHintAction: [{ type: i0.Output, args: ["fieldHintAction"] }], changeSetChange: [{ type: i0.Output, args: ["changeSetChange"] }], validChange: [{ type: i0.Output, args: ["validChange"] }], dirtyChange: [{ type: i0.Output, args: ["dirtyChange"] }] } });
|
|
6075
6407
|
|
|
6076
6408
|
/** Prefix of the well-known names of delivered forms (`form-sftp-configuration`). */
|
|
6077
6409
|
const FORM_WELL_KNOWN_NAME_PREFIX = 'form-';
|
|
@@ -7866,7 +8198,7 @@ class EntityPageComponent {
|
|
|
7866
8198
|
}
|
|
7867
8199
|
}
|
|
7868
8200
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: EntityPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7869
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: EntityPageComponent, isStandalone: true, selector: "mm-entity-page", inputs: { formKey: { classPropertyName: "formKey", publicName: "formKey", isSignal: true, isRequired: false, transformFunction: null }, ckTypeId: { classPropertyName: "ckTypeId", publicName: "ckTypeId", isSignal: true, isRequired: false, transformFunction: null }, rtId: { classPropertyName: "rtId", publicName: "rtId", isSignal: true, isRequired: false, transformFunction: null }, canWrite: { classPropertyName: "canWrite", publicName: "canWrite", isSignal: true, isRequired: false, transformFunction: null }, messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: false, transformFunction: null }, routerNavigation: { classPropertyName: "routerNavigation", publicName: "routerNavigation", isSignal: true, isRequired: false, transformFunction: null }, actionBarPosition: { classPropertyName: "actionBarPosition", publicName: "actionBarPosition", isSignal: true, isRequired: false, transformFunction: null }, labelResolver: { classPropertyName: "labelResolver", publicName: "labelResolver", isSignal: true, isRequired: false, transformFunction: null }, defaultSort: { classPropertyName: "defaultSort", publicName: "defaultSort", isSignal: true, isRequired: false, transformFunction: null }, initialValues: { classPropertyName: "initialValues", publicName: "initialValues", isSignal: true, isRequired: false, transformFunction: null }, beforeSave: { classPropertyName: "beforeSave", publicName: "beforeSave", isSignal: true, isRequired: false, transformFunction: null }, listToolbarActions: { classPropertyName: "listToolbarActions", publicName: "listToolbarActions", isSignal: true, isRequired: false, transformFunction: null }, listRowActions: { classPropertyName: "listRowActions", publicName: "listRowActions", isSignal: true, isRequired: false, transformFunction: null }, listRowMenuActions: { classPropertyName: "listRowMenuActions", publicName: "listRowMenuActions", isSignal: true, isRequired: false, transformFunction: null }, editMode: { classPropertyName: "editMode", publicName: "editMode", isSignal: true, isRequired: false, transformFunction: null }, listRowClass: { classPropertyName: "listRowClass", publicName: "listRowClass", isSignal: true, isRequired: false, transformFunction: null }, listBooleanDisplay: { classPropertyName: "listBooleanDisplay", publicName: "listBooleanDisplay", isSignal: true, isRequired: false, transformFunction: null }, listRowLabelField: { classPropertyName: "listRowLabelField", publicName: "listRowLabelField", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { navigate: "navigate", saved: "saved", deleted: "deleted" }, providers: [{ provide: HAS_UNSAVED_CHANGES, useExisting: EntityPageComponent }], queries: [{ propertyName: "pageActions", first: true, predicate: EntityPageActionsDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "form", first: true, predicate: ["entityForm"], descendants: true, isSignal: true }, { propertyName: "list", first: true, predicate: ["entityList"], descendants: true, isSignal: true }, { propertyName: "listElement", first: true, predicate: ["entityList"], descendants: true, read: ElementRef, isSignal: true }], ngImport: i0, template: "<div class=\"mm-entity-page\">\n @switch (view()) {\n @case ('loading') {\n <div class=\"mm-entity-page__state\">{{ msgs().loading }}</div>\n }\n\n @case ('error') {\n <div class=\"mm-entity-page__state mm-entity-page__state--error\" role=\"alert\">\n <p>{{ errorMessage() }}</p>\n @if (baseModel() && !isSingleton()) {\n <button kendoButton fillMode=\"flat\" [svgIcon]=\"backIcon\" (click)=\"onBack()\">{{ msgs().back }}</button>\n }\n </div>\n }\n\n @case ('list') {\n @if (baseModel(); as model) {\n <header class=\"mm-entity-page__header\">\n <div class=\"mm-entity-page__titles\">\n <h2 class=\"mm-entity-page__title\">{{ listTitle() }}</h2>\n @if (localizedBase()?.description; as description) {\n <p class=\"mm-entity-page__description\">{{ description }}</p>\n }\n </div>\n @if (pageActions() || canCreateFromList()) {\n <div class=\"mm-entity-page__header-actions\">\n @if (pageActions(); as actions) {\n <div class=\"mm-entity-page__actions\" data-entity-page-host-actions>\n <ng-container *ngTemplateOutlet=\"actions.templateRef; context: actionsContext()\" />\n </div>\n }\n <!-- The page's one solid primary action (AB#6211, action guideline \u00A79). -->\n @if (canCreateFromList()) {\n <button kendoButton type=\"button\" themeColor=\"primary\" [svgIcon]=\"addIcon\"\n data-entity-page-create (click)=\"onCreateFromHeader()\">{{ createLabel() }}</button>\n }\n </div>\n }\n </header>\n <mm-entity-list\n #entityList\n class=\"mm-entity-page__list\"\n [model]=\"model\"\n [canWrite]=\"effectiveCanWrite()\"\n [messages]=\"msgs()\"\n [showTypeColumn]=\"showTypeColumn()\"\n [defaultSort]=\"effectiveDefaultSort()\"\n [labelResolver]=\"effectiveLabelResolver()\"\n [showCreateAction]=\"false\"\n [openAction]=\"effectiveListOpenAction()\"\n [toolbarActions]=\"listToolbarActions()\"\n [rowActions]=\"listRowActions()\"\n [rowMenuActions]=\"listRowMenuActions()\"\n [rowClass]=\"effectiveListRowClass()\"\n [booleanDisplay]=\"effectiveListBooleanDisplay()\"\n [rowLabelField]=\"effectiveRowLabelField()\"\n (createRequested)=\"onCreateRequested($event)\"\n (openRequested)=\"onOpenRequested($event)\"\n />\n\n <!-- Dialog mode (editMode 'dialog', AB#5623): create / edit over the list, actions in the\n dialog's bottom bar (Cancel left of the primary Save, as in the record row dialog). -->\n @if (dialogOpen()) {\n @if (formModel(); as formModelInDialog) {\n <kendo-dialog\n class=\"mm-entity-page__dialog\"\n data-entity-page-dialog\n [title]=\"title()\"\n [width]=\"760\"\n [maxWidth]=\"'95vw'\"\n [maxHeight]=\"'90vh'\"\n (close)=\"onDialogCancel()\"\n >\n <kendo-dialog-messages [closeTitle]=\"msgs().close\" />\n <div class=\"mm-entity-page__dialog-body\">\n @if (mode() === 'view') {\n <p class=\"mm-entity-page__notice\">{{ msgs().readOnlyNotice }}</p>\n }\n <mm-entity-form\n #entityForm\n class=\"mm-entity-page__form\"\n [model]=\"formModelInDialog\"\n [mode]=\"mode()\"\n [state]=\"state()\"\n [readOnly]=\"readOnly()\"\n [messages]=\"msgs()\"\n [records]=\"records()\"\n [labelResolver]=\"effectiveLabelResolver()\"\n [initialValues]=\"createInitialValues()\"\n />\n </div>\n <kendo-dialog-actions>\n @if (pageActions(); as actions) {\n <ng-container *ngTemplateOutlet=\"actions.templateRef; context: dialogActionsContext()\" />\n }\n <button kendoButton type=\"button\" data-entity-page-dialog-cancel (click)=\"onDialogCancel()\">\n {{ mode() === 'view' ? msgs().close : msgs().cancel }}\n </button>\n @if (canDeleteEntity()) {\n <button kendoButton type=\"button\" fillMode=\"outline\" themeColor=\"error\" [svgIcon]=\"deleteIcon\" (click)=\"onDelete()\">\n {{ msgs().delete }}\n </button>\n }\n @if (mode() !== 'view') {\n <button kendoButton type=\"button\" themeColor=\"primary\" [svgIcon]=\"saveIcon\"\n [disabled]=\"saving() || !!saveBlockedReason()\" [attr.title]=\"saveBlockedReason()\"\n data-entity-page-save (click)=\"onSave()\">\n {{ msgs().save }}\n </button>\n }\n </kendo-dialog-actions>\n </kendo-dialog>\n }\n }\n }\n }\n\n @case ('form') {\n @if (formModel(); as model) {\n <header class=\"mm-entity-page__header\">\n <div class=\"mm-entity-page__titles\">\n <h2 class=\"mm-entity-page__title\">{{ title() }}</h2>\n @if (mode() !== 'create' && entityRtId()) {\n <mm-entity-id-info\n [rtId]=\"entityRtId()!\"\n [rtCkTypeId]=\"entityCkTypeId() ?? model.rtCkTypeId\"\n [ckTypeId]=\"entityCkTypeId() ?? model.rtCkTypeId\"\n [buttonText]=\"msgs().copyId\"\n [tooltip]=\"msgs().copyIdTooltip\"\n [copiedMessage]=\"msgs().copiedId\"\n [copyFailedMessage]=\"msgs().copyFailed\"\n />\n }\n </div>\n @if (effectiveActionBarPosition() === 'top') {\n <ng-container *ngTemplateOutlet=\"formActions\" />\n }\n </header>\n @if (mode() === 'view') {\n <p class=\"mm-entity-page__notice\">{{ msgs().readOnlyNotice }}</p>\n }\n @if (mode() === 'create' && singletonWellKnownName()) {\n <p class=\"mm-entity-page__notice\">{{ msgs().singletonCreateHint }}</p>\n }\n <mm-entity-form\n #entityForm\n class=\"mm-entity-page__form\"\n [model]=\"model\"\n [mode]=\"mode()\"\n [state]=\"state()\"\n [readOnly]=\"readOnly()\"\n [messages]=\"msgs()\"\n [records]=\"records()\"\n [labelResolver]=\"effectiveLabelResolver()\"\n [initialValues]=\"createInitialValues()\"\n />\n @if (effectiveActionBarPosition() === 'bottom') {\n <footer class=\"mm-entity-page__footer\" data-entity-page-footer>\n <ng-container *ngTemplateOutlet=\"formActions\" />\n </footer>\n }\n\n <ng-template #formActions>\n <div class=\"mm-entity-page__actions\">\n @if (pageActions(); as actions) {\n <ng-container *ngTemplateOutlet=\"actions.templateRef; context: actionsContext()\" />\n }\n @if (!isSingleton()) {\n <button kendoButton fillMode=\"flat\" [svgIcon]=\"backIcon\" data-entity-page-back (click)=\"onBack()\">\n {{ mode() === 'view' ? msgs().back : msgs().cancel }}\n </button>\n }\n @if (canDeleteEntity()) {\n <button kendoButton fillMode=\"outline\" themeColor=\"error\" [svgIcon]=\"deleteIcon\" (click)=\"onDelete()\">\n {{ msgs().delete }}\n </button>\n }\n @if (mode() !== 'view') {\n <button kendoButton themeColor=\"primary\" [svgIcon]=\"saveIcon\" [disabled]=\"saving() || !!saveBlockedReason()\"\n [attr.title]=\"saveBlockedReason()\" data-entity-page-save (click)=\"onSave()\">\n {{ msgs().save }}\n </button>\n }\n </div>\n </ng-template>\n }\n }\n }\n</div>\n", styles: [":host{display:block;height:100%;min-height:0}.mm-entity-page{display:flex;flex-direction:column;gap:12px;height:100%;min-height:0;padding:16px;box-sizing:border-box;color:var(--theme-text-primary, inherit)}.mm-entity-page__header{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:12px}.mm-entity-page__titles{display:flex;flex-direction:column;gap:4px;min-width:0}.mm-entity-page__title{margin:0;font-size:1.25rem;font-weight:600;overflow-wrap:anywhere}.mm-entity-page__description,.mm-entity-page__notice{margin:0;color:var(--theme-text-secondary, inherit);opacity:.85}.mm-entity-page__actions,.mm-entity-page__header-actions{display:flex;flex-wrap:wrap;gap:8px}.mm-entity-page__list{flex:1 1 auto;min-height:300px}.mm-entity-page__form{flex:1 1 auto;min-height:0;overflow:auto}.mm-entity-page__state{padding:24px 0;color:var(--theme-text-secondary, inherit)}.mm-entity-page__state--error{color:var(--theme-status-error, inherit)}.mm-entity-page__footer{display:flex;justify-content:flex-end;flex-shrink:0;padding-top:12px;border-top:1px solid var(--theme-border-subtle, rgba(0, 0, 0, .12))}.mm-entity-page__dialog-body{display:flex;flex-direction:column;gap:12px}\n"], dependencies: [{ kind: "directive", type: MmDialogActionsDirective, selector: "kendo-dialog-actions" }, { kind: "component", type: EntityListComponent, selector: "mm-entity-list", inputs: ["model", "canWrite", "messages", "listStateKey", "showTypeColumn", "defaultSort", "labelResolver", "toolbarActions", "showCreateAction", "openAction", "rowActions", "rowMenuActions", "rowClass", "booleanDisplay", "rowLabelField"], outputs: ["createRequested", "openRequested", "deleted"] }, { kind: "component", type: EntityFormComponent, selector: "mm-entity-form", inputs: ["model", "mode", "state", "readOnly", "messages", "records", "labelResolver", "initialValues", "beforeSave"], outputs: ["changeSetChange", "validChange", "dirtyChange"] }, { kind: "component", type: EntityIdInfoComponent, selector: "mm-entity-id-info", inputs: ["rtId", "rtCkTypeId", "ckTypeId", "buttonText", "tooltip", "copiedMessage", "copyFailedMessage"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i1$3.DialogComponent, selector: "kendo-dialog", inputs: ["actions", "actionsLayout", "autoFocusedElement", "closable", "title", "width", "minWidth", "maxWidth", "height", "minHeight", "maxHeight", "animation"], outputs: ["action", "close"], exportAs: ["kendoDialog"] }, { kind: "component", type: i1$3.DialogActionsComponent, selector: "kendo-dialog-actions", inputs: ["actions", "layout"], outputs: ["action"] }, { kind: "directive", type: i1$3.CustomMessagesComponent, selector: "kendo-dialog-messages, kendo-window-messages" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
8201
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: EntityPageComponent, isStandalone: true, selector: "mm-entity-page", inputs: { formKey: { classPropertyName: "formKey", publicName: "formKey", isSignal: true, isRequired: false, transformFunction: null }, ckTypeId: { classPropertyName: "ckTypeId", publicName: "ckTypeId", isSignal: true, isRequired: false, transformFunction: null }, rtId: { classPropertyName: "rtId", publicName: "rtId", isSignal: true, isRequired: false, transformFunction: null }, canWrite: { classPropertyName: "canWrite", publicName: "canWrite", isSignal: true, isRequired: false, transformFunction: null }, messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: false, transformFunction: null }, routerNavigation: { classPropertyName: "routerNavigation", publicName: "routerNavigation", isSignal: true, isRequired: false, transformFunction: null }, actionBarPosition: { classPropertyName: "actionBarPosition", publicName: "actionBarPosition", isSignal: true, isRequired: false, transformFunction: null }, labelResolver: { classPropertyName: "labelResolver", publicName: "labelResolver", isSignal: true, isRequired: false, transformFunction: null }, defaultSort: { classPropertyName: "defaultSort", publicName: "defaultSort", isSignal: true, isRequired: false, transformFunction: null }, initialValues: { classPropertyName: "initialValues", publicName: "initialValues", isSignal: true, isRequired: false, transformFunction: null }, beforeSave: { classPropertyName: "beforeSave", publicName: "beforeSave", isSignal: true, isRequired: false, transformFunction: null }, listToolbarActions: { classPropertyName: "listToolbarActions", publicName: "listToolbarActions", isSignal: true, isRequired: false, transformFunction: null }, listRowActions: { classPropertyName: "listRowActions", publicName: "listRowActions", isSignal: true, isRequired: false, transformFunction: null }, listRowMenuActions: { classPropertyName: "listRowMenuActions", publicName: "listRowMenuActions", isSignal: true, isRequired: false, transformFunction: null }, editMode: { classPropertyName: "editMode", publicName: "editMode", isSignal: true, isRequired: false, transformFunction: null }, listRowClass: { classPropertyName: "listRowClass", publicName: "listRowClass", isSignal: true, isRequired: false, transformFunction: null }, listBooleanDisplay: { classPropertyName: "listBooleanDisplay", publicName: "listBooleanDisplay", isSignal: true, isRequired: false, transformFunction: null }, listRowLabelField: { classPropertyName: "listRowLabelField", publicName: "listRowLabelField", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { navigate: "navigate", saved: "saved", deleted: "deleted" }, providers: [{ provide: HAS_UNSAVED_CHANGES, useExisting: EntityPageComponent }], queries: [{ propertyName: "pageActions", first: true, predicate: EntityPageActionsDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "form", first: true, predicate: ["entityForm"], descendants: true, isSignal: true }, { propertyName: "list", first: true, predicate: ["entityList"], descendants: true, isSignal: true }, { propertyName: "listElement", first: true, predicate: ["entityList"], descendants: true, read: ElementRef, isSignal: true }], ngImport: i0, template: "<div class=\"mm-entity-page\">\n @switch (view()) {\n @case ('loading') {\n <div class=\"mm-entity-page__state\">{{ msgs().loading }}</div>\n }\n\n @case ('error') {\n <div class=\"mm-entity-page__state mm-entity-page__state--error\" role=\"alert\">\n <p>{{ errorMessage() }}</p>\n @if (baseModel() && !isSingleton()) {\n <button kendoButton fillMode=\"flat\" [svgIcon]=\"backIcon\" (click)=\"onBack()\">{{ msgs().back }}</button>\n }\n </div>\n }\n\n @case ('list') {\n @if (baseModel(); as model) {\n <header class=\"mm-entity-page__header\">\n <div class=\"mm-entity-page__titles\">\n <h2 class=\"mm-entity-page__title\">{{ listTitle() }}</h2>\n @if (localizedBase()?.description; as description) {\n <p class=\"mm-entity-page__description\">{{ description }}</p>\n }\n </div>\n @if (pageActions() || canCreateFromList()) {\n <div class=\"mm-entity-page__header-actions\">\n @if (pageActions(); as actions) {\n <div class=\"mm-entity-page__actions\" data-entity-page-host-actions>\n <ng-container *ngTemplateOutlet=\"actions.templateRef; context: actionsContext()\" />\n </div>\n }\n <!-- The page's one solid primary action (AB#6211, action guideline \u00A79). -->\n @if (canCreateFromList()) {\n <button kendoButton type=\"button\" themeColor=\"primary\" [svgIcon]=\"addIcon\"\n data-entity-page-create (click)=\"onCreateFromHeader()\">{{ createLabel() }}</button>\n }\n </div>\n }\n </header>\n <mm-entity-list\n #entityList\n class=\"mm-entity-page__list\"\n [model]=\"model\"\n [canWrite]=\"effectiveCanWrite()\"\n [messages]=\"msgs()\"\n [showTypeColumn]=\"showTypeColumn()\"\n [defaultSort]=\"effectiveDefaultSort()\"\n [labelResolver]=\"effectiveLabelResolver()\"\n [showCreateAction]=\"false\"\n [openAction]=\"effectiveListOpenAction()\"\n [toolbarActions]=\"listToolbarActions()\"\n [rowActions]=\"listRowActions()\"\n [rowMenuActions]=\"listRowMenuActions()\"\n [rowClass]=\"effectiveListRowClass()\"\n [booleanDisplay]=\"effectiveListBooleanDisplay()\"\n [rowLabelField]=\"effectiveRowLabelField()\"\n (createRequested)=\"onCreateRequested($event)\"\n (openRequested)=\"onOpenRequested($event)\"\n />\n\n <!-- Dialog mode (editMode 'dialog', AB#5623): create / edit over the list, actions in the\n dialog's bottom bar (Cancel left of the primary Save, as in the record row dialog). -->\n @if (dialogOpen()) {\n @if (formModel(); as formModelInDialog) {\n <kendo-dialog\n class=\"mm-entity-page__dialog\"\n data-entity-page-dialog\n [title]=\"title()\"\n [width]=\"760\"\n [maxWidth]=\"'95vw'\"\n [maxHeight]=\"'90vh'\"\n (close)=\"onDialogCancel()\"\n >\n <kendo-dialog-messages [closeTitle]=\"msgs().close\" />\n <div class=\"mm-entity-page__dialog-body\">\n @if (mode() === 'view') {\n <p class=\"mm-entity-page__notice\">{{ msgs().readOnlyNotice }}</p>\n }\n <mm-entity-form\n #entityForm\n class=\"mm-entity-page__form\"\n [model]=\"formModelInDialog\"\n [mode]=\"mode()\"\n [state]=\"state()\"\n [readOnly]=\"readOnly()\"\n [messages]=\"msgs()\"\n [records]=\"records()\"\n [labelResolver]=\"effectiveLabelResolver()\"\n [initialValues]=\"createInitialValues()\"\n />\n </div>\n <kendo-dialog-actions>\n @if (pageActions(); as actions) {\n <ng-container *ngTemplateOutlet=\"actions.templateRef; context: dialogActionsContext()\" />\n }\n <button kendoButton type=\"button\" data-entity-page-dialog-cancel (click)=\"onDialogCancel()\">\n {{ mode() === 'view' ? msgs().close : msgs().cancel }}\n </button>\n @if (canDeleteEntity()) {\n <button kendoButton type=\"button\" fillMode=\"outline\" themeColor=\"error\" [svgIcon]=\"deleteIcon\" (click)=\"onDelete()\">\n {{ msgs().delete }}\n </button>\n }\n @if (mode() !== 'view') {\n <button kendoButton type=\"button\" themeColor=\"primary\" [svgIcon]=\"saveIcon\"\n [disabled]=\"saving() || !!saveBlockedReason()\" [attr.title]=\"saveBlockedReason()\"\n data-entity-page-save (click)=\"onSave()\">\n {{ msgs().save }}\n </button>\n }\n </kendo-dialog-actions>\n </kendo-dialog>\n }\n }\n }\n }\n\n @case ('form') {\n @if (formModel(); as model) {\n <header class=\"mm-entity-page__header\">\n <div class=\"mm-entity-page__titles\">\n <h2 class=\"mm-entity-page__title\">{{ title() }}</h2>\n @if (mode() !== 'create' && entityRtId()) {\n <mm-entity-id-info\n [rtId]=\"entityRtId()!\"\n [rtCkTypeId]=\"entityCkTypeId() ?? model.rtCkTypeId\"\n [ckTypeId]=\"entityCkTypeId() ?? model.rtCkTypeId\"\n [buttonText]=\"msgs().copyId\"\n [tooltip]=\"msgs().copyIdTooltip\"\n [copiedMessage]=\"msgs().copiedId\"\n [copyFailedMessage]=\"msgs().copyFailed\"\n />\n }\n </div>\n @if (effectiveActionBarPosition() === 'top') {\n <ng-container *ngTemplateOutlet=\"formActions\" />\n }\n </header>\n @if (mode() === 'view') {\n <p class=\"mm-entity-page__notice\">{{ msgs().readOnlyNotice }}</p>\n }\n @if (mode() === 'create' && singletonWellKnownName()) {\n <p class=\"mm-entity-page__notice\">{{ msgs().singletonCreateHint }}</p>\n }\n <mm-entity-form\n #entityForm\n class=\"mm-entity-page__form\"\n [model]=\"model\"\n [mode]=\"mode()\"\n [state]=\"state()\"\n [readOnly]=\"readOnly()\"\n [messages]=\"msgs()\"\n [records]=\"records()\"\n [labelResolver]=\"effectiveLabelResolver()\"\n [initialValues]=\"createInitialValues()\"\n />\n @if (effectiveActionBarPosition() === 'bottom') {\n <footer class=\"mm-entity-page__footer\" data-entity-page-footer>\n <ng-container *ngTemplateOutlet=\"formActions\" />\n </footer>\n }\n\n <ng-template #formActions>\n <div class=\"mm-entity-page__actions\">\n @if (pageActions(); as actions) {\n <ng-container *ngTemplateOutlet=\"actions.templateRef; context: actionsContext()\" />\n }\n @if (!isSingleton()) {\n <button kendoButton fillMode=\"flat\" [svgIcon]=\"backIcon\" data-entity-page-back (click)=\"onBack()\">\n {{ mode() === 'view' ? msgs().back : msgs().cancel }}\n </button>\n }\n @if (canDeleteEntity()) {\n <button kendoButton fillMode=\"outline\" themeColor=\"error\" [svgIcon]=\"deleteIcon\" (click)=\"onDelete()\">\n {{ msgs().delete }}\n </button>\n }\n @if (mode() !== 'view') {\n <button kendoButton themeColor=\"primary\" [svgIcon]=\"saveIcon\" [disabled]=\"saving() || !!saveBlockedReason()\"\n [attr.title]=\"saveBlockedReason()\" data-entity-page-save (click)=\"onSave()\">\n {{ msgs().save }}\n </button>\n }\n </div>\n </ng-template>\n }\n }\n }\n</div>\n", styles: [":host{display:block;height:100%;min-height:0}.mm-entity-page{display:flex;flex-direction:column;gap:12px;height:100%;min-height:0;padding:16px;box-sizing:border-box;color:var(--theme-text-primary, inherit)}.mm-entity-page__header{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:12px}.mm-entity-page__titles{display:flex;flex-direction:column;gap:4px;min-width:0}.mm-entity-page__title{margin:0;font-size:1.25rem;font-weight:600;overflow-wrap:anywhere}.mm-entity-page__description,.mm-entity-page__notice{margin:0;color:var(--theme-text-secondary, inherit);opacity:.85}.mm-entity-page__actions,.mm-entity-page__header-actions{display:flex;flex-wrap:wrap;gap:8px}.mm-entity-page__list{flex:1 1 auto;min-height:300px}.mm-entity-page__form{flex:1 1 auto;min-height:0;overflow:auto}.mm-entity-page__state{padding:24px 0;color:var(--theme-text-secondary, inherit)}.mm-entity-page__state--error{color:var(--theme-status-error, inherit)}.mm-entity-page__footer{display:flex;justify-content:flex-end;flex-shrink:0;padding-top:12px;border-top:1px solid var(--theme-border-subtle, rgba(0, 0, 0, .12))}.mm-entity-page__dialog-body{display:flex;flex-direction:column;gap:12px}\n"], dependencies: [{ kind: "directive", type: MmDialogActionsDirective, selector: "kendo-dialog-actions" }, { kind: "component", type: EntityListComponent, selector: "mm-entity-list", inputs: ["model", "canWrite", "messages", "listStateKey", "showTypeColumn", "defaultSort", "labelResolver", "toolbarActions", "showCreateAction", "openAction", "rowActions", "rowMenuActions", "rowClass", "booleanDisplay", "rowLabelField"], outputs: ["createRequested", "openRequested", "deleted"] }, { kind: "component", type: EntityFormComponent, selector: "mm-entity-form", inputs: ["model", "mode", "state", "readOnly", "messages", "records", "labelResolver", "initialValues", "beforeSave", "crossFieldValidators", "fieldErrors", "fieldHints"], outputs: ["fieldHintAction", "changeSetChange", "validChange", "dirtyChange"] }, { kind: "component", type: EntityIdInfoComponent, selector: "mm-entity-id-info", inputs: ["rtId", "rtCkTypeId", "ckTypeId", "buttonText", "tooltip", "copiedMessage", "copyFailedMessage"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i1$3.DialogComponent, selector: "kendo-dialog", inputs: ["actions", "actionsLayout", "autoFocusedElement", "closable", "title", "width", "minWidth", "maxWidth", "height", "minHeight", "maxHeight", "animation"], outputs: ["action", "close"], exportAs: ["kendoDialog"] }, { kind: "component", type: i1$3.DialogActionsComponent, selector: "kendo-dialog-actions", inputs: ["actions", "layout"], outputs: ["action"] }, { kind: "directive", type: i1$3.CustomMessagesComponent, selector: "kendo-dialog-messages, kendo-window-messages" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
7870
8202
|
}
|
|
7871
8203
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: EntityPageComponent, decorators: [{
|
|
7872
8204
|
type: Component,
|
|
@@ -7993,5 +8325,5 @@ function entityFormRoutes(opts = {}) {
|
|
|
7993
8325
|
* Generated bundle index. Do not edit.
|
|
7994
8326
|
*/
|
|
7995
8327
|
|
|
7996
|
-
export { BUILT_IN_DEFAULT_FORM, DEFAULT_ENTITY_FORMS_MESSAGES, DEFAULT_GENERATED_SECTION_TITLE, DEFAULT_SECTION_KEY, ENTITY_FORM_ACTION_CONFIRMATION, ENTITY_FORM_BEFORE_SAVE, ENTITY_FORM_DANGER_CONFIRMATION, ENTITY_FORM_FALLBACK_FORMS, ENTITY_FORM_LABEL_RESOLVER, ENTITY_FORM_SECRET_KEY_RING_CONFIGURED, ENTITY_FORM_SECRET_PLACEHOLDER_VALUES, ENTITY_FORM_UNSET_PLACEHOLDER_VALUES, ENTITY_LIST_ROW_CLASS, ENTITY_PAGE_NEW, ENTITY_PAGE_TYPE_QUERY_PARAM, EntityFormComponent, EntityFormDataService, EntityFormRecordsFieldComponent, EntityFormReferenceFieldComponent, EntityFormSaveVeto, EntityFormSecretEditorComponent, EntityFormService, EntityListComponent, EntityListDataSourceDirective, EntityPageActionsDirective, EntityPageComponent, GENERATED_SECTION_KEY, SYSTEM_PROPERTIES, associationFieldKey, associationRoleName, autoEditorFor, buildChangeSet, canonicaliseEntityFormPrefill, canonicalisePath, ckTypeDisplayName, ckTypeShortName, confirmEntityFormAction, confirmEntityFormDanger, entityDeleteConfirmation, entityFormCatalog, entityFormKey, entityFormPrefillState, entityFormRoutes, entityFormTypeTitles, entityFormUnsetPlaceholderFields, entityFormUnsetPlaceholderLookup, entityListAttributeNames, entityListCreateLabel, entityListIncludesDerivedTypes, formatEntityFormsMessage, humanizeCkTypeName, isChainEndForm, isEditorCompatible, isEntityFormSaveVeto, isEntityFormUnsetPlaceholder, isSecretMetaData, isVisible, localizeEntityForm, localizeEntityFormTitle, localizeEntityListColumns, mergeEntityFormPrefill, mergeEntityFormsMessages, parseDefault, parseEntityForm, parseEntityForms, parseVisibleWhen, pickEntityForm, provideEntityFormFallbacks, resolveEntityForm, resolveEntityFormLabel, resolveListDefaultSort, runEntityFormBeforeSave, secretMetaDataMarker, secretStatusLabelsOf, selectFallbackForms, shortTypeName, toAttributeInputs, toCkRecordInfo, toCkTypeInfo, toEntityListColumn, toEntityListRow, toFormValue, toKebabTypeKey, toListViewRowClass, withFallbackForms };
|
|
8328
|
+
export { BUILT_IN_DEFAULT_FORM, DEFAULT_ENTITY_FORMS_MESSAGES, DEFAULT_GENERATED_SECTION_TITLE, DEFAULT_SECTION_KEY, ENTITY_FORM_ACTION_CONFIRMATION, ENTITY_FORM_BEFORE_SAVE, ENTITY_FORM_CROSS_FIELD_VALIDATORS, ENTITY_FORM_DANGER_CONFIRMATION, ENTITY_FORM_FALLBACK_FORMS, ENTITY_FORM_LABEL_RESOLVER, ENTITY_FORM_SECRET_KEY_RING_CONFIGURED, ENTITY_FORM_SECRET_PLACEHOLDER_VALUES, ENTITY_FORM_UNSET_PLACEHOLDER_VALUES, ENTITY_LIST_ROW_CLASS, ENTITY_PAGE_NEW, ENTITY_PAGE_TYPE_QUERY_PARAM, EntityFormComponent, EntityFormDataService, EntityFormRecordsFieldComponent, EntityFormReferenceFieldComponent, EntityFormSaveVeto, EntityFormSecretEditorComponent, EntityFormService, EntityListComponent, EntityListDataSourceDirective, EntityPageActionsDirective, EntityPageComponent, GENERATED_SECTION_KEY, SYSTEM_PROPERTIES, associationFieldKey, associationRoleName, autoEditorFor, buildChangeSet, canonicaliseEntityFormPrefill, canonicalisePath, ckTypeDisplayName, ckTypeShortName, confirmEntityFormAction, confirmEntityFormDanger, crossFieldValidatorApplies, entityDeleteConfirmation, entityFormCatalog, entityFormKey, entityFormPrefillState, entityFormRoutes, entityFormTypeTitles, entityFormUnsetPlaceholderFields, entityFormUnsetPlaceholderLookup, entityListAttributeNames, entityListCreateLabel, entityListIncludesDerivedTypes, flattenCrossFieldValidators, formatEntityFormsMessage, humanizeCkTypeName, isChainEndForm, isEditorCompatible, isEntityFormSaveVeto, isEntityFormUnsetPlaceholder, isSecretMetaData, isVisible, localizeEntityForm, localizeEntityFormTitle, localizeEntityListColumns, mergeEntityFormPrefill, mergeEntityFormsMessages, parseDefault, parseEntityForm, parseEntityForms, parseVisibleWhen, pickEntityForm, provideEntityFormCrossFieldValidators, provideEntityFormFallbacks, resolveEntityForm, resolveEntityFormLabel, resolveListDefaultSort, runCrossFieldValidators, runEntityFormBeforeSave, secretMetaDataMarker, secretStatusLabelsOf, selectFallbackForms, shortTypeName, toAttributeInputs, toCkRecordInfo, toCkTypeInfo, toEntityListColumn, toEntityListRow, toFormValue, toKebabTypeKey, toListViewRowClass, withFallbackForms };
|
|
7997
8329
|
//# sourceMappingURL=meshmakers-octo-ui-entity-forms.mjs.map
|