@alauda-fe/crd-form 0.0.8 → 1.0.1-alpha.0

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.
Files changed (99) hide show
  1. package/README.md +7 -0
  2. package/fesm2022/alauda-fe-crd-form.mjs +3088 -0
  3. package/fesm2022/alauda-fe-crd-form.mjs.map +1 -0
  4. package/package.json +12 -14
  5. package/types/alauda-fe-crd-form.d.ts +934 -0
  6. package/esm2022/alauda-fe-crd-form.mjs +0 -5
  7. package/esm2022/lib/abstract/base-array.mjs +0 -117
  8. package/esm2022/lib/crd-form/component.mjs +0 -325
  9. package/esm2022/lib/crd-form/helper.mjs +0 -32
  10. package/esm2022/lib/crd-form.module.mjs +0 -115
  11. package/esm2022/lib/field-controls/expressions/expression-core.mjs +0 -2
  12. package/esm2022/lib/field-controls/expressions/props-expression.mjs +0 -58
  13. package/esm2022/lib/field-controls/form-item.component.mjs +0 -215
  14. package/esm2022/lib/field-controls/index.mjs +0 -8
  15. package/esm2022/lib/field-controls/module.mjs +0 -143
  16. package/esm2022/lib/field-controls/operand-advanced-field-group.component.mjs +0 -80
  17. package/esm2022/lib/field-controls/operand-array-field-group.component.mjs +0 -112
  18. package/esm2022/lib/field-controls/operand-field-group.component.mjs +0 -88
  19. package/esm2022/lib/field-controls/operand-field.component.mjs +0 -877
  20. package/esm2022/lib/field-controls/widgets/array-table/component.mjs +0 -109
  21. package/esm2022/lib/field-controls/widgets/basic-auth-secret/component.mjs +0 -116
  22. package/esm2022/lib/field-controls/widgets/basic-auth-secret/create/component.mjs +0 -211
  23. package/esm2022/lib/field-controls/widgets/basic-auth-secret/type.mjs +0 -2
  24. package/esm2022/lib/field-controls/widgets/index.mjs +0 -8
  25. package/esm2022/lib/field-controls/widgets/k8s-resource-prefix/component.mjs +0 -169
  26. package/esm2022/lib/field-controls/widgets/k8s-resource-prefix/util.mjs +0 -40
  27. package/esm2022/lib/field-controls/widgets/link/component.mjs +0 -68
  28. package/esm2022/lib/field-controls/widgets/resource-requirements/resource-requirements.component.mjs +0 -521
  29. package/esm2022/lib/field-controls/widgets/utils.mjs +0 -73
  30. package/esm2022/lib/field-controls/widgets/yaml-editor/yaml-editor.component.mjs +0 -94
  31. package/esm2022/lib/field-widgets/htpasswd/component.mjs +0 -40
  32. package/esm2022/lib/field-widgets/htpasswd/form.mjs +0 -240
  33. package/esm2022/lib/field-widgets/htpasswd/index.mjs +0 -4
  34. package/esm2022/lib/field-widgets/htpasswd/module.mjs +0 -54
  35. package/esm2022/lib/field-widgets/htpasswd/utils.mjs +0 -38
  36. package/esm2022/lib/field-widgets/index.mjs +0 -2
  37. package/esm2022/lib/remote-widgets/constants.mjs +0 -4
  38. package/esm2022/lib/remote-widgets/index.mjs +0 -4
  39. package/esm2022/lib/remote-widgets/remote-widget.service.mjs +0 -42
  40. package/esm2022/lib/remote-widgets/token.mjs +0 -7
  41. package/esm2022/lib/spec-descriptors/capability/capability.component.mjs +0 -139
  42. package/esm2022/lib/spec-descriptors/capability-list/capability-list.component.mjs +0 -189
  43. package/esm2022/lib/spec-descriptors/index.mjs +0 -4
  44. package/esm2022/lib/spec-descriptors/util.mjs +0 -13
  45. package/esm2022/lib/types/index.mjs +0 -89
  46. package/esm2022/lib/utils/capability.mjs +0 -306
  47. package/esm2022/lib/utils/constant.mjs +0 -22
  48. package/esm2022/lib/utils/helper.mjs +0 -196
  49. package/esm2022/lib/utils/index.mjs +0 -6
  50. package/esm2022/lib/utils/service-model.mjs +0 -12
  51. package/esm2022/lib/utils/util.mjs +0 -307
  52. package/esm2022/public-api.mjs +0 -13
  53. package/index.d.ts +0 -5
  54. package/lib/abstract/base-array.d.ts +0 -31
  55. package/lib/crd-form/component.d.ts +0 -58
  56. package/lib/crd-form/helper.d.ts +0 -7
  57. package/lib/crd-form.module.d.ts +0 -15
  58. package/lib/field-controls/expressions/expression-core.d.ts +0 -6
  59. package/lib/field-controls/expressions/props-expression.d.ts +0 -36
  60. package/lib/field-controls/form-item.component.d.ts +0 -19
  61. package/lib/field-controls/index.d.ts +0 -7
  62. package/lib/field-controls/module.d.ts +0 -23
  63. package/lib/field-controls/operand-advanced-field-group.component.d.ts +0 -16
  64. package/lib/field-controls/operand-array-field-group.component.d.ts +0 -8
  65. package/lib/field-controls/operand-field-group.component.d.ts +0 -21
  66. package/lib/field-controls/operand-field.component.d.ts +0 -109
  67. package/lib/field-controls/widgets/array-table/component.d.ts +0 -8
  68. package/lib/field-controls/widgets/basic-auth-secret/component.d.ts +0 -26
  69. package/lib/field-controls/widgets/basic-auth-secret/create/component.d.ts +0 -45
  70. package/lib/field-controls/widgets/basic-auth-secret/type.d.ts +0 -11
  71. package/lib/field-controls/widgets/index.d.ts +0 -7
  72. package/lib/field-controls/widgets/k8s-resource-prefix/component.d.ts +0 -35
  73. package/lib/field-controls/widgets/k8s-resource-prefix/util.d.ts +0 -3
  74. package/lib/field-controls/widgets/link/component.d.ts +0 -20
  75. package/lib/field-controls/widgets/resource-requirements/resource-requirements.component.d.ts +0 -85
  76. package/lib/field-controls/widgets/utils.d.ts +0 -17
  77. package/lib/field-controls/widgets/yaml-editor/yaml-editor.component.d.ts +0 -36
  78. package/lib/field-widgets/htpasswd/component.d.ts +0 -9
  79. package/lib/field-widgets/htpasswd/form.d.ts +0 -34
  80. package/lib/field-widgets/htpasswd/index.d.ts +0 -3
  81. package/lib/field-widgets/htpasswd/module.d.ts +0 -13
  82. package/lib/field-widgets/htpasswd/utils.d.ts +0 -15
  83. package/lib/field-widgets/index.d.ts +0 -1
  84. package/lib/remote-widgets/constants.d.ts +0 -3
  85. package/lib/remote-widgets/index.d.ts +0 -3
  86. package/lib/remote-widgets/remote-widget.service.d.ts +0 -28
  87. package/lib/remote-widgets/token.d.ts +0 -3
  88. package/lib/spec-descriptors/capability/capability.component.d.ts +0 -20
  89. package/lib/spec-descriptors/capability-list/capability-list.component.d.ts +0 -34
  90. package/lib/spec-descriptors/index.d.ts +0 -3
  91. package/lib/spec-descriptors/util.d.ts +0 -4
  92. package/lib/types/index.d.ts +0 -136
  93. package/lib/utils/capability.d.ts +0 -62
  94. package/lib/utils/constant.d.ts +0 -12
  95. package/lib/utils/helper.d.ts +0 -58
  96. package/lib/utils/index.d.ts +0 -5
  97. package/lib/utils/service-model.d.ts +0 -44
  98. package/lib/utils/util.d.ts +0 -44
  99. package/public-api.d.ts +0 -9
