@alauda-fe/crd-form 0.0.9 → 1.0.1-alpha.1

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