@@ -0,0 +1,3088 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, forwardRef, ChangeDetectorRef, Input, ChangeDetectionStrategy, Component, EventEmitter, Output, ViewChild, Injector, HostBinding, Directive, NgModule } from '@angular/core';
3
+ import { escapeRegExp, get, includes, some, cloneDeep, map, reduce, find, set, last, isEmpty, identity, toPath, flatten, times, isArray, flatMap, flatMapDepth, union, pick, startCase, parseInt as parseInt$1, uniqWith, groupBy, sortBy, omit, merge, template, differenceBy, uniq, flattenDeep, fromPairs, toString } from 'lodash-es';
4
+ import { __decorate, __metadata } from 'tslib';
5
+ import * as i2 from '@alauda/ui';
6
+ import { FormModule, IconModule, TooltipModule, ButtonModule, DIALOG_DATA, DialogRef, MessageService, InputModule, DialogModule, DialogService, DialogSize, SelectModule, TagModule, RadioModule, SwitchModule, LabelPosition } from '@alauda/ui';
7
+ import * as i4 from '@alauda-fe/dynamic-plugin-sdk';
8
+ import { parseJSONStream, TRUE, FALSE, parseJson, isEqual, PurePipe, TranslatePipe, K8sApiService, TranslateService, K8S_RESOURCE_NAME_BASE, SecretType, COMMON_RESOURCE_DEFINITIONS, K8sUtilService, publishRef, skipError, ObservableInput, K8S_UTIL_PIPES_MODULE, TOKEN_RESOURCE_DEFINITIONS, ValueHook, SanitizePipe, FieldNotAvailablePipe, bind, stringify, parse, API_GATEWAY, startWithCondition } from '@alauda-fe/dynamic-plugin-sdk';
9
+ import * as i2$1 from '@alauda-fe/dynamic-plugin-shared';
10
+ import { isJsonObjectString, ErrorsMapperComponent, HelpDocDirective, ARRAY_FORM_TABLE_MODULE, StrongPasswordDirective, createNestedFormControl, formatCPU, formatMemory, resourceUnits, getResourceValue, getResourceViewModel, initGreaterValidator, transferResource, RESOURCE_MAC_TYPES, PasswordInputComponent, ReadonlyFieldDirective, ParseJsonTranslatePipe, ScrollToFirstInvalidDirective, ErrorsMapperDirective } from '@alauda-fe/dynamic-plugin-shared';
11
+ import * as i1 from '@angular/forms';
12
+ import { FormBuilder, Validators, FormsModule, ReactiveFormsModule, FormGroupDirective, NG_VALUE_ACCESSOR, ControlContainer, FormControl } from '@angular/forms';
13
+ import { isImmutable, fromJS, Map as Map$1, List } from 'immutable';
14
+ import { finalize, filter, map as map$1, Subject, combineLatest, startWith, switchMap, takeUntil, Observable, BehaviorSubject, pluck, tap, of, debounceTime, distinctUntilChanged, isObservable, take } from 'rxjs';
15
+ import { CodeEditorComponent, yamlWriteOptions, createActions, viewActions, yamlReadOptions } from '@alauda/code-editor';
16
+ import * as i1$1 from '@angular/common';
17
+ import { CommonModule } from '@angular/common';
18
+ import { HttpClient } from '@angular/common/http';
19
+ import { encode, decode } from 'ab64';
20
+ import { BaseResourceFormComponent, BaseResourceFormGroupComponent } from 'ng-resource-form-util';
21
+ import { hashSync } from 'bcryptjs';
22
+
23
+ var Validations;
24
+ (function (Validations) {
25
+ Validations["maximum"] = "maximum";
26
+ Validations["minimum"] = "minimum";
27
+ Validations["maxLength"] = "maxLength";
28
+ Validations["minLength"] = "minLength";
29
+ Validations["pattern"] = "pattern";
30
+ Validations["required"] = "required";
31
+ })(Validations || (Validations = {}));
32
+ const SpecCapabilityUIPrefix = 'urn:alm:descriptor:com.tectonic.ui';
33
+ const SpecCapabilityWidgetsPrefix = 'urn:alm:descriptor:widgets';
34
+ var SpecCapability;
35
+ (function (SpecCapability) {
36
+ /**
37
+ * 表单 UI 控件
38
+ */
39
+ // 基础 UI 控件
40
+ SpecCapability["text"] = "urn:alm:descriptor:com.tectonic.ui:text";
41
+ SpecCapability["textarea"] = "urn:alm:descriptor:com.tectonic.ui:textarea";
42
+ SpecCapability["yaml"] = "urn:alm:descriptor:com.tectonic.ui:yaml";
43
+ SpecCapability["number"] = "urn:alm:descriptor:com.tectonic.ui:number";
44
+ SpecCapability["podCount"] = "urn:alm:descriptor:com.tectonic.ui:podCount";
45
+ SpecCapability["booleanSwitch"] = "urn:alm:descriptor:com.tectonic.ui:booleanSwitch";
46
+ SpecCapability["radio"] = "urn:alm:descriptor:com.tectonic.ui:radio:";
47
+ SpecCapability["tagsInput"] = "urn:alm:descriptor:com.tectonic.ui:tagsInput";
48
+ SpecCapability["select"] = "urn:alm:descriptor:com.tectonic.ui:select:";
49
+ SpecCapability["password"] = "urn:alm:descriptor:com.tectonic.ui:password";
50
+ SpecCapability["confirmPassword"] = "urn:alm:descriptor:com.tectonic.ui:password:confirm";
51
+ SpecCapability["externalPassword"] = "urn:alm:descriptor:com.tectonic.ui:externalPassword";
52
+ // 高级 UI 控件 widgets
53
+ SpecCapability["widgets"] = "urn:alm:descriptor:widgets:";
54
+ SpecCapability["remote"] = "urn:alm:descriptor:remote:";
55
+ SpecCapability["k8sResourcePrefix"] = "urn:alm:descriptor:io.kubernetes:";
56
+ SpecCapability["basicAuthSecret"] = "urn:alm:descriptor:com.tectonic.ui:basicAuthSecret";
57
+ SpecCapability["resourceRequirements"] = "urn:alm:descriptor:com.tectonic.ui:resourceRequirements";
58
+ SpecCapability["arrayFieldGroup"] = "urn:alm:descriptor:com.tectonic.ui:arrayFieldGroup:";
59
+ SpecCapability["arrayTable"] = "urn:alm:descriptor:widgets:common:arrayTable";
60
+ SpecCapability["array"] = "urn:alm:descriptor:com.tectonic.ui:array";
61
+ /**
62
+ * @deprecated
63
+ */
64
+ SpecCapability["object"] = "urn:alm:descriptor:com.tectonic.ui:object";
65
+ /**
66
+ * aui-form 表单元素
67
+ */
68
+ SpecCapability["label"] = "urn:alm:descriptor:label:";
69
+ SpecCapability["description"] = "urn:alm:descriptor:description:";
70
+ SpecCapability["placeholder"] = "urn:alm:descriptor:placeholder:";
71
+ SpecCapability["tooltip"] = "urn:alm:descriptor:tooltip:";
72
+ SpecCapability["descriptionAsLink"] = "urn:alm:descriptor:descriptionAsLink";
73
+ SpecCapability["docOption"] = "urn:alm:descriptor:docOption:";
74
+ SpecCapability["docLink"] = "urn:alm:descriptor:docLink:";
75
+ SpecCapability["validation"] = "urn:alm:descriptor:com.tectonic.ui:validation:";
76
+ SpecCapability["copyable"] = "urn:alm:descriptor:copyable";
77
+ /**
78
+ * 表单布局/控制能力
79
+ */
80
+ SpecCapability["hidden"] = "urn:alm:descriptor:com.tectonic.ui:hidden";
81
+ SpecCapability["defaultValue"] = "urn:alm:descriptor:com.tectonic.default:";
82
+ SpecCapability["fieldGroup"] = "urn:alm:descriptor:com.tectonic.ui:fieldGroup:";
83
+ SpecCapability["advanced"] = "urn:alm:descriptor:com.tectonic.ui:advanced";
84
+ SpecCapability["fieldDependency"] = "urn:alm:descriptor:com.tectonic.ui:fieldDependency:";
85
+ SpecCapability["oneOf"] = "urn:alm:descriptor:oneOf:";
86
+ /**
87
+ * UI 控件特性扩展
88
+ */
89
+ SpecCapability["expression"] = "urn:alm:descriptor:expression:";
90
+ // urn:alm:descriptor:yaml:actions:disabled:diffMode,recover
91
+ SpecCapability["yamlActionsDisabled"] = "urn:alm:descriptor:yaml:actions:disabled:";
92
+ // urn:alm:descriptor:yaml:result:json
93
+ // urn:alm:descriptor:yaml:result:stringify
94
+ SpecCapability["yamlResult"] = "urn:alm:descriptor:yaml:result:";
95
+ // object 和 array 组件折叠, 默认为展开
96
+ SpecCapability["folded"] = "urn:alm:descriptor:com.tectonic.ui:folded";
97
+ // array 组件在没有 Value 的前提下支持不保留首项
98
+ SpecCapability["emptyArray"] = "urn:alm:descriptor:com.tectonic.ui:emptyArray";
99
+ // 用于支持复数场景,如 multiselect,tags-input 等
100
+ SpecCapability["multiple"] = "urn:alm:descriptor:com.tectonic.ui:multiple";
101
+ SpecCapability["allowCreate"] = "urn:alm:descriptor:com.tectonic.ui:allowCreate";
102
+ SpecCapability["creatable"] = "urn:alm:descriptor:com.tectonic.ui:creatable";
103
+ SpecCapability["clearable"] = "urn:alm:descriptor:com.tectonic.ui:clearable";
104
+ SpecCapability["disabled"] = "urn:alm:descriptor:com.tectonic.ui:disabled";
105
+ /**
106
+ * 其他
107
+ */
108
+ // 用于做control唯一识别的依据,缺省情况下 path 将作为依据
109
+ SpecCapability["pathTag"] = "urn:alm:descriptor:com.tectonic.ui:path.tag:";
110
+ })(SpecCapability || (SpecCapability = {}));
111
+
112
+ const NodeModel = {
113
+ apiVersion: 'v1',
114
+ label: 'Node',
115
+ labelKey: 'public~Node',
116
+ plural: 'nodes',
117
+ abbr: 'N',
118
+ kind: 'Node',
119
+ id: 'node',
120
+ labelPlural: 'Nodes',
121
+ labelPluralKey: 'public~Nodes',
122
+ };
123
+
124
+ var ServiceModels = /*#__PURE__*/Object.freeze({
125
+ __proto__: null,
126
+ NodeModel: NodeModel
127
+ });
128
+
129
+ const MAX_DEPTH = 1;
130
+ const SCHEMA_PATH = ['properties', 'spec'];
131
+ const DESCRIPTOR_DEFINITION_KEY = 'x-descriptors';
132
+ const NamespacedResourceKind = Object.values(ServiceModels)
133
+ .filter(i => i.namespaced)
134
+ .map(i => i.kind);
135
+ // Regex for SpecCapability.arrayFieldGroup and SpecCapability.fieldGroup
136
+ const ARRAY_FIELD_GROUP_PATTERN = escapeRegExp(SpecCapability.arrayFieldGroup);
137
+ const FIELD_GROUP_PATTERN = escapeRegExp(SpecCapability.fieldGroup);
138
+ const GROUP_PATTERN = new RegExp(`^(${FIELD_GROUP_PATTERN}|${ARRAY_FIELD_GROUP_PATTERN})(.*)$`);
139
+ const DEFAULT_VALUE_PATTERN = new RegExp(`^${escapeRegExp(SpecCapability.defaultValue)}(.*)$`);
140
+ const REGEXP_K8S_RESOURCE_CAPABILITY = escapeRegExp(SpecCapability.k8sResourcePrefix);
141
+ const REGEXP_CAPABILITY_VALIDATION = escapeRegExp(SpecCapability.validation);
142
+ const REGEXP_FIELD_DEPENDENCY_CAPABILITY = escapeRegExp(SpecCapability.fieldDependency);
143
+ const REGEXP_SELECT_CAPABILITY = escapeRegExp(SpecCapability.select);
144
+ const REGEXP_K8S_RESOURCE_SUFFIX = new RegExp(`^${REGEXP_K8S_RESOURCE_CAPABILITY}(?:core[:~]v1[:~])?([^?]*)(?:\\?\\+)?([^?]*)?(?:\\?\\=)?([^?]*)?$`);
145
+ const SupportValidation = Object.values(Validations).join('|');
146
+ const REGEXP_VALIDATION_SUFFIX = new RegExp(`^${REGEXP_CAPABILITY_VALIDATION}(${SupportValidation})(?::(.+))?$`);
147
+
148
+ const isRequired = (field) => field?.required ||
149
+ Object.keys(field?.validations || {})?.includes(Validations.required);
150
+ const filterMapByKey = (map, predicate) => {
151
+ const m = new Map();
152
+ map.forEach((v, k) => {
153
+ if (predicate(k)) {
154
+ m.set(k, v);
155
+ }
156
+ });
157
+ return m;
158
+ };
159
+ const getMatchArrayIndex = (arrPath) => {
160
+ const matched = arrPath.match(/(^.*)\[(\d+)]$/);
161
+ return +get(matched, '[2]', 0);
162
+ };
163
+ const isGroupField = (field) => field.type === 'object';
164
+ const isArrayField = (field) => field.type === 'array';
165
+ const isRemoteField = (field) => field.capabilities.some(c => c.startsWith(SpecCapability.remote));
166
+ const isArrayFieldTable = (field) => isArrayField(field) &&
167
+ field.capabilities.some(c => c.startsWith(SpecCapability.arrayTable));
168
+ const isCreatable = (field) => field.capabilities.some(c => c.startsWith(SpecCapability.creatable));
169
+ const isMultiple = (field) => field.capabilities.some(c => c.startsWith(SpecCapability.multiple));
170
+ const isAllowCreate = (field) => field.capabilities.some(c => c.startsWith(SpecCapability.allowCreate));
171
+ const isClearable = (field) => field.capabilities.some(c => c.startsWith(SpecCapability.clearable));
172
+ const isFolded = (field) => field.capabilities.some(c => c.startsWith(SpecCapability.folded));
173
+ const isEmptyArray = (field) => field.capabilities.some(c => c.startsWith(SpecCapability.emptyArray));
174
+ function hasDescriptor(field, prefix, suffix = null) {
175
+ return suffix
176
+ ? includes(field.capabilities, `${prefix}${suffix}`)
177
+ : some(field.capabilities, capability => capability.startsWith(prefix));
178
+ }
179
+ /*
180
+ * Matches a path that contains an array index. Use Sting.match against an OperandField 'path'
181
+ * property to determine if it contains an array index. It will parse the path into three parts,
182
+ * [match, pathBeforeIndex, index, pathAfterIndex]. For example:
183
+ *
184
+ * const [match, pathBeforeIndex, index, pathAfterIndex] =
185
+ * 'path.before[0].path.after'.match(ARRAY_INDEX_PATTERN);
186
+ *
187
+ * console.log(match);
188
+ * > 'path.before[0].path.after'
189
+ *
190
+ * console.log(pathBeforeIndex);
191
+ * > 'path.before'
192
+ *
193
+ * console.log(index)
194
+ * > '0'
195
+ *
196
+ * console.log(pathAfterIndex)
197
+ * > 'path.after'
198
+ *
199
+ */
200
+ const ARRAY_INDEX_PATTERN = /^(.*)\[(\d+)]\.?(.*)$/;
201
+ function parseArrayPath(path) {
202
+ const [match, pathBeforeIndex, index, pathAfterIndex] = ARRAY_INDEX_PATTERN.exec(path) || [];
203
+ return match
204
+ ? { index: parseInt(index, 10), match, pathBeforeIndex, pathAfterIndex }
205
+ : { match };
206
+ }
207
+ function getArrayGroupName(field) {
208
+ if (hasDescriptor(field, SpecCapability.arrayFieldGroup)) {
209
+ return field.capabilities
210
+ .find(capability => capability.startsWith(SpecCapability.arrayFieldGroup))
211
+ .slice(SpecCapability.arrayFieldGroup.length);
212
+ }
213
+ return '';
214
+ }
215
+ function getGroupName(field) {
216
+ if (hasDescriptor(field, SpecCapability.fieldGroup)) {
217
+ return field.capabilities
218
+ .find(capability => capability.startsWith(SpecCapability.fieldGroup))
219
+ .slice(SpecCapability.fieldGroup.length);
220
+ }
221
+ return '';
222
+ }
223
+ /**
224
+ * 递归修复树形结构中 数组类型的索引
225
+ *
226
+ * @export
227
+ * @param {OperandField} field
228
+ * @param {string} fromPath
229
+ * @param {string} toPath
230
+ * @returns
231
+ *
232
+ */
233
+ const repairFieldChildPathByCorrectIndex = (field, fromPath, toPath) => {
234
+ const targetField = cloneDeep(field);
235
+ if (isGroupField(targetField)) {
236
+ targetField.fieldList = map(targetField.fieldList, f => ({
237
+ ...f,
238
+ path: f.path.replace(fromPath, toPath),
239
+ }));
240
+ }
241
+ else if (isArrayField(targetField)) {
242
+ targetField.fieldLists = reduce(targetField.fieldLists, (t, c) => [
243
+ ...t,
244
+ map(c, f => repairFieldChildPathByCorrectIndex(f, fromPath, toPath)),
245
+ ], []);
246
+ }
247
+ return {
248
+ ...targetField,
249
+ path: targetField.path.replace(fromPath, toPath),
250
+ };
251
+ };
252
+ const getRelatedFields = (normalFields) => map(normalFields, field => {
253
+ if (getArrayGroupName(field)) {
254
+ const { pathBeforeIndex, index } = parseArrayPath(field.path);
255
+ return {
256
+ ...field,
257
+ parent: pathBeforeIndex,
258
+ inParentIndex: index,
259
+ };
260
+ }
261
+ if (getGroupName(field)) {
262
+ const groupNameFromDefinition = `spec.${getGroupName(field)}`;
263
+ const parent = field.path.slice(0, groupNameFromDefinition.length);
264
+ return {
265
+ ...field,
266
+ parent,
267
+ };
268
+ }
269
+ return field;
270
+ });
271
+ const getTreeFields = (rootFields, basicFields) => {
272
+ if (basicFields.length > 0) {
273
+ return rootFields.reduce((acc, field) => {
274
+ field._dirty = true;
275
+ const children = basicFields.filter(f => f.parent === field.path);
276
+ children.forEach(c => (c._dirty = true));
277
+ if (isArrayField(field)) {
278
+ field.fieldLists = children
279
+ .reduce((acc, child) => {
280
+ acc[child.inParentIndex] = [
281
+ ...(acc[child.inParentIndex] || []),
282
+ child,
283
+ ];
284
+ return acc;
285
+ }, [])
286
+ .map(m => getTreeFields(m, basicFields.filter(f => !f._dirty)));
287
+ }
288
+ else if (isGroupField(field)) {
289
+ field.fieldList = getTreeFields(children, basicFields.filter(f => !f._dirty));
290
+ }
291
+ return [...acc, field];
292
+ }, []);
293
+ }
294
+ return rootFields.map(f => {
295
+ f._dirty = true;
296
+ return f;
297
+ });
298
+ };
299
+ const getMatchedCapabilityValue = (capabilities, descriptor) => capabilities
300
+ .find(capability => capability.startsWith(descriptor))
301
+ ?.slice(descriptor.length) || '';
302
+ function evalInContext(stringExpression, context) {
303
+ // replace eval, skip eslint & sonar safe check
304
+ function evil(fn) {
305
+ const Fn = Function;
306
+ return new Fn(`return ${fn}`);
307
+ }
308
+ try {
309
+ return evil(stringExpression).call(context);
310
+ }
311
+ catch {
312
+ console.error('expression is invalid:', stringExpression);
313
+ return stringExpression;
314
+ }
315
+ }
316
+ function coerceBoolean(val) {
317
+ return val === 'true';
318
+ }
319
+ function coerceNumber(val, fallbackValue = 0) {
320
+ return _isNumberValue(val) ? Number(val) : fallbackValue;
321
+ }
322
+ function _isNumberValue(value) {
323
+ // parseFloat(value) handles most of the cases we're interested in (it treats null, empty string,
324
+ // and other non-number values as NaN, where Number just uses 0) but it considers the string
325
+ // '123hello' to be a valid number. Therefore we also check if Number(value) is NaN.
326
+ return (!isNaN(typeof value === 'string' && parseFloat(value)) &&
327
+ !isNaN(Number(value)));
328
+ }
329
+ function getOperandPath(field) {
330
+ const idField = field?.capabilities.find(c => c.startsWith(SpecCapability.pathTag));
331
+ if (idField) {
332
+ return `${field.path}@${idField.slice(SpecCapability.pathTag.length)}`;
333
+ }
334
+ return field.path;
335
+ }
336
+ function getPathFromTagPath(pathWithTag) {
337
+ return pathWithTag.split('@')[0];
338
+ }
339
+ // 获取path下所有的filed,例如spec.a 能匹配到 spec.a.a1 spec.a.a2
340
+ const getFieldsByPath = (path, fields) => fields.filter(field => getOperandPath(field).startsWith(path));
341
+
342
+ function getBasicAuthSecretConfig(field) {
343
+ const configPrefix = `${SpecCapability.basicAuthSecret}:`;
344
+ const capability = find(field.capabilities, descriptor => descriptor.startsWith(configPrefix));
345
+ if (!capability) {
346
+ return null;
347
+ }
348
+ const configStr = capability.slice(configPrefix.length);
349
+ return parseJSONStream(configStr)[0];
350
+ }
351
+ function getRadioOptions(capabilities) {
352
+ const items = capabilities
353
+ .filter(c => c.startsWith(SpecCapability.radio))
354
+ .map(c => c.split(SpecCapability.radio)[1]);
355
+ return items
356
+ .filter(item => item.split(':').length === 1)
357
+ .map(item => {
358
+ const zhPrefix = `${item}:zh:`;
359
+ const enPrefix = `${item}:en:`;
360
+ const zhDescriptor = items.find(value => value.startsWith(zhPrefix));
361
+ const enDescriptor = items.find(value => value.startsWith(enPrefix));
362
+ return {
363
+ value: item,
364
+ display: {
365
+ zh: zhDescriptor ? zhDescriptor.split(zhPrefix)[1] : item,
366
+ en: enDescriptor ? enDescriptor.split(enPrefix)[1] : item,
367
+ },
368
+ };
369
+ });
370
+ }
371
+ function setRadiosDefaultValue(descriptors) {
372
+ // Set radio default selected item
373
+ const defaultValueMap = (descriptors || [])
374
+ .filter(d => d[DESCRIPTOR_DEFINITION_KEY].some(item => item.startsWith(SpecCapability.radio)))
375
+ .map(item => ({
376
+ path: item.path,
377
+ value: item[DESCRIPTOR_DEFINITION_KEY].filter(c => c.startsWith(SpecCapability.radio))
378
+ .map(c => c.split(SpecCapability.radio)[1])
379
+ .find(c => c.split(':').length === 1),
380
+ }))
381
+ .reduce((acc, cur) => ({
382
+ ...set(acc, cur.path, cur.value),
383
+ }), {});
384
+ return {
385
+ spec: {
386
+ ...defaultValueMap,
387
+ },
388
+ };
389
+ }
390
+ const getBooleanSwitchOptions = (capabilities) => {
391
+ const items = capabilities
392
+ .filter(c => c.startsWith(SpecCapability.booleanSwitch))
393
+ .map(c => c.split(SpecCapability.booleanSwitch)[1]);
394
+ return [TRUE, FALSE].map(item => {
395
+ const zhPrefix = `:${item}:zh:`;
396
+ const enPrefix = `:${item}:en:`;
397
+ const zhDescriptor = items.find(value => value.startsWith(zhPrefix));
398
+ const enDescriptor = items.find(value => value.startsWith(enPrefix));
399
+ return {
400
+ value: item,
401
+ display: zhDescriptor && enDescriptor
402
+ ? {
403
+ zh: zhDescriptor ? zhDescriptor.split(zhPrefix)[1] : item,
404
+ en: enDescriptor ? enDescriptor.split(enPrefix)[1] : item,
405
+ }
406
+ : item === TRUE
407
+ ? 'yes'
408
+ : 'no',
409
+ };
410
+ });
411
+ };
412
+ const convertBooleanSwitchValue = (value, capabilities) => {
413
+ const options = getBooleanSwitchOptions(capabilities);
414
+ return options.find(item => item.value === (value ? TRUE : FALSE))?.display;
415
+ };
416
+ function convertValue(value, type) {
417
+ switch (type) {
418
+ case 'number':
419
+ case 'integer': {
420
+ return coerceNumber(value);
421
+ }
422
+ case 'boolean': {
423
+ return coerceBoolean(value);
424
+ }
425
+ default: {
426
+ // 兼容 value 为 json 字符串的情况
427
+ return isJsonObjectString(value)
428
+ ? parseJson(value, value)
429
+ : value || undefined;
430
+ }
431
+ }
432
+ }
433
+ function getDefaultValue(field) {
434
+ const defaultValueDescriptor = find(field.capabilities, descriptor => descriptor.startsWith(SpecCapability.defaultValue));
435
+ if (defaultValueDescriptor) {
436
+ const [, value] = DEFAULT_VALUE_PATTERN.exec(defaultValueDescriptor) || [];
437
+ return convertValue(value, field.type);
438
+ }
439
+ }
440
+ const UI_FIELDS = [
441
+ SpecCapability.text,
442
+ {
443
+ spec: `${SpecCapability.text}:link`,
444
+ refer: SpecCapability.text,
445
+ },
446
+ {
447
+ spec: `${SpecCapability.text}:link:`,
448
+ prefix: true,
449
+ },
450
+ SpecCapability.password,
451
+ SpecCapability.confirmPassword,
452
+ SpecCapability.externalPassword,
453
+ SpecCapability.number,
454
+ SpecCapability.textarea,
455
+ {
456
+ spec: SpecCapability.podCount,
457
+ refer: SpecCapability.number,
458
+ },
459
+ SpecCapability.booleanSwitch,
460
+ {
461
+ spec: SpecCapability.select,
462
+ prefix: true,
463
+ },
464
+ SpecCapability.resourceRequirements,
465
+ SpecCapability.yaml,
466
+ SpecCapability.object,
467
+ SpecCapability.array,
468
+ {
469
+ spec: SpecCapability.radio,
470
+ prefix: true,
471
+ },
472
+ {
473
+ spec: SpecCapability.k8sResourcePrefix,
474
+ prefix: true,
475
+ },
476
+ {
477
+ spec: SpecCapability.basicAuthSecret,
478
+ prefix: true,
479
+ },
480
+ {
481
+ spec: SpecCapability.widgets,
482
+ prefix: true,
483
+ },
484
+ {
485
+ spec: SpecCapability.remote,
486
+ prefix: true,
487
+ },
488
+ {
489
+ spec: SpecCapability.tagsInput,
490
+ prefix: true,
491
+ },
492
+ ];
493
+ function getFieldType(field) {
494
+ const { capabilities } = field;
495
+ const result = UI_FIELDS.find(specField => {
496
+ if (typeof specField === 'string') {
497
+ return capabilities.includes(specField);
498
+ }
499
+ return specField.prefix
500
+ ? capabilities.some(c => c.startsWith(specField.spec))
501
+ : capabilities.includes(specField.spec);
502
+ });
503
+ return typeof result === 'string' ? result : (result?.refer ?? result?.spec);
504
+ }
505
+ function getBasicCapabilityType(capabilities) {
506
+ if (capabilities.includes(SpecCapability.text)) {
507
+ return 'string';
508
+ }
509
+ if (capabilities.includes(SpecCapability.number) ||
510
+ capabilities.includes(SpecCapability.podCount)) {
511
+ return 'number';
512
+ }
513
+ if (capabilities.includes(SpecCapability.booleanSwitch)) {
514
+ return 'boolean';
515
+ }
516
+ if (capabilities.includes(SpecCapability.object)) {
517
+ return 'object';
518
+ }
519
+ if (capabilities.includes(SpecCapability.array)) {
520
+ return 'array';
521
+ }
522
+ }
523
+ function getDisplayByCapability(capabilities, name, fallback) {
524
+ const enDes = `${name}en:`;
525
+ const zhDes = `${name}zh:`;
526
+ const en = find(capabilities, descriptor => descriptor.startsWith(enDes))?.split(enDes)?.[1];
527
+ const zh = find(capabilities, descriptor => descriptor.startsWith(zhDes))?.split(zhDes)?.[1];
528
+ return en || zh
529
+ ? { en: en || zh || fallback, zh: zh || en || fallback }
530
+ : fallback
531
+ ? { en: fallback, zh: fallback }
532
+ : null;
533
+ }
534
+ function getFieldDisplayName(field) {
535
+ return getDisplayByCapability(field.capabilities, SpecCapability.label, field.displayName ?? '');
536
+ }
537
+ function getFieldDescription$1(field) {
538
+ return getDisplayByCapability(field.capabilities, SpecCapability.description, field.description ?? '');
539
+ }
540
+ function getFieldPlaceholder$1(field) {
541
+ return getDisplayByCapability(field.capabilities, SpecCapability.placeholder);
542
+ }
543
+ function getFieldTooltip(field) {
544
+ return getDisplayByCapability(field.capabilities, SpecCapability.tooltip);
545
+ }
546
+ function isFieldCopyable(field) {
547
+ return !!find(field.capabilities, descriptor => descriptor === SpecCapability.copyable);
548
+ }
549
+ function isFieldDescriptionAsLink(field) {
550
+ return !!find(field.capabilities, descriptor => descriptor === SpecCapability.descriptionAsLink);
551
+ }
552
+ function getFieldDocLink(field) {
553
+ const docLinkDescriptor = find(field.capabilities, descriptor => descriptor.startsWith(SpecCapability.docLink));
554
+ if (docLinkDescriptor) {
555
+ return docLinkDescriptor.split(SpecCapability.docLink)[1];
556
+ }
557
+ }
558
+ // cspell:disable-next-line
559
+ // k8s params should conform to urn:alm:descriptor:io.kubernetes:Secret?=isGlobal=true:labelSelector=plugins.cpaas.io%2Fvictoriametrics%3Dtrue
560
+ // : is used by dividing meta params and queryParams,both should be url encoded(percent encoding)
561
+ const K8S_RESOURCE_META_PARAMS_DIVIDER = ':';
562
+ function getK8sResourcePrefixOptions(field) {
563
+ const capability = find(field.capabilities, descriptor => descriptor.startsWith(SpecCapability.k8sResourcePrefix));
564
+ const multiple = field.capabilities.some(descriptor => descriptor.startsWith(SpecCapability.multiple));
565
+ const validations = getCapabilityValidations(field.capabilities);
566
+ const [, resource, , qComponents] = capability.match(REGEXP_K8S_RESOURCE_SUFFIX) ?? [];
567
+ const groupVersionKind = resource?.replace(/:/g, '~');
568
+ const kind = last(groupVersionKind.split('~'));
569
+ const [metaStr, queryParamsStr] = (qComponents ?? '').split(K8S_RESOURCE_META_PARAMS_DIVIDER);
570
+ const meta = resolveKVParams(metaStr);
571
+ const queryParams = resolveKVParams(queryParamsStr);
572
+ return {
573
+ namespaced: NamespacedResourceKind.includes(kind),
574
+ labelSelector: queryParams.labelSelector,
575
+ isGlobal: !!meta.isGlobal,
576
+ groupVersionKind, // 现有的 apiversion,apiGroup 皆由环境配置,可以暂时不用
577
+ type: last(groupVersionKind.split('~')),
578
+ multiple,
579
+ validations,
580
+ };
581
+ }
582
+ // resolve a=b&c=d 格式数据
583
+ function resolveKVParams(str) {
584
+ return (str || '')
585
+ .split('&')
586
+ .filter(i => !isEmpty(i))
587
+ .reduce((acc, curr) => {
588
+ const [k, v] = curr.split('=');
589
+ acc[k] = decodeURIComponent(v);
590
+ return acc;
591
+ }, {});
592
+ }
593
+ function getCapabilityDisabled(capabilities) {
594
+ return capabilities.includes(SpecCapability.disabled);
595
+ }
596
+ function getCapabilityValidations(capabilities) {
597
+ const validations = capabilities?.filter(c => c.startsWith(SpecCapability.validation));
598
+ return validations.reduce((acc, descriptor) => {
599
+ const [, validation, param] = descriptor.match(REGEXP_VALIDATION_SUFFIX) ?? [];
600
+ if (!validation) {
601
+ return acc;
602
+ }
603
+ if (validation === Validations.pattern) {
604
+ acc[validation] = param;
605
+ }
606
+ else if (validation === Validations.required) {
607
+ acc[validation] = Boolean(param);
608
+ }
609
+ else {
610
+ acc[validation] = +param;
611
+ }
612
+ return acc;
613
+ }, {});
614
+ }
615
+ function getOneOfMap(field) {
616
+ const map = {};
617
+ const capabilities = field.capabilities.filter(c => c.startsWith(SpecCapability.oneOf));
618
+ capabilities.forEach(c => {
619
+ const str = c.split(SpecCapability.oneOf)[1];
620
+ // 这里 path 与后端约束直接支持 path@tag 模式
621
+ const [value, ...path] = str.split(':');
622
+ map[value] = [...path];
623
+ });
624
+ return map;
625
+ }
626
+ function fieldShouldReveal(field) {
627
+ return (!field.capabilities.includes(SpecCapability.hidden) &&
628
+ identity(getFieldType(field)));
629
+ }
630
+
631
+ function getPropertyDepth(property, depth = 0) {
632
+ if (!property || !['object', 'array'].includes(property.type)) {
633
+ return depth;
634
+ }
635
+ return Math.max(0, ...Object.values(property.properties || property.items?.properties || {}).map(nestedProperty => getPropertyDepth(nestedProperty, depth + 1)));
636
+ }
637
+ function getFieldsFromDescriptor({ path, description, displayName, 'x-descriptors': capabilities = [], }, data, openApi, _originDescriptors) {
638
+ const { match, pathBeforeIndex, pathAfterIndex } = parseArrayPath(path);
639
+ const filedBasicType = getBasicCapabilityType(capabilities);
640
+ const disabled = getCapabilityDisabled(capabilities);
641
+ const validations = getCapabilityValidations(capabilities);
642
+ if (match) {
643
+ const n = get(data, toPath(`spec.${pathBeforeIndex}`), []).length || 1;
644
+ const pathAfterIndexStr = `.${pathAfterIndex}`;
645
+ let extra = [];
646
+ if (_originDescriptors) {
647
+ extra = flatten(_originDescriptors
648
+ .filter(d => d.path.startsWith(`${pathBeforeIndex}[0]`) && d.path !== path)
649
+ .map(d => times(n, index => {
650
+ const oPath = d.path.replace(`${pathBeforeIndex}[0]`, `${pathBeforeIndex}[${index}]`);
651
+ return {
652
+ ...d,
653
+ path: oPath,
654
+ };
655
+ }).slice(1)));
656
+ }
657
+ return flatten([
658
+ ...times(n, index => {
659
+ const propertyPath = `spec.${pathBeforeIndex}[${index}]${pathAfterIndex && pathAfterIndexStr}`;
660
+ const property = getOpenApiPropertyByPath(`spec.${path}`, openApi);
661
+ return {
662
+ path: propertyPath,
663
+ value: get(data, propertyPath),
664
+ description,
665
+ displayName,
666
+ capabilities,
667
+ type: filedBasicType || property?.type,
668
+ required: null,
669
+ disabled,
670
+ validations: {
671
+ ...validations,
672
+ ...(property?.required && { required: true }),
673
+ },
674
+ };
675
+ }),
676
+ ...extra.map(e => getFieldsFromDescriptor(e, data, openApi)),
677
+ ]);
678
+ }
679
+ // 通过 descriptor 查找原始 CRD 节点,推导类型、validation 等信息
680
+ const propertyPath = `spec.${path}`;
681
+ const property = getOpenApiPropertyByPath(propertyPath, openApi);
682
+ return [
683
+ {
684
+ path: propertyPath,
685
+ description,
686
+ displayName,
687
+ capabilities,
688
+ disabled,
689
+ value: get(data, propertyPath),
690
+ type: filedBasicType || property?.type,
691
+ required: null,
692
+ validations: {
693
+ ...validations,
694
+ ...(property?.required && { required: true }),
695
+ },
696
+ },
697
+ ];
698
+ }
699
+ function getOpenApiPropertyByPath(descriptorPath, openApi) {
700
+ const paths = descriptorPath.split('.');
701
+ try {
702
+ return paths.reduce((acc, path) => {
703
+ acc = path.includes('[0]')
704
+ ? acc.items.properties[path.split('[0]')[0]]
705
+ : acc.properties[path];
706
+ return acc;
707
+ }, openApi);
708
+ }
709
+ catch {
710
+ return null;
711
+ }
712
+ }
713
+ function getFieldsFromOpenApiSchema(openApi, descriptors, data, openApiSchemaPath = SCHEMA_PATH, maxDepth = MAX_DEPTH) {
714
+ const path = isArray(openApiSchemaPath)
715
+ ? openApiSchemaPath
716
+ : openApiSchemaPath.split('.').filter(Boolean);
717
+ const properties = get(openApi, [...path, 'properties'], {});
718
+ const required = get(openApi, [...path, 'required'], []);
719
+ return reduce(properties, (accumulator, _property, propertyName) => {
720
+ const property = _property;
721
+ if (!property.type || getPropertyDepth(property) > maxDepth) {
722
+ return accumulator;
723
+ }
724
+ return [
725
+ ...accumulator,
726
+ ...flattenNestedProperties(propertyName, property, descriptors, data, {
727
+ required: required.includes(propertyName),
728
+ }),
729
+ ];
730
+ }, []);
731
+ }
732
+ function flattenNestedProperties(propertyName, property, descriptors, data, { currentCapabilities = [], currentPath = [], required = false, }) {
733
+ if (!property) {
734
+ return [];
735
+ }
736
+ const handleObjectProperty = () => flatMap(property.properties, (nestedProperty, nestedPropertyName) => flattenNestedProperties(nestedPropertyName, nestedProperty, descriptors, data, {
737
+ currentCapabilities: [
738
+ ...currentCapabilities,
739
+ `${SpecCapability.fieldGroup}${propertyName}`,
740
+ ],
741
+ currentPath: [...currentPath, propertyName],
742
+ required: (property.required || []).includes(nestedPropertyName),
743
+ }));
744
+ const handleArrayProperty = () => {
745
+ // Find the number of array elements that are already defined in the provided object
746
+ const n = get(data, `spec.${currentPath.join('.')}${propertyName}`, []).length || 1;
747
+ // Since _.times will return a multidimensional array of OperandFields (OperandField[][]), we
748
+ // need to flatten one level deeper than _.flatMap provides.
749
+ return flatMapDepth(property.items.properties, (nestedProperty, nestedPropertyName) =>
750
+ // Repeat recursion (n) times so that the correct number of fields are created for
751
+ // existing values in obj. This ensures that further nested fields also get created.
752
+ times(n, index => flattenNestedProperties(nestedPropertyName, nestedProperty, descriptors, data, {
753
+ currentCapabilities: [
754
+ ...currentCapabilities,
755
+ `${SpecCapability.arrayFieldGroup}${propertyName}`,
756
+ ],
757
+ currentPath: [...currentPath, `${propertyName}[${index}]`], // Array field paths must include an index
758
+ required: (property?.required || []).includes(nestedPropertyName),
759
+ })), 2);
760
+ };
761
+ const handleAtomicProperty = () => {
762
+ const path = [...currentPath, propertyName].join('.');
763
+ const descriptor = descriptors.find(item => item.path === modifyArrayFieldPathIndex(path, () => 0));
764
+ const capabilities = union(descriptor?.[DESCRIPTOR_DEFINITION_KEY] || [], currentCapabilities, getCapabilitiesForOpenApiProperty(property, descriptor?.[DESCRIPTOR_DEFINITION_KEY]));
765
+ const validations = getCapabilityValidations(capabilities);
766
+ const fieldPath = `spec.${path}`;
767
+ return [
768
+ {
769
+ path: fieldPath,
770
+ type: property.type,
771
+ required,
772
+ capabilities,
773
+ description: descriptor?.description || property.description,
774
+ displayName: descriptor?.displayName || startCase(propertyName),
775
+ validations: {
776
+ ...pick(property, Object.keys(Validations)),
777
+ ...validations,
778
+ },
779
+ value: get(data, fieldPath),
780
+ },
781
+ ];
782
+ };
783
+ switch (property.type) {
784
+ case 'object': {
785
+ return handleObjectProperty();
786
+ }
787
+ case 'array': {
788
+ return handleArrayProperty();
789
+ }
790
+ default: {
791
+ return handleAtomicProperty();
792
+ }
793
+ }
794
+ }
795
+ // Accepts an OpenAPI spec property and returns a corresponding SpecCapability[] array.
796
+ function getCapabilitiesForOpenApiProperty(property, capabilities = []) {
797
+ const formControlCapabilities = [
798
+ SpecCapabilityUIPrefix,
799
+ SpecCapabilityWidgetsPrefix,
800
+ SpecCapability.k8sResourcePrefix,
801
+ ];
802
+ if (capabilities.some(i => formControlCapabilities.some(k => i.startsWith(k)))) {
803
+ return [];
804
+ }
805
+ if (property.enum) {
806
+ return (property.enum || []).map((option) => `${SpecCapability.select}${option}`);
807
+ }
808
+ switch (property.type) {
809
+ case 'integer': {
810
+ return [SpecCapability.number];
811
+ }
812
+ case 'boolean': {
813
+ return [SpecCapability.booleanSwitch];
814
+ }
815
+ default: {
816
+ return [SpecCapability.text];
817
+ }
818
+ }
819
+ }
820
+ function modifyArrayFieldPathIndex(path, operation) {
821
+ const { match, index, pathBeforeIndex, pathAfterIndex } = parseArrayPath(path);
822
+ const pathAfterIndexStr = `.${pathAfterIndex}`;
823
+ return match
824
+ ? `${pathBeforeIndex}[${operation(index)}]${pathAfterIndex && pathAfterIndexStr}`
825
+ : path;
826
+ }
827
+ function pathToArray(path) {
828
+ return map(toPath(path), subPath => /^\d+$/.test(subPath) ? parseInt$1(subPath, 10) : subPath);
829
+ }
830
+ function parseGroupDescriptor(field) {
831
+ const groupDescriptor = find(field.capabilities, descriptor => descriptor.startsWith(SpecCapability.fieldGroup) ||
832
+ descriptor.startsWith(SpecCapability.arrayFieldGroup));
833
+ const [match, groupType, groupName] = GROUP_PATTERN.exec(groupDescriptor) || [];
834
+ return { match, groupName, groupType };
835
+ }
836
+ function normalizePath(path) {
837
+ return path?.startsWith('spec.') ? path : `spec.${path}`;
838
+ }
839
+ function getFormData(formData, path, enableConvert = true) {
840
+ const value = formData.getIn(pathToArray(normalizePath(path)));
841
+ return enableConvert && value == null ? null : value;
842
+ }
843
+ function createCapabilityField(descriptors = [], openApiSchema, data, openApiSchemaPath) {
844
+ const openApiFields = getFieldsFromOpenApiSchema(openApiSchema, descriptors, data, openApiSchemaPath);
845
+ const descriptorFields = uniqWith(reduce(descriptors, (accumulator, descriptor) => openApiFields?.some(field => field.path === `spec.${descriptor.path}`)
846
+ ? accumulator
847
+ : [
848
+ ...accumulator,
849
+ ...getFieldsFromDescriptor(descriptor, data, openApiSchema, descriptors),
850
+ ], []), isEqual);
851
+ const basicFields = [...openApiFields, ...descriptorFields];
852
+ const relationFields = getRelatedFields(basicFields.filter(fieldShouldReveal));
853
+ const treeFields = [
854
+ ...getTreeFields(relationFields.filter(f => !f.parent), relationFields.filter(f => !!f.parent)),
855
+ // 兼容老的数据结构
856
+ ...relationFields.filter(f => !f._dirty),
857
+ ];
858
+ // 保留,兼容老数据结构
859
+ const [advancedFields = [], arrayFields = [], groupFields = [], normalFields = [],] = reduce(treeFields, ([advancedFieldsAccumulator = [], arrayFieldsAccumulator = [], groupFieldsAccumulator = [], normalFieldsAccumulator = [],], field) => {
860
+ const mappers = [
861
+ { spec: SpecCapability.arrayFieldGroup, acc: arrayFieldsAccumulator },
862
+ { spec: SpecCapability.fieldGroup, acc: groupFieldsAccumulator },
863
+ { spec: SpecCapability.advanced, acc: advancedFieldsAccumulator },
864
+ ];
865
+ const acc = mappers.find(mapper => hasDescriptor(field, mapper.spec))?.acc;
866
+ return [
867
+ advancedFieldsAccumulator,
868
+ arrayFieldsAccumulator,
869
+ groupFieldsAccumulator,
870
+ normalFieldsAccumulator,
871
+ ].map(r => {
872
+ if ((!acc && r === normalFieldsAccumulator) || r === acc) {
873
+ return [...r, field];
874
+ }
875
+ return r;
876
+ });
877
+ }, []);
878
+ return {
879
+ normalFields: sortFields(normalFields, descriptors),
880
+ fieldGroups: sortGroupFields(groupFields, descriptors, descriptorFields),
881
+ arrayFieldGroups: getArrayFields(arrayFields, descriptorFields),
882
+ advancedFields: sortFields(advancedFields, descriptors),
883
+ descriptorFields,
884
+ openApiFields,
885
+ basicFields,
886
+ treeFields,
887
+ };
888
+ }
889
+ function getArrayFields(fields, descriptorFields) {
890
+ // array fields
891
+ const groupedArrayFieldsByName = groupBy(fields, field => {
892
+ const { groupName } = parseGroupDescriptor(field);
893
+ return groupName;
894
+ });
895
+ // Map {groupName: string, fieldLists: OperandField[][]}, where OperandField is a nested array
896
+ // of the appropriate fields, grouped by index.
897
+ return map(groupedArrayFieldsByName, (fieldsInGroup, groupName) => ({
898
+ groupName,
899
+ displayName: startCase(groupName),
900
+ capabilities: descriptorFields.find(field => field.path === `spec.${groupName}`)
901
+ ?.capabilities ?? [],
902
+ fieldLists: reduce(fieldsInGroup, (fieldListsAccumulator, field) => {
903
+ const { index, match } = parseArrayPath(field.path);
904
+ if (match) {
905
+ fieldListsAccumulator[index] = [
906
+ ...(fieldListsAccumulator[index] || []),
907
+ field,
908
+ ];
909
+ }
910
+ return fieldListsAccumulator;
911
+ }, []),
912
+ _dirty: false,
913
+ }));
914
+ }
915
+ function sortFields(fields, descriptors) {
916
+ return sortBy(fields, field => descriptors.findIndex(d => normalizePath(d.path) === normalizePath(field.path)));
917
+ }
918
+ function sortGroupFields(fields, descriptors, descriptorFields) {
919
+ const groupedFieldsByName = groupBy(sortFields(fields, descriptors), field => {
920
+ const { groupName } = parseGroupDescriptor(field);
921
+ return groupName;
922
+ });
923
+ return map(groupedFieldsByName, (fieldList, groupName) => ({
924
+ groupName,
925
+ displayName: startCase(groupName),
926
+ capabilities: descriptorFields.find(field => field.path === `spec.${groupName}`)
927
+ ?.capabilities ?? [],
928
+ fieldList,
929
+ }));
930
+ }
931
+
932
+ const EXPRESSION_PROPS_PREFIX = `${SpecCapability.expression}props.`;
933
+ const EXPRESSION_PROPS_OPTIONS_PREFIX = `${EXPRESSION_PROPS_PREFIX}options:`;
934
+ const EXPRESSION_PROPS_DEFAULT_PREFIX = `${EXPRESSION_PROPS_PREFIX}default:`;
935
+ const EXPRESSION_PROPS_HIDDEN_PREFIX = `${EXPRESSION_PROPS_PREFIX}hidden:`;
936
+ const EXPRESSION_PROPS_ALLOW_CREATE_PREFIX = `${EXPRESSION_PROPS_PREFIX}allowCreate:`;
937
+ class PropsFieldExpression {
938
+ constructor(field) {
939
+ this.expressions = this.evaluatePropsExpressions(field);
940
+ }
941
+ evaluatePropsExpressions(field) {
942
+ return {
943
+ options: this.evaluateOptionsExpression(field),
944
+ default: this.evaluateCommonPropsExpression(field, EXPRESSION_PROPS_DEFAULT_PREFIX),
945
+ hidden: this.evaluateCommonPropsExpression(field, EXPRESSION_PROPS_HIDDEN_PREFIX),
946
+ subscribedContextPaths: this.evaluateSubscribedContextPaths(field),
947
+ subscribedFormDataPaths: this.evaluateSubscribedFormDataPaths(field),
948
+ };
949
+ }
950
+ evaluateOptionsExpression(field) {
951
+ const propsVisible = field.capabilities.some(c => c.startsWith(EXPRESSION_PROPS_OPTIONS_PREFIX));
952
+ return propsVisible
953
+ ? {
954
+ api: getMatchedCapabilityValue(field.capabilities, `${EXPRESSION_PROPS_OPTIONS_PREFIX}api:`),
955
+ labelPath: getMatchedCapabilityValue(field.capabilities, `${EXPRESSION_PROPS_OPTIONS_PREFIX}label:path:`),
956
+ valuePath: getMatchedCapabilityValue(field.capabilities, `${EXPRESSION_PROPS_OPTIONS_PREFIX}value:path:`),
957
+ expression: getMatchedCapabilityValue(field.capabilities, `${EXPRESSION_PROPS_OPTIONS_PREFIX}`),
958
+ }
959
+ : null;
960
+ }
961
+ evaluateCommonPropsExpression(field, prefix) {
962
+ return getMatchedCapabilityValue(field.capabilities, prefix);
963
+ }
964
+ evaluateSubscribedContextPaths(field) {
965
+ return field.capabilities.reduce((p, c) => {
966
+ const matched = c.match(/(?<=\${context.)[^\t\n\v\f\r{}]+(?=})/g) || [];
967
+ return [...p, ...matched];
968
+ }, []);
969
+ }
970
+ evaluateSubscribedFormDataPaths(field) {
971
+ return field.capabilities.reduce((p, c) => {
972
+ const matched = c.match(/(?<=\${formData.)[^\t\n\v\f\r{}]+(?=})/g) || [];
973
+ return [...p, ...matched];
974
+ }, []);
975
+ }
976
+ }
977
+ const compareWithSubscribedPaths = (dynamicExpression, prev, next) => {
978
+ const [prevFormContext, prevFormDataState] = prev;
979
+ const [nextFormContext, nextFormDataState] = next;
980
+ return (!dynamicExpression.subscribedContextPaths.some(path => !isEqual(get(prevFormContext, path), get(nextFormContext, path))) &&
981
+ !dynamicExpression.subscribedFormDataPaths.some(path => !isEqual(getFormData(prevFormDataState, path), getFormData(nextFormDataState, path))));
982
+ };
983
+
984
+ class FormItemComponent {
985
+ constructor() {
986
+ this.getFieldTooltip = getFieldTooltip;
987
+ this.getFieldDescription = getFieldDescription$1;
988
+ this.getFieldDocLink = getFieldDocLink;
989
+ this.isFieldDescriptionAsLink = isFieldDescriptionAsLink;
990
+ this.fieldComponent = inject(forwardRef(() => OperandFieldComponent));
991
+ this.cdr = inject(ChangeDetectorRef);
992
+ // FIXME: 部分页面需要调用 markForCheck 才行, 需要确认为啥使用了 ChangeDetectionStrategy.Default 数据变更之后视图依旧不同步更新
993
+ this.fieldComponent.crdForm.form.ngSubmit.subscribe(() => this.cdr.markForCheck());
994
+ }
995
+ showFieldCopyable(field, isDisabled) {
996
+ return isFieldCopyable(field) && isDisabled;
997
+ }
998
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: FormItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
999
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: FormItemComponent, isStandalone: true, selector: "acl-crd-form-item", inputs: { plain: "plain" }, ngImport: i0, template: "@if (\n {\n label: fieldComponent.field | pure: fieldComponent.getFieldDisplayName,\n };\n as _\n) {\n <aui-form-item\n [emptyAddon]=\"false\"\n [plain]=\"plain\"\n [attr.data-test]=\"_.label ? 'AUI-FORM-ITEM/' + (_.label | translate) : null\"\n width=\"large\"\n >\n @if (_.label) {\n <label auiFormItemLabel>{{ _.label | translate }}</label>\n }\n <!-- for a required mark in aui-form-item label -->\n @if (!fieldComponent.isDisabled) {\n <ng-container\n auiFormItemControl\n [required]=\"fieldComponent.isRequired\"\n ></ng-container>\n }\n <ng-content></ng-content>\n @if (!fieldComponent.isDisabled) {\n <div auiFormItemHint>\n @if (\n (fieldComponent.crdForm.form.submitted ||\n fieldComponent.control.dirty) &&\n fieldComponent.control.invalid &&\n !fieldComponent.isCustomErrorsMapper\n ) {\n <acl-errors-mapper [errors]=\"fieldComponent.control.errors\">\n </acl-errors-mapper>\n }\n <div>\n @if (!(fieldComponent.field | pure: isFieldDescriptionAsLink)) {\n {{ fieldComponent.field | pure: getFieldDescription | translate }}\n }\n @if (fieldComponent.field | pure: getFieldDocLink; as link) {\n <a\n href=\"javascript:;\"\n [aclHelpDoc]=\"link\"\n aclHelpDocTarget=\"blank\"\n >\n @if (fieldComponent.field | pure: isFieldDescriptionAsLink) {\n {{\n fieldComponent.field | pure: getFieldDescription | translate\n }}\n }\n <aui-icon icon=\"jump\"></aui-icon>\n </a>\n }\n </div>\n </div>\n }\n @if (\n (fieldComponent.field | pure: getFieldTooltip) ||\n (fieldComponent.field\n | pure: showFieldCopyable : fieldComponent.isDisabled)\n ) {\n <div auiFormItemAddon>\n @if (\n fieldComponent.field\n | pure: showFieldCopyable : fieldComponent.isDisabled\n ) {\n <aui-icon\n icon=\"copy\"\n [auiTooltipCopy]=\"fieldComponent.control.value\"\n ></aui-icon>\n }\n @if (fieldComponent.field | pure: getFieldTooltip; as tooltip) {\n <aui-icon\n icon=\"question_circle\"\n [class]=\"\n (fieldComponent.field\n | pure: showFieldCopyable : fieldComponent.isDisabled)\n ? 'tw-ml-8'\n : ''\n \"\n [auiTooltip]=\"tooltipTmp\"\n ></aui-icon>\n <ng-template #tooltipTmp>\n <span style=\"white-space: pre-line\">\n {{ tooltip | translate }}</span\n >\n </ng-template>\n }\n </div>\n }\n </aui-form-item>\n}\n", styles: [":host::ng-deep label{word-break:break-word}aui-form-item ::ng-deep .aui-form-item__content--large aui-switch.aui-form-item__control{flex:unset}\n"], dependencies: [{ kind: "ngmodule", type: FormModule }, { kind: "component", type: i2.FormItemComponent, selector: "aui-form-item", inputs: ["labelWidth", "width", "labelPosition", "emptyAddon", "plain"] }, { kind: "directive", type: i2.FormItemAddonDirective, selector: "[auiFormItemAddon]" }, { kind: "directive", type: i2.FormItemHintDirective, selector: "[auiFormItemHint]" }, { kind: "directive", type: i2.FormItemLabelDirective, selector: "label[auiFormItemLabel]" }, { kind: "directive", type: i2.FormItemControlDirective, selector: "[auiFormItemControl]", inputs: ["required"] }, { kind: "ngmodule", type: IconModule }, { kind: "component", type: i2.IconComponent, selector: "aui-icon", inputs: ["icon", "light", "dark", "link", "margin", "size", "color", "background", "backgroundColor"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i2.TooltipDirective, selector: "[auiTooltip]", inputs: ["auiTooltip", "auiTooltipContext", "auiTooltipClass", "auiTooltipType", "auiTooltipPosition", "auiTooltipTrigger", "auiTooltipDisabled", "auiTooltipHideOnClick", "auiTooltipAnimType"], outputs: ["auiTooltipVisibleChange"], exportAs: ["auiTooltip"] }, { kind: "directive", type: i2.TooltipCopyDirective, selector: "[auiTooltipCopy]", inputs: ["auiTooltipPosition", "auiTooltipDisabled", "auiTooltipCopy", "auiTooltipCopyTip", "auiTooltipCopySuccessTip", "auiTooltipCopyFailTip"] }, { kind: "component", type: ErrorsMapperComponent, selector: "acl-errors-mapper", inputs: ["errors", "errorsMapper", "errorsMapperFn", "controlName", "ignoreUnknownError"] }, { kind: "directive", type: HelpDocDirective, selector: "[aclHelpDoc]", inputs: ["aclHelpDoc", "aclHelpDocTarget"] }, { kind: "pipe", type: PurePipe, name: "pure" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.Default }); }
1000
+ }
1001
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: FormItemComponent, decorators: [{
1002
+ type: Component,
1003
+ args: [{ selector: 'acl-crd-form-item', changeDetection: ChangeDetectionStrategy.Default, standalone: true, imports: [
1004
+ PurePipe,
1005
+ TranslatePipe,
1006
+ FormModule,
1007
+ IconModule,
1008
+ TooltipModule,
1009
+ ErrorsMapperComponent,
1010
+ HelpDocDirective,
1011
+ ], template: "@if (\n {\n label: fieldComponent.field | pure: fieldComponent.getFieldDisplayName,\n };\n as _\n) {\n <aui-form-item\n [emptyAddon]=\"false\"\n [plain]=\"plain\"\n [attr.data-test]=\"_.label ? 'AUI-FORM-ITEM/' + (_.label | translate) : null\"\n width=\"large\"\n >\n @if (_.label) {\n <label auiFormItemLabel>{{ _.label | translate }}</label>\n }\n <!-- for a required mark in aui-form-item label -->\n @if (!fieldComponent.isDisabled) {\n <ng-container\n auiFormItemControl\n [required]=\"fieldComponent.isRequired\"\n ></ng-container>\n }\n <ng-content></ng-content>\n @if (!fieldComponent.isDisabled) {\n <div auiFormItemHint>\n @if (\n (fieldComponent.crdForm.form.submitted ||\n fieldComponent.control.dirty) &&\n fieldComponent.control.invalid &&\n !fieldComponent.isCustomErrorsMapper\n ) {\n <acl-errors-mapper [errors]=\"fieldComponent.control.errors\">\n </acl-errors-mapper>\n }\n <div>\n @if (!(fieldComponent.field | pure: isFieldDescriptionAsLink)) {\n {{ fieldComponent.field | pure: getFieldDescription | translate }}\n }\n @if (fieldComponent.field | pure: getFieldDocLink; as link) {\n <a\n href=\"javascript:;\"\n [aclHelpDoc]=\"link\"\n aclHelpDocTarget=\"blank\"\n >\n @if (fieldComponent.field | pure: isFieldDescriptionAsLink) {\n {{\n fieldComponent.field | pure: getFieldDescription | translate\n }}\n }\n <aui-icon icon=\"jump\"></aui-icon>\n </a>\n }\n </div>\n </div>\n }\n @if (\n (fieldComponent.field | pure: getFieldTooltip) ||\n (fieldComponent.field\n | pure: showFieldCopyable : fieldComponent.isDisabled)\n ) {\n <div auiFormItemAddon>\n @if (\n fieldComponent.field\n | pure: showFieldCopyable : fieldComponent.isDisabled\n ) {\n <aui-icon\n icon=\"copy\"\n [auiTooltipCopy]=\"fieldComponent.control.value\"\n ></aui-icon>\n }\n @if (fieldComponent.field | pure: getFieldTooltip; as tooltip) {\n <aui-icon\n icon=\"question_circle\"\n [class]=\"\n (fieldComponent.field\n | pure: showFieldCopyable : fieldComponent.isDisabled)\n ? 'tw-ml-8'\n : ''\n \"\n [auiTooltip]=\"tooltipTmp\"\n ></aui-icon>\n <ng-template #tooltipTmp>\n <span style=\"white-space: pre-line\">\n {{ tooltip | translate }}</span\n >\n </ng-template>\n }\n </div>\n }\n </aui-form-item>\n}\n", styles: [":host::ng-deep label{word-break:break-word}aui-form-item ::ng-deep .aui-form-item__content--large aui-switch.aui-form-item__control{flex:unset}\n"] }]
1012
+ }], ctorParameters: () => [], propDecorators: { plain: [{
1013
+ type: Input
1014
+ }] } });
1015
+
1016
+ class OperandArrayFieldGroupComponent extends BaseOperandFiledArrayComponent {
1017
+ ngOnInit() {
1018
+ // 如果 arrayFieldGroup 配置了 urn:alm:descriptor:com.tectonic.ui:emptyArray 并且没有 value 值,则不保留首项
1019
+ if (!get(this.arrayFieldGroup.value, 'length') &&
1020
+ isEmptyArray(this.arrayFieldGroup)) {
1021
+ this.removeItem(0);
1022
+ }
1023
+ }
1024
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: OperandArrayFieldGroupComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1025
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: OperandArrayFieldGroupComponent, isStandalone: true, selector: "acl-operand-array-field-group", usesInheritance: true, ngImport: i0, template: "<div\n [class.expanded]=\"expanded\"\n class=\"field-group\"\n>\n <div class=\"header\">\n <div\n class=\"title\"\n (click)=\"expanded = !expanded\"\n >\n @if (!expanded) {\n <aui-icon\n size=\"20px,20px\"\n icon=\"caret_down_s\"\n ></aui-icon>\n }\n @if (expanded) {\n <aui-icon\n size=\"20px,20px\"\n icon=\"caret_down_s\"\n ></aui-icon>\n }\n <span>{{ arrayFieldGroup | pure: getFieldDisplayName | translate }}</span>\n </div>\n <div class=\"description\"></div>\n </div>\n <div\n class=\"content\"\n [hidden]=\"!expanded\"\n >\n @for (list of arrayFieldGroup.fieldLists; track list; let i = $index) {\n <div class=\"array-item\">\n @if (!readonly) {\n <div class=\"array-item__remove\">\n <button\n aui-button=\"text\"\n size=\"small\"\n (click)=\"removeItem(i)\"\n >\n <aui-icon icon=\"minus_circle\"></aui-icon>\n <span>{{ 'remove' | translate }}</span>\n </button>\n </div>\n }\n @for (field of list; track field) {\n <div>\n <acl-operand-field\n [field]=\"field\"\n [fields]=\"fields\"\n [formDataState]=\"formDataState\"\n [formErrors]=\"formErrors\"\n [readonly]=\"readonly\"\n (valueChange)=\"fieldValueChange($event)\"\n >\n </acl-operand-field>\n </div>\n }\n </div>\n }\n @if (!readonly) {\n <div class=\"array-item__add\">\n <button\n aui-button=\"text\"\n size=\"small\"\n (click)=\"addItem()\"\n >\n <aui-icon icon=\"plus_circle\"></aui-icon>\n <span\n >{{ 'add' | translate }}\n {{ arrayFieldGroup | pure: getFieldDisplayName | translate }}</span\n >\n </button>\n </div>\n }\n </div>\n</div>\n", styles: [".field-group{border:1px solid rgb(var(--aui-color-n-7));background-color:rgb(var(--aui-color-n-10));position:relative;margin-bottom:16px;border-radius:2px}.field-group .title{padding:0 20px;font-size:14px;font-weight:500;display:flex;align-items:center;height:60px;line-height:20px;color:rgb(var(--aui-color-n-1));cursor:pointer}.field-group .title aui-icon{margin-right:20px;font-size:20px}.field-group .description{display:block;padding-left:22px;font-size:12px;line-height:16px;color:rgb(var(--aui-color-n-4))}.field-group:not(.expanded) aui-icon[icon=caret_down_s]{transform:rotate(-90deg)}.field-group.expanded>.header>.title{border-bottom:1px solid rgb(var(--aui-color-n-8))}.field-group.expanded>.header>.description{display:block;margin-top:4px}.field-group .content{padding:8px 12px}.field-group .content.no-title{padding-top:0}.field-group .array-item__remove{display:flex;justify-content:flex-end;margin-bottom:4px}.field-group .array-item__add,.field-group .array-item__remove{text-align:center}.field-group .array-item__add aui-icon,.field-group .array-item__remove aui-icon{margin-right:4px}\n"], dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => IconModule) }, { kind: "component", type: i0.forwardRef(() => i2.IconComponent), selector: "aui-icon", inputs: ["icon", "light", "dark", "link", "margin", "size", "color", "background", "backgroundColor"] }, { kind: "ngmodule", type: i0.forwardRef(() => ButtonModule) }, { kind: "component", type: i0.forwardRef(() => i2.ButtonComponent), selector: "button[aui-button]", inputs: ["aui-button", "size", "plain", "loading", "round", "square"] }, { kind: "component", type: i0.forwardRef(() => OperandFieldComponent), selector: "acl-operand-field", inputs: ["field", "readonly", "fields", "formDataState", "formErrors"], outputs: ["valueChange", "itemRemove"] }, { kind: "pipe", type: i0.forwardRef(() => PurePipe), name: "pure" }, { kind: "pipe", type: i0.forwardRef(() => TranslatePipe), name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1026
+ }
1027
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: OperandArrayFieldGroupComponent, decorators: [{
1028
+ type: Component,
1029
+ args: [{ selector: 'acl-operand-array-field-group', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
1030
+ PurePipe,
1031
+ TranslatePipe,
1032
+ IconModule,
1033
+ ButtonModule,
1034
+ forwardRef(() => OperandFieldComponent),
1035
+ ], template: "<div\n [class.expanded]=\"expanded\"\n class=\"field-group\"\n>\n <div class=\"header\">\n <div\n class=\"title\"\n (click)=\"expanded = !expanded\"\n >\n @if (!expanded) {\n <aui-icon\n size=\"20px,20px\"\n icon=\"caret_down_s\"\n ></aui-icon>\n }\n @if (expanded) {\n <aui-icon\n size=\"20px,20px\"\n icon=\"caret_down_s\"\n ></aui-icon>\n }\n <span>{{ arrayFieldGroup | pure: getFieldDisplayName | translate }}</span>\n </div>\n <div class=\"description\"></div>\n </div>\n <div\n class=\"content\"\n [hidden]=\"!expanded\"\n >\n @for (list of arrayFieldGroup.fieldLists; track list; let i = $index) {\n <div class=\"array-item\">\n @if (!readonly) {\n <div class=\"array-item__remove\">\n <button\n aui-button=\"text\"\n size=\"small\"\n (click)=\"removeItem(i)\"\n >\n <aui-icon icon=\"minus_circle\"></aui-icon>\n <span>{{ 'remove' | translate }}</span>\n </button>\n </div>\n }\n @for (field of list; track field) {\n <div>\n <acl-operand-field\n [field]=\"field\"\n [fields]=\"fields\"\n [formDataState]=\"formDataState\"\n [formErrors]=\"formErrors\"\n [readonly]=\"readonly\"\n (valueChange)=\"fieldValueChange($event)\"\n >\n </acl-operand-field>\n </div>\n }\n </div>\n }\n @if (!readonly) {\n <div class=\"array-item__add\">\n <button\n aui-button=\"text\"\n size=\"small\"\n (click)=\"addItem()\"\n >\n <aui-icon icon=\"plus_circle\"></aui-icon>\n <span\n >{{ 'add' | translate }}\n {{ arrayFieldGroup | pure: getFieldDisplayName | translate }}</span\n >\n </button>\n </div>\n }\n </div>\n</div>\n", styles: [".field-group{border:1px solid rgb(var(--aui-color-n-7));background-color:rgb(var(--aui-color-n-10));position:relative;margin-bottom:16px;border-radius:2px}.field-group .title{padding:0 20px;font-size:14px;font-weight:500;display:flex;align-items:center;height:60px;line-height:20px;color:rgb(var(--aui-color-n-1));cursor:pointer}.field-group .title aui-icon{margin-right:20px;font-size:20px}.field-group .description{display:block;padding-left:22px;font-size:12px;line-height:16px;color:rgb(var(--aui-color-n-4))}.field-group:not(.expanded) aui-icon[icon=caret_down_s]{transform:rotate(-90deg)}.field-group.expanded>.header>.title{border-bottom:1px solid rgb(var(--aui-color-n-8))}.field-group.expanded>.header>.description{display:block;margin-top:4px}.field-group .content{padding:8px 12px}.field-group .content.no-title{padding-top:0}.field-group .array-item__remove{display:flex;justify-content:flex-end;margin-bottom:4px}.field-group .array-item__add,.field-group .array-item__remove{text-align:center}.field-group .array-item__add aui-icon,.field-group .array-item__remove aui-icon{margin-right:4px}\n"] }]
1036
+ }] });
1037
+
1038
+ class OperandFieldGroupComponent {
1039
+ constructor() {
1040
+ this.readonly = false;
1041
+ this.valueChange = new EventEmitter();
1042
+ }
1043
+ get expanded() {
1044
+ return this._expanded ?? !isFolded(this.fieldGroup);
1045
+ }
1046
+ set expanded(expanded) {
1047
+ this._expanded = expanded;
1048
+ }
1049
+ fieldValueChange(e) {
1050
+ this.valueChange.emit(e);
1051
+ }
1052
+ getGroupName(field) {
1053
+ return getFieldDisplayName(field) || field.groupName;
1054
+ }
1055
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: OperandFieldGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1056
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: OperandFieldGroupComponent, isStandalone: true, selector: "acl-operand-field-group", inputs: { fields: "fields", fieldGroup: "fieldGroup", formDataState: "formDataState", formErrors: "formErrors", readonly: "readonly" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<div\n class=\"field-group\"\n [class.expanded]=\"expanded\"\n>\n <div class=\"header\">\n <div\n class=\"title\"\n (click)=\"expanded = !expanded\"\n >\n @if (!expanded) {\n <aui-icon icon=\"caret_down_s\"></aui-icon>\n }\n @if (expanded) {\n <aui-icon icon=\"caret_down_s\"></aui-icon>\n }\n <span>{{ fieldGroup | pure: getGroupName | translate }}</span>\n </div>\n </div>\n <div\n class=\"content\"\n [hidden]=\"!expanded\"\n >\n @for (field of fieldGroup.fieldList; track field) {\n <acl-operand-field\n [field]=\"$any(field)\"\n [fields]=\"fields\"\n [readonly]=\"readonly\"\n [formDataState]=\"formDataState\"\n [formErrors]=\"formErrors\"\n (valueChange)=\"fieldValueChange($event)\"\n >\n </acl-operand-field>\n }\n </div>\n</div>\n", styles: [".field-group{border:1px solid rgb(var(--aui-color-n-7));background-color:rgb(var(--aui-color-n-10));position:relative;margin-bottom:16px;border-radius:2px}.field-group .title{padding:0 20px;font-size:14px;font-weight:500;display:flex;align-items:center;height:60px;line-height:20px;color:rgb(var(--aui-color-n-1));cursor:pointer}.field-group .title aui-icon{margin-right:20px;font-size:20px}.field-group .description{display:block;padding-left:22px;font-size:12px;line-height:16px;color:rgb(var(--aui-color-n-4))}.field-group:not(.expanded) aui-icon[icon=caret_down_s]{transform:rotate(-90deg)}.field-group.expanded>.header>.title{border-bottom:1px solid rgb(var(--aui-color-n-8))}.field-group.expanded>.header>.description{display:block;margin-top:4px}.field-group .content{padding:8px 12px}.field-group .content.no-title{padding-top:0}.field-group .array-item__remove{display:flex;justify-content:flex-end;margin-bottom:4px}.field-group .array-item__add,.field-group .array-item__remove{text-align:center}.field-group .array-item__add aui-icon,.field-group .array-item__remove aui-icon{margin-right:4px}\n"], dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => IconModule) }, { kind: "component", type: i0.forwardRef(() => i2.IconComponent), selector: "aui-icon", inputs: ["icon", "light", "dark", "link", "margin", "size", "color", "background", "backgroundColor"] }, { kind: "component", type: i0.forwardRef(() => OperandFieldComponent), selector: "acl-operand-field", inputs: ["field", "readonly", "fields", "formDataState", "formErrors"], outputs: ["valueChange", "itemRemove"] }, { kind: "pipe", type: i0.forwardRef(() => PurePipe), name: "pure" }, { kind: "pipe", type: i0.forwardRef(() => TranslatePipe), name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1057
+ }
1058
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: OperandFieldGroupComponent, decorators: [{
1059
+ type: Component,
1060
+ args: [{ selector: 'acl-operand-field-group', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
1061
+ PurePipe,
1062
+ TranslatePipe,
1063
+ IconModule,
1064
+ forwardRef(() => OperandFieldComponent),
1065
+ ], template: "<div\n class=\"field-group\"\n [class.expanded]=\"expanded\"\n>\n <div class=\"header\">\n <div\n class=\"title\"\n (click)=\"expanded = !expanded\"\n >\n @if (!expanded) {\n <aui-icon icon=\"caret_down_s\"></aui-icon>\n }\n @if (expanded) {\n <aui-icon icon=\"caret_down_s\"></aui-icon>\n }\n <span>{{ fieldGroup | pure: getGroupName | translate }}</span>\n </div>\n </div>\n <div\n class=\"content\"\n [hidden]=\"!expanded\"\n >\n @for (field of fieldGroup.fieldList; track field) {\n <acl-operand-field\n [field]=\"$any(field)\"\n [fields]=\"fields\"\n [readonly]=\"readonly\"\n [formDataState]=\"formDataState\"\n [formErrors]=\"formErrors\"\n (valueChange)=\"fieldValueChange($event)\"\n >\n </acl-operand-field>\n }\n </div>\n</div>\n", styles: [".field-group{border:1px solid rgb(var(--aui-color-n-7));background-color:rgb(var(--aui-color-n-10));position:relative;margin-bottom:16px;border-radius:2px}.field-group .title{padding:0 20px;font-size:14px;font-weight:500;display:flex;align-items:center;height:60px;line-height:20px;color:rgb(var(--aui-color-n-1));cursor:pointer}.field-group .title aui-icon{margin-right:20px;font-size:20px}.field-group .description{display:block;padding-left:22px;font-size:12px;line-height:16px;color:rgb(var(--aui-color-n-4))}.field-group:not(.expanded) aui-icon[icon=caret_down_s]{transform:rotate(-90deg)}.field-group.expanded>.header>.title{border-bottom:1px solid rgb(var(--aui-color-n-8))}.field-group.expanded>.header>.description{display:block;margin-top:4px}.field-group .content{padding:8px 12px}.field-group .content.no-title{padding-top:0}.field-group .array-item__remove{display:flex;justify-content:flex-end;margin-bottom:4px}.field-group .array-item__add,.field-group .array-item__remove{text-align:center}.field-group .array-item__add aui-icon,.field-group .array-item__remove aui-icon{margin-right:4px}\n"] }]
1066
+ }], propDecorators: { fields: [{
1067
+ type: Input
1068
+ }], fieldGroup: [{
1069
+ type: Input
1070
+ }], formDataState: [{
1071
+ type: Input
1072
+ }], formErrors: [{
1073
+ type: Input
1074
+ }], readonly: [{
1075
+ type: Input
1076
+ }], valueChange: [{
1077
+ type: Output
1078
+ }] } });
1079
+
1080
+ class CrdFormArrayTableComponent extends BaseOperandFiledArrayComponent {
1081
+ ngOnInit() {
1082
+ // arrayField group 不需要默认保留一项
1083
+ if (!get(this.arrayFieldGroup.value, 'length')) {
1084
+ this.removeItem(0);
1085
+ }
1086
+ }
1087
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: CrdFormArrayTableComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1088
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: CrdFormArrayTableComponent, isStandalone: true, selector: "acl-crd-array-table", usesInheritance: true, ngImport: i0, template: "<aui-form-item [emptyAddon]=\"false\">\n <label auiFormItemLabel>{{\n arrayFieldGroup | pure: getFieldDisplayName | translate\n }}</label>\n\n <acl-array-form-table\n style=\"flex: 1\"\n (remove)=\"removeItem($event)\"\n (add)=\"addItem()\"\n [rows]=\"arrayFieldGroup.fieldLists\"\n [readonly]=\"readonly\"\n class=\"form-table__flex-layout\"\n [resourceNameTranslated]=\"\n arrayFieldGroup | pure: getFieldDisplayName | translate\n \"\n >\n <ng-container *aclArrayFormTableHeader>\n @for (field of basicArrayFieldTemplate; track field) {\n @if (field | pure: fieldIsRequired) {\n <th required>\n {{ field | pure: getFieldDisplayName | translate }}\n </th>\n } @else {\n <th>{{ field | pure: getFieldDisplayName | translate }}</th>\n }\n }\n </ng-container>\n\n <!-- Input row -->\n <ng-container *aclArrayFormTableRow=\"let fieldList; let index = index\">\n @for (field of fieldList; track trackByFn(index); let index = $index) {\n <td>\n <acl-operand-field\n [field]=\"field\"\n [formDataState]=\"formDataState\"\n [formErrors]=\"formErrors\"\n [readonly]=\"readonly\"\n (valueChange)=\"fieldValueChange($event)\"\n >\n </acl-operand-field>\n </td>\n }\n </ng-container>\n </acl-array-form-table>\n</aui-form-item>\n", styles: [":host{flex:1}:host ::ng-deep acl-array-form-table .acl-array-form-table__readonly-mode tbody tr{height:auto}:host ::ng-deep acl-array-form-table .aui-form-item{margin-bottom:0}:host ::ng-deep acl-array-form-table .aui-form-item .aui-form-item__label-wrapper{display:none}:host ::ng-deep acl-array-form-table .aui-form-item .aui-form-item__content{min-height:auto}:host ::ng-deep acl-array-form-table .aui-form-item .aui-form-item__content .aui-form-item__control{max-width:100%}:host ::ng-deep acl-array-form-table .acl-array-form-table tbody td{vertical-align:top}\n"], dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => FormModule) }, { kind: "component", type: i0.forwardRef(() => i2.FormItemComponent), selector: "aui-form-item", inputs: ["labelWidth", "width", "labelPosition", "emptyAddon", "plain"] }, { kind: "directive", type: i0.forwardRef(() => i2.FormItemLabelDirective), selector: "label[auiFormItemLabel]" }, { kind: "component", type: i0.forwardRef(() => i2$1.ArrayFormTableComponent), selector: "acl-array-form-table", inputs: ["rowSeparator", "rows", "resourceName", "resourceNameTranslated", "readonly", "addDisabled", "actionColumnDivider", "showZeroState", "showRowError", "rowBackgroundColorFn", "minRow", "minRowTooltip", "maxRow", "maxRowTooltip"], outputs: ["add", "remove"] }, { kind: "directive", type: i0.forwardRef(() => i2$1.ArrayFormTableHeaderDirective), selector: "[aclArrayFormTableHeader]" }, { kind: "directive", type: i0.forwardRef(() => i2$1.ArrayFormTableRowDirective), selector: "[aclArrayFormTableRow]" }, { kind: "component", type: i0.forwardRef(() => OperandFieldComponent), selector: "acl-operand-field", inputs: ["field", "readonly", "fields", "formDataState", "formErrors"], outputs: ["valueChange", "itemRemove"] }, { kind: "pipe", type: i0.forwardRef(() => PurePipe), name: "pure" }, { kind: "pipe", type: i0.forwardRef(() => TranslatePipe), name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1089
+ }
1090
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: CrdFormArrayTableComponent, decorators: [{
1091
+ type: Component,
1092
+ args: [{ selector: 'acl-crd-array-table', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
1093
+ FormModule,
1094
+ ARRAY_FORM_TABLE_MODULE,
1095
+ forwardRef(() => OperandFieldComponent),
1096
+ PurePipe,
1097
+ TranslatePipe,
1098
+ ], template: "<aui-form-item [emptyAddon]=\"false\">\n <label auiFormItemLabel>{{\n arrayFieldGroup | pure: getFieldDisplayName | translate\n }}</label>\n\n <acl-array-form-table\n style=\"flex: 1\"\n (remove)=\"removeItem($event)\"\n (add)=\"addItem()\"\n [rows]=\"arrayFieldGroup.fieldLists\"\n [readonly]=\"readonly\"\n class=\"form-table__flex-layout\"\n [resourceNameTranslated]=\"\n arrayFieldGroup | pure: getFieldDisplayName | translate\n \"\n >\n <ng-container *aclArrayFormTableHeader>\n @for (field of basicArrayFieldTemplate; track field) {\n @if (field | pure: fieldIsRequired) {\n <th required>\n {{ field | pure: getFieldDisplayName | translate }}\n </th>\n } @else {\n <th>{{ field | pure: getFieldDisplayName | translate }}</th>\n }\n }\n </ng-container>\n\n <!-- Input row -->\n <ng-container *aclArrayFormTableRow=\"let fieldList; let index = index\">\n @for (field of fieldList; track trackByFn(index); let index = $index) {\n <td>\n <acl-operand-field\n [field]=\"field\"\n [formDataState]=\"formDataState\"\n [formErrors]=\"formErrors\"\n [readonly]=\"readonly\"\n (valueChange)=\"fieldValueChange($event)\"\n >\n </acl-operand-field>\n </td>\n }\n </ng-container>\n </acl-array-form-table>\n</aui-form-item>\n", styles: [":host{flex:1}:host ::ng-deep acl-array-form-table .acl-array-form-table__readonly-mode tbody tr{height:auto}:host ::ng-deep acl-array-form-table .aui-form-item{margin-bottom:0}:host ::ng-deep acl-array-form-table .aui-form-item .aui-form-item__label-wrapper{display:none}:host ::ng-deep acl-array-form-table .aui-form-item .aui-form-item__content{min-height:auto}:host ::ng-deep acl-array-form-table .aui-form-item .aui-form-item__content .aui-form-item__control{max-width:100%}:host ::ng-deep acl-array-form-table .acl-array-form-table tbody td{vertical-align:top}\n"] }]
1099
+ }] });
1100
+
1101
+ class BasicAuthCreateSecretDialogComponent {
1102
+ constructor() {
1103
+ this.dialogData = inject(DIALOG_DATA);
1104
+ this.dialogRef = inject(DialogRef);
1105
+ this.fb = inject(FormBuilder);
1106
+ this.k8sApi = inject(K8sApiService);
1107
+ this.cdr = inject(ChangeDetectorRef);
1108
+ this.message = inject(MessageService);
1109
+ this.translate = inject(TranslateService);
1110
+ this.submitting = false;
1111
+ this.K8S_RESOURCE_NAME_BASE = K8S_RESOURCE_NAME_BASE;
1112
+ this.usernameKey = this.dialogData.config?.usernameKey ?? 'username';
1113
+ this.passwordKey = this.dialogData.config?.passwordKey ?? 'password';
1114
+ this.usernameReadonly = !!this.dialogData.config?.usernameReadonly;
1115
+ this.strongPassword = !!this.dialogData.config?.strongPassword;
1116
+ this.password = !!this.dialogData.config?.password;
1117
+ this.showPassword = false;
1118
+ this.formGroup = this.fb.group({
1119
+ name: this.fb.control(this.dialogData.config?.secretName || '', [
1120
+ Validators.required,
1121
+ Validators.pattern(K8S_RESOURCE_NAME_BASE.pattern),
1122
+ Validators.maxLength(63),
1123
+ ]),
1124
+ username: this.fb.control(this.dialogData.config?.usernameDefault || ''),
1125
+ password: this.fb.control('', [Validators.required]),
1126
+ });
1127
+ }
1128
+ confirm() {
1129
+ this.form.onSubmit(null);
1130
+ if (!this.form.valid) {
1131
+ return;
1132
+ }
1133
+ this.submitting = true;
1134
+ const value = this.form.value;
1135
+ const data = {
1136
+ [this.passwordKey]: encode(value.password),
1137
+ };
1138
+ if (value.username) {
1139
+ data[this.usernameKey] = encode(value.username);
1140
+ }
1141
+ const resource = {
1142
+ kind: 'Secret',
1143
+ apiVersion: 'v1',
1144
+ metadata: {
1145
+ name: value.name,
1146
+ namespace: this.dialogData.namespace,
1147
+ },
1148
+ type: SecretType.Opaque,
1149
+ data,
1150
+ };
1151
+ this.k8sApi
1152
+ .postResource({
1153
+ definition: COMMON_RESOURCE_DEFINITIONS.SECRET,
1154
+ cluster: this.dialogData.cluster,
1155
+ namespace: this.dialogData.namespace,
1156
+ resource,
1157
+ })
1158
+ .pipe(finalize(() => {
1159
+ this.submitting = false;
1160
+ this.cdr.markForCheck();
1161
+ }))
1162
+ .subscribe(res => {
1163
+ this.dialogRef.close(res);
1164
+ this.message.success(this.translate.get('create_success'));
1165
+ });
1166
+ }
1167
+ toggleShowPassword() {
1168
+ this.showPassword = !this.showPassword;
1169
+ }
1170
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: BasicAuthCreateSecretDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1171
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: BasicAuthCreateSecretDialogComponent, isStandalone: true, selector: "ng-component", viewQueries: [{ propertyName: "form", first: true, predicate: FormGroupDirective, descendants: true, static: true }], ngImport: i0, template: "<aui-dialog-header>\n {{ 'create_secret' | translate }}\n</aui-dialog-header>\n\n<aui-dialog-content>\n <form\n auiForm\n [formGroup]=\"formGroup\"\n >\n <aui-form-item>\n <label auiFormItemLabel>\n {{ 'name' | translate }}\n </label>\n <input\n type=\"text\"\n required\n aui-input\n auiFormItemControl\n formControlName=\"name\"\n />\n <acl-errors-mapper\n auiFormItemError\n [errors]=\"formGroup.get('name').errors\"\n [errorsMapper]=\"{\n pattern: K8S_RESOURCE_NAME_BASE.tip | translate,\n }\"\n ></acl-errors-mapper>\n </aui-form-item>\n <aui-form-item>\n <label auiFormItemLabel>{{ 'config' | translate }}</label>\n <div class=\"form-table__flex-layout tw-flex-1\">\n <table class=\"acl-array-form-table\">\n <thead>\n <tr>\n <th>{{ 'key' | translate }}</th>\n <th>{{ 'value' | translate }}</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <td>\n <input\n type=\"text\"\n required\n aui-input\n readonly\n [ngModel]=\"usernameKey\"\n [ngModelOptions]=\"{ standalone: true }\"\n />\n </td>\n <td>\n <input\n type=\"text\"\n aui-input\n auiFormItemControl\n formControlName=\"username\"\n [readonly]=\"usernameReadonly\"\n />\n </td>\n </tr>\n <tr>\n <td>\n <input\n type=\"text\"\n required\n aui-input\n readonly\n [ngModel]=\"passwordKey\"\n [ngModelOptions]=\"{ standalone: true }\"\n />\n </td>\n <td>\n @if (strongPassword && !password) {\n <input\n type=\"password\"\n required\n aui-input\n auiFormItemControl\n formControlName=\"password\"\n aclStrongPassword\n />\n }\n @if (!strongPassword && !password) {\n <input\n type=\"text\"\n required\n aui-input\n auiFormItemControl\n formControlName=\"password\"\n />\n }\n @if (password && !strongPassword) {\n <aui-input-group\n auiFormItemControl\n required\n >\n <input\n auiFormItemControl\n aui-input\n required\n formControlName=\"password\"\n [type]=\"showPassword ? 'text' : 'password'\"\n />\n <div\n auiInputSuffix\n class=\"password__suffix\"\n (click)=\"toggleShowPassword()\"\n >\n <aui-icon\n [icon]=\"showPassword ? 'eye_s' : 'eye_slash_s'\"\n ></aui-icon>\n </div>\n </aui-input-group>\n }\n\n @if (formGroup.get('password').dirty || form?.submitted) {\n <acl-errors-mapper\n auiFormItemError\n [errors]=\"formGroup.get('password').errors\"\n ></acl-errors-mapper>\n }\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </aui-form-item>\n </form>\n</aui-dialog-content>\n\n<aui-dialog-footer>\n <button\n aui-button=\"primary\"\n (click)=\"confirm()\"\n [loading]=\"submitting\"\n [disabled]=\"submitting\"\n >\n {{ 'create' | translate }}\n </button>\n <button\n aui-button\n auiDialogClose\n >\n {{ 'cancel' | translate }}\n </button>\n</aui-dialog-footer>\n", styles: [":host::ng-deep .aui-form-item__label-wrapper{width:114px}:host::ng-deep label{word-break:break-all}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: FormModule }, { kind: "directive", type: i2.FormDirective, selector: "form[auiForm]", inputs: ["auiFormLabelWidth", "auiFormLabelPosition", "auiFormEmptyAddon", "auiFormInline"], exportAs: ["auiForm"] }, { kind: "component", type: i2.FormItemComponent, selector: "aui-form-item", inputs: ["labelWidth", "width", "labelPosition", "emptyAddon", "plain"] }, { kind: "directive", type: i2.FormItemErrorDirective, selector: "[auiFormItemError]" }, { kind: "directive", type: i2.FormItemLabelDirective, selector: "label[auiFormItemLabel]" }, { kind: "directive", type: i2.FormItemControlDirective, selector: "[auiFormItemControl]", inputs: ["required"] }, { kind: "ngmodule", type: InputModule }, { kind: "component", type: i2.InputComponent, selector: "input[aui-input],textarea[aui-input]", inputs: ["size", "disabled"] }, { kind: "component", type: i2.InputGroupComponent, selector: "aui-input-group" }, { kind: "directive", type: i2.InputSuffixDirective, selector: "[auiInputSuffix]" }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[aui-button]", inputs: ["aui-button", "size", "plain", "loading", "round", "square"] }, { kind: "ngmodule", type: IconModule }, { kind: "component", type: i2.IconComponent, selector: "aui-icon", inputs: ["icon", "light", "dark", "link", "margin", "size", "color", "background", "backgroundColor"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i2.DialogHeaderComponent, selector: "aui-dialog-header", inputs: ["divider", "closeable", "result"] }, { kind: "component", type: i2.DialogContentComponent, selector: "aui-dialog-content" }, { kind: "component", type: i2.DialogFooterComponent, selector: "aui-dialog-footer" }, { kind: "directive", type: i2.DialogCloseDirective, selector: "[auiDialogClose]", inputs: ["auiDialogClose"], exportAs: ["auiDialogClose"] }, { kind: "component", type: ErrorsMapperComponent, selector: "acl-errors-mapper", inputs: ["errors", "errorsMapper", "errorsMapperFn", "controlName", "ignoreUnknownError"] }, { kind: "directive", type: StrongPasswordDirective, selector: "input[aclStrongPassword][ngModel],input[aclStrongPassword][formControl],input[aclStrongPassword][formControlName]", inputs: ["aclStrongPassword", "required", "specialChars", "minlength", "maxlength", "notStartsWith"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1172
+ }
1173
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: BasicAuthCreateSecretDialogComponent, decorators: [{
1174
+ type: Component,
1175
+ args: [{ changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
1176
+ FormsModule,
1177
+ ReactiveFormsModule,
1178
+ FormModule,
1179
+ InputModule,
1180
+ ButtonModule,
1181
+ IconModule,
1182
+ DialogModule,
1183
+ ErrorsMapperComponent,
1184
+ StrongPasswordDirective,
1185
+ TranslatePipe,
1186
+ ], template: "<aui-dialog-header>\n {{ 'create_secret' | translate }}\n</aui-dialog-header>\n\n<aui-dialog-content>\n <form\n auiForm\n [formGroup]=\"formGroup\"\n >\n <aui-form-item>\n <label auiFormItemLabel>\n {{ 'name' | translate }}\n </label>\n <input\n type=\"text\"\n required\n aui-input\n auiFormItemControl\n formControlName=\"name\"\n />\n <acl-errors-mapper\n auiFormItemError\n [errors]=\"formGroup.get('name').errors\"\n [errorsMapper]=\"{\n pattern: K8S_RESOURCE_NAME_BASE.tip | translate,\n }\"\n ></acl-errors-mapper>\n </aui-form-item>\n <aui-form-item>\n <label auiFormItemLabel>{{ 'config' | translate }}</label>\n <div class=\"form-table__flex-layout tw-flex-1\">\n <table class=\"acl-array-form-table\">\n <thead>\n <tr>\n <th>{{ 'key' | translate }}</th>\n <th>{{ 'value' | translate }}</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <td>\n <input\n type=\"text\"\n required\n aui-input\n readonly\n [ngModel]=\"usernameKey\"\n [ngModelOptions]=\"{ standalone: true }\"\n />\n </td>\n <td>\n <input\n type=\"text\"\n aui-input\n auiFormItemControl\n formControlName=\"username\"\n [readonly]=\"usernameReadonly\"\n />\n </td>\n </tr>\n <tr>\n <td>\n <input\n type=\"text\"\n required\n aui-input\n readonly\n [ngModel]=\"passwordKey\"\n [ngModelOptions]=\"{ standalone: true }\"\n />\n </td>\n <td>\n @if (strongPassword && !password) {\n <input\n type=\"password\"\n required\n aui-input\n auiFormItemControl\n formControlName=\"password\"\n aclStrongPassword\n />\n }\n @if (!strongPassword && !password) {\n <input\n type=\"text\"\n required\n aui-input\n auiFormItemControl\n formControlName=\"password\"\n />\n }\n @if (password && !strongPassword) {\n <aui-input-group\n auiFormItemControl\n required\n >\n <input\n auiFormItemControl\n aui-input\n required\n formControlName=\"password\"\n [type]=\"showPassword ? 'text' : 'password'\"\n />\n <div\n auiInputSuffix\n class=\"password__suffix\"\n (click)=\"toggleShowPassword()\"\n >\n <aui-icon\n [icon]=\"showPassword ? 'eye_s' : 'eye_slash_s'\"\n ></aui-icon>\n </div>\n </aui-input-group>\n }\n\n @if (formGroup.get('password').dirty || form?.submitted) {\n <acl-errors-mapper\n auiFormItemError\n [errors]=\"formGroup.get('password').errors\"\n ></acl-errors-mapper>\n }\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </aui-form-item>\n </form>\n</aui-dialog-content>\n\n<aui-dialog-footer>\n <button\n aui-button=\"primary\"\n (click)=\"confirm()\"\n [loading]=\"submitting\"\n [disabled]=\"submitting\"\n >\n {{ 'create' | translate }}\n </button>\n <button\n aui-button\n auiDialogClose\n >\n {{ 'cancel' | translate }}\n </button>\n</aui-dialog-footer>\n", styles: [":host::ng-deep .aui-form-item__label-wrapper{width:114px}:host::ng-deep label{word-break:break-all}\n"] }]
1187
+ }], propDecorators: { form: [{
1188
+ type: ViewChild,
1189
+ args: [FormGroupDirective, { static: true }]
1190
+ }] } });
1191
+
1192
+ class BasicAuthSecretComponent extends BaseResourceFormComponent {
1193
+ constructor() {
1194
+ super(inject(Injector));
1195
+ this.k8sApi = inject(K8sApiService);
1196
+ this.crdForm = inject(CrdFormComponent);
1197
+ this.dialog = inject(DialogService);
1198
+ this.k8sUtil = inject(K8sUtilService);
1199
+ this.config$ = this.field$.pipe(filter(field => !!field), map$1(field => getBasicAuthSecretConfig(field)), publishRef());
1200
+ this.reload$ = new Subject();
1201
+ this.resources$ = combineLatest([
1202
+ this.crdForm.formContext$,
1203
+ this.config$,
1204
+ this.reload$.pipe(startWith(null)),
1205
+ ]).pipe(switchMap(([{ cluster, namespace }, config]) => this.k8sApi
1206
+ .getResourceList({
1207
+ definition: COMMON_RESOURCE_DEFINITIONS.SECRET,
1208
+ namespace: config?.namespace ?? namespace,
1209
+ cluster: config?.cluster ?? cluster,
1210
+ })
1211
+ .pipe(map$1(res => res.items), skipError([]), map$1(items => items.filter(item => [SecretType.Opaque, SecretType.BasicAuth].includes(item.type))))), publishRef());
1212
+ this.resources$.pipe(takeUntil(this.destroy$)).subscribe(items => {
1213
+ if (this.form.value &&
1214
+ !items.some(item => this.k8sUtil.getName(item) === this.form.value)) {
1215
+ this.form.reset();
1216
+ }
1217
+ });
1218
+ }
1219
+ createForm() {
1220
+ // 使用 control 的 validators 而非 required 指令目地是后者会导致 control 实例化后 dirty
1221
+ return this.fb.control(null, this.required ? Validators.required : null);
1222
+ }
1223
+ create() {
1224
+ this.config$.subscribe(config => {
1225
+ const dialogRef = this.dialog.open(BasicAuthCreateSecretDialogComponent, {
1226
+ size: DialogSize.Big,
1227
+ data: {
1228
+ cluster: config?.cluster ?? this.crdForm.formContext.cluster,
1229
+ namespace: config?.namespace ?? this.crdForm.formContext.namespace,
1230
+ config,
1231
+ },
1232
+ });
1233
+ return dialogRef.afterClosed().subscribe((res) => {
1234
+ if (res) {
1235
+ this.reload$.next();
1236
+ this.form.setValue(res.metadata.name);
1237
+ }
1238
+ });
1239
+ });
1240
+ }
1241
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: BasicAuthSecretComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1242
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: BasicAuthSecretComponent, isStandalone: true, selector: "acl-crd-basic-auth-secret", inputs: { required: "required", field: "field" }, usesInheritance: true, ngImport: i0, template: "<aui-select\n class=\"tw-flex-1 tw-mr-[4px]\"\n [formControl]=\"form\"\n>\n @for (item of resources$ | async; track item) {\n <aui-option\n [value]=\"item | aclName\"\n [label]=\"item | aclName\"\n >\n {{ item | aclName }}\n </aui-option>\n }\n <aui-option-placeholder>{{ 'no_data' | translate }}</aui-option-placeholder>\n</aui-select>\n<button\n aui-button=\"default\"\n type=\"button\"\n (click)=\"create()\"\n>\n {{ 'create' | translate }}\n</button>\n", styles: [":host{display:flex}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i2.SelectComponent, selector: "aui-select" }, { kind: "component", type: i2.OptionComponent, selector: "aui-option", inputs: ["label", "labelContext", "value", "disabled"] }, { kind: "component", type: i2.OptionPlaceholderComponent, selector: "aui-option-placeholder" }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.ButtonComponent, selector: "button[aui-button]", inputs: ["aui-button", "size", "plain", "loading", "round", "square"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: i4.K8sNamePipe, name: "aclName" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1243
+ }
1244
+ __decorate([
1245
+ ObservableInput(),
1246
+ __metadata("design:type", Observable)
1247
+ ], BasicAuthSecretComponent.prototype, "field$", void 0);
1248
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: BasicAuthSecretComponent, decorators: [{
1249
+ type: Component,
1250
+ args: [{ selector: 'acl-crd-basic-auth-secret', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
1251
+ CommonModule,
1252
+ ReactiveFormsModule,
1253
+ SelectModule,
1254
+ ButtonModule,
1255
+ TranslatePipe,
1256
+ K8S_UTIL_PIPES_MODULE,
1257
+ ], template: "<aui-select\n class=\"tw-flex-1 tw-mr-[4px]\"\n [formControl]=\"form\"\n>\n @for (item of resources$ | async; track item) {\n <aui-option\n [value]=\"item | aclName\"\n [label]=\"item | aclName\"\n >\n {{ item | aclName }}\n </aui-option>\n }\n <aui-option-placeholder>{{ 'no_data' | translate }}</aui-option-placeholder>\n</aui-select>\n<button\n aui-button=\"default\"\n type=\"button\"\n (click)=\"create()\"\n>\n {{ 'create' | translate }}\n</button>\n", styles: [":host{display:flex}\n"] }]
1258
+ }], ctorParameters: () => [], propDecorators: { required: [{
1259
+ type: Input
1260
+ }], field: [{
1261
+ type: Input
1262
+ }], field$: [] } });
1263
+
1264
+ function findResourceType(type, definitions) {
1265
+ type = plural(type.toLowerCase());
1266
+ return Object.entries(definitions).find(([_k, v]) => v.type === type)?.[0];
1267
+ }
1268
+ function plural(word) {
1269
+ const plural = {
1270
+ '(quiz)$': '$1zes',
1271
+ '^(ox)$': '$1en',
1272
+ '([m|l])ouse$': '$1ice',
1273
+ // cspell:disable-next-line
1274
+ '(matr|vert|ind)ix|ex$': '$1ices',
1275
+ '(x|ch|ss|sh)$': '$1es',
1276
+ // cspell:disable-next-line
1277
+ '([^aeiouy]|qu)y$': '$1ies',
1278
+ '(hive)$': '$1s',
1279
+ '(?:([^f])fe|([lr])f)$': '$1$2ves',
1280
+ // cspell:disable-next-line
1281
+ '(shea|lea|loa|thie)f$': '$1ves',
1282
+ sis$: 'ses',
1283
+ '([ti])um$': '$1a',
1284
+ // cspell:disable-next-line
1285
+ '(tomat|potat|ech|her|vet)o$': '$1oes',
1286
+ '(bu)s$': '$1ses',
1287
+ '(alias)$': '$1es',
1288
+ // cspell:disable-next-line
1289
+ '(octop)us$': '$1i',
1290
+ '(ax|test)is$': '$1es',
1291
+ '(us)$': '$1es',
1292
+ '([^s]+)$': '$1s',
1293
+ };
1294
+ // check for matches using regular expressions
1295
+ Object.keys(plural).forEach(reg => {
1296
+ const pattern = new RegExp(reg, 'i');
1297
+ if (pattern.test(word)) {
1298
+ word = word.replace(pattern, plural[reg]);
1299
+ }
1300
+ });
1301
+ return word;
1302
+ }
1303
+
1304
+ class K8sResourcePrefixComponent extends BaseResourceFormComponent {
1305
+ constructor() {
1306
+ super(inject(Injector));
1307
+ this.k8sApi = inject(K8sApiService);
1308
+ this.crdForm = inject(CrdFormComponent);
1309
+ this.resourceDefinitions = inject(TOKEN_RESOURCE_DEFINITIONS);
1310
+ this.init$$ = new BehaviorSubject(false);
1311
+ this.readonly = false;
1312
+ this.options$ = this.field$.pipe(map$1(field => getK8sResourcePrefixOptions(field)));
1313
+ this.resources$ = this.options$.pipe(switchMap(option => this.k8sApi[option.isGlobal ? 'getGlobalResourceList' : 'getResourceList']({
1314
+ type: findResourceType(option.type, this.resourceDefinitions),
1315
+ ...(option.namespaced
1316
+ ? option.isGlobal
1317
+ ? { namespaced: true }
1318
+ : { namespace: this.crdForm?.formContext?.namespace }
1319
+ : null),
1320
+ ...(!option.isGlobal && {
1321
+ cluster: this.crdForm?.formContext?.cluster,
1322
+ }),
1323
+ ...(option.labelSelector && {
1324
+ queryParams: { labelSelector: option.labelSelector },
1325
+ }),
1326
+ }).pipe(pluck('items'))), skipError(), tap(() => this.init$$.next(true)));
1327
+ }
1328
+ createForm() {
1329
+ return this.fb.control(null);
1330
+ }
1331
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: K8sResourcePrefixComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1332
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: K8sResourcePrefixComponent, isStandalone: true, selector: "acl-crd-resource-prefix", inputs: { field: "field", readonly: "readonly", formErrors: "formErrors" }, usesInheritance: true, ngImport: i0, template: "@if ((options$ | async)?.multiple) {\n <aui-multi-select\n class=\"select\"\n [formControl]=\"form\"\n [hidden]=\"readonly || !(init$$ | async)\"\n [maxRowCount]=\"3\"\n >\n @for (item of resources$ | async; track item) {\n <aui-option\n [value]=\"item | aclName\"\n [label]=\"item | aclName\"\n >\n {{ item | aclName }}\n </aui-option>\n }\n </aui-multi-select>\n @if (readonly) {\n @for (tag of $any(form.value); track tag; let ind = $index) {\n <aui-tag\n type=\"info\"\n size=\"mini\"\n [border]=\"true\"\n [auiTooltip]=\"tag\"\n >\n {{ tag }}\n </aui-tag>\n }\n }\n} @else {\n <aui-select\n [formControl]=\"form\"\n class=\"select\"\n [hidden]=\"readonly\"\n >\n @for (item of resources$ | async; track item) {\n <aui-option\n [value]=\"item | aclName\"\n [label]=\"item | aclName\"\n >\n {{ item | aclName }}\n </aui-option>\n }\n <aui-option-placeholder>{{ 'no_data' | translate }}</aui-option-placeholder>\n </aui-select>\n @if (readonly) {\n <span>{{ form.value }}</span>\n }\n}\n", styles: [":host{flex:1}.select{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i2.SelectComponent, selector: "aui-select" }, { kind: "component", type: i2.OptionComponent, selector: "aui-option", inputs: ["label", "labelContext", "value", "disabled"] }, { kind: "component", type: i2.OptionPlaceholderComponent, selector: "aui-option-placeholder" }, { kind: "component", type: i2.MultiSelectComponent, selector: "aui-multi-select", inputs: ["tagClassFn", "maxRowCount", "customRowHeight", "allowSelectAll"] }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i2.TagComponent, selector: "aui-tag", inputs: ["type", "size", "closeable", "border", "solid", "invalid", "round", "color", "allowClick"], outputs: ["close"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i2.TooltipDirective, selector: "[auiTooltip]", inputs: ["auiTooltip", "auiTooltipContext", "auiTooltipClass", "auiTooltipType", "auiTooltipPosition", "auiTooltipTrigger", "auiTooltipDisabled", "auiTooltipHideOnClick", "auiTooltipAnimType"], outputs: ["auiTooltipVisibleChange"], exportAs: ["auiTooltip"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: i4.K8sNamePipe, name: "aclName" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1333
+ }
1334
+ __decorate([
1335
+ ObservableInput(),
1336
+ __metadata("design:type", Observable)
1337
+ ], K8sResourcePrefixComponent.prototype, "field$", void 0);
1338
+ __decorate([
1339
+ ValueHook(function (formErrors) {
1340
+ this.form?.setErrors(isEmpty(formErrors) ? null : formErrors);
1341
+ }),
1342
+ __metadata("design:type", Object)
1343
+ ], K8sResourcePrefixComponent.prototype, "formErrors", void 0);
1344
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: K8sResourcePrefixComponent, decorators: [{
1345
+ type: Component,
1346
+ args: [{ selector: 'acl-crd-resource-prefix', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
1347
+ CommonModule,
1348
+ ReactiveFormsModule,
1349
+ SelectModule,
1350
+ TagModule,
1351
+ TooltipModule,
1352
+ TranslatePipe,
1353
+ K8S_UTIL_PIPES_MODULE,
1354
+ ], template: "@if ((options$ | async)?.multiple) {\n <aui-multi-select\n class=\"select\"\n [formControl]=\"form\"\n [hidden]=\"readonly || !(init$$ | async)\"\n [maxRowCount]=\"3\"\n >\n @for (item of resources$ | async; track item) {\n <aui-option\n [value]=\"item | aclName\"\n [label]=\"item | aclName\"\n >\n {{ item | aclName }}\n </aui-option>\n }\n </aui-multi-select>\n @if (readonly) {\n @for (tag of $any(form.value); track tag; let ind = $index) {\n <aui-tag\n type=\"info\"\n size=\"mini\"\n [border]=\"true\"\n [auiTooltip]=\"tag\"\n >\n {{ tag }}\n </aui-tag>\n }\n }\n} @else {\n <aui-select\n [formControl]=\"form\"\n class=\"select\"\n [hidden]=\"readonly\"\n >\n @for (item of resources$ | async; track item) {\n <aui-option\n [value]=\"item | aclName\"\n [label]=\"item | aclName\"\n >\n {{ item | aclName }}\n </aui-option>\n }\n <aui-option-placeholder>{{ 'no_data' | translate }}</aui-option-placeholder>\n </aui-select>\n @if (readonly) {\n <span>{{ form.value }}</span>\n }\n}\n", styles: [":host{flex:1}.select{display:block}\n"] }]
1355
+ }], ctorParameters: () => [], propDecorators: { field: [{
1356
+ type: Input
1357
+ }], field$: [], readonly: [{
1358
+ type: Input
1359
+ }], formErrors: [{
1360
+ type: Input
1361
+ }] } });
1362
+
1363
+ function isLink(field) {
1364
+ const { capabilities } = field;
1365
+ return capabilities.some(c => c.startsWith(`${SpecCapability.text}:link`));
1366
+ }
1367
+ /**
1368
+ * 获取链接参数
1369
+ *
1370
+ * @see https://jira.alauda.cn/browse/ACP-32703
1371
+ */
1372
+ function resolveLinkOptions(field) {
1373
+ const linkCapability = field.capabilities.find(capability => capability.startsWith(SpecCapability.text));
1374
+ const target = linkCapability?.split(`${SpecCapability.text}:link:`)?.[1];
1375
+ return { target: target || '_blank' };
1376
+ }
1377
+ class LinkComponent extends createNestedFormControl({
1378
+ autoEmitChange: true,
1379
+ }) {
1380
+ get options() {
1381
+ return resolveLinkOptions(this.field);
1382
+ }
1383
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: LinkComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1384
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: LinkComponent, isStandalone: true, selector: "acl-crd-link", inputs: { field: "field" }, providers: [
1385
+ {
1386
+ provide: NG_VALUE_ACCESSOR,
1387
+ useExisting: forwardRef(() => LinkComponent),
1388
+ multi: true,
1389
+ },
1390
+ ], usesInheritance: true, ngImport: i0, template: "<a\n [href]=\"model | aclSanitize: 'url'\"\n [target]=\"options.target\"\n>\n <span>{{ model }}</span>\n @if (options.target === '_blank') {\n <aui-icon\n icon=\"jump\"\n margin=\"left\"\n >\n </aui-icon>\n }\n</a>\n", styles: [":host{flex:none!important}\n"], dependencies: [{ kind: "ngmodule", type: IconModule }, { kind: "component", type: i2.IconComponent, selector: "aui-icon", inputs: ["icon", "light", "dark", "link", "margin", "size", "color", "background", "backgroundColor"] }, { kind: "pipe", type: SanitizePipe, name: "aclSanitize" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1391
+ }
1392
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: LinkComponent, decorators: [{
1393
+ type: Component,
1394
+ args: [{ standalone: true, selector: 'acl-crd-link', changeDetection: ChangeDetectionStrategy.OnPush, providers: [
1395
+ {
1396
+ provide: NG_VALUE_ACCESSOR,
1397
+ useExisting: forwardRef(() => LinkComponent),
1398
+ multi: true,
1399
+ },
1400
+ ], imports: [IconModule, SanitizePipe], template: "<a\n [href]=\"model | aclSanitize: 'url'\"\n [target]=\"options.target\"\n>\n <span>{{ model }}</span>\n @if (options.target === '_blank') {\n <aui-icon\n icon=\"jump\"\n margin=\"left\"\n >\n </aui-icon>\n }\n</a>\n", styles: [":host{flex:none!important}\n"] }]
1401
+ }], propDecorators: { field: [{
1402
+ type: Input
1403
+ }] } });
1404
+
1405
+ function getConfigurations(specCapability, part) {
1406
+ const regExp = new RegExp(`^${escapeRegExp(part)}(.*)$`);
1407
+ const [_, config] = regExp.exec(specCapability) || [];
1408
+ return config;
1409
+ }
1410
+ // urn:alm:descriptor:com.tectonic.ui:resourceRequirements:required
1411
+ // urn:alm:descriptor:com.tectonic.ui:resourceRequirements:required:limit-memory&limit-cpu&request-memory&request-cpu
1412
+ // urn:alm:descriptor:com.tectonic.ui:resourceRequirements:required:limit&request-memory
1413
+ function resolveRequirementsRequiredOptions(field) {
1414
+ if (!field) {
1415
+ return null;
1416
+ }
1417
+ const options = field.capabilities.filter(descriptor => descriptor.startsWith(SpecCapability.resourceRequirements));
1418
+ const allRequired = options.includes(`${SpecCapability.resourceRequirements}:required`);
1419
+ if (allRequired) {
1420
+ return {
1421
+ required: {
1422
+ limit: ['cpu', 'memory'],
1423
+ request: ['cpu', 'memory'],
1424
+ },
1425
+ };
1426
+ }
1427
+ const requiredMap = options.reduce((prev, curr) => {
1428
+ const partsStr = curr.split(`${SpecCapability.resourceRequirements}:required:`)?.[1];
1429
+ partsStr?.split('&')?.forEach(optionStr => {
1430
+ const options = optionStr?.split('-');
1431
+ if (options.length === 1) {
1432
+ prev[options[0]].add('memory').add('cpu');
1433
+ }
1434
+ if (options.length > 1) {
1435
+ prev[options[0]].add(options[1]);
1436
+ }
1437
+ });
1438
+ return prev;
1439
+ }, {
1440
+ limit: new Set(),
1441
+ request: new Set(),
1442
+ });
1443
+ return {
1444
+ required: {
1445
+ limit: Array.from(requiredMap.limit),
1446
+ request: Array.from(requiredMap.request),
1447
+ },
1448
+ };
1449
+ }
1450
+ // urn:alm:descriptor:com.tectonic.ui:resourceRequirements:min:{"limits": {"cpu":"2c", "memory":"500Mi"}, "requests":{"cpu":"100m", "memory":"250Mi"}}
1451
+ // urn:alm:descriptor:com.tectonic.ui:resourceRequirements:max:{"limits": {"cpu":"4c", "memory":"500Mi"}, "requests":{"cpu":"4c", "memory":"500Mi"}}
1452
+ function resolveRequirementsMinOrMaxOptions(field) {
1453
+ if (!field) {
1454
+ return null;
1455
+ }
1456
+ const options = field.capabilities.filter(descriptor => descriptor.startsWith(SpecCapability.resourceRequirements));
1457
+ const getConfigurationMap = (option, capability) => {
1458
+ const configuration = getConfigurations(option, capability);
1459
+ const { limits, requests } = parseJson(configuration, {
1460
+ limits: { cpu: null, memory: null },
1461
+ requests: { cpu: null, memory: null },
1462
+ });
1463
+ return { limits, requests };
1464
+ };
1465
+ const getResourceMinOrMaxMap = (suffix) => {
1466
+ const option = options.find(option => option.includes(`${SpecCapability.resourceRequirements}:${suffix}:`));
1467
+ return getConfigurationMap(option, `${SpecCapability.resourceRequirements}:${suffix}:`);
1468
+ };
1469
+ return {
1470
+ min: getResourceMinOrMaxMap('min'),
1471
+ max: getResourceMinOrMaxMap('max'),
1472
+ };
1473
+ }
1474
+
1475
+ function handleValidationErrors(valueCtrl, errors) {
1476
+ // 这里避免覆盖其它 errors
1477
+ const combinedErrors = { ...valueCtrl.errors, ...errors };
1478
+ valueCtrl.setErrors(combinedErrors);
1479
+ return combinedErrors;
1480
+ }
1481
+ function valueFormat(type, value) {
1482
+ return type === 'cpu' ? formatCPU(value) : formatMemory(value);
1483
+ }
1484
+ function getCurrentValue(group, type) {
1485
+ const valueCtrl = group.get('value');
1486
+ const value = valueCtrl.value;
1487
+ const unit = group.get('unit').value;
1488
+ return valueFormat(type, (value || 0) + unit);
1489
+ }
1490
+ class ResourceRequirementsComponent extends BaseResourceFormGroupComponent {
1491
+ get requiredOptions() {
1492
+ return resolveRequirementsRequiredOptions(this.fieldComponent?.field);
1493
+ }
1494
+ get limitMemoryRequired() {
1495
+ return this.requiredOptions.required?.limit?.includes('memory');
1496
+ }
1497
+ get limitCpuRequired() {
1498
+ return this.requiredOptions.required?.limit?.includes('cpu');
1499
+ }
1500
+ get requestMemoryRequired() {
1501
+ return this.requiredOptions.required?.request?.includes('memory');
1502
+ }
1503
+ get requestCpuRequired() {
1504
+ return this.requiredOptions.required?.request?.includes('cpu');
1505
+ }
1506
+ get minMaxOptions() {
1507
+ return resolveRequirementsMinOrMaxOptions(this.fieldComponent?.field);
1508
+ }
1509
+ get limitMemoryMin() {
1510
+ return this.minMaxOptions.min.limits?.memory;
1511
+ }
1512
+ get limitCpuMin() {
1513
+ return this.minMaxOptions.min.limits?.cpu;
1514
+ }
1515
+ get requestMemoryMin() {
1516
+ return this.minMaxOptions.min.requests?.memory;
1517
+ }
1518
+ get requestCpuMin() {
1519
+ return this.minMaxOptions.min.requests?.cpu;
1520
+ }
1521
+ get limitMemoryMax() {
1522
+ return this.minMaxOptions.max.limits?.memory;
1523
+ }
1524
+ get limitCpuMax() {
1525
+ return this.minMaxOptions.max.limits?.cpu;
1526
+ }
1527
+ get requestMemoryMax() {
1528
+ return this.minMaxOptions.max.requests?.memory;
1529
+ }
1530
+ get requestCpuMax() {
1531
+ return this.minMaxOptions.max.requests?.cpu;
1532
+ }
1533
+ constructor() {
1534
+ super(inject(Injector));
1535
+ this.resourceUnits = resourceUnits;
1536
+ this.getResourceValue = getResourceValue;
1537
+ this.getResourceViewModel = getResourceViewModel;
1538
+ this.fieldComponent = inject(forwardRef(() => OperandFieldComponent), {
1539
+ optional: true,
1540
+ });
1541
+ this.controlContainer = inject(ControlContainer, {
1542
+ optional: true,
1543
+ });
1544
+ this.translate = inject(TranslateService);
1545
+ }
1546
+ ngOnInit() {
1547
+ super.ngOnInit();
1548
+ const greaterValidatorSubscriptions = [
1549
+ initGreaterValidator('cpu', this.form),
1550
+ initGreaterValidator('memory', this.form),
1551
+ ];
1552
+ this.destroy$.subscribe(() => {
1553
+ greaterValidatorSubscriptions.forEach(sub => sub.unsubscribe());
1554
+ });
1555
+ }
1556
+ createForm() {
1557
+ return this.fb.group({
1558
+ limits: this.fb.group({
1559
+ cpu: this.fb.group({
1560
+ value: '',
1561
+ unit: 'c',
1562
+ }, {
1563
+ validators: [
1564
+ this.minValidator(this.limitCpuMin, 'cpu'),
1565
+ this.maxValidator(this.limitCpuMax, 'cpu'),
1566
+ ],
1567
+ }),
1568
+ memory: this.fb.group({
1569
+ value: '',
1570
+ unit: 'Mi',
1571
+ }, {
1572
+ validators: [
1573
+ this.minValidator(this.limitMemoryMin, 'memory'),
1574
+ this.maxValidator(this.limitMemoryMax, 'memory'),
1575
+ ],
1576
+ }),
1577
+ }),
1578
+ requests: this.fb.group({
1579
+ cpu: this.fb.group({
1580
+ value: '',
1581
+ unit: 'c',
1582
+ }, {
1583
+ validators: [
1584
+ this.minValidator(this.requestCpuMin, 'cpu'),
1585
+ this.maxValidator(this.requestCpuMax, 'cpu'),
1586
+ ],
1587
+ }),
1588
+ memory: this.fb.group({
1589
+ value: '',
1590
+ unit: 'Mi',
1591
+ }, {
1592
+ validators: [
1593
+ this.minValidator(this.requestMemoryMin, 'memory'),
1594
+ this.maxValidator(this.requestMemoryMax, 'memory'),
1595
+ ],
1596
+ }),
1597
+ }),
1598
+ });
1599
+ }
1600
+ getDefaultFormModel() {
1601
+ return {
1602
+ limits: {
1603
+ cpu: {
1604
+ value: '',
1605
+ unit: 'c',
1606
+ },
1607
+ memory: {
1608
+ value: '',
1609
+ unit: 'Mi',
1610
+ },
1611
+ },
1612
+ requests: {
1613
+ cpu: {
1614
+ value: '',
1615
+ unit: 'c',
1616
+ },
1617
+ memory: {
1618
+ value: '',
1619
+ unit: 'Mi',
1620
+ },
1621
+ },
1622
+ };
1623
+ }
1624
+ adaptFormModel(formModel) {
1625
+ this.formatFormModel(formModel);
1626
+ return {
1627
+ requests: transferResource(formModel.requests),
1628
+ limits: transferResource(formModel.limits),
1629
+ };
1630
+ }
1631
+ minValidator(min, type) {
1632
+ return (group) => {
1633
+ if (!min) {
1634
+ return null;
1635
+ }
1636
+ const valueCtrl = group.get('value');
1637
+ const currentValue = getCurrentValue(group, type);
1638
+ const minThreshold = valueFormat(type, min);
1639
+ if (currentValue < minThreshold) {
1640
+ return handleValidationErrors(valueCtrl, { min: true });
1641
+ }
1642
+ const errors = omit(valueCtrl.errors, 'min');
1643
+ valueCtrl.setErrors(isEmpty(errors) ? null : errors);
1644
+ return null;
1645
+ };
1646
+ }
1647
+ maxValidator(max, type) {
1648
+ return (group) => {
1649
+ if (!max) {
1650
+ return null;
1651
+ }
1652
+ const valueCtrl = group.get('value');
1653
+ const currentValue = getCurrentValue(group, type);
1654
+ const maxThreshold = valueFormat(type, max);
1655
+ if (currentValue > maxThreshold) {
1656
+ return handleValidationErrors(valueCtrl, { max: true });
1657
+ }
1658
+ const errors = omit(valueCtrl.errors, 'max');
1659
+ valueCtrl.setErrors(isEmpty(errors) ? null : errors);
1660
+ return null;
1661
+ };
1662
+ }
1663
+ formatFormModel(formModel) {
1664
+ Object.values(formModel).forEach(modelValue => {
1665
+ Object.values(modelValue).forEach(v => {
1666
+ v.value = `${v.value}`;
1667
+ });
1668
+ });
1669
+ }
1670
+ getCpuUnitLabel(value) {
1671
+ return value === 'm'
1672
+ ? ''
1673
+ : resourceUnits.cpu.find(unit => unit.value === value).label;
1674
+ }
1675
+ adaptResourceModel(resources) {
1676
+ const resourcesModel = {};
1677
+ if (resources) {
1678
+ Object.keys(resources).forEach(kind => {
1679
+ const resourceKind = kind;
1680
+ resourcesModel[resourceKind] = Object.keys(resources[resourceKind])
1681
+ .filter(key => RESOURCE_MAC_TYPES.includes(key))
1682
+ .reduce((item, type) => {
1683
+ const resourceType = type;
1684
+ item[resourceType] = getResourceViewModel(resources[resourceKind][resourceType], resourceType);
1685
+ return item;
1686
+ }, {});
1687
+ });
1688
+ }
1689
+ return merge(this.getDefaultFormModel(), resourcesModel);
1690
+ }
1691
+ getMinOrMaxErrorsMapper(value, kind, type, _locale) {
1692
+ const resourceCtrl = getResourceViewModel(value, type);
1693
+ return this.translate.get(`warning_${kind}`, {
1694
+ value: resourceCtrl.value + this.translate.get(resourceCtrl.unit),
1695
+ });
1696
+ }
1697
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: ResourceRequirementsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1698
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: ResourceRequirementsComponent, isStandalone: true, selector: "acl-crd-resource-requirements", inputs: { readOnly: "readOnly", field: "field" }, usesInheritance: true, ngImport: i0, template: "@if (!readOnly) {\n <form [formGroup]=\"form\">\n <div class=\"resource_requirements\">\n <div class=\"input-group-label\">\n {{ 'resource_requirements_requests' | translate }}\n </div>\n <div\n class=\"input-group-wrapper tw-items-start\"\n formGroupName=\"requests\"\n >\n <div class=\"tw-flex tw-flex-col tw-flex-1\">\n <div\n class=\"input-groups-wrapper cpu\"\n formGroupName=\"cpu\"\n >\n <aui-input-group>\n <div\n auiInputAddonBefore\n class=\"addon-label\"\n [ngClass]=\"{\n 'tw-required-mark': requestCpuRequired,\n }\"\n >\n CPU\n </div>\n <input\n aui-input\n type=\"number\"\n [required]=\"requestCpuRequired\"\n auiFormItemControl\n formControlName=\"value\"\n />\n <aui-select\n auiInputAddonAfter\n auiFormItemControl\n formControlName=\"unit\"\n >\n @for (unit of resourceUnits['cpu']; track unit) {\n <aui-option\n [value]=\"unit.value\"\n [label]=\"unit.label | translate\"\n >\n {{ unit.label | translate }}\n </aui-option>\n }\n </aui-select>\n </aui-input-group>\n </div>\n @if (\n form.get('requests.cpu.value')?.dirty ||\n $any(controlContainer?.formDirective)?.submitted\n ) {\n <acl-errors-mapper\n [errors]=\"form.get('requests.cpu.value').errors\"\n [errorsMapper]=\"{\n min:\n requestCpuMin\n | pure\n : getMinOrMaxErrorsMapper\n : 'min'\n : 'cpu'\n : translate.locale,\n max:\n requestCpuMax\n | pure\n : getMinOrMaxErrorsMapper\n : 'max'\n : 'cpu'\n : translate.locale,\n }\"\n class=\"tw-text-s tw-text-red\"\n >\n </acl-errors-mapper>\n }\n </div>\n <div class=\"tw-flex tw-flex-col tw-flex-1\">\n <div\n class=\"input-groups-wrapper memory\"\n [formGroupName]=\"'memory'\"\n >\n <aui-input-group>\n <div\n auiInputAddonBefore\n class=\"addon-label\"\n [ngClass]=\"{\n 'tw-required-mark': requestMemoryRequired,\n }\"\n >\n {{ 'memory' | translate }}\n </div>\n <input\n aui-input\n type=\"number\"\n auiFormItemControl\n formControlName=\"value\"\n [required]=\"requestMemoryRequired\"\n />\n <aui-select\n auiInputAddonAfter\n auiFormItemControl\n formControlName=\"unit\"\n >\n @for (unit of resourceUnits['memory']; track unit) {\n <aui-option [value]=\"unit\">\n {{ unit }}\n </aui-option>\n }\n </aui-select>\n </aui-input-group>\n </div>\n @if (\n form.get('requests.memory.value')?.dirty ||\n $any(controlContainer?.formDirective)?.submitted\n ) {\n <acl-errors-mapper\n [errors]=\"form.get('requests.memory.value').errors\"\n [errorsMapper]=\"{\n min:\n requestMemoryMin\n | pure\n : getMinOrMaxErrorsMapper\n : 'min'\n : 'memory'\n : translate.locale,\n max:\n requestMemoryMax\n | pure\n : getMinOrMaxErrorsMapper\n : 'max'\n : 'memory'\n : translate.locale,\n }\"\n class=\"tw-text-s tw-text-red\"\n >\n </acl-errors-mapper>\n }\n </div>\n </div>\n </div>\n <div class=\"resource_requirements\">\n <div class=\"input-group-label\">\n {{ 'resource_requirements_limits' | translate }}\n </div>\n <div\n class=\"input-group-wrapper tw-items-start\"\n formGroupName=\"limits\"\n >\n <div class=\"tw-flex tw-flex-col tw-flex-1\">\n <div\n class=\"input-groups-wrapper cpu\"\n [formGroupName]=\"'cpu'\"\n >\n <aui-input-group>\n <div\n auiInputAddonBefore\n class=\"addon-label\"\n [ngClass]=\"{\n 'tw-required-mark': limitCpuRequired,\n }\"\n >\n CPU\n </div>\n <input\n aui-input\n type=\"number\"\n auiFormItemControl\n formControlName=\"value\"\n [required]=\"limitCpuRequired\"\n />\n <aui-select\n auiInputAddonAfter\n auiFormItemControl\n formControlName=\"unit\"\n >\n @for (unit of resourceUnits['cpu']; track unit) {\n <aui-option\n [value]=\"unit.value\"\n [label]=\"unit.label | translate\"\n >\n {{ unit.label | translate }}\n </aui-option>\n }\n </aui-select>\n </aui-input-group>\n </div>\n @if (\n form.get('limits.cpu.value')?.dirty ||\n $any(controlContainer?.formDirective)?.submitted\n ) {\n <acl-errors-mapper\n [errors]=\"form.get('limits.cpu.value').errors\"\n [errorsMapper]=\"{\n cpu_max: 'request_greater_than_limits_error' | translate,\n min:\n limitCpuMin\n | pure\n : getMinOrMaxErrorsMapper\n : 'min'\n : 'cpu'\n : translate.locale,\n max:\n limitCpuMax\n | pure\n : getMinOrMaxErrorsMapper\n : 'max'\n : 'cpu'\n : translate.locale,\n }\"\n class=\"tw-text-s tw-text-red\"\n >\n </acl-errors-mapper>\n }\n </div>\n <div class=\"tw-flex tw-flex-col tw-flex-1\">\n <div\n class=\"input-groups-wrapper memory\"\n [formGroupName]=\"'memory'\"\n >\n <aui-input-group>\n <div\n auiInputAddonBefore\n class=\"addon-label\"\n [ngClass]=\"{\n 'tw-required-mark': limitMemoryRequired,\n }\"\n >\n {{ 'memory' | translate }}\n </div>\n <input\n aui-input\n type=\"number\"\n auiFormItemControl\n formControlName=\"value\"\n [required]=\"limitMemoryRequired\"\n />\n <aui-select\n auiInputAddonAfter\n auiFormItemControl\n formControlName=\"unit\"\n >\n @for (unit of resourceUnits['memory']; track unit) {\n <aui-option [value]=\"unit\">\n {{ unit }}\n </aui-option>\n }\n </aui-select>\n </aui-input-group>\n </div>\n @if (\n form.get('limits.memory.value')?.dirty ||\n $any(controlContainer?.formDirective)?.submitted\n ) {\n <acl-errors-mapper\n [errors]=\"form.get('limits.memory.value').errors\"\n [errorsMapper]=\"{\n memory_max: 'request_greater_than_limits_error' | translate,\n min:\n limitMemoryMin\n | pure\n : getMinOrMaxErrorsMapper\n : 'min'\n : 'memory'\n : translate.locale,\n max:\n limitMemoryMax\n | pure\n : getMinOrMaxErrorsMapper\n : 'max'\n : 'memory'\n : translate.locale,\n }\"\n class=\"tw-text-s tw-text-red\"\n >\n </acl-errors-mapper>\n }\n </div>\n </div>\n </div>\n </form>\n} @else {\n <div class=\"resource_requirements-display\">\n <div class=\"resource_requirements-display-item\">\n <label class=\"resource_requirements-display-item__label\">{{\n 'resource_requirements_requests' | translate\n }}</label>\n <aui-icon\n icon=\"prod:cpu\"\n size=\"16px\"\n color=\"#6359b4\"\n margin=\"right\"\n [title]=\"'cpu' | translate\"\n ></aui-icon\n ><span class=\"tw-mr-16\"\n >{{\n form.get('requests').get('cpu').value\n | pure: getResourceValue\n | aclFieldNotAvailable\n }}{{\n form.get('requests').get('cpu.unit').value\n | pure: getCpuUnitLabel\n | translate\n }}\n </span>\n <aui-icon\n icon=\"prod:memory\"\n size=\"16px\"\n color=\"#007cb5\"\n margin=\"right\"\n [title]=\"'memory' | translate\"\n ></aui-icon\n >{{\n form.get('requests').get('memory').value\n | pure: getResourceValue\n | aclFieldNotAvailable\n }}\n </div>\n <div class=\"resource_requirements-display-item\">\n <label class=\"resource_requirements-display-item__label\">{{\n 'resource_requirements_limits' | translate\n }}</label>\n <aui-icon\n icon=\"prod:cpu\"\n size=\"16px\"\n color=\"#6359b4\"\n margin=\"right\"\n [title]=\"'cpu' | translate\"\n ></aui-icon\n ><span class=\"tw-mr-16\"\n >{{\n form.get('limits').get('cpu').value\n | pure: getResourceValue\n | aclFieldNotAvailable\n }}{{\n form.get('limits').get('cpu.unit').value\n | pure: getCpuUnitLabel\n | translate\n }}\n </span>\n <aui-icon\n icon=\"prod:memory\"\n size=\"16px\"\n color=\"#007cb5\"\n margin=\"right\"\n [title]=\"'memory' | translate\"\n ></aui-icon\n >{{\n form.get('limits').get('memory').value\n | pure: getResourceValue\n | aclFieldNotAvailable\n }}\n </div>\n </div>\n}\n", styles: [":host .resource_requirements:not(:last-of-type){margin-bottom:8px}:host .input-group-wrapper{display:flex}:host .input-group-label{line-height:var(--aui-inline-height-m)}:host aui-input-group{flex:1}:host aui-input-group ::ng-deep .aui-input-group__addon--after{padding:0}:host aui-input-group ::ng-deep .aui-input-group__addon--after aui-select{width:60px}:host aui-input-group ::ng-deep .aui-input-group__addon--after aui-select .aui-input-group{width:62px}html:not([lang|=zh]) :host aui-input-group ::ng-deep .aui-input-group__addon--after aui-select{width:78px}html:not([lang|=zh]) :host aui-input-group ::ng-deep .aui-input-group__addon--after aui-select .aui-input-group{width:80px}:host aui-input-group ::ng-deep .aui-input-group__addon--after aui-select .aui-input{border:0;background-color:transparent!important;border-top-right-radius:var(--aui-border-radius-m);border-bottom-right-radius:var(--aui-border-radius-m)}:host .addon-label{white-space:nowrap}:host .input-groups-wrapper{display:flex;flex:1;align-items:center}:host .input-groups-wrapper:first-child{margin-right:8px}:host .resource_requirements-display-item{display:flex;font-size:14px;line-height:20px;color:rgb(var(--aui-color-main-text));align-items:center;margin-top:8px}:host .resource_requirements-display-item:first-child{margin-top:0}:host .resource_requirements-display-item__label{white-space:nowrap;margin-right:8px}:host .resource_requirements-display-item__value{min-width:0;flex:1;white-space:nowrap;display:flex}:host .resource_requirements-display-item__value__overflow{display:block;overflow:hidden;text-overflow:ellipsis}:host .resource_requirements-display-item__value__wrap{white-space:pre-wrap;flex-wrap:wrap}:host .resource_requirements-display-item__label,:host .resource_requirements-display-item__value{height:100%;align-items:flex-start}:host ::ng-deep .aui-input-group__addon--before{width:70px}html:not([lang|=zh]) :host ::ng-deep .memory .aui-input-group__addon--before{width:82px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "ngmodule", type: FormModule }, { kind: "directive", type: i2.FormItemControlDirective, selector: "[auiFormItemControl]", inputs: ["required"] }, { kind: "ngmodule", type: InputModule }, { kind: "component", type: i2.InputComponent, selector: "input[aui-input],textarea[aui-input]", inputs: ["size", "disabled"] }, { kind: "component", type: i2.InputGroupComponent, selector: "aui-input-group" }, { kind: "directive", type: i2.InputAddonBeforeDirective, selector: "[auiInputAddonBefore]" }, { kind: "directive", type: i2.InputAddonAfterDirective, selector: "[auiInputAddonAfter]" }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i2.SelectComponent, selector: "aui-select" }, { kind: "component", type: i2.OptionComponent, selector: "aui-option", inputs: ["label", "labelContext", "value", "disabled"] }, { kind: "ngmodule", type: IconModule }, { kind: "component", type: i2.IconComponent, selector: "aui-icon", inputs: ["icon", "light", "dark", "link", "margin", "size", "color", "background", "backgroundColor"] }, { kind: "component", type: ErrorsMapperComponent, selector: "acl-errors-mapper", inputs: ["errors", "errorsMapper", "errorsMapperFn", "controlName", "ignoreUnknownError"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: PurePipe, name: "pure" }, { kind: "pipe", type: FieldNotAvailablePipe, name: "aclFieldNotAvailable" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1699
+ }
1700
+ __decorate([
1701
+ bind,
1702
+ __metadata("design:type", Function),
1703
+ __metadata("design:paramtypes", [String, String]),
1704
+ __metadata("design:returntype", void 0)
1705
+ ], ResourceRequirementsComponent.prototype, "minValidator", null);
1706
+ __decorate([
1707
+ bind,
1708
+ __metadata("design:type", Function),
1709
+ __metadata("design:paramtypes", [String, String]),
1710
+ __metadata("design:returntype", void 0)
1711
+ ], ResourceRequirementsComponent.prototype, "maxValidator", null);
1712
+ __decorate([
1713
+ bind,
1714
+ __metadata("design:type", Function),
1715
+ __metadata("design:paramtypes", [String, String, String, String]),
1716
+ __metadata("design:returntype", void 0)
1717
+ ], ResourceRequirementsComponent.prototype, "getMinOrMaxErrorsMapper", null);
1718
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: ResourceRequirementsComponent, decorators: [{
1719
+ type: Component,
1720
+ args: [{ selector: 'acl-crd-resource-requirements', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
1721
+ CommonModule,
1722
+ ReactiveFormsModule,
1723
+ FormModule,
1724
+ InputModule,
1725
+ SelectModule,
1726
+ IconModule,
1727
+ ErrorsMapperComponent,
1728
+ TranslatePipe,
1729
+ PurePipe,
1730
+ FieldNotAvailablePipe,
1731
+ ], template: "@if (!readOnly) {\n <form [formGroup]=\"form\">\n <div class=\"resource_requirements\">\n <div class=\"input-group-label\">\n {{ 'resource_requirements_requests' | translate }}\n </div>\n <div\n class=\"input-group-wrapper tw-items-start\"\n formGroupName=\"requests\"\n >\n <div class=\"tw-flex tw-flex-col tw-flex-1\">\n <div\n class=\"input-groups-wrapper cpu\"\n formGroupName=\"cpu\"\n >\n <aui-input-group>\n <div\n auiInputAddonBefore\n class=\"addon-label\"\n [ngClass]=\"{\n 'tw-required-mark': requestCpuRequired,\n }\"\n >\n CPU\n </div>\n <input\n aui-input\n type=\"number\"\n [required]=\"requestCpuRequired\"\n auiFormItemControl\n formControlName=\"value\"\n />\n <aui-select\n auiInputAddonAfter\n auiFormItemControl\n formControlName=\"unit\"\n >\n @for (unit of resourceUnits['cpu']; track unit) {\n <aui-option\n [value]=\"unit.value\"\n [label]=\"unit.label | translate\"\n >\n {{ unit.label | translate }}\n </aui-option>\n }\n </aui-select>\n </aui-input-group>\n </div>\n @if (\n form.get('requests.cpu.value')?.dirty ||\n $any(controlContainer?.formDirective)?.submitted\n ) {\n <acl-errors-mapper\n [errors]=\"form.get('requests.cpu.value').errors\"\n [errorsMapper]=\"{\n min:\n requestCpuMin\n | pure\n : getMinOrMaxErrorsMapper\n : 'min'\n : 'cpu'\n : translate.locale,\n max:\n requestCpuMax\n | pure\n : getMinOrMaxErrorsMapper\n : 'max'\n : 'cpu'\n : translate.locale,\n }\"\n class=\"tw-text-s tw-text-red\"\n >\n </acl-errors-mapper>\n }\n </div>\n <div class=\"tw-flex tw-flex-col tw-flex-1\">\n <div\n class=\"input-groups-wrapper memory\"\n [formGroupName]=\"'memory'\"\n >\n <aui-input-group>\n <div\n auiInputAddonBefore\n class=\"addon-label\"\n [ngClass]=\"{\n 'tw-required-mark': requestMemoryRequired,\n }\"\n >\n {{ 'memory' | translate }}\n </div>\n <input\n aui-input\n type=\"number\"\n auiFormItemControl\n formControlName=\"value\"\n [required]=\"requestMemoryRequired\"\n />\n <aui-select\n auiInputAddonAfter\n auiFormItemControl\n formControlName=\"unit\"\n >\n @for (unit of resourceUnits['memory']; track unit) {\n <aui-option [value]=\"unit\">\n {{ unit }}\n </aui-option>\n }\n </aui-select>\n </aui-input-group>\n </div>\n @if (\n form.get('requests.memory.value')?.dirty ||\n $any(controlContainer?.formDirective)?.submitted\n ) {\n <acl-errors-mapper\n [errors]=\"form.get('requests.memory.value').errors\"\n [errorsMapper]=\"{\n min:\n requestMemoryMin\n | pure\n : getMinOrMaxErrorsMapper\n : 'min'\n : 'memory'\n : translate.locale,\n max:\n requestMemoryMax\n | pure\n : getMinOrMaxErrorsMapper\n : 'max'\n : 'memory'\n : translate.locale,\n }\"\n class=\"tw-text-s tw-text-red\"\n >\n </acl-errors-mapper>\n }\n </div>\n </div>\n </div>\n <div class=\"resource_requirements\">\n <div class=\"input-group-label\">\n {{ 'resource_requirements_limits' | translate }}\n </div>\n <div\n class=\"input-group-wrapper tw-items-start\"\n formGroupName=\"limits\"\n >\n <div class=\"tw-flex tw-flex-col tw-flex-1\">\n <div\n class=\"input-groups-wrapper cpu\"\n [formGroupName]=\"'cpu'\"\n >\n <aui-input-group>\n <div\n auiInputAddonBefore\n class=\"addon-label\"\n [ngClass]=\"{\n 'tw-required-mark': limitCpuRequired,\n }\"\n >\n CPU\n </div>\n <input\n aui-input\n type=\"number\"\n auiFormItemControl\n formControlName=\"value\"\n [required]=\"limitCpuRequired\"\n />\n <aui-select\n auiInputAddonAfter\n auiFormItemControl\n formControlName=\"unit\"\n >\n @for (unit of resourceUnits['cpu']; track unit) {\n <aui-option\n [value]=\"unit.value\"\n [label]=\"unit.label | translate\"\n >\n {{ unit.label | translate }}\n </aui-option>\n }\n </aui-select>\n </aui-input-group>\n </div>\n @if (\n form.get('limits.cpu.value')?.dirty ||\n $any(controlContainer?.formDirective)?.submitted\n ) {\n <acl-errors-mapper\n [errors]=\"form.get('limits.cpu.value').errors\"\n [errorsMapper]=\"{\n cpu_max: 'request_greater_than_limits_error' | translate,\n min:\n limitCpuMin\n | pure\n : getMinOrMaxErrorsMapper\n : 'min'\n : 'cpu'\n : translate.locale,\n max:\n limitCpuMax\n | pure\n : getMinOrMaxErrorsMapper\n : 'max'\n : 'cpu'\n : translate.locale,\n }\"\n class=\"tw-text-s tw-text-red\"\n >\n </acl-errors-mapper>\n }\n </div>\n <div class=\"tw-flex tw-flex-col tw-flex-1\">\n <div\n class=\"input-groups-wrapper memory\"\n [formGroupName]=\"'memory'\"\n >\n <aui-input-group>\n <div\n auiInputAddonBefore\n class=\"addon-label\"\n [ngClass]=\"{\n 'tw-required-mark': limitMemoryRequired,\n }\"\n >\n {{ 'memory' | translate }}\n </div>\n <input\n aui-input\n type=\"number\"\n auiFormItemControl\n formControlName=\"value\"\n [required]=\"limitMemoryRequired\"\n />\n <aui-select\n auiInputAddonAfter\n auiFormItemControl\n formControlName=\"unit\"\n >\n @for (unit of resourceUnits['memory']; track unit) {\n <aui-option [value]=\"unit\">\n {{ unit }}\n </aui-option>\n }\n </aui-select>\n </aui-input-group>\n </div>\n @if (\n form.get('limits.memory.value')?.dirty ||\n $any(controlContainer?.formDirective)?.submitted\n ) {\n <acl-errors-mapper\n [errors]=\"form.get('limits.memory.value').errors\"\n [errorsMapper]=\"{\n memory_max: 'request_greater_than_limits_error' | translate,\n min:\n limitMemoryMin\n | pure\n : getMinOrMaxErrorsMapper\n : 'min'\n : 'memory'\n : translate.locale,\n max:\n limitMemoryMax\n | pure\n : getMinOrMaxErrorsMapper\n : 'max'\n : 'memory'\n : translate.locale,\n }\"\n class=\"tw-text-s tw-text-red\"\n >\n </acl-errors-mapper>\n }\n </div>\n </div>\n </div>\n </form>\n} @else {\n <div class=\"resource_requirements-display\">\n <div class=\"resource_requirements-display-item\">\n <label class=\"resource_requirements-display-item__label\">{{\n 'resource_requirements_requests' | translate\n }}</label>\n <aui-icon\n icon=\"prod:cpu\"\n size=\"16px\"\n color=\"#6359b4\"\n margin=\"right\"\n [title]=\"'cpu' | translate\"\n ></aui-icon\n ><span class=\"tw-mr-16\"\n >{{\n form.get('requests').get('cpu').value\n | pure: getResourceValue\n | aclFieldNotAvailable\n }}{{\n form.get('requests').get('cpu.unit').value\n | pure: getCpuUnitLabel\n | translate\n }}\n </span>\n <aui-icon\n icon=\"prod:memory\"\n size=\"16px\"\n color=\"#007cb5\"\n margin=\"right\"\n [title]=\"'memory' | translate\"\n ></aui-icon\n >{{\n form.get('requests').get('memory').value\n | pure: getResourceValue\n | aclFieldNotAvailable\n }}\n </div>\n <div class=\"resource_requirements-display-item\">\n <label class=\"resource_requirements-display-item__label\">{{\n 'resource_requirements_limits' | translate\n }}</label>\n <aui-icon\n icon=\"prod:cpu\"\n size=\"16px\"\n color=\"#6359b4\"\n margin=\"right\"\n [title]=\"'cpu' | translate\"\n ></aui-icon\n ><span class=\"tw-mr-16\"\n >{{\n form.get('limits').get('cpu').value\n | pure: getResourceValue\n | aclFieldNotAvailable\n }}{{\n form.get('limits').get('cpu.unit').value\n | pure: getCpuUnitLabel\n | translate\n }}\n </span>\n <aui-icon\n icon=\"prod:memory\"\n size=\"16px\"\n color=\"#007cb5\"\n margin=\"right\"\n [title]=\"'memory' | translate\"\n ></aui-icon\n >{{\n form.get('limits').get('memory').value\n | pure: getResourceValue\n | aclFieldNotAvailable\n }}\n </div>\n </div>\n}\n", styles: [":host .resource_requirements:not(:last-of-type){margin-bottom:8px}:host .input-group-wrapper{display:flex}:host .input-group-label{line-height:var(--aui-inline-height-m)}:host aui-input-group{flex:1}:host aui-input-group ::ng-deep .aui-input-group__addon--after{padding:0}:host aui-input-group ::ng-deep .aui-input-group__addon--after aui-select{width:60px}:host aui-input-group ::ng-deep .aui-input-group__addon--after aui-select .aui-input-group{width:62px}html:not([lang|=zh]) :host aui-input-group ::ng-deep .aui-input-group__addon--after aui-select{width:78px}html:not([lang|=zh]) :host aui-input-group ::ng-deep .aui-input-group__addon--after aui-select .aui-input-group{width:80px}:host aui-input-group ::ng-deep .aui-input-group__addon--after aui-select .aui-input{border:0;background-color:transparent!important;border-top-right-radius:var(--aui-border-radius-m);border-bottom-right-radius:var(--aui-border-radius-m)}:host .addon-label{white-space:nowrap}:host .input-groups-wrapper{display:flex;flex:1;align-items:center}:host .input-groups-wrapper:first-child{margin-right:8px}:host .resource_requirements-display-item{display:flex;font-size:14px;line-height:20px;color:rgb(var(--aui-color-main-text));align-items:center;margin-top:8px}:host .resource_requirements-display-item:first-child{margin-top:0}:host .resource_requirements-display-item__label{white-space:nowrap;margin-right:8px}:host .resource_requirements-display-item__value{min-width:0;flex:1;white-space:nowrap;display:flex}:host .resource_requirements-display-item__value__overflow{display:block;overflow:hidden;text-overflow:ellipsis}:host .resource_requirements-display-item__value__wrap{white-space:pre-wrap;flex-wrap:wrap}:host .resource_requirements-display-item__label,:host .resource_requirements-display-item__value{height:100%;align-items:flex-start}:host ::ng-deep .aui-input-group__addon--before{width:70px}html:not([lang|=zh]) :host ::ng-deep .memory .aui-input-group__addon--before{width:82px}\n"] }]
1732
+ }], ctorParameters: () => [], propDecorators: { readOnly: [{
1733
+ type: Input
1734
+ }], field: [{
1735
+ type: Input
1736
+ }], minValidator: [], maxValidator: [], getMinOrMaxErrorsMapper: [] } });
1737
+
1738
+ class YamlEditorComponent extends BaseResourceFormGroupComponent {
1739
+ constructor() {
1740
+ super(inject(Injector));
1741
+ this.disabledActionsConfig = {};
1742
+ this.resultFormat = 'json';
1743
+ this.fieldComponent = inject(forwardRef(() => OperandFieldComponent));
1744
+ this.disabledActionsConfig = this.getDisabledActionsConfig(this.fieldComponent?.field);
1745
+ this.resultFormat = this.getResultFormat(this.fieldComponent?.field);
1746
+ }
1747
+ getResultFormat(field) {
1748
+ return (field?.capabilities
1749
+ .find(c => c.startsWith(SpecCapability.yamlResult))
1750
+ ?.split(SpecCapability.yamlResult)?.[1] || 'json');
1751
+ }
1752
+ createForm() {
1753
+ return this.fb.group({
1754
+ yaml: null,
1755
+ });
1756
+ }
1757
+ getDisabledActionsConfig(field) {
1758
+ const disabledActions = field?.capabilities
1759
+ .find(c => c.startsWith(SpecCapability.yamlActionsDisabled))
1760
+ ?.split(SpecCapability.yamlActionsDisabled)?.[1]
1761
+ ?.split(',') || [];
1762
+ return disabledActions.reduce((acc, cur) => ({ ...acc, [cur]: false }), {});
1763
+ }
1764
+ adaptResourceModel(resource) {
1765
+ try {
1766
+ return {
1767
+ yaml: resource
1768
+ ? stringify(this.resultFormat === 'json'
1769
+ ? resource
1770
+ : JSON.parse(resource))
1771
+ : '',
1772
+ };
1773
+ }
1774
+ catch (e) {
1775
+ console.error(e);
1776
+ return {
1777
+ yaml: '',
1778
+ };
1779
+ }
1780
+ }
1781
+ adaptFormModel(formModel) {
1782
+ try {
1783
+ const parsedYaml = parse(formModel.yaml);
1784
+ return this.resultFormat === 'json'
1785
+ ? parsedYaml
1786
+ : parsedYaml
1787
+ ? JSON.stringify(parsedYaml)
1788
+ : '';
1789
+ }
1790
+ catch { }
1791
+ return null;
1792
+ }
1793
+ getActionsConfig(defaultActions, disabledActions) {
1794
+ return {
1795
+ ...defaultActions,
1796
+ ...disabledActions,
1797
+ };
1798
+ }
1799
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: YamlEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1800
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.1", type: YamlEditorComponent, isStandalone: true, selector: "acl-crd-yaml-editor", inputs: { actionsConfig: "actionsConfig", options: "options" }, usesInheritance: true, ngImport: i0, template: "<form\n aui-form\n [formGroup]=\"form\"\n>\n <aui-code-editor\n auiFormItemControl\n formControlName=\"yaml\"\n [actionsConfig]=\"\n actionsConfig | pure: getActionsConfig : disabledActionsConfig\n \"\n [options]=\"options\"\n ></aui-code-editor>\n</form>\n", styles: [":host{width:100%}:host form{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: FormModule }, { kind: "directive", type: i2.FormItemControlDirective, selector: "[auiFormItemControl]", inputs: ["required"] }, { kind: "component", type: CodeEditorComponent, selector: "aui-code-editor", inputs: ["options", "plain", "showLanguageLabel", "value", "originalValue", "actionsConfig", "previewMode", "diffMode", "modelUri"], outputs: ["editorChange", "editorBlur"] }, { kind: "pipe", type: PurePipe, name: "pure" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1801
+ }
1802
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: YamlEditorComponent, decorators: [{
1803
+ type: Component,
1804
+ args: [{ selector: 'acl-crd-yaml-editor', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [ReactiveFormsModule, FormModule, CodeEditorComponent, PurePipe], template: "<form\n aui-form\n [formGroup]=\"form\"\n>\n <aui-code-editor\n auiFormItemControl\n formControlName=\"yaml\"\n [actionsConfig]=\"\n actionsConfig | pure: getActionsConfig : disabledActionsConfig\n \"\n [options]=\"options\"\n ></aui-code-editor>\n</form>\n", styles: [":host{width:100%}:host form{width:100%}\n"] }]
1805
+ }], ctorParameters: () => [], propDecorators: { actionsConfig: [{
1806
+ type: Input
1807
+ }], options: [{
1808
+ type: Input
1809
+ }] } });
1810
+
1811
+ const PASSWORD_REVEAL = '******';
1812
+ const ENCODING_MAPPER = {
1813
+ base64: {
1814
+ decode,
1815
+ encode,
1816
+ },
1817
+ };
1818
+ class OperandFieldComponent {
1819
+ constructor() {
1820
+ this.readonly = false;
1821
+ this.valueChange = new EventEmitter();
1822
+ this.itemRemove = new EventEmitter();
1823
+ this.control = new FormControl();
1824
+ this.onDestroy$ = new Subject();
1825
+ this.getFieldType = getFieldType;
1826
+ this.isLink = isLink;
1827
+ this.SpecCapability = SpecCapability;
1828
+ this.getFieldDisplayName = getFieldDisplayName;
1829
+ this.getFieldDescription = getFieldDescription$1;
1830
+ this.getFieldPlaceholder = getFieldPlaceholder$1;
1831
+ this.getRadioOptions = getRadioOptions;
1832
+ this.editorOptions = yamlWriteOptions;
1833
+ this.editorActions = createActions;
1834
+ this.isGroupField = isGroupField;
1835
+ this.isArrayField = isArrayField;
1836
+ this.isArrayFieldTable = isArrayFieldTable;
1837
+ this.convertBooleanSwitchValue = convertBooleanSwitchValue;
1838
+ this.loading$ = new BehaviorSubject(false);
1839
+ this.PASSWORD_REVEAL = PASSWORD_REVEAL;
1840
+ this.isBasicTypeField = (filed) => ![
1841
+ SpecCapability.object,
1842
+ SpecCapability.array,
1843
+ SpecCapability.password,
1844
+ SpecCapability.confirmPassword,
1845
+ SpecCapability.externalPassword,
1846
+ ].includes(getFieldType(filed));
1847
+ this.viewActions = viewActions;
1848
+ this.viewOptions = yamlReadOptions;
1849
+ this.crdForm = inject(CrdFormComponent);
1850
+ this.http = inject(HttpClient);
1851
+ this.cdr = inject(ChangeDetectorRef);
1852
+ this.getWidgets = (capabilities) => {
1853
+ const descriptor = capabilities.find(c => c.startsWith(SpecCapability.widgets));
1854
+ return descriptor
1855
+ ? this.crdForm.widgets?.find(w => w.descriptor === descriptor.split('?=')[0])
1856
+ : null;
1857
+ };
1858
+ this.dynamicOptionRefresh$$ = new BehaviorSubject(null);
1859
+ this.dynamicOptionRefreshDisabled$$ = new BehaviorSubject(false);
1860
+ this.dynamicOptionLoading$$ = new Subject();
1861
+ this.dynamicExpression$ = this.field$.pipe(map$1(field => {
1862
+ return new PropsFieldExpression(field).expressions;
1863
+ }), publishRef());
1864
+ this.dynamicOptions$ = this.field$.pipe(switchMap(field => {
1865
+ const dynamicExpression = new PropsFieldExpression(field).expressions;
1866
+ if (!dynamicExpression.options) {
1867
+ return of(this.getSelectOptions(field).map(value => ({
1868
+ label: value,
1869
+ value,
1870
+ })));
1871
+ }
1872
+ return combineLatest([
1873
+ this.dynamicOptionRefresh$$,
1874
+ combineLatest([this.crdForm.formContext$, this.formDataState$]).pipe(debounceTime(100), distinctUntilChanged((p, n) => compareWithSubscribedPaths(dynamicExpression, p, n)), tap(([formContext, formDataState]) => {
1875
+ if (this.crdForm.debug) {
1876
+ /* eslint-disable no-console */
1877
+ console.log('field: ', field, 'formContext: ', formContext, 'formDataState: ', formDataState.toJS());
1878
+ }
1879
+ })),
1880
+ ]).pipe(map$1(([, [formContext, formDataState]]) => [formContext, formDataState]), tap(() => {
1881
+ this.dynamicOptionLoading$$.next(true);
1882
+ }), switchMap(([formContext, formDataState]) => {
1883
+ let result = [];
1884
+ const { api, labelPath, valuePath, expression } = dynamicExpression.options;
1885
+ const stringExpressionContext = this.getStringExpressionContext(formContext, formDataState);
1886
+ // console.log('api: ', api);
1887
+ const url = template(api)(stringExpressionContext);
1888
+ this.dynamicOptionRefreshDisabled$$.next(url.includes('//'));
1889
+ if (!api && expression) {
1890
+ result = evalInContext(expression, stringExpressionContext);
1891
+ }
1892
+ else {
1893
+ return stringExpressionContext.fetchResourceList(url, (item) => {
1894
+ const value = get(item, valuePath, '');
1895
+ return {
1896
+ label: get(item, labelPath, value),
1897
+ value,
1898
+ };
1899
+ });
1900
+ }
1901
+ return isObservable(result) ? result : of(result);
1902
+ }), tap(() => {
1903
+ this.dynamicOptionLoading$$.next(false);
1904
+ }));
1905
+ }), publishRef());
1906
+ this.staticDefaultValue$ = this.field$.pipe(switchMap(field => {
1907
+ const defaultValueExpression = new PropsFieldExpression(field)
1908
+ .expressions;
1909
+ if (!defaultValueExpression.default ||
1910
+ this.getFieldCurrentValue() !== undefined) {
1911
+ return of({
1912
+ value: this.getFieldValue(),
1913
+ isDynamic: false,
1914
+ });
1915
+ }
1916
+ return combineLatest([
1917
+ this.crdForm.formContext$,
1918
+ this.formDataState$,
1919
+ ]).pipe(distinctUntilChanged((p, n) => compareWithSubscribedPaths(defaultValueExpression, p, n)), map$1(([formContext, formDataState]) => template(defaultValueExpression.default)(this.getStringExpressionContext(formContext, formDataState))), map$1(value => ({
1920
+ value,
1921
+ isDynamic: true,
1922
+ })));
1923
+ }), publishRef());
1924
+ this.dynamicHiddenValue$ = this.field$.pipe(switchMap(field => {
1925
+ const { expressions } = new PropsFieldExpression(field);
1926
+ if (!expressions.hidden) {
1927
+ return of(false);
1928
+ }
1929
+ return combineLatest([
1930
+ this.crdForm.formContext$,
1931
+ this.formDataState$,
1932
+ ]).pipe(distinctUntilChanged((p, n) => compareWithSubscribedPaths(expressions, p, n)), map$1(([formContext, formDataState]) => template(expressions.hidden)(this.getStringExpressionContext(formContext, formDataState)) === 'true'));
1933
+ }));
1934
+ this.getStringExpressionContext = (formContext, formDataState) => ({
1935
+ fetchResourceList: this.fetchResourceList,
1936
+ context: formContext || {},
1937
+ formData: formDataState.toJS()?.spec || {},
1938
+ });
1939
+ this.fetchResourceList = (url, callback) => {
1940
+ // 例如 '/kubernetes/global/api/v1/namespaces//secrets' 表示 formData.namespace 没有插值
1941
+ if (url.includes('//')) {
1942
+ return of([]);
1943
+ }
1944
+ this.loading$.next(true);
1945
+ return this.http
1946
+ .get(`${API_GATEWAY}${url}`)
1947
+ .pipe(map$1(res => res.items.map(item => callback.call(this, item))), skipError([]), finalize(() => {
1948
+ this.loading$.next(false);
1949
+ }));
1950
+ };
1951
+ }
1952
+ get isDisabled() {
1953
+ return this.readonly || this.field?.disabled;
1954
+ }
1955
+ get effectControlDefaultValue() {
1956
+ return this.crdForm.effectControlDefaultValue;
1957
+ }
1958
+ get isRequired() {
1959
+ return isRequired(this.field);
1960
+ }
1961
+ get isCreatable() {
1962
+ return isCreatable(this.field);
1963
+ }
1964
+ get isMultiple() {
1965
+ return isMultiple(this.field);
1966
+ }
1967
+ get isAllowCreate() {
1968
+ return isAllowCreate(this.field);
1969
+ }
1970
+ get isClearable() {
1971
+ return isClearable(this.field);
1972
+ }
1973
+ // 通过hidden属性隐藏不必要的元素,和 aclScrollToFirstInvalid 指令过滤隐藏元素保持一致
1974
+ get isHidden() {
1975
+ return ((this.hasFieldDependency() && !this.checkFieldDependency(this.field)) ||
1976
+ this._hidden);
1977
+ }
1978
+ set isHidden(hidden) {
1979
+ this._hidden = hidden;
1980
+ this.cdr.markForCheck();
1981
+ }
1982
+ get isCustomErrorsMapper() {
1983
+ return getFieldType(this.field) === SpecCapability.resourceRequirements;
1984
+ }
1985
+ registerControl() {
1986
+ this.crdForm.controlMap.set(getOperandPath(this.field), this.control);
1987
+ }
1988
+ unRegisterControl() {
1989
+ this.crdForm.controlMap.delete(getOperandPath(this.field));
1990
+ }
1991
+ ngOnInit() {
1992
+ this.dynamicHiddenValue$.subscribe(value => {
1993
+ this.isHidden = value;
1994
+ });
1995
+ this.registerControl();
1996
+ if (this.field.validations) {
1997
+ const validators = map(this.field.validations, (val, rule) => {
1998
+ switch (rule) {
1999
+ case Validations.maximum: {
2000
+ return Validators.max(val);
2001
+ }
2002
+ case Validations.minimum: {
2003
+ return Validators.min(val);
2004
+ }
2005
+ case Validations.required: {
2006
+ return Validators.required;
2007
+ }
2008
+ case Validations.maxLength: {
2009
+ return Validators.maxLength(val);
2010
+ }
2011
+ case Validations.minLength: {
2012
+ return Validators.minLength(val);
2013
+ }
2014
+ case Validations.pattern: {
2015
+ return Validators.pattern(val);
2016
+ }
2017
+ default: {
2018
+ return null;
2019
+ }
2020
+ }
2021
+ }).filter(v => !!v);
2022
+ if (validators.length) {
2023
+ this.control.addValidators((this._validators = validators));
2024
+ }
2025
+ }
2026
+ }
2027
+ // 将 valueChanges 的逻辑移动到 ngAfterViewInit 中,主要是为了避免全局 ValidatorsDirective带来的影响,需要等到ValidatorsDirective的ngAfterViewInit之后再订阅control的valueChanges
2028
+ ngAfterViewInit() {
2029
+ this.control.valueChanges
2030
+ .pipe(startWithCondition(this.effectControlDefaultValue, this.control.value), debounceTime(50), distinctUntilChanged(), takeUntil(this.onDestroy$), filter(v =>
2031
+ // FIXME: This is hack. yaml value will only be null if format error(because try-catch), the data flow now is from control => formDataState => control(will judge equality),this will make control be empty
2032
+ getFieldType(this.field) === SpecCapability.yaml ? v !== null : true))
2033
+ .subscribe(value => {
2034
+ this.valueChange.emit({
2035
+ field: this.field,
2036
+ data: value,
2037
+ errors: this.control.errors,
2038
+ });
2039
+ });
2040
+ }
2041
+ ngOnDestroy() {
2042
+ this.onDestroy$.next();
2043
+ this.onDestroy$.complete();
2044
+ this.unRegisterControl();
2045
+ if (this._validators?.length) {
2046
+ this.control.removeValidators(this._validators);
2047
+ }
2048
+ }
2049
+ ngOnChanges({ formDataState }) {
2050
+ if (this.field && formDataState?.firstChange) {
2051
+ this.staticDefaultValue$
2052
+ .pipe(take(1), filter(({ value }) => value !== undefined))
2053
+ .subscribe(({ value, isDynamic }) => {
2054
+ this.control.setValue(value, { emitEvent: isDynamic });
2055
+ });
2056
+ }
2057
+ else if (formDataState?.currentValue) {
2058
+ const currentValue = getFormData(formDataState.currentValue, this.field.path, false);
2059
+ const prevValue = getFormData(formDataState.previousValue, this.field.path, false);
2060
+ const rawValue = isImmutable(currentValue)
2061
+ ? currentValue.toJS()
2062
+ : currentValue;
2063
+ if (!isEqual(rawValue, prevValue) &&
2064
+ !isEqual(rawValue, this.control.value)) {
2065
+ this.control.setValue(rawValue);
2066
+ }
2067
+ }
2068
+ }
2069
+ getFieldCurrentValue() {
2070
+ let value = getFormData(this.formDataState, this.field.path, false);
2071
+ // 如果值是 Immutable object 类型,需要转成原始 JS Object
2072
+ if (isImmutable(value)) {
2073
+ value = value.toJS();
2074
+ }
2075
+ return value;
2076
+ }
2077
+ getFieldValue(useDefault = true) {
2078
+ const currentValue = this.getFieldCurrentValue();
2079
+ if (currentValue === undefined && useDefault) {
2080
+ return getDefaultValue(this.field);
2081
+ }
2082
+ return currentValue;
2083
+ }
2084
+ getOptionDisplay(value, options) {
2085
+ return options.find(item => item.value === value)?.display;
2086
+ }
2087
+ getSelectOptions(field) {
2088
+ return field.capabilities
2089
+ .filter(c => c.startsWith(SpecCapability.select))
2090
+ .map(c => c.split(SpecCapability.select)?.[1]);
2091
+ }
2092
+ getEncoding(field, type) {
2093
+ const prefix = `urn:alm:descriptor:${type}:encoding:`;
2094
+ const capability = field.capabilities.find(it => it.startsWith(prefix));
2095
+ let encoding;
2096
+ if (capability) {
2097
+ encoding = ENCODING_MAPPER[capability.slice(prefix.length)];
2098
+ }
2099
+ return (encoding || {
2100
+ encode: identity,
2101
+ decode: identity,
2102
+ });
2103
+ }
2104
+ hasFieldDependency() {
2105
+ return this.field.capabilities.some(c => c.startsWith(SpecCapability.fieldDependency));
2106
+ }
2107
+ checkFieldDependency(field) {
2108
+ try {
2109
+ const dependencies = field?.capabilities
2110
+ .filter(c => c.startsWith(SpecCapability.fieldDependency))
2111
+ .map(i => i.split(SpecCapability.fieldDependency)[1]);
2112
+ if (!dependencies?.length) {
2113
+ return true;
2114
+ }
2115
+ const parentPaths = dependencies.map(d => d.split(':'));
2116
+ const state = parentPaths.every(([path, ...values]) => {
2117
+ // Support depend one of values
2118
+ const dependencyField = this.fields.find(f => f.path === normalizePath(path));
2119
+ const dependencyDefaultValue = getDefaultValue(dependencyField);
2120
+ const formStateValue = getFormData(this.formDataState, path);
2121
+ const currentValue = formStateValue === null || formStateValue === undefined
2122
+ ? dependencyDefaultValue
2123
+ : formStateValue;
2124
+ return values.some(val => convertValue(val, dependencyField.type) === currentValue);
2125
+ });
2126
+ /**
2127
+ * 父 field dependency 不满足时,即隐藏时,本 field 也应当隐藏。
2128
+ * 因为在大部分情形下,fieldDependency 与 oneOf 搭配来描述一组关联关系,很少只有 b 仅依赖于 a,当 a 隐藏后,还要根据 a 的默认值要求显示 b 的情况,
2129
+ * 对于该情况,可以多加一个配备了额外 fieldDependency 的 Descriptor 来描述 b
2130
+ */
2131
+ return (parentPaths.every(([path]) => this.checkFieldDependency(this.fields.find(i => i.path === path))) && state);
2132
+ }
2133
+ catch (error) {
2134
+ console.error(error);
2135
+ return false;
2136
+ }
2137
+ }
2138
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: OperandFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2139
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.1", type: OperandFieldComponent, isStandalone: true, selector: "acl-operand-field", inputs: { field: "field", readonly: "readonly", fields: "fields", formDataState: "formDataState", formErrors: "formErrors" }, outputs: { valueChange: "valueChange", itemRemove: "itemRemove" }, host: { properties: { "hidden": "this.isHidden" } }, usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"field\">\n <ng-container\n *ngIf=\"{\n fieldType: field | pure: getFieldType,\n isBasicTypeField: field | pure: isBasicTypeField,\n } as meta\"\n >\n <ng-container *ngIf=\"meta.isBasicTypeField; else advancedFiled\">\n <acl-crd-form-item\n *ngIf=\"!(field.capabilities | pure: getWidgets)\"\n [ngSwitch]=\"meta.fieldType\"\n >\n <input\n *ngSwitchCase=\"SpecCapability.number\"\n type=\"number\"\n aui-input\n auiFormItemControl\n [required]=\"isRequired\"\n [formControl]=\"control\"\n [aclReadonlyField]=\"isDisabled\"\n [placeholder]=\"field | pure: getFieldPlaceholder | translate\"\n />\n <ng-container *ngSwitchCase=\"SpecCapability.booleanSwitch\">\n <aui-switch\n auiFormItemControl\n [aclReadonlyField]=\"isDisabled\"\n [aclReadonlyFieldTemplate]=\"switchReadonly\"\n [formControl]=\"control\"\n ></aui-switch>\n <ng-template #switchReadonly>{{\n control.value\n | pure: convertBooleanSwitchValue : field.capabilities\n | translate\n }}</ng-template>\n </ng-container>\n <ng-container *ngSwitchCase=\"SpecCapability.select\">\n <aui-multi-select\n *ngIf=\"isMultiple\"\n [maxRowCount]=\"3\"\n auiFormItemControl\n [clearable]=\"true\"\n [filterable]=\"true\"\n [formControl]=\"control\"\n [required]=\"isRequired\"\n [aclReadonlyField]=\"isDisabled\"\n [loading]=\"loading$ | async\"\n [allowCreate]=\"isAllowCreate\"\n >\n <aui-option\n *ngFor=\"let option of dynamicOptions$ | async\"\n [value]=\"option.value\"\n [label]=\"option.label\"\n >\n {{ option.label }}\n </aui-option>\n <aui-option-placeholder>{{\n 'no_data' | translate\n }}</aui-option-placeholder>\n </aui-multi-select>\n\n <aui-select\n *ngIf=\"!isMultiple\"\n auiFormItemControl\n [clearable]=\"true\"\n [filterable]=\"true\"\n [formControl]=\"control\"\n [required]=\"isRequired\"\n [aclReadonlyField]=\"isDisabled\"\n [loading]=\"loading$ | async\"\n [allowCreate]=\"isAllowCreate\"\n >\n <aui-option\n *ngFor=\"let option of dynamicOptions$ | async\"\n [value]=\"option.value\"\n [label]=\"option.label | aclParseJsonTranslate\"\n >\n {{ option.label | aclParseJsonTranslate }}\n </aui-option>\n <aui-option-placeholder>{{\n 'no_data' | translate\n }}</aui-option-placeholder>\n </aui-select>\n\n <button\n *ngIf=\"(dynamicExpression$ | async).options\"\n style=\"margin-left: 4px\"\n aui-button\n type=\"button\"\n [square]=\"true\"\n [disabled]=\"\n (dynamicOptionRefreshDisabled$$ | async) ||\n (dynamicOptionLoading$$ | async)\n \"\n [loading]=\"dynamicOptionLoading$$ | async\"\n (click)=\"dynamicOptionRefresh$$.next()\"\n >\n <aui-icon icon=\"rotate_right\"></aui-icon>\n </button>\n </ng-container>\n <aui-radio-group\n *ngSwitchCase=\"SpecCapability.radio\"\n auiFormItemControl\n [formControl]=\"control\"\n [required]=\"isRequired\"\n [aclReadonlyField]=\"isDisabled\"\n [aclReadonlyFieldTemplate]=\"radioLabel\"\n >\n <ng-container>\n <aui-radio-button\n *ngFor=\"let option of field.capabilities | pure: getRadioOptions\"\n [value]=\"option.value\"\n >\n {{ option.display | translate }}\n </aui-radio-button>\n <ng-template #radioLabel>\n {{\n control.value\n | pure\n : getOptionDisplay\n : (field.capabilities | pure: getRadioOptions)\n | translate\n }}\n </ng-template>\n </ng-container>\n </aui-radio-group>\n <ng-container *ngSwitchCase=\"SpecCapability.resourceRequirements\">\n <acl-crd-resource-requirements\n auiFormItemControl\n [required]=\"isRequired\"\n [formControl]=\"control\"\n [aclReadonlyField]=\"isDisabled\"\n [aclReadonlyFieldTemplate]=\"resourceRequirementsReadonly\"\n ></acl-crd-resource-requirements>\n <ng-template #resourceRequirementsReadonly>\n <acl-crd-resource-requirements\n auiFormItemControl\n [ngModel]=\"control.value\"\n [readOnly]=\"true\"\n ></acl-crd-resource-requirements>\n </ng-template>\n </ng-container>\n <ng-container *ngSwitchCase=\"SpecCapability.yaml\">\n <acl-crd-yaml-editor\n auiFormItemControl\n [formControl]=\"control\"\n [required]=\"isRequired\"\n [actionsConfig]=\"editorActions\"\n [options]=\"editorOptions\"\n [aclReadonlyField]=\"isDisabled\"\n [aclReadonlyFieldTemplate]=\"yamlReadonly\"\n ></acl-crd-yaml-editor>\n <ng-template #yamlReadonly>\n <acl-crd-yaml-editor\n auiFormItemControl\n [ngModel]=\"control.value\"\n [actionsConfig]=\"viewActions\"\n [options]=\"viewOptions\"\n ></acl-crd-yaml-editor>\n </ng-template>\n </ng-container>\n <ng-container *ngSwitchCase=\"SpecCapability.k8sResourcePrefix\">\n <acl-crd-resource-prefix\n auiFormItemControl\n [formErrors]=\"control.errors\"\n [field]=\"field\"\n [required]=\"isRequired\"\n [formControl]=\"control\"\n [aclReadonlyField]=\"isDisabled\"\n [aclReadonlyFieldTemplate]=\"resourcePrefixReadonly\"\n ></acl-crd-resource-prefix>\n <ng-template #resourcePrefixReadonly>\n <acl-crd-resource-prefix\n auiFormItemControl\n [field]=\"field\"\n [ngModel]=\"control.value\"\n [readonly]=\"true\"\n ></acl-crd-resource-prefix>\n </ng-template>\n </ng-container>\n <ng-container *ngSwitchCase=\"SpecCapability.basicAuthSecret\">\n <acl-crd-basic-auth-secret\n auiFormItemControl\n [field]=\"field\"\n [required]=\"isRequired\"\n [formControl]=\"control\"\n [aclReadonlyField]=\"isDisabled\"\n ></acl-crd-basic-auth-secret>\n </ng-container>\n <textarea\n *ngSwitchCase=\"SpecCapability.textarea\"\n auiFormItemControl\n aui-input\n [required]=\"isRequired\"\n [formControl]=\"control\"\n [aclReadonlyField]=\"isDisabled\"\n [placeholder]=\"field | pure: getFieldPlaceholder | translate\"\n ></textarea>\n <aui-tags-input\n *ngSwitchCase=\"SpecCapability.tagsInput\"\n auiFormItemControl\n class=\"tw-flex-1\"\n [required]=\"isRequired\"\n [formControl]=\"control\"\n [placeholder]=\"field | pure: getFieldPlaceholder | translate\"\n [aclReadonlyField]=\"isDisabled\"\n [clearable]=\"isClearable\"\n ></aui-tags-input>\n <ng-container *ngSwitchDefault>\n <acl-crd-link\n *ngIf=\"(field | pure: isLink) && isDisabled; else textField\"\n auiFormItemControl\n [field]=\"field\"\n [formControl]=\"control\"\n ></acl-crd-link>\n </ng-container>\n <ng-template #textField>\n <input\n type=\"text\"\n auiFormItemControl\n [required]=\"isRequired\"\n aui-input\n [formControl]=\"control\"\n [placeholder]=\"field | pure: getFieldPlaceholder | translate\"\n [aclReadonlyField]=\"isDisabled\"\n />\n </ng-template>\n </acl-crd-form-item>\n <div\n class=\"tw-flex tw-w-full tw-flex-col\"\n *ngIf=\"field.capabilities | pure: getWidgets as widget\"\n >\n <ng-container *ngComponentOutlet=\"widget.component\"></ng-container>\n </div>\n </ng-container>\n <ng-template #advancedFiled>\n <ng-container\n *ngIf=\"\n meta.fieldType === SpecCapability.password ||\n meta.fieldType === SpecCapability.confirmPassword ||\n meta.fieldType === SpecCapability.externalPassword\n \"\n >\n <acl-crd-form-item\n *ngIf=\"isDisabled\"\n [plain]=\"true\"\n >\n <ng-container *ngTemplateOutlet=\"passwordView\"></ng-container>\n </acl-crd-form-item>\n <acl-password-input\n *ngIf=\"!isDisabled\"\n [initPassword]=\"control.value\"\n [label]=\"field | pure: getFieldDisplayName | translate\"\n [hint]=\"field | pure: getFieldDescription | translate\"\n [formControl]=\"control\"\n [required]=\"isRequired\"\n [readonly]=\"crdForm.readonly\"\n [isUpdate]=\"!!control.value && !control.dirty\"\n [strongPassword]=\"meta.fieldType !== SpecCapability.externalPassword\"\n [enableConfirm]=\"meta.fieldType === SpecCapability.confirmPassword\"\n width=\"large\"\n [encoding]=\"field | pure: getEncoding : 'password'\"\n [pattern]=\"field.validations?.pattern\"\n [placeholder]=\"field | pure: getFieldPlaceholder | translate\"\n ></acl-password-input>\n </ng-container>\n <!-- group field -->\n <ng-container *ngIf=\"isGroupField(field) && field.fieldList?.length > 0\">\n <acl-operand-field-group\n [fields]=\"fields\"\n [fieldGroup]=\"field\"\n [readonly]=\"isDisabled\"\n [formDataState]=\"formDataState\"\n [formErrors]=\"formErrors\"\n (valueChange)=\"valueChange.emit($event)\"\n >\n </acl-operand-field-group>\n </ng-container>\n <!-- array field groups -->\n <!-- array field table -->\n <ng-container *ngIf=\"isArrayField(field)\">\n <acl-crd-array-table\n *ngIf=\"field | pure: isArrayFieldTable; else defaultArrayFiled\"\n [arrayFieldGroup]=\"field\"\n [formDataState]=\"formDataState\"\n [readonly]=\"isDisabled\"\n (valueChange)=\"valueChange.emit($event)\"\n >\n </acl-crd-array-table>\n <ng-template #defaultArrayFiled>\n <acl-operand-array-field-group\n [arrayFieldGroup]=\"field\"\n [fields]=\"fields\"\n [readonly]=\"isDisabled\"\n [formDataState]=\"formDataState\"\n (valueChange)=\"valueChange.emit($event)\"\n >\n </acl-operand-array-field-group>\n </ng-template>\n </ng-container>\n </ng-template>\n </ng-container>\n</ng-container>\n\n<ng-template #passwordView>\n {{ PASSWORD_REVEAL }}\n</ng-template>\n", styles: [":host .input-group{width:100%}:host ::ng-deep .aui-form-item__label-wrapper:not(.hasLabel){display:none}\n"], dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => CommonModule) }, { kind: "directive", type: i0.forwardRef(() => i1$1.NgComponentOutlet), selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: i0.forwardRef(() => i1$1.NgForOf), selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i0.forwardRef(() => i1$1.NgIf), selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i0.forwardRef(() => i1$1.NgTemplateOutlet), selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i0.forwardRef(() => i1$1.NgSwitch), selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i0.forwardRef(() => i1$1.NgSwitchCase), selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i0.forwardRef(() => i1$1.NgSwitchDefault), selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: i0.forwardRef(() => FormsModule) }, { kind: "directive", type: i0.forwardRef(() => i1.DefaultValueAccessor), selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i0.forwardRef(() => i1.NumberValueAccessor), selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i0.forwardRef(() => i1.NgControlStatus), selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i0.forwardRef(() => i1.RequiredValidator), selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i0.forwardRef(() => i1.PatternValidator), selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i0.forwardRef(() => i1.NgModel), selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: i0.forwardRef(() => ReactiveFormsModule) }, { kind: "directive", type: i0.forwardRef(() => i1.FormControlDirective), selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: i0.forwardRef(() => FormModule) }, { kind: "directive", type: i0.forwardRef(() => i2.FormItemControlDirective), selector: "[auiFormItemControl]", inputs: ["required"] }, { kind: "ngmodule", type: i0.forwardRef(() => InputModule) }, { kind: "component", type: i0.forwardRef(() => i2.InputComponent), selector: "input[aui-input],textarea[aui-input]", inputs: ["size", "disabled"] }, { kind: "component", type: i0.forwardRef(() => i2.TagsInputComponent), selector: "aui-tags-input", inputs: ["placeholder", "size", "clearable", "allowRepeat", "allowEmpty", "readonlyTags", "maxRowCount", "customRowHeight", "inputValidator", "inputAsyncValidator"] }, { kind: "ngmodule", type: i0.forwardRef(() => SelectModule) }, { kind: "component", type: i0.forwardRef(() => i2.SelectComponent), selector: "aui-select" }, { kind: "component", type: i0.forwardRef(() => i2.OptionComponent), selector: "aui-option", inputs: ["label", "labelContext", "value", "disabled"] }, { kind: "component", type: i0.forwardRef(() => i2.OptionPlaceholderComponent), selector: "aui-option-placeholder" }, { kind: "component", type: i0.forwardRef(() => i2.MultiSelectComponent), selector: "aui-multi-select", inputs: ["tagClassFn", "maxRowCount", "customRowHeight", "allowSelectAll"] }, { kind: "ngmodule", type: i0.forwardRef(() => RadioModule) }, { kind: "component", type: i0.forwardRef(() => i2.RadioGroupComponent), selector: "aui-radio-group", inputs: ["size", "direction", "plain", "name"] }, { kind: "component", type: i0.forwardRef(() => i2.RadioButtonComponent), selector: "aui-radio-button" }, { kind: "ngmodule", type: i0.forwardRef(() => SwitchModule) }, { kind: "component", type: i0.forwardRef(() => i2.SwitchComponent), selector: "aui-switch", inputs: ["loading"] }, { kind: "ngmodule", type: i0.forwardRef(() => TagModule) }, { kind: "ngmodule", type: i0.forwardRef(() => IconModule) }, { kind: "component", type: i0.forwardRef(() => i2.IconComponent), selector: "aui-icon", inputs: ["icon", "light", "dark", "link", "margin", "size", "color", "background", "backgroundColor"] }, { kind: "ngmodule", type: i0.forwardRef(() => ButtonModule) }, { kind: "component", type: i0.forwardRef(() => i2.ButtonComponent), selector: "button[aui-button]", inputs: ["aui-button", "size", "plain", "loading", "round", "square"] }, { kind: "ngmodule", type: i0.forwardRef(() => TooltipModule) }, { kind: "component", type: i0.forwardRef(() => FormItemComponent), selector: "acl-crd-form-item", inputs: ["plain"] }, { kind: "component", type: i0.forwardRef(() => OperandFieldGroupComponent), selector: "acl-operand-field-group", inputs: ["fields", "fieldGroup", "formDataState", "formErrors", "readonly"], outputs: ["valueChange"] }, { kind: "component", type: i0.forwardRef(() => OperandArrayFieldGroupComponent), selector: "acl-operand-array-field-group" }, { kind: "component", type: i0.forwardRef(() => CrdFormArrayTableComponent), selector: "acl-crd-array-table" }, { kind: "component", type: i0.forwardRef(() => ResourceRequirementsComponent), selector: "acl-crd-resource-requirements", inputs: ["readOnly", "field"] }, { kind: "component", type: i0.forwardRef(() => YamlEditorComponent), selector: "acl-crd-yaml-editor", inputs: ["actionsConfig", "options"] }, { kind: "component", type: i0.forwardRef(() => K8sResourcePrefixComponent), selector: "acl-crd-resource-prefix", inputs: ["field", "readonly", "formErrors"] }, { kind: "component", type: i0.forwardRef(() => BasicAuthSecretComponent), selector: "acl-crd-basic-auth-secret", inputs: ["required", "field"] }, { kind: "component", type: i0.forwardRef(() => LinkComponent), selector: "acl-crd-link", inputs: ["field"] }, { kind: "component", type: i0.forwardRef(() => PasswordInputComponent), selector: "acl-password-input", inputs: ["initPassword", "label", "hint", "specialChars", "strongPassword", "enableConfirm", "width", "toggleable", "pattern", "encoding", "placeholder", "readonly", "isUpdate", "required"] }, { kind: "directive", type: i0.forwardRef(() => ReadonlyFieldDirective), selector: "[aclReadonlyField]", inputs: ["aclReadonlyField", "hidden", "aclReadonlyFieldTemplate", "aclReadonlyFieldTemplateContext"] }, { kind: "pipe", type: i0.forwardRef(() => i1$1.AsyncPipe), name: "async" }, { kind: "pipe", type: i0.forwardRef(() => ParseJsonTranslatePipe), name: "aclParseJsonTranslate" }, { kind: "pipe", type: i0.forwardRef(() => PurePipe), name: "pure" }, { kind: "pipe", type: i0.forwardRef(() => TranslatePipe), name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2140
+ }
2141
+ __decorate([
2142
+ ObservableInput(),
2143
+ __metadata("design:type", Observable)
2144
+ ], OperandFieldComponent.prototype, "field$", void 0);
2145
+ __decorate([
2146
+ ObservableInput(),
2147
+ __metadata("design:type", Observable)
2148
+ ], OperandFieldComponent.prototype, "formDataState$", void 0);
2149
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: OperandFieldComponent, decorators: [{
2150
+ type: Component,
2151
+ args: [{ selector: 'acl-operand-field', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
2152
+ CommonModule,
2153
+ FormsModule,
2154
+ ReactiveFormsModule,
2155
+ FormModule,
2156
+ InputModule,
2157
+ SelectModule,
2158
+ RadioModule,
2159
+ SwitchModule,
2160
+ TagModule,
2161
+ IconModule,
2162
+ ButtonModule,
2163
+ TooltipModule,
2164
+ forwardRef(() => FormItemComponent),
2165
+ forwardRef(() => OperandFieldGroupComponent),
2166
+ forwardRef(() => OperandArrayFieldGroupComponent),
2167
+ forwardRef(() => CrdFormArrayTableComponent),
2168
+ forwardRef(() => ResourceRequirementsComponent),
2169
+ forwardRef(() => YamlEditorComponent),
2170
+ K8sResourcePrefixComponent,
2171
+ BasicAuthSecretComponent,
2172
+ LinkComponent,
2173
+ PasswordInputComponent,
2174
+ ReadonlyFieldDirective,
2175
+ ParseJsonTranslatePipe,
2176
+ PurePipe,
2177
+ TranslatePipe,
2178
+ ], template: "<ng-container *ngIf=\"field\">\n <ng-container\n *ngIf=\"{\n fieldType: field | pure: getFieldType,\n isBasicTypeField: field | pure: isBasicTypeField,\n } as meta\"\n >\n <ng-container *ngIf=\"meta.isBasicTypeField; else advancedFiled\">\n <acl-crd-form-item\n *ngIf=\"!(field.capabilities | pure: getWidgets)\"\n [ngSwitch]=\"meta.fieldType\"\n >\n <input\n *ngSwitchCase=\"SpecCapability.number\"\n type=\"number\"\n aui-input\n auiFormItemControl\n [required]=\"isRequired\"\n [formControl]=\"control\"\n [aclReadonlyField]=\"isDisabled\"\n [placeholder]=\"field | pure: getFieldPlaceholder | translate\"\n />\n <ng-container *ngSwitchCase=\"SpecCapability.booleanSwitch\">\n <aui-switch\n auiFormItemControl\n [aclReadonlyField]=\"isDisabled\"\n [aclReadonlyFieldTemplate]=\"switchReadonly\"\n [formControl]=\"control\"\n ></aui-switch>\n <ng-template #switchReadonly>{{\n control.value\n | pure: convertBooleanSwitchValue : field.capabilities\n | translate\n }}</ng-template>\n </ng-container>\n <ng-container *ngSwitchCase=\"SpecCapability.select\">\n <aui-multi-select\n *ngIf=\"isMultiple\"\n [maxRowCount]=\"3\"\n auiFormItemControl\n [clearable]=\"true\"\n [filterable]=\"true\"\n [formControl]=\"control\"\n [required]=\"isRequired\"\n [aclReadonlyField]=\"isDisabled\"\n [loading]=\"loading$ | async\"\n [allowCreate]=\"isAllowCreate\"\n >\n <aui-option\n *ngFor=\"let option of dynamicOptions$ | async\"\n [value]=\"option.value\"\n [label]=\"option.label\"\n >\n {{ option.label }}\n </aui-option>\n <aui-option-placeholder>{{\n 'no_data' | translate\n }}</aui-option-placeholder>\n </aui-multi-select>\n\n <aui-select\n *ngIf=\"!isMultiple\"\n auiFormItemControl\n [clearable]=\"true\"\n [filterable]=\"true\"\n [formControl]=\"control\"\n [required]=\"isRequired\"\n [aclReadonlyField]=\"isDisabled\"\n [loading]=\"loading$ | async\"\n [allowCreate]=\"isAllowCreate\"\n >\n <aui-option\n *ngFor=\"let option of dynamicOptions$ | async\"\n [value]=\"option.value\"\n [label]=\"option.label | aclParseJsonTranslate\"\n >\n {{ option.label | aclParseJsonTranslate }}\n </aui-option>\n <aui-option-placeholder>{{\n 'no_data' | translate\n }}</aui-option-placeholder>\n </aui-select>\n\n <button\n *ngIf=\"(dynamicExpression$ | async).options\"\n style=\"margin-left: 4px\"\n aui-button\n type=\"button\"\n [square]=\"true\"\n [disabled]=\"\n (dynamicOptionRefreshDisabled$$ | async) ||\n (dynamicOptionLoading$$ | async)\n \"\n [loading]=\"dynamicOptionLoading$$ | async\"\n (click)=\"dynamicOptionRefresh$$.next()\"\n >\n <aui-icon icon=\"rotate_right\"></aui-icon>\n </button>\n </ng-container>\n <aui-radio-group\n *ngSwitchCase=\"SpecCapability.radio\"\n auiFormItemControl\n [formControl]=\"control\"\n [required]=\"isRequired\"\n [aclReadonlyField]=\"isDisabled\"\n [aclReadonlyFieldTemplate]=\"radioLabel\"\n >\n <ng-container>\n <aui-radio-button\n *ngFor=\"let option of field.capabilities | pure: getRadioOptions\"\n [value]=\"option.value\"\n >\n {{ option.display | translate }}\n </aui-radio-button>\n <ng-template #radioLabel>\n {{\n control.value\n | pure\n : getOptionDisplay\n : (field.capabilities | pure: getRadioOptions)\n | translate\n }}\n </ng-template>\n </ng-container>\n </aui-radio-group>\n <ng-container *ngSwitchCase=\"SpecCapability.resourceRequirements\">\n <acl-crd-resource-requirements\n auiFormItemControl\n [required]=\"isRequired\"\n [formControl]=\"control\"\n [aclReadonlyField]=\"isDisabled\"\n [aclReadonlyFieldTemplate]=\"resourceRequirementsReadonly\"\n ></acl-crd-resource-requirements>\n <ng-template #resourceRequirementsReadonly>\n <acl-crd-resource-requirements\n auiFormItemControl\n [ngModel]=\"control.value\"\n [readOnly]=\"true\"\n ></acl-crd-resource-requirements>\n </ng-template>\n </ng-container>\n <ng-container *ngSwitchCase=\"SpecCapability.yaml\">\n <acl-crd-yaml-editor\n auiFormItemControl\n [formControl]=\"control\"\n [required]=\"isRequired\"\n [actionsConfig]=\"editorActions\"\n [options]=\"editorOptions\"\n [aclReadonlyField]=\"isDisabled\"\n [aclReadonlyFieldTemplate]=\"yamlReadonly\"\n ></acl-crd-yaml-editor>\n <ng-template #yamlReadonly>\n <acl-crd-yaml-editor\n auiFormItemControl\n [ngModel]=\"control.value\"\n [actionsConfig]=\"viewActions\"\n [options]=\"viewOptions\"\n ></acl-crd-yaml-editor>\n </ng-template>\n </ng-container>\n <ng-container *ngSwitchCase=\"SpecCapability.k8sResourcePrefix\">\n <acl-crd-resource-prefix\n auiFormItemControl\n [formErrors]=\"control.errors\"\n [field]=\"field\"\n [required]=\"isRequired\"\n [formControl]=\"control\"\n [aclReadonlyField]=\"isDisabled\"\n [aclReadonlyFieldTemplate]=\"resourcePrefixReadonly\"\n ></acl-crd-resource-prefix>\n <ng-template #resourcePrefixReadonly>\n <acl-crd-resource-prefix\n auiFormItemControl\n [field]=\"field\"\n [ngModel]=\"control.value\"\n [readonly]=\"true\"\n ></acl-crd-resource-prefix>\n </ng-template>\n </ng-container>\n <ng-container *ngSwitchCase=\"SpecCapability.basicAuthSecret\">\n <acl-crd-basic-auth-secret\n auiFormItemControl\n [field]=\"field\"\n [required]=\"isRequired\"\n [formControl]=\"control\"\n [aclReadonlyField]=\"isDisabled\"\n ></acl-crd-basic-auth-secret>\n </ng-container>\n <textarea\n *ngSwitchCase=\"SpecCapability.textarea\"\n auiFormItemControl\n aui-input\n [required]=\"isRequired\"\n [formControl]=\"control\"\n [aclReadonlyField]=\"isDisabled\"\n [placeholder]=\"field | pure: getFieldPlaceholder | translate\"\n ></textarea>\n <aui-tags-input\n *ngSwitchCase=\"SpecCapability.tagsInput\"\n auiFormItemControl\n class=\"tw-flex-1\"\n [required]=\"isRequired\"\n [formControl]=\"control\"\n [placeholder]=\"field | pure: getFieldPlaceholder | translate\"\n [aclReadonlyField]=\"isDisabled\"\n [clearable]=\"isClearable\"\n ></aui-tags-input>\n <ng-container *ngSwitchDefault>\n <acl-crd-link\n *ngIf=\"(field | pure: isLink) && isDisabled; else textField\"\n auiFormItemControl\n [field]=\"field\"\n [formControl]=\"control\"\n ></acl-crd-link>\n </ng-container>\n <ng-template #textField>\n <input\n type=\"text\"\n auiFormItemControl\n [required]=\"isRequired\"\n aui-input\n [formControl]=\"control\"\n [placeholder]=\"field | pure: getFieldPlaceholder | translate\"\n [aclReadonlyField]=\"isDisabled\"\n />\n </ng-template>\n </acl-crd-form-item>\n <div\n class=\"tw-flex tw-w-full tw-flex-col\"\n *ngIf=\"field.capabilities | pure: getWidgets as widget\"\n >\n <ng-container *ngComponentOutlet=\"widget.component\"></ng-container>\n </div>\n </ng-container>\n <ng-template #advancedFiled>\n <ng-container\n *ngIf=\"\n meta.fieldType === SpecCapability.password ||\n meta.fieldType === SpecCapability.confirmPassword ||\n meta.fieldType === SpecCapability.externalPassword\n \"\n >\n <acl-crd-form-item\n *ngIf=\"isDisabled\"\n [plain]=\"true\"\n >\n <ng-container *ngTemplateOutlet=\"passwordView\"></ng-container>\n </acl-crd-form-item>\n <acl-password-input\n *ngIf=\"!isDisabled\"\n [initPassword]=\"control.value\"\n [label]=\"field | pure: getFieldDisplayName | translate\"\n [hint]=\"field | pure: getFieldDescription | translate\"\n [formControl]=\"control\"\n [required]=\"isRequired\"\n [readonly]=\"crdForm.readonly\"\n [isUpdate]=\"!!control.value && !control.dirty\"\n [strongPassword]=\"meta.fieldType !== SpecCapability.externalPassword\"\n [enableConfirm]=\"meta.fieldType === SpecCapability.confirmPassword\"\n width=\"large\"\n [encoding]=\"field | pure: getEncoding : 'password'\"\n [pattern]=\"field.validations?.pattern\"\n [placeholder]=\"field | pure: getFieldPlaceholder | translate\"\n ></acl-password-input>\n </ng-container>\n <!-- group field -->\n <ng-container *ngIf=\"isGroupField(field) && field.fieldList?.length > 0\">\n <acl-operand-field-group\n [fields]=\"fields\"\n [fieldGroup]=\"field\"\n [readonly]=\"isDisabled\"\n [formDataState]=\"formDataState\"\n [formErrors]=\"formErrors\"\n (valueChange)=\"valueChange.emit($event)\"\n >\n </acl-operand-field-group>\n </ng-container>\n <!-- array field groups -->\n <!-- array field table -->\n <ng-container *ngIf=\"isArrayField(field)\">\n <acl-crd-array-table\n *ngIf=\"field | pure: isArrayFieldTable; else defaultArrayFiled\"\n [arrayFieldGroup]=\"field\"\n [formDataState]=\"formDataState\"\n [readonly]=\"isDisabled\"\n (valueChange)=\"valueChange.emit($event)\"\n >\n </acl-crd-array-table>\n <ng-template #defaultArrayFiled>\n <acl-operand-array-field-group\n [arrayFieldGroup]=\"field\"\n [fields]=\"fields\"\n [readonly]=\"isDisabled\"\n [formDataState]=\"formDataState\"\n (valueChange)=\"valueChange.emit($event)\"\n >\n </acl-operand-array-field-group>\n </ng-template>\n </ng-container>\n </ng-template>\n </ng-container>\n</ng-container>\n\n<ng-template #passwordView>\n {{ PASSWORD_REVEAL }}\n</ng-template>\n", styles: [":host .input-group{width:100%}:host ::ng-deep .aui-form-item__label-wrapper:not(.hasLabel){display:none}\n"] }]
2179
+ }], propDecorators: { field: [{
2180
+ type: Input
2181
+ }], field$: [], readonly: [{
2182
+ type: Input
2183
+ }], fields: [{
2184
+ type: Input
2185
+ }], formDataState: [{
2186
+ type: Input
2187
+ }], formDataState$: [], formErrors: [{
2188
+ type: Input
2189
+ }], valueChange: [{
2190
+ type: Output
2191
+ }], itemRemove: [{
2192
+ type: Output
2193
+ }], isHidden: [{
2194
+ type: HostBinding,
2195
+ args: ['hidden']
2196
+ }] } });
2197
+
2198
+ class OperandAdvancedFieldGroupComponent {
2199
+ constructor() {
2200
+ this.readonly = false;
2201
+ this.valueChange = new EventEmitter();
2202
+ this.expanded = false;
2203
+ this.startCase = startCase;
2204
+ }
2205
+ fieldValueChange(e) {
2206
+ this.valueChange.emit(e);
2207
+ }
2208
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: OperandAdvancedFieldGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2209
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: OperandAdvancedFieldGroupComponent, isStandalone: true, selector: "acl-operand-advanced-field-group", inputs: { fields: "fields", fieldList: "fieldList", formDataState: "formDataState", formErrors: "formErrors", readonly: "readonly" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<div\n [class.expanded]=\"expanded\"\n class=\"field-group\"\n>\n <div class=\"header\">\n <div\n class=\"title\"\n (click)=\"expanded = !expanded\"\n >\n @if (!expanded) {\n <aui-icon\n size=\"20px,20px\"\n icon=\"caret_down_s\"\n ></aui-icon>\n }\n @if (expanded) {\n <aui-icon\n size=\"20px,20px\"\n icon=\"caret_down_s\"\n ></aui-icon>\n }\n <span>{{ 'advanced_fields' | translate }}</span>\n </div>\n </div>\n <div\n class=\"content\"\n [hidden]=\"!expanded\"\n >\n @for (field of fieldList; track field) {\n <acl-operand-field\n [field]=\"field\"\n [fields]=\"fields\"\n [formDataState]=\"formDataState\"\n [formErrors]=\"formErrors\"\n [readonly]=\"readonly\"\n (valueChange)=\"fieldValueChange($event)\"\n >\n </acl-operand-field>\n }\n </div>\n</div>\n", styles: [".field-group{border:1px solid rgb(var(--aui-color-n-7));background-color:rgb(var(--aui-color-n-10));position:relative;margin-bottom:16px;border-radius:2px}.field-group .title{padding:0 20px;font-size:14px;font-weight:500;display:flex;align-items:center;height:60px;line-height:20px;color:rgb(var(--aui-color-n-1));cursor:pointer}.field-group .title aui-icon{margin-right:20px;font-size:20px}.field-group .description{display:block;padding-left:22px;font-size:12px;line-height:16px;color:rgb(var(--aui-color-n-4))}.field-group:not(.expanded) aui-icon[icon=caret_down_s]{transform:rotate(-90deg)}.field-group.expanded>.header>.title{border-bottom:1px solid rgb(var(--aui-color-n-8))}.field-group.expanded>.header>.description{display:block;margin-top:4px}.field-group .content{padding:8px 12px}.field-group .content.no-title{padding-top:0}.field-group .array-item__remove{display:flex;justify-content:flex-end;margin-bottom:4px}.field-group .array-item__add,.field-group .array-item__remove{text-align:center}.field-group .array-item__add aui-icon,.field-group .array-item__remove aui-icon{margin-right:4px}\n"], dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => IconModule) }, { kind: "component", type: i0.forwardRef(() => i2.IconComponent), selector: "aui-icon", inputs: ["icon", "light", "dark", "link", "margin", "size", "color", "background", "backgroundColor"] }, { kind: "component", type: i0.forwardRef(() => OperandFieldComponent), selector: "acl-operand-field", inputs: ["field", "readonly", "fields", "formDataState", "formErrors"], outputs: ["valueChange", "itemRemove"] }, { kind: "pipe", type: i0.forwardRef(() => TranslatePipe), name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2210
+ }
2211
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: OperandAdvancedFieldGroupComponent, decorators: [{
2212
+ type: Component,
2213
+ args: [{ selector: 'acl-operand-advanced-field-group', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [TranslatePipe, IconModule, forwardRef(() => OperandFieldComponent)], template: "<div\n [class.expanded]=\"expanded\"\n class=\"field-group\"\n>\n <div class=\"header\">\n <div\n class=\"title\"\n (click)=\"expanded = !expanded\"\n >\n @if (!expanded) {\n <aui-icon\n size=\"20px,20px\"\n icon=\"caret_down_s\"\n ></aui-icon>\n }\n @if (expanded) {\n <aui-icon\n size=\"20px,20px\"\n icon=\"caret_down_s\"\n ></aui-icon>\n }\n <span>{{ 'advanced_fields' | translate }}</span>\n </div>\n </div>\n <div\n class=\"content\"\n [hidden]=\"!expanded\"\n >\n @for (field of fieldList; track field) {\n <acl-operand-field\n [field]=\"field\"\n [fields]=\"fields\"\n [formDataState]=\"formDataState\"\n [formErrors]=\"formErrors\"\n [readonly]=\"readonly\"\n (valueChange)=\"fieldValueChange($event)\"\n >\n </acl-operand-field>\n }\n </div>\n</div>\n", styles: [".field-group{border:1px solid rgb(var(--aui-color-n-7));background-color:rgb(var(--aui-color-n-10));position:relative;margin-bottom:16px;border-radius:2px}.field-group .title{padding:0 20px;font-size:14px;font-weight:500;display:flex;align-items:center;height:60px;line-height:20px;color:rgb(var(--aui-color-n-1));cursor:pointer}.field-group .title aui-icon{margin-right:20px;font-size:20px}.field-group .description{display:block;padding-left:22px;font-size:12px;line-height:16px;color:rgb(var(--aui-color-n-4))}.field-group:not(.expanded) aui-icon[icon=caret_down_s]{transform:rotate(-90deg)}.field-group.expanded>.header>.title{border-bottom:1px solid rgb(var(--aui-color-n-8))}.field-group.expanded>.header>.description{display:block;margin-top:4px}.field-group .content{padding:8px 12px}.field-group .content.no-title{padding-top:0}.field-group .array-item__remove{display:flex;justify-content:flex-end;margin-bottom:4px}.field-group .array-item__add,.field-group .array-item__remove{text-align:center}.field-group .array-item__add aui-icon,.field-group .array-item__remove aui-icon{margin-right:4px}\n"] }]
2214
+ }], propDecorators: { fields: [{
2215
+ type: Input
2216
+ }], fieldList: [{
2217
+ type: Input
2218
+ }], formDataState: [{
2219
+ type: Input
2220
+ }], formErrors: [{
2221
+ type: Input
2222
+ }], readonly: [{
2223
+ type: Input
2224
+ }], valueChange: [{
2225
+ type: Output
2226
+ }] } });
2227
+
2228
+ // 去除 others 和 paths 中主 path 相同的部分
2229
+ function differPathsTag(paths, others) {
2230
+ return differenceBy(paths, others, pathWithTag => getPathFromTagPath(pathWithTag));
2231
+ }
2232
+ function getAllOtherTagPath(fields, paths) {
2233
+ return fields
2234
+ .map(path => getOperandPath(path))
2235
+ .filter(path => !paths.includes(path));
2236
+ }
2237
+ function matchValueAgainstOneOf(field, currentValue) {
2238
+ // oneOfMap 里应当为 tagged path
2239
+ const oneOfMap = getOneOfMap(field);
2240
+ // 使用两个 set 处理多条 OneOf 中存在公共 path 的情形
2241
+ const dirtyPathSet = new Set();
2242
+ const validPathSet = new Set();
2243
+ Object.entries(oneOfMap).forEach(([value, paths]) => {
2244
+ paths.forEach(path => {
2245
+ (convertValue(value, field.type) === currentValue
2246
+ ? validPathSet
2247
+ : dirtyPathSet).add(path);
2248
+ });
2249
+ });
2250
+ return {
2251
+ dirtyPaths: Array.from(dirtyPathSet)
2252
+ .filter(i => !validPathSet.has(i))
2253
+ .map(path => normalizePath(path)),
2254
+ validPaths: Array.from(validPathSet).map(path => normalizePath(path)),
2255
+ };
2256
+ }
2257
+
2258
+ class CrdFormComponent {
2259
+ constructor() {
2260
+ this.debug = false;
2261
+ this.openApiSchemaPath = SCHEMA_PATH;
2262
+ this.readonly = false;
2263
+ this.labelPosition = LabelPosition.Right;
2264
+ this.formStateChange = new EventEmitter();
2265
+ this.formSchemaChange = new EventEmitter();
2266
+ this.formErrors = {};
2267
+ // 一个全局的 controlMap,方便控制 field 主动校验。
2268
+ // 该 controlMap 以及所有 field 里的 control 实例,都是为了数据追踪与错误同步(control.error -> crdForm error),本身不影响提交,由 crd-form 的 error 去阻塞提交。
2269
+ this.controlMap = new Map();
2270
+ // 被隐藏起来的表单的路径集合
2271
+ this.dirtyPathsSet = new Set();
2272
+ }
2273
+ ngOnChanges({ openApiSchema, descriptors, data }) {
2274
+ if (openApiSchema?.currentValue || descriptors?.currentValue) {
2275
+ this.setUpForm();
2276
+ }
2277
+ else if (data?.currentValue) {
2278
+ this.formDataState = fromJS(data.currentValue);
2279
+ }
2280
+ }
2281
+ setUpForm() {
2282
+ this.formDataState = fromJS(this.data || {});
2283
+ const { normalFields, fieldGroups, arrayFieldGroups, advancedFields, descriptorFields, openApiFields, basicFields, treeFields, } = createCapabilityField(this.descriptors || [], this.openApiSchema || {}, this.data, this.openApiSchemaPath);
2284
+ this.fields = basicFields.filter(fieldShouldReveal);
2285
+ if (this.debug) {
2286
+ /* eslint-disable no-console */
2287
+ console.info('openApiFields:', openApiFields);
2288
+ console.info('descriptorFields:', descriptorFields);
2289
+ console.info('basicFields:', basicFields);
2290
+ console.info('normalFields', normalFields);
2291
+ console.info('fieldGroups:', fieldGroups);
2292
+ console.info('arrayFieldGroups:', arrayFieldGroups);
2293
+ console.info('advancedFields:', advancedFields);
2294
+ console.info('treeFields:', treeFields);
2295
+ /* eslint-enable no-console */
2296
+ }
2297
+ this.normalFields = normalFields;
2298
+ this.fieldGroups = fieldGroups;
2299
+ this.arrayFieldGroups = arrayFieldGroups;
2300
+ this.advancedFields = advancedFields;
2301
+ this.formSchemaChange.emit({
2302
+ openApiFields,
2303
+ descriptorFields,
2304
+ });
2305
+ }
2306
+ fieldValueChange(event) {
2307
+ let onceDirtyPathsSet = new Set();
2308
+ // TODO: 待review确认后移除该开关
2309
+ if (this.formContext?.gates?.includes('onceDirtyPathsSet')) {
2310
+ const operandPath = getOperandPath(event.field);
2311
+ // 如果表单被隐藏且这次change是因为直接改变了包含该路径的父路径的值(例如编辑yaml)
2312
+ // 那就阻止此子路径值的change逻辑
2313
+ if (this.dirtyPathsSet.has(operandPath) &&
2314
+ this._lastUpdateField?.path &&
2315
+ operandPath.startsWith(`${this._lastUpdateField.path}.`)) {
2316
+ return;
2317
+ }
2318
+ }
2319
+ else {
2320
+ onceDirtyPathsSet = this.dirtyPathsSet;
2321
+ }
2322
+ const eventData = event.data;
2323
+ if (event.field.capabilities.some(c => c.startsWith(SpecCapability.oneOf))) {
2324
+ const { dirtyPaths, validPaths } = this.resolveExpiredPath(event.field, eventData);
2325
+ dirtyPaths.forEach(path => {
2326
+ this.dirtyPathsSet.add(normalizePath(path));
2327
+ onceDirtyPathsSet.add(normalizePath(path));
2328
+ });
2329
+ validPaths.forEach(path => {
2330
+ this.updateValidPathValue(path);
2331
+ });
2332
+ }
2333
+ const allOtherPaths = getAllOtherTagPath(this.fields, Array.from(onceDirtyPathsSet));
2334
+ const removedPaths = uniq(
2335
+ // 同一 path 可能有多个 tag,假设某个 tagged path 有效,则其对应 path 数据不应该删除
2336
+ differPathsTag(Array.from(onceDirtyPathsSet), allOtherPaths).map(path => getPathFromTagPath(path))).filter(
2337
+ // 只清空叶子结点,以适配 yaml 情况
2338
+ path => !this.fields.some(field => {
2339
+ const isParentPath = field.path.startsWith(`${path}.`);
2340
+ if (isParentPath) {
2341
+ // 该 field 亦为 dirty,不以为依据
2342
+ return !onceDirtyPathsSet.has(field.path);
2343
+ }
2344
+ return false;
2345
+ }));
2346
+ if (eventData == null && !this.keepEmptyPath) {
2347
+ if (!onceDirtyPathsSet.has(getOperandPath(event.field))) {
2348
+ this.deleteFormData(event.field.path);
2349
+ }
2350
+ }
2351
+ else {
2352
+ this.updateFormData(event.field, eventData);
2353
+ }
2354
+ removedPaths.forEach(path => {
2355
+ this.deleteFormData(path);
2356
+ });
2357
+ this.refreshValidation();
2358
+ this.formStateChange.emit({
2359
+ data: this.formDataState.toJS(),
2360
+ errors: this.formErrors,
2361
+ });
2362
+ }
2363
+ deleteFormData(path) {
2364
+ this.formDataState = this.formDataState.deleteIn(pathToArray(path));
2365
+ this.controlMap.get(path)?.setValue(null);
2366
+ this.formStateChange.emit({
2367
+ data: this.formDataState.toJS(),
2368
+ errors: this.formErrors,
2369
+ });
2370
+ }
2371
+ updateValidPathValue(path) {
2372
+ // 如果有效路径是上一次的无效路径,则意味着该路径的值在上次被重置了,所以当该路径又需要显示给用户时应该使用默认值
2373
+ const useDefault = this.dirtyPathsSet.has(normalizePath(path));
2374
+ this.dirtyPathsSet.delete(normalizePath(path));
2375
+ // 如果对一组表单都有依赖,那路径可能是这组表单的父路径,所以需要把所有子孙都找出来
2376
+ const fields = getFieldsByPath(path, [
2377
+ ...this.normalFields,
2378
+ ...flattenDeep(this.fieldGroups.map(group => group.fieldList)),
2379
+ ...flattenDeep(this.arrayFieldGroups.map(arrayGroup => arrayGroup.fieldLists)),
2380
+ ...this.advancedFields,
2381
+ ]);
2382
+ fields.forEach(field => {
2383
+ // 理论上 oneof 只影响视图,但实际还会影响 formDataState,所以需要同步更新 formDataState
2384
+ let value = this.controlMap.get(getOperandPath(field)).value;
2385
+ if (!value && useDefault) {
2386
+ value = getDefaultValue(field);
2387
+ }
2388
+ this.updateFormData(field, value);
2389
+ });
2390
+ }
2391
+ updateFormData(field, data) {
2392
+ if (!field)
2393
+ return;
2394
+ const { match, index, pathBeforeIndex, pathAfterIndex } = parseArrayPath(field.path);
2395
+ if (match && index === 0) {
2396
+ this.formDataState = this.initializeFormDataArrayProperty(this.formDataState, pathBeforeIndex, pathAfterIndex, data);
2397
+ }
2398
+ this.formDataState = this.formDataState.setIn(pathToArray(field.path), data);
2399
+ this._lastUpdateField = field;
2400
+ }
2401
+ refreshValidation() {
2402
+ const errors = Array.from(this.controlMap).reduce((acc, [pathWithTag, control]) => {
2403
+ if (this.dirtyPathsSet.has(pathWithTag)) {
2404
+ return acc;
2405
+ }
2406
+ const path = getPathFromTagPath(pathWithTag);
2407
+ acc[path] = isEmpty(control.errors) ? null : control.errors;
2408
+ return acc;
2409
+ }, {});
2410
+ const result = fromPairs(Object.entries(errors ?? {}).filter(([_k, v]) => !!v));
2411
+ this.formErrors = isEmpty(result) ? null : result;
2412
+ }
2413
+ // 当某个 field 发生数据变化,返回其相关 oneOf path 是否应该移除
2414
+ // 仅当当前 field 中 oneOf 条件与当前数据不匹配,
2415
+ resolveExpiredPath(field, currentValue) {
2416
+ const { dirtyPaths, validPaths } = matchValueAgainstOneOf(field, currentValue);
2417
+ const otherFieldStatus = this.fields
2418
+ .filter(i => getOperandPath(i) !== getOperandPath(field))
2419
+ .map(field => ({
2420
+ path: getOperandPath(field),
2421
+ result: matchValueAgainstOneOf(field, this.controlMap.get(getOperandPath(field))?.value),
2422
+ }));
2423
+ const newDirtyPaths = validPaths.filter(path => {
2424
+ // 当前 valid path 在其他 field 中为 dirty,若该 field 本身也为 dirty 则忽略该影响,仍然判定为 valid,否则(该 field 有效)认定为 dirty
2425
+ const fieldCandidates = otherFieldStatus.filter(status => status.result.dirtyPaths.includes(path));
2426
+ return fieldCandidates.some(({ path }) => !otherFieldStatus.some(status => status.result.dirtyPaths.includes(path)));
2427
+ });
2428
+ return {
2429
+ dirtyPaths: [...dirtyPaths, ...newDirtyPaths],
2430
+ validPaths: validPaths.filter(path => !newDirtyPaths.includes(path)),
2431
+ };
2432
+ }
2433
+ initializeFormDataArrayProperty(state, pathBeforeIndex, pathAfterIndex, value) {
2434
+ if (state.getIn([...pathToArray(pathBeforeIndex), 0])) {
2435
+ return state;
2436
+ }
2437
+ const item = Map$1({}).setIn(pathToArray(pathAfterIndex), value);
2438
+ const list = List([item]);
2439
+ return state.setIn(pathToArray(pathBeforeIndex), list);
2440
+ }
2441
+ submit() {
2442
+ this.refreshValidation();
2443
+ this.form.onSubmit(null);
2444
+ }
2445
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: CrdFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2446
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: CrdFormComponent, isStandalone: true, selector: "acl-crd-form", inputs: { openApiSchema: "openApiSchema", descriptors: "descriptors", data: "data", debug: "debug", openApiSchemaPath: "openApiSchemaPath", readonly: "readonly", labelWidth: "labelWidth", labelPosition: "labelPosition", cluster: "cluster", namespace: "namespace", formContext: "formContext", keepEmptyPath: "keepEmptyPath", effectControlDefaultValue: "effectControlDefaultValue", uiContext: "uiContext", widgets: "widgets" }, outputs: { formStateChange: "formStateChange", formSchemaChange: "formSchemaChange" }, viewQueries: [{ propertyName: "form", first: true, predicate: ["form"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<form\n auiForm\n [aclScrollToFirstInvalid]=\"!!formErrors\"\n #form=\"ngForm\"\n [auiFormLabelPosition]=\"labelPosition\"\n [auiFormLabelWidth]=\"labelWidth\"\n>\n <!-- normal fields -->\n @for (field of normalFields; track field) {\n <acl-operand-field\n [fields]=\"fields\"\n [field]=\"field\"\n [formDataState]=\"formDataState\"\n [readonly]=\"readonly\"\n (valueChange)=\"fieldValueChange($event)\"\n >\n </acl-operand-field>\n }\n\n <!-- field groups \u517C\u5BB9\uFF0C\u9700\u8981\u4FDD\u7559-->\n @for (group of fieldGroups; track group) {\n <acl-operand-field-group\n [fields]=\"fields\"\n [fieldGroup]=\"group\"\n [formDataState]=\"formDataState\"\n [formErrors]=\"formErrors\"\n [readonly]=\"readonly\"\n (valueChange)=\"fieldValueChange($event)\"\n >\n </acl-operand-field-group>\n }\n\n <!-- array field groups \u517C\u5BB9\uFF0C\u9700\u8981\u4FDD\u7559 -->\n @for (group of arrayFieldGroups; track group) {\n <acl-operand-array-field-group\n [arrayFieldGroup]=\"group\"\n [formDataState]=\"formDataState\"\n [readonly]=\"readonly\"\n (valueChange)=\"fieldValueChange($event)\"\n (itemRemove)=\"deleteFormData($event)\"\n >\n </acl-operand-array-field-group>\n }\n\n <!-- advanced fields -->\n @if (advancedFields?.length) {\n <acl-operand-advanced-field-group\n [fields]=\"fields\"\n [fieldList]=\"advancedFields\"\n [formDataState]=\"formDataState\"\n [readonly]=\"readonly\"\n (valueChange)=\"fieldValueChange($event)\"\n ></acl-operand-advanced-field-group>\n }\n</form>\n", styles: [":host{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => FormsModule) }, { kind: "directive", type: i0.forwardRef(() => i1.ɵNgNoValidate), selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i0.forwardRef(() => i1.NgControlStatusGroup), selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i0.forwardRef(() => i1.NgForm), selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: i0.forwardRef(() => FormModule) }, { kind: "directive", type: i0.forwardRef(() => i2.FormDirective), selector: "form[auiForm]", inputs: ["auiFormLabelWidth", "auiFormLabelPosition", "auiFormEmptyAddon", "auiFormInline"], exportAs: ["auiForm"] }, { kind: "component", type: i0.forwardRef(() => OperandFieldComponent), selector: "acl-operand-field", inputs: ["field", "readonly", "fields", "formDataState", "formErrors"], outputs: ["valueChange", "itemRemove"] }, { kind: "component", type: i0.forwardRef(() => OperandFieldGroupComponent), selector: "acl-operand-field-group", inputs: ["fields", "fieldGroup", "formDataState", "formErrors", "readonly"], outputs: ["valueChange"] }, { kind: "component", type: i0.forwardRef(() => OperandArrayFieldGroupComponent), selector: "acl-operand-array-field-group" }, { kind: "component", type: i0.forwardRef(() => OperandAdvancedFieldGroupComponent), selector: "acl-operand-advanced-field-group", inputs: ["fields", "fieldList", "formDataState", "formErrors", "readonly"], outputs: ["valueChange"] }, { kind: "directive", type: i0.forwardRef(() => ScrollToFirstInvalidDirective), selector: "[aclScrollToFirstInvalid]", inputs: ["labelOffset", "aclScrollToFirstInvalid"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2447
+ }
2448
+ __decorate([
2449
+ ObservableInput(),
2450
+ __metadata("design:type", Observable)
2451
+ ], CrdFormComponent.prototype, "formContext$", void 0);
2452
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: CrdFormComponent, decorators: [{
2453
+ type: Component,
2454
+ args: [{ selector: 'acl-crd-form', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
2455
+ FormsModule,
2456
+ FormModule,
2457
+ forwardRef(() => OperandFieldComponent),
2458
+ forwardRef(() => OperandFieldGroupComponent),
2459
+ forwardRef(() => OperandArrayFieldGroupComponent),
2460
+ forwardRef(() => OperandAdvancedFieldGroupComponent),
2461
+ ScrollToFirstInvalidDirective,
2462
+ ], template: "<form\n auiForm\n [aclScrollToFirstInvalid]=\"!!formErrors\"\n #form=\"ngForm\"\n [auiFormLabelPosition]=\"labelPosition\"\n [auiFormLabelWidth]=\"labelWidth\"\n>\n <!-- normal fields -->\n @for (field of normalFields; track field) {\n <acl-operand-field\n [fields]=\"fields\"\n [field]=\"field\"\n [formDataState]=\"formDataState\"\n [readonly]=\"readonly\"\n (valueChange)=\"fieldValueChange($event)\"\n >\n </acl-operand-field>\n }\n\n <!-- field groups \u517C\u5BB9\uFF0C\u9700\u8981\u4FDD\u7559-->\n @for (group of fieldGroups; track group) {\n <acl-operand-field-group\n [fields]=\"fields\"\n [fieldGroup]=\"group\"\n [formDataState]=\"formDataState\"\n [formErrors]=\"formErrors\"\n [readonly]=\"readonly\"\n (valueChange)=\"fieldValueChange($event)\"\n >\n </acl-operand-field-group>\n }\n\n <!-- array field groups \u517C\u5BB9\uFF0C\u9700\u8981\u4FDD\u7559 -->\n @for (group of arrayFieldGroups; track group) {\n <acl-operand-array-field-group\n [arrayFieldGroup]=\"group\"\n [formDataState]=\"formDataState\"\n [readonly]=\"readonly\"\n (valueChange)=\"fieldValueChange($event)\"\n (itemRemove)=\"deleteFormData($event)\"\n >\n </acl-operand-array-field-group>\n }\n\n <!-- advanced fields -->\n @if (advancedFields?.length) {\n <acl-operand-advanced-field-group\n [fields]=\"fields\"\n [fieldList]=\"advancedFields\"\n [formDataState]=\"formDataState\"\n [readonly]=\"readonly\"\n (valueChange)=\"fieldValueChange($event)\"\n ></acl-operand-advanced-field-group>\n }\n</form>\n", styles: [":host{width:100%}\n"] }]
2463
+ }], propDecorators: { openApiSchema: [{
2464
+ type: Input
2465
+ }], descriptors: [{
2466
+ type: Input
2467
+ }], data: [{
2468
+ type: Input
2469
+ }], debug: [{
2470
+ type: Input
2471
+ }], openApiSchemaPath: [{
2472
+ type: Input
2473
+ }], readonly: [{
2474
+ type: Input
2475
+ }], labelWidth: [{
2476
+ type: Input
2477
+ }], labelPosition: [{
2478
+ type: Input
2479
+ }], cluster: [{
2480
+ type: Input
2481
+ }], namespace: [{
2482
+ type: Input
2483
+ }], formContext: [{
2484
+ type: Input
2485
+ }], formContext$: [], keepEmptyPath: [{
2486
+ type: Input
2487
+ }], effectControlDefaultValue: [{
2488
+ type: Input
2489
+ }], uiContext: [{
2490
+ type: Input
2491
+ }], formStateChange: [{
2492
+ type: Output
2493
+ }], formSchemaChange: [{
2494
+ type: Output
2495
+ }], form: [{
2496
+ type: ViewChild,
2497
+ args: ['form', { static: true }]
2498
+ }], widgets: [{
2499
+ type: Input
2500
+ }] } });
2501
+
2502
+ class BaseOperandFiledArrayComponent {
2503
+ constructor() {
2504
+ this.readonly = false;
2505
+ this.valueChange = new EventEmitter();
2506
+ this.itemRemove = new EventEmitter();
2507
+ this.getFieldDisplayName = getFieldDisplayName;
2508
+ this.crdForm = inject(CrdFormComponent);
2509
+ }
2510
+ get expanded() {
2511
+ return this._expanded ?? !isFolded(this.arrayFieldGroup);
2512
+ }
2513
+ set expanded(expanded) {
2514
+ this._expanded = expanded;
2515
+ }
2516
+ ngOnChanges({ arrayFieldGroup, formDataState }) {
2517
+ if (!this.basicArrayFieldTemplate &&
2518
+ arrayFieldGroup.currentValue?.fieldLists?.length > 0) {
2519
+ this.basicArrayFieldTemplate = last(arrayFieldGroup.currentValue.fieldLists);
2520
+ }
2521
+ if (formDataState?.currentValue && formDataState?.previousValue) {
2522
+ const currValue = getFormData(formDataState.currentValue, this.arrayFieldGroup.path);
2523
+ const arrayFieldLength = this.arrayFieldGroup.fieldLists?.length;
2524
+ if (currValue?.size > arrayFieldLength) {
2525
+ Array.from({ length: currValue.size - arrayFieldLength }).forEach(() => {
2526
+ this.addItem();
2527
+ });
2528
+ }
2529
+ }
2530
+ }
2531
+ fieldValueChange(e) {
2532
+ this.valueChange.emit(e);
2533
+ }
2534
+ addItem() {
2535
+ const newFields = this.basicArrayFieldTemplate.map(field => {
2536
+ const toPath = modifyArrayFieldPathIndex(field.path, () => this.arrayFieldGroup.fieldLists.length);
2537
+ return {
2538
+ ...repairFieldChildPathByCorrectIndex(field, field.path, toPath),
2539
+ };
2540
+ });
2541
+ this.arrayFieldGroup.fieldLists = [
2542
+ ...this.arrayFieldGroup.fieldLists,
2543
+ newFields,
2544
+ ];
2545
+ }
2546
+ removeItem(index) {
2547
+ const groupToRemove = this.arrayFieldGroup.fieldLists[index];
2548
+ const groupUntouched = this.arrayFieldGroup.fieldLists.filter((_, idx) => idx < index);
2549
+ const groupToLeftShift = this.arrayFieldGroup.fieldLists.filter((_, idx) => idx > index);
2550
+ const leftShiftedGroups = groupToLeftShift.map(group => group.map(field => {
2551
+ const toPath = modifyArrayFieldPathIndex(field.path, idx => idx - 1);
2552
+ return {
2553
+ ...repairFieldChildPathByCorrectIndex(field, field.path, toPath),
2554
+ };
2555
+ }));
2556
+ this.arrayFieldGroup.fieldLists = [...groupUntouched, ...leftShiftedGroups];
2557
+ const [match, formDataPathToRemove] = /^(.*\[\d+]).*$/.exec(groupToRemove?.[0].path) || [];
2558
+ if (match) {
2559
+ this.itemRemove.next(formDataPathToRemove);
2560
+ }
2561
+ this.crdForm.controlMap.forEach((_, key) => {
2562
+ if (key.startsWith(`${this.arrayFieldGroup.path}[${this.arrayFieldGroup.fieldLists.length}]`)) {
2563
+ this.crdForm.controlMap.delete(key);
2564
+ }
2565
+ });
2566
+ this.crdForm.refreshValidation();
2567
+ this.deleteFormData(`${this.arrayFieldGroup.path}[${index}]`);
2568
+ }
2569
+ deleteFormData(path) {
2570
+ this.valueChange.next({
2571
+ field: {
2572
+ ...this.arrayFieldGroup,
2573
+ path,
2574
+ },
2575
+ data: null,
2576
+ });
2577
+ }
2578
+ fieldIsRequired(field) {
2579
+ return (field?.required ||
2580
+ Object.keys(field?.validations || {})?.includes(Validations.required));
2581
+ }
2582
+ get columnFields() {
2583
+ return this.basicArrayFieldTemplate;
2584
+ }
2585
+ trackByFn(index) {
2586
+ return index;
2587
+ }
2588
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: BaseOperandFiledArrayComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2589
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.1", type: BaseOperandFiledArrayComponent, isStandalone: true, inputs: { arrayFieldGroup: "arrayFieldGroup", formDataState: "formDataState", formErrors: "formErrors", isArrayTable: "isArrayTable", readonly: "readonly", fields: "fields" }, outputs: { valueChange: "valueChange", itemRemove: "itemRemove" }, usesOnChanges: true, ngImport: i0 }); }
2590
+ }
2591
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: BaseOperandFiledArrayComponent, decorators: [{
2592
+ type: Directive
2593
+ }], propDecorators: { arrayFieldGroup: [{
2594
+ type: Input
2595
+ }], formDataState: [{
2596
+ type: Input
2597
+ }], formErrors: [{
2598
+ type: Input
2599
+ }], isArrayTable: [{
2600
+ type: Input
2601
+ }], readonly: [{
2602
+ type: Input
2603
+ }], fields: [{
2604
+ type: Input
2605
+ }], valueChange: [{
2606
+ type: Output
2607
+ }], itemRemove: [{
2608
+ type: Output
2609
+ }] } });
2610
+
2611
+ const WIDGETS = [
2612
+ CrdFormArrayTableComponent,
2613
+ K8sResourcePrefixComponent,
2614
+ ResourceRequirementsComponent,
2615
+ YamlEditorComponent,
2616
+ BasicAuthSecretComponent,
2617
+ BasicAuthCreateSecretDialogComponent,
2618
+ ];
2619
+ const EXPORTABLES = [
2620
+ FormItemComponent,
2621
+ OperandAdvancedFieldGroupComponent,
2622
+ OperandArrayFieldGroupComponent,
2623
+ OperandFieldGroupComponent,
2624
+ OperandFieldComponent,
2625
+ ...WIDGETS,
2626
+ ];
2627
+ class FieldControlsModule {
2628
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: FieldControlsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
2629
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.1", ngImport: i0, type: FieldControlsModule, imports: [FormItemComponent,
2630
+ OperandAdvancedFieldGroupComponent,
2631
+ OperandArrayFieldGroupComponent,
2632
+ OperandFieldGroupComponent,
2633
+ OperandFieldComponent, CrdFormArrayTableComponent,
2634
+ K8sResourcePrefixComponent,
2635
+ ResourceRequirementsComponent,
2636
+ YamlEditorComponent,
2637
+ BasicAuthSecretComponent,
2638
+ BasicAuthCreateSecretDialogComponent], exports: [FormItemComponent,
2639
+ OperandAdvancedFieldGroupComponent,
2640
+ OperandArrayFieldGroupComponent,
2641
+ OperandFieldGroupComponent,
2642
+ OperandFieldComponent, CrdFormArrayTableComponent,
2643
+ K8sResourcePrefixComponent,
2644
+ ResourceRequirementsComponent,
2645
+ YamlEditorComponent,
2646
+ BasicAuthSecretComponent,
2647
+ BasicAuthCreateSecretDialogComponent] }); }
2648
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: FieldControlsModule, imports: [EXPORTABLES] }); }
2649
+ }
2650
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: FieldControlsModule, decorators: [{
2651
+ type: NgModule,
2652
+ args: [{
2653
+ imports: [...EXPORTABLES],
2654
+ exports: EXPORTABLES,
2655
+ }]
2656
+ }] });
2657
+
2658
+ function getFieldCapability(field, type, capabilityKey, language) {
2659
+ const capabilities = field.capabilities;
2660
+ let prefix = `urn:alm:descriptor:${type}:${capabilityKey}`;
2661
+ if (language) {
2662
+ prefix += `:${language}:`;
2663
+ }
2664
+ else {
2665
+ prefix += ':';
2666
+ }
2667
+ const capability = capabilities?.find(c => c.startsWith(prefix));
2668
+ return capability?.slice(prefix.length);
2669
+ }
2670
+ function getFieldLabel(field, type) {
2671
+ return {
2672
+ en: getFieldCapability(field, type, 'label', 'en'),
2673
+ zh: getFieldCapability(field, type, 'label', 'zh'),
2674
+ };
2675
+ }
2676
+ function getFieldDescription(field, type) {
2677
+ return {
2678
+ en: getFieldCapability(field, type, 'description', 'en'),
2679
+ zh: getFieldCapability(field, type, 'description', 'zh'),
2680
+ };
2681
+ }
2682
+ function getFieldPlaceholder(field, type) {
2683
+ return {
2684
+ en: getFieldCapability(field, type, 'placeholder', 'en'),
2685
+ zh: getFieldCapability(field, type, 'placeholder', 'zh'),
2686
+ };
2687
+ }
2688
+ function getUsernameDefaultValue(field) {
2689
+ return getFieldCapability(field, 'username', 'default');
2690
+ }
2691
+ function isFieldDisabled(field, type) {
2692
+ const capabilities = field.capabilities;
2693
+ return !!capabilities?.find(c => c === `urn:alm:descriptor:${type}:disabled`);
2694
+ }
2695
+
2696
+ class HtpasswdFormComponent extends BaseResourceFormComponent {
2697
+ constructor() {
2698
+ super(...arguments);
2699
+ this.isDisabled = false;
2700
+ // `null` is required because the default value is `null`,
2701
+ // if it is `undefined` here, it will cause form value change event unexpectedly...
2702
+ this.originalResource = null;
2703
+ this.getFieldDescription = getFieldDescription;
2704
+ this.isFieldDisabled = isFieldDisabled;
2705
+ this.getFieldPlaceholder = getFieldPlaceholder;
2706
+ this.getFieldLabel = getFieldLabel;
2707
+ }
2708
+ createForm() {
2709
+ return this.fb.group({
2710
+ username: '',
2711
+ password: '',
2712
+ });
2713
+ }
2714
+ adaptResourceModel(resource) {
2715
+ let username = '';
2716
+ if (resource) {
2717
+ const parts = resource.split(':');
2718
+ parts.pop();
2719
+ username = parts.join(':');
2720
+ if (!this.originalUsername) {
2721
+ this.originalUsername = username;
2722
+ this.originalResource = resource;
2723
+ }
2724
+ }
2725
+ return {
2726
+ username,
2727
+ password: '',
2728
+ };
2729
+ }
2730
+ adaptFormModel({ username, password, }) {
2731
+ if (!username || !password || !this.form.get('password').dirty) {
2732
+ return this.originalResource;
2733
+ }
2734
+ return [username, hashSync(password)].join(':');
2735
+ }
2736
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: HtpasswdFormComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
2737
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: HtpasswdFormComponent, isStandalone: true, selector: "acl-htpasswd-form", inputs: { field: "field", required: "required", isUpdate: "isUpdate", isDisabled: "isDisabled" }, usesInheritance: true, ngImport: i0, template: `<ng-container [formGroup]="form">
2738
+ @if (
2739
+ (field | pure: getFieldLabel : 'username' | translate) || 'username'
2740
+ | translate;
2741
+ as label
2742
+ ) {
2743
+ <aui-form-item width="large">
2744
+ <label auiFormItemLabel>{{ label }}</label>
2745
+ <input
2746
+ aui-input
2747
+ auiFormItemControl
2748
+ formControlName="username"
2749
+ [required]="required"
2750
+ aclErrorsMapper
2751
+ [aclErrorsMapperOutlet]="usernameError"
2752
+ [aclReadonlyField]="
2753
+ isDisabled || (field | pure: isFieldDisabled : 'username')
2754
+ "
2755
+ [placeholder]="
2756
+ field | pure: getFieldPlaceholder : 'username' | translate
2757
+ "
2758
+ />
2759
+ <div
2760
+ #usernameError
2761
+ auiFormItemError
2762
+ ></div>
2763
+ @if (
2764
+ field | pure: getFieldDescription : 'username' | translate;
2765
+ as description
2766
+ ) {
2767
+ <div auiFormItemHint>
2768
+ {{ description }}
2769
+ </div>
2770
+ }
2771
+ </aui-form-item>
2772
+ }
2773
+ @if (
2774
+ (field | pure: getFieldLabel : 'password' | translate) || 'password'
2775
+ | translate;
2776
+ as label
2777
+ ) {
2778
+ <aui-form-item width="large">
2779
+ <label auiFormItemLabel>{{ label }}</label>
2780
+ <input
2781
+ aui-input
2782
+ type="password"
2783
+ auiFormItemControl
2784
+ formControlName="password"
2785
+ aclStrongPassword
2786
+ [required]="
2787
+ (!isUpdate || originalUsername !== form.get('username').value) &&
2788
+ required
2789
+ "
2790
+ aclErrorsMapper
2791
+ [aclErrorsMapperOutlet]="passwordError"
2792
+ [aclReadonlyField]="
2793
+ isDisabled || (field | pure: isFieldDisabled : 'password')
2794
+ "
2795
+ [aclReadonlyFieldTemplate]="passwordTemplate"
2796
+ [placeholder]="
2797
+ field | pure: getFieldPlaceholder : 'password' | translate
2798
+ "
2799
+ />
2800
+ <div
2801
+ #passwordError
2802
+ auiFormItemError
2803
+ ></div>
2804
+ @if (
2805
+ field | pure: getFieldDescription : 'password' | translate;
2806
+ as description
2807
+ ) {
2808
+ <div auiFormItemHint>
2809
+ {{ description }}
2810
+ </div>
2811
+ }
2812
+ </aui-form-item>
2813
+ }
2814
+ <ng-template #passwordTemplate> ****** </ng-template>
2815
+ </ng-container>`, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: FormModule }, { kind: "component", type: i2.FormItemComponent, selector: "aui-form-item", inputs: ["labelWidth", "width", "labelPosition", "emptyAddon", "plain"] }, { kind: "directive", type: i2.FormItemErrorDirective, selector: "[auiFormItemError]" }, { kind: "directive", type: i2.FormItemHintDirective, selector: "[auiFormItemHint]" }, { kind: "directive", type: i2.FormItemLabelDirective, selector: "label[auiFormItemLabel]" }, { kind: "directive", type: i2.FormItemControlDirective, selector: "[auiFormItemControl]", inputs: ["required"] }, { kind: "ngmodule", type: InputModule }, { kind: "component", type: i2.InputComponent, selector: "input[aui-input],textarea[aui-input]", inputs: ["size", "disabled"] }, { kind: "directive", type: ErrorsMapperDirective, selector: "[aclErrorsMapper]", inputs: ["aclErrorsMapper", "aclErrorsMapperFn", "aclErrorsMapperDisabled", "aclErrorsMapperOutlet", "aclErrorsMapperControlName"] }, { kind: "directive", type: ReadonlyFieldDirective, selector: "[aclReadonlyField]", inputs: ["aclReadonlyField", "hidden", "aclReadonlyFieldTemplate", "aclReadonlyFieldTemplateContext"] }, { kind: "directive", type: StrongPasswordDirective, selector: "input[aclStrongPassword][ngModel],input[aclStrongPassword][formControl],input[aclStrongPassword][formControlName]", inputs: ["aclStrongPassword", "required", "specialChars", "minlength", "maxlength", "notStartsWith"] }, { kind: "pipe", type: PurePipe, name: "pure" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2816
+ }
2817
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: HtpasswdFormComponent, decorators: [{
2818
+ type: Component,
2819
+ args: [{
2820
+ selector: 'acl-htpasswd-form',
2821
+ template: `<ng-container [formGroup]="form">
2822
+ @if (
2823
+ (field | pure: getFieldLabel : 'username' | translate) || 'username'
2824
+ | translate;
2825
+ as label
2826
+ ) {
2827
+ <aui-form-item width="large">
2828
+ <label auiFormItemLabel>{{ label }}</label>
2829
+ <input
2830
+ aui-input
2831
+ auiFormItemControl
2832
+ formControlName="username"
2833
+ [required]="required"
2834
+ aclErrorsMapper
2835
+ [aclErrorsMapperOutlet]="usernameError"
2836
+ [aclReadonlyField]="
2837
+ isDisabled || (field | pure: isFieldDisabled : 'username')
2838
+ "
2839
+ [placeholder]="
2840
+ field | pure: getFieldPlaceholder : 'username' | translate
2841
+ "
2842
+ />
2843
+ <div
2844
+ #usernameError
2845
+ auiFormItemError
2846
+ ></div>
2847
+ @if (
2848
+ field | pure: getFieldDescription : 'username' | translate;
2849
+ as description
2850
+ ) {
2851
+ <div auiFormItemHint>
2852
+ {{ description }}
2853
+ </div>
2854
+ }
2855
+ </aui-form-item>
2856
+ }
2857
+ @if (
2858
+ (field | pure: getFieldLabel : 'password' | translate) || 'password'
2859
+ | translate;
2860
+ as label
2861
+ ) {
2862
+ <aui-form-item width="large">
2863
+ <label auiFormItemLabel>{{ label }}</label>
2864
+ <input
2865
+ aui-input
2866
+ type="password"
2867
+ auiFormItemControl
2868
+ formControlName="password"
2869
+ aclStrongPassword
2870
+ [required]="
2871
+ (!isUpdate || originalUsername !== form.get('username').value) &&
2872
+ required
2873
+ "
2874
+ aclErrorsMapper
2875
+ [aclErrorsMapperOutlet]="passwordError"
2876
+ [aclReadonlyField]="
2877
+ isDisabled || (field | pure: isFieldDisabled : 'password')
2878
+ "
2879
+ [aclReadonlyFieldTemplate]="passwordTemplate"
2880
+ [placeholder]="
2881
+ field | pure: getFieldPlaceholder : 'password' | translate
2882
+ "
2883
+ />
2884
+ <div
2885
+ #passwordError
2886
+ auiFormItemError
2887
+ ></div>
2888
+ @if (
2889
+ field | pure: getFieldDescription : 'password' | translate;
2890
+ as description
2891
+ ) {
2892
+ <div auiFormItemHint>
2893
+ {{ description }}
2894
+ </div>
2895
+ }
2896
+ </aui-form-item>
2897
+ }
2898
+ <ng-template #passwordTemplate> ****** </ng-template>
2899
+ </ng-container>`,
2900
+ changeDetection: ChangeDetectionStrategy.OnPush,
2901
+ standalone: true,
2902
+ imports: [
2903
+ ReactiveFormsModule,
2904
+ FormModule,
2905
+ InputModule,
2906
+ ErrorsMapperDirective,
2907
+ ReadonlyFieldDirective,
2908
+ StrongPasswordDirective,
2909
+ PurePipe,
2910
+ TranslatePipe,
2911
+ ],
2912
+ }]
2913
+ }], propDecorators: { field: [{
2914
+ type: Input
2915
+ }], required: [{
2916
+ type: Input
2917
+ }], isUpdate: [{
2918
+ type: Input
2919
+ }], isDisabled: [{
2920
+ type: Input
2921
+ }] } });
2922
+
2923
+ class HtpasswdComponent {
2924
+ constructor() {
2925
+ this.fieldComponent = inject(forwardRef(() => OperandFieldComponent));
2926
+ this.isUpdate =
2927
+ !!this.fieldComponent.control.value && !this.fieldComponent.control.dirty;
2928
+ const defaultUsername = getUsernameDefaultValue(this.fieldComponent.field);
2929
+ if (defaultUsername && !this.isUpdate) {
2930
+ this.fieldComponent.control.setValue(`${defaultUsername}:`);
2931
+ }
2932
+ }
2933
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: HtpasswdComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2934
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.1", type: HtpasswdComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: `<acl-htpasswd-form
2935
+ [isDisabled]="fieldComponent.isDisabled"
2936
+ [formControl]="fieldComponent.control"
2937
+ [field]="fieldComponent.field"
2938
+ [required]="fieldComponent.isRequired"
2939
+ [isUpdate]="isUpdate"
2940
+ ></acl-htpasswd-form>`, isInline: true, dependencies: [{ kind: "component", type: HtpasswdFormComponent, selector: "acl-htpasswd-form", inputs: ["field", "required", "isUpdate", "isDisabled"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2941
+ }
2942
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: HtpasswdComponent, decorators: [{
2943
+ type: Component,
2944
+ args: [{
2945
+ template: `<acl-htpasswd-form
2946
+ [isDisabled]="fieldComponent.isDisabled"
2947
+ [formControl]="fieldComponent.control"
2948
+ [field]="fieldComponent.field"
2949
+ [required]="fieldComponent.isRequired"
2950
+ [isUpdate]="isUpdate"
2951
+ ></acl-htpasswd-form>`,
2952
+ changeDetection: ChangeDetectionStrategy.OnPush,
2953
+ standalone: true,
2954
+ imports: [HtpasswdFormComponent, ReactiveFormsModule],
2955
+ }]
2956
+ }], ctorParameters: () => [] });
2957
+
2958
+ const COMPONENTS = [HtpasswdComponent, HtpasswdFormComponent];
2959
+ class HtpasswdModule {
2960
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: HtpasswdModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
2961
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.1", ngImport: i0, type: HtpasswdModule, imports: [HtpasswdComponent, HtpasswdFormComponent], exports: [HtpasswdComponent, HtpasswdFormComponent] }); }
2962
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: HtpasswdModule, imports: [COMPONENTS] }); }
2963
+ }
2964
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: HtpasswdModule, decorators: [{
2965
+ type: NgModule,
2966
+ args: [{
2967
+ imports: [...COMPONENTS],
2968
+ exports: COMPONENTS,
2969
+ }]
2970
+ }] });
2971
+
2972
+ const capabilityComponents = Map$1()
2973
+ .set(SpecCapability.resourceRequirements, SpecCapability.resourceRequirements)
2974
+ .set(SpecCapability.select, SpecCapability.resourceRequirements);
2975
+ const capabilityFor = (specCapability) => {
2976
+ if (isEmpty(specCapability)) {
2977
+ return SpecCapability.text;
2978
+ }
2979
+ return specCapability;
2980
+ };
2981
+
2982
+ class SpecCapabilityComponent {
2983
+ constructor() {
2984
+ this.fields = [];
2985
+ this.SpecCapability = SpecCapability;
2986
+ this.getFieldDisplayName = getFieldDisplayName;
2987
+ this.getFieldDescription = getFieldDescription$1;
2988
+ this.yamlReadOptions = yamlReadOptions;
2989
+ this.viewActions = viewActions;
2990
+ this.isArrayField = isArrayField;
2991
+ }
2992
+ get isHidden() {
2993
+ return this.shouldBeHidden();
2994
+ }
2995
+ getCapability(capabilities) {
2996
+ const capability = capabilities.find(c => c.startsWith(SpecCapability.resourceRequirements) ||
2997
+ c.startsWith(SpecCapability.booleanSwitch) ||
2998
+ c.startsWith(SpecCapability.yaml) ||
2999
+ c.startsWith(SpecCapability.object) ||
3000
+ c.startsWith(SpecCapability.array));
3001
+ return capabilityFor(capability);
3002
+ }
3003
+ toDefault(input) {
3004
+ return input ? toString(input) : '-';
3005
+ }
3006
+ shouldBeHidden() {
3007
+ if (this.field.capabilities.some(c => c.startsWith(SpecCapability.fieldDependency))) {
3008
+ const dependency = this.field.capabilities
3009
+ .find(c => c.startsWith(SpecCapability.fieldDependency))
3010
+ .split(SpecCapability.fieldDependency)[1];
3011
+ const [path, value] = dependency.split(':');
3012
+ const dependencyField = this.fields.find(f => f.path === normalizePath(path));
3013
+ const dependencyDefaultValue = getDefaultValue(dependencyField);
3014
+ return ((get(this.data, dependencyField.path) ?? dependencyDefaultValue) !==
3015
+ convertValue(value, dependencyField.type));
3016
+ }
3017
+ return false;
3018
+ }
3019
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: SpecCapabilityComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3020
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.1", type: SpecCapabilityComponent, isStandalone: true, selector: "acl-spec-descriptor-capability", inputs: { field: "field", fields: "fields", data: "data" }, host: { properties: { "class.hidden": "this.isHidden" } }, ngImport: i0, template: "<ng-container *ngIf=\"field?.capabilities | pure: getCapability as type\">\n <div class=\"field-set-item__label\">\n {{ field | pure: getFieldDisplayName | translate }}\n </div>\n\n <ng-container [ngSwitch]=\"type\">\n <ng-container *ngSwitchCase=\"SpecCapability.resourceRequirements\">\n <acl-crd-resource-requirements\n [ngModel]=\"field?.value\"\n [field]=\"field\"\n [readOnly]=\"true\"\n >\n </acl-crd-resource-requirements>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"SpecCapability.booleanSwitch\">\n {{ (field.value ? 'switch_open' : 'switch_close') | translate }}\n </ng-container>\n\n <ng-container *ngSwitchCase=\"SpecCapability.yaml\">\n <acl-crd-yaml-editor\n [ngModel]=\"field?.value\"\n [actionsConfig]=\"viewActions\"\n [options]=\"yamlReadOptions\"\n >\n </acl-crd-yaml-editor>\n </ng-container>\n\n <ng-container>\n <div\n *ngSwitchDefault\n class=\"field-set-item__value field-set-item__value__overflow field-set-item__value__wrap\"\n >\n {{ field?.value | pure: toDefault }}\n </div>\n </ng-container>\n </ng-container>\n</ng-container>\n", styles: [":host{display:flex;min-height:20px;line-height:20px;align-items:flex-start;overflow:hidden;color:use-rgb(n-1)}:host.hidden{display:none}:host ::ng-deep .edit-icon{margin-left:9px;cursor:pointer}.field-set-item__label{margin-right:8px;text-align:right}.field-set-item__label:not(:empty):after{content:\":\";margin-left:2px}.field-set-item__value{min-width:0;flex:1;white-space:nowrap;display:flex}.field-set-item__value__overflow{display:block;overflow:hidden;text-overflow:ellipsis}.field-set-item__value__wrap{white-space:pre-wrap;flex-wrap:wrap}.field-set-item__label,.field-set-item__value{height:100%;align-items:flex-start}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1$1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$1.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ResourceRequirementsComponent, selector: "acl-crd-resource-requirements", inputs: ["readOnly", "field"] }, { kind: "component", type: YamlEditorComponent, selector: "acl-crd-yaml-editor", inputs: ["actionsConfig", "options"] }, { kind: "pipe", type: PurePipe, name: "pure" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3021
+ }
3022
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: SpecCapabilityComponent, decorators: [{
3023
+ type: Component,
3024
+ args: [{ selector: 'acl-spec-descriptor-capability', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
3025
+ CommonModule,
3026
+ FormsModule,
3027
+ PurePipe,
3028
+ TranslatePipe,
3029
+ ResourceRequirementsComponent,
3030
+ YamlEditorComponent,
3031
+ ], template: "<ng-container *ngIf=\"field?.capabilities | pure: getCapability as type\">\n <div class=\"field-set-item__label\">\n {{ field | pure: getFieldDisplayName | translate }}\n </div>\n\n <ng-container [ngSwitch]=\"type\">\n <ng-container *ngSwitchCase=\"SpecCapability.resourceRequirements\">\n <acl-crd-resource-requirements\n [ngModel]=\"field?.value\"\n [field]=\"field\"\n [readOnly]=\"true\"\n >\n </acl-crd-resource-requirements>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"SpecCapability.booleanSwitch\">\n {{ (field.value ? 'switch_open' : 'switch_close') | translate }}\n </ng-container>\n\n <ng-container *ngSwitchCase=\"SpecCapability.yaml\">\n <acl-crd-yaml-editor\n [ngModel]=\"field?.value\"\n [actionsConfig]=\"viewActions\"\n [options]=\"yamlReadOptions\"\n >\n </acl-crd-yaml-editor>\n </ng-container>\n\n <ng-container>\n <div\n *ngSwitchDefault\n class=\"field-set-item__value field-set-item__value__overflow field-set-item__value__wrap\"\n >\n {{ field?.value | pure: toDefault }}\n </div>\n </ng-container>\n </ng-container>\n</ng-container>\n", styles: [":host{display:flex;min-height:20px;line-height:20px;align-items:flex-start;overflow:hidden;color:use-rgb(n-1)}:host.hidden{display:none}:host ::ng-deep .edit-icon{margin-left:9px;cursor:pointer}.field-set-item__label{margin-right:8px;text-align:right}.field-set-item__label:not(:empty):after{content:\":\";margin-left:2px}.field-set-item__value{min-width:0;flex:1;white-space:nowrap;display:flex}.field-set-item__value__overflow{display:block;overflow:hidden;text-overflow:ellipsis}.field-set-item__value__wrap{white-space:pre-wrap;flex-wrap:wrap}.field-set-item__label,.field-set-item__value{height:100%;align-items:flex-start}\n"] }]
3032
+ }], propDecorators: { field: [{
3033
+ type: Input
3034
+ }], fields: [{
3035
+ type: Input
3036
+ }], data: [{
3037
+ type: Input
3038
+ }], isHidden: [{
3039
+ type: HostBinding,
3040
+ args: ['class.hidden']
3041
+ }] } });
3042
+
3043
+ class SpecCapabilityListComponent {
3044
+ constructor() {
3045
+ this.openApiSchemaPath = SCHEMA_PATH;
3046
+ this.createCapabilityField = createCapabilityField;
3047
+ // TODO: Need Correct Ux For Deep Object & Array Type
3048
+ this.excludes = (fields) => fields.filter(field => !['object', 'array'].includes(getFieldType(field) || field.type));
3049
+ this.debugLog = (fields) => {
3050
+ /* eslint-disable no-console */
3051
+ if (this.debug) {
3052
+ console.log('treeFields:', fields.treeFields);
3053
+ console.log('openApiFields:', fields.openApiFields);
3054
+ console.log('descriptorFields:', fields.descriptorFields);
3055
+ console.log('basicFields:', fields.basicFields);
3056
+ console.log('normalFields', fields.normalFields);
3057
+ console.log('fieldGroups:', fields.fieldGroups);
3058
+ console.log('arrayFieldGroups:', fields.arrayFieldGroups);
3059
+ console.log('advancedFields:', fields.advancedFields);
3060
+ }
3061
+ /* eslint-enable no-console */
3062
+ return fields;
3063
+ };
3064
+ }
3065
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: SpecCapabilityListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3066
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: SpecCapabilityListComponent, isStandalone: true, selector: "acl-spec-descriptor-capability-list", inputs: { descriptors: "descriptors", debug: "debug", data: "data", openApiSchema: "openApiSchema", openApiSchemaPath: "openApiSchemaPath" }, ngImport: i0, template: "@if (\n descriptors\n | pure: createCapabilityField : openApiSchema : data : openApiSchemaPath\n | pure: debugLog;\n as fields\n) {\n @for (field of fields.normalFields | pure: excludes; track field) {\n <acl-spec-descriptor-capability\n [field]=\"field\"\n [fields]=\"fields.basicFields\"\n [data]=\"data\"\n ></acl-spec-descriptor-capability>\n }\n @if (fields.fieldGroups; as groups) {\n @for (group of groups; track group) {\n <div class=\"group-field-capability\">\n <div class=\"group-field-capability--header\">{{ group.groupName }}</div>\n <div class=\"group-field-capability--content\">\n @for (field of group.fieldList | pure: excludes; track field) {\n <acl-spec-descriptor-capability\n [field]=\"$any(field)\"\n [fields]=\"fields.basicFields\"\n [data]=\"data\"\n ></acl-spec-descriptor-capability>\n }\n </div>\n </div>\n }\n }\n @if (fields.advancedFields; as advanced) {\n @if (advanced.length > 0) {\n <div class=\"group-field-capability\">\n <div class=\"group-field-capability--header\">\n {{ 'advanced_fields' | translate }}\n </div>\n <div class=\"group-field-capability--content\">\n @for (field of advanced | pure: excludes; track field) {\n <acl-spec-descriptor-capability\n [field]=\"field\"\n [fields]=\"fields.basicFields\"\n [data]=\"data\"\n ></acl-spec-descriptor-capability>\n }\n </div>\n </div>\n }\n }\n @if (fields.arrayFieldGroups; as arrayGroups) {\n <div class=\"array-group-field-capability\">\n @for (groups of arrayGroups; track groups) {\n <div class=\"group-field-capability\">\n <div class=\"group-field-capability--header\">\n {{ groups.groupName | translate }}\n </div>\n @for (fieldList of groups.fieldLists; track fieldList) {\n <div class=\"group-field-capability--content\">\n @for (field of fieldList | pure: excludes; track field) {\n <acl-spec-descriptor-capability\n [field]=\"field\"\n [fields]=\"fields.basicFields\"\n [data]=\"data\"\n ></acl-spec-descriptor-capability>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n}\n", styles: [":host:after{clear:both;content:\".\";display:block;width:0;height:0;visibility:hidden}:host acl-spec-descriptor-capability{margin-bottom:12px;min-height:22px}:host>acl-spec-descriptor-capability{width:100%;box-sizing:border-box}:host .group-field-capability{padding:15px 0 12px;border-top:1px dashed #ededed}:host .group-field-capability--header{font-size:16px;font-weight:500;display:flex;line-height:22px;color:rgb(var(--aui-color-n-1))}:host .group-field-capability--content acl-spec-descriptor-capability:first-child{margin-top:12px}:host .group-field-capability--content acl-spec-descriptor-capability:last-child{margin-bottom:0}:host .array-group-field-capability .group-field-capability--content{padding:8px;margin-top:8px;background-color:#fafafa;border-left:4px solid #f0f0f0}:host .array-group-field-capability .group-field-capability--content acl-spec-descriptor-capability:first-child{margin-top:0}\n"], dependencies: [{ kind: "component", type: SpecCapabilityComponent, selector: "acl-spec-descriptor-capability", inputs: ["field", "fields", "data"] }, { kind: "pipe", type: PurePipe, name: "pure" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3067
+ }
3068
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: SpecCapabilityListComponent, decorators: [{
3069
+ type: Component,
3070
+ args: [{ selector: 'acl-spec-descriptor-capability-list', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [PurePipe, TranslatePipe, SpecCapabilityComponent], template: "@if (\n descriptors\n | pure: createCapabilityField : openApiSchema : data : openApiSchemaPath\n | pure: debugLog;\n as fields\n) {\n @for (field of fields.normalFields | pure: excludes; track field) {\n <acl-spec-descriptor-capability\n [field]=\"field\"\n [fields]=\"fields.basicFields\"\n [data]=\"data\"\n ></acl-spec-descriptor-capability>\n }\n @if (fields.fieldGroups; as groups) {\n @for (group of groups; track group) {\n <div class=\"group-field-capability\">\n <div class=\"group-field-capability--header\">{{ group.groupName }}</div>\n <div class=\"group-field-capability--content\">\n @for (field of group.fieldList | pure: excludes; track field) {\n <acl-spec-descriptor-capability\n [field]=\"$any(field)\"\n [fields]=\"fields.basicFields\"\n [data]=\"data\"\n ></acl-spec-descriptor-capability>\n }\n </div>\n </div>\n }\n }\n @if (fields.advancedFields; as advanced) {\n @if (advanced.length > 0) {\n <div class=\"group-field-capability\">\n <div class=\"group-field-capability--header\">\n {{ 'advanced_fields' | translate }}\n </div>\n <div class=\"group-field-capability--content\">\n @for (field of advanced | pure: excludes; track field) {\n <acl-spec-descriptor-capability\n [field]=\"field\"\n [fields]=\"fields.basicFields\"\n [data]=\"data\"\n ></acl-spec-descriptor-capability>\n }\n </div>\n </div>\n }\n }\n @if (fields.arrayFieldGroups; as arrayGroups) {\n <div class=\"array-group-field-capability\">\n @for (groups of arrayGroups; track groups) {\n <div class=\"group-field-capability\">\n <div class=\"group-field-capability--header\">\n {{ groups.groupName | translate }}\n </div>\n @for (fieldList of groups.fieldLists; track fieldList) {\n <div class=\"group-field-capability--content\">\n @for (field of fieldList | pure: excludes; track field) {\n <acl-spec-descriptor-capability\n [field]=\"field\"\n [fields]=\"fields.basicFields\"\n [data]=\"data\"\n ></acl-spec-descriptor-capability>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n}\n", styles: [":host:after{clear:both;content:\".\";display:block;width:0;height:0;visibility:hidden}:host acl-spec-descriptor-capability{margin-bottom:12px;min-height:22px}:host>acl-spec-descriptor-capability{width:100%;box-sizing:border-box}:host .group-field-capability{padding:15px 0 12px;border-top:1px dashed #ededed}:host .group-field-capability--header{font-size:16px;font-weight:500;display:flex;line-height:22px;color:rgb(var(--aui-color-n-1))}:host .group-field-capability--content acl-spec-descriptor-capability:first-child{margin-top:12px}:host .group-field-capability--content acl-spec-descriptor-capability:last-child{margin-bottom:0}:host .array-group-field-capability .group-field-capability--content{padding:8px;margin-top:8px;background-color:#fafafa;border-left:4px solid #f0f0f0}:host .array-group-field-capability .group-field-capability--content acl-spec-descriptor-capability:first-child{margin-top:0}\n"] }]
3071
+ }], propDecorators: { descriptors: [{
3072
+ type: Input
3073
+ }], debug: [{
3074
+ type: Input
3075
+ }], data: [{
3076
+ type: Input
3077
+ }], openApiSchema: [{
3078
+ type: Input
3079
+ }], openApiSchemaPath: [{
3080
+ type: Input
3081
+ }] } });
3082
+
3083
+ /**
3084
+ * Generated bundle index. Do not edit.
3085
+ */
3086
+
3087
+ export { BaseOperandFiledArrayComponent, BasicAuthCreateSecretDialogComponent, BasicAuthSecretComponent, CrdFormArrayTableComponent, CrdFormComponent, DEFAULT_VALUE_PATTERN, DESCRIPTOR_DEFINITION_KEY, FieldControlsModule, FormItemComponent, GROUP_PATTERN, HtpasswdComponent, HtpasswdFormComponent, HtpasswdModule, K8sResourcePrefixComponent, LinkComponent, MAX_DEPTH, NamespacedResourceKind, NodeModel, OperandAdvancedFieldGroupComponent, OperandArrayFieldGroupComponent, OperandFieldComponent, OperandFieldGroupComponent, PASSWORD_REVEAL, REGEXP_CAPABILITY_VALIDATION, REGEXP_FIELD_DEPENDENCY_CAPABILITY, REGEXP_K8S_RESOURCE_CAPABILITY, REGEXP_K8S_RESOURCE_SUFFIX, REGEXP_SELECT_CAPABILITY, REGEXP_VALIDATION_SUFFIX, ResourceRequirementsComponent, SCHEMA_PATH, SpecCapability, SpecCapabilityComponent, SpecCapabilityListComponent, SpecCapabilityUIPrefix, SpecCapabilityWidgetsPrefix, Validations, YamlEditorComponent, _isNumberValue, capabilityComponents, capabilityFor, coerceBoolean, coerceNumber, convertBooleanSwitchValue, convertValue, createCapabilityField, evalInContext, fieldShouldReveal, filterMapByKey, flattenNestedProperties, getArrayGroupName, getBasicAuthSecretConfig, getBasicCapabilityType, getBooleanSwitchOptions, getCapabilitiesForOpenApiProperty, getCapabilityDisabled, getCapabilityValidations, getDefaultValue, getFieldDescription$1 as getFieldDescription, getFieldDisplayName, getFieldDocLink, getFieldPlaceholder$1 as getFieldPlaceholder, getFieldTooltip, getFieldType, getFieldsByPath, getFieldsFromDescriptor, getFieldsFromOpenApiSchema, getFormData, getGroupName, getK8sResourcePrefixOptions, getMatchArrayIndex, getMatchedCapabilityValue, getOneOfMap, getOpenApiPropertyByPath, getOperandPath, getPathFromTagPath, getPropertyDepth, getRadioOptions, getRelatedFields, getTreeFields, hasDescriptor, isAllowCreate, isArrayField, isArrayFieldTable, isClearable, isCreatable, isEmptyArray, isFieldCopyable, isFieldDescriptionAsLink, isFolded, isGroupField, isLink, isMultiple, isRemoteField, isRequired, modifyArrayFieldPathIndex, normalizePath, parseArrayPath, parseGroupDescriptor, pathToArray, repairFieldChildPathByCorrectIndex, resolveKVParams, resolveLinkOptions, setRadiosDefaultValue };
3088
+ //# sourceMappingURL=alauda-fe-crd-form.mjs.map