@rancher/shell 0.3.20 → 0.3.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/translations/en-us.yaml +8 -2
- package/assets/translations/zh-hans.yaml +8 -1
- package/cloud-credential/__tests__/azure.test.ts +53 -0
- package/cloud-credential/azure.vue +6 -0
- package/components/GrowlManager.vue +33 -30
- package/components/Questions/Array.vue +2 -2
- package/components/Questions/Boolean.vue +7 -1
- package/components/Questions/CloudCredential.vue +1 -0
- package/components/Questions/Enum.vue +21 -2
- package/components/Questions/Float.vue +8 -3
- package/components/Questions/Int.vue +8 -3
- package/components/Questions/Question.js +72 -0
- package/components/Questions/QuestionMap.vue +2 -1
- package/components/Questions/Radio.vue +33 -0
- package/components/Questions/Reference.vue +2 -0
- package/components/Questions/String.vue +8 -3
- package/components/Questions/Yaml.vue +46 -0
- package/components/Questions/__tests__/Boolean.test.ts +123 -0
- package/components/Questions/__tests__/Float.test.ts +123 -0
- package/components/Questions/__tests__/Int.test.ts +123 -0
- package/components/Questions/__tests__/String.test.ts +123 -0
- package/components/Questions/__tests__/Yaml.test.ts +123 -0
- package/components/Questions/index.vue +8 -1
- package/components/ResourceTable.vue +6 -12
- package/components/SideNav.vue +634 -0
- package/components/__tests__/NamespaceFilter.test.ts +3 -4
- package/components/form/ResourceQuota/ProjectRow.vue +38 -15
- package/components/form/UnitInput.vue +1 -0
- package/components/form/__tests__/KeyValue.test.ts +2 -1
- package/components/form/__tests__/UnitInput.test.ts +2 -2
- package/components/formatter/ClusterProvider.vue +9 -3
- package/components/formatter/LinkName.vue +12 -1
- package/components/formatter/__tests__/ClusterProvider.test.ts +5 -1
- package/components/nav/Header.vue +1 -0
- package/components/nav/WorkspaceSwitcher.vue +4 -1
- package/config/settings.ts +59 -2
- package/config/types.js +2 -0
- package/core/plugin-helpers.js +4 -1
- package/core/types.ts +1 -0
- package/creators/pkg/files/.github/workflows/build-extension-catalog.yml +28 -0
- package/creators/pkg/files/.github/workflows/build-extension-charts.yml +26 -0
- package/creators/pkg/init +63 -4
- package/detail/provisioning.cattle.io.cluster.vue +4 -2
- package/edit/fleet.cattle.io.gitrepo.vue +8 -0
- package/edit/provisioning.cattle.io.cluster/rke2.vue +4 -4
- package/layouts/default.vue +11 -597
- package/middleware/authenticated.js +2 -14
- package/mixins/__tests__/chart.test.ts +40 -0
- package/mixins/chart.js +5 -0
- package/models/catalog.cattle.io.clusterrepo.js +6 -2
- package/models/fleet.cattle.io.cluster.js +10 -2
- package/models/fleet.cattle.io.gitrepo.js +3 -1
- package/package.json +1 -1
- package/pages/c/_cluster/fleet/index.vue +4 -0
- package/pages/c/_cluster/gatekeeper/index.vue +10 -1
- package/pages/c/_cluster/uiplugins/index.vue +3 -3
- package/plugins/steve/__tests__/header-warnings.spec.ts +238 -0
- package/plugins/steve/actions.js +4 -23
- package/plugins/steve/header-warnings.ts +91 -0
- package/promptRemove/management.cattle.io.project.vue +9 -6
- package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +8 -0
- package/rancher-components/components/Form/Radio/RadioButton.test.ts +7 -3
- package/scripts/extension/parse-tag-name +30 -0
- package/types/shell/index.d.ts +3 -0
- package/utils/auth.js +17 -0
- package/utils/object.js +0 -1
- package/utils/settings.ts +2 -17
- package/utils/validators/__tests__/cidr.test.ts +33 -0
- package/utils/validators/cidr.js +5 -0
- package/vue-config-helper.js +135 -0
- package/vue.config.js +23 -139
- package/yarn-error.log +200 -0
- package/creators/pkg/files/.github/workflows/build-container.yml +0 -64
- package/creators/pkg/files/.github/workflows/build-extension.yml +0 -110
|
@@ -2291,6 +2291,7 @@ gatekeeperIndex:
|
|
|
2291
2291
|
poweredBy: OPA Gatekeeper
|
|
2292
2292
|
unavailable: OPA + Gatekeeper is not available in the system-charts catalog.
|
|
2293
2293
|
violations: Violations
|
|
2294
|
+
deprecated: The OPA Gatekeeper chart is deprecated as of Rancher 2.8 and will be removed in a future release. Please consider switching to <a target="_blank" rel="noopener noreferrer nofollow" href="https://www.kubewarden.io">Kubewarden</a>.
|
|
2294
2295
|
|
|
2295
2296
|
gatekeeperInstall:
|
|
2296
2297
|
auditInterval: Auto Interval
|
|
@@ -2357,6 +2358,9 @@ growl:
|
|
|
2357
2358
|
podSecurity:
|
|
2358
2359
|
message: "The creation of this Pod would violate existing restricted policies for the adopted Namespace"
|
|
2359
2360
|
title: PodSecurity violation
|
|
2361
|
+
kubeApiHeaderWarning:
|
|
2362
|
+
titleCreate: "{resourceType} Creation Warning"
|
|
2363
|
+
titleUpdate: "{resourceType} Update Warning"
|
|
2360
2364
|
|
|
2361
2365
|
hpa:
|
|
2362
2366
|
detail:
|
|
@@ -3041,7 +3045,7 @@ login:
|
|
|
3041
3045
|
noResponse: "No response received"
|
|
3042
3046
|
error: An error occurred logging in. Please try again.
|
|
3043
3047
|
clientError: Invalid username or password. Please try again.
|
|
3044
|
-
specificError: 'An error
|
|
3048
|
+
specificError: 'An error occurred logging in: {msg}'
|
|
3045
3049
|
useLocal: Use a local user
|
|
3046
3050
|
loginWithProvider: Log in with {provider}
|
|
3047
3051
|
username: Username
|
|
@@ -3442,7 +3446,7 @@ namespace:
|
|
|
3442
3446
|
workloads: Workloads
|
|
3443
3447
|
label: Namespace
|
|
3444
3448
|
selectNamespace: Select Namespace
|
|
3445
|
-
createNamespace: Create a
|
|
3449
|
+
createNamespace: Create a new Namespace
|
|
3446
3450
|
selectOrCreate: Select or Create a Namespace
|
|
3447
3451
|
resourceStates:
|
|
3448
3452
|
success: 'Active'
|
|
@@ -5634,6 +5638,8 @@ validation:
|
|
|
5634
5638
|
logdna:
|
|
5635
5639
|
apiKey: Required an "Api Key" to be set.
|
|
5636
5640
|
invalidCron: Invalid cron schedule
|
|
5641
|
+
invalidCidr: "Invalid CIDR"
|
|
5642
|
+
invalidIP: "Invalid IP"
|
|
5637
5643
|
k8s:
|
|
5638
5644
|
name: Must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc').
|
|
5639
5645
|
identifier:
|
|
@@ -3051,6 +3051,7 @@ login:
|
|
|
3051
3051
|
noResponse: "没有收到响应。"
|
|
3052
3052
|
error: 登录时发生错误,请重试。
|
|
3053
3053
|
clientError: 无效的用户名或密码,请重试。
|
|
3054
|
+
specificError: '登录时发生错误:{msg}'
|
|
3054
3055
|
useLocal: 使用本地账号登录
|
|
3055
3056
|
loginWithProvider: 使用 {provider} 登录
|
|
3056
3057
|
username: 用户名
|
|
@@ -3525,8 +3526,11 @@ navLink:
|
|
|
3525
3526
|
label: 链接标签
|
|
3526
3527
|
description:
|
|
3527
3528
|
label: 链接描述
|
|
3529
|
+
groupImage:
|
|
3530
|
+
label: 组图片
|
|
3528
3531
|
iconSrc:
|
|
3529
|
-
|
|
3532
|
+
tip: '图片的高度应为 21 像素,最大宽度为 200 像素。最大文件大小为 20KB。支持的格式:JPEG、PNG、SVG。'
|
|
3533
|
+
label: 添加图片
|
|
3530
3534
|
networkpolicy:
|
|
3531
3535
|
egress:
|
|
3532
3536
|
label: Egress 规则
|
|
@@ -5640,6 +5644,8 @@ validation:
|
|
|
5640
5644
|
logdna:
|
|
5641
5645
|
apiKey: 需要设置“API 密钥”。
|
|
5642
5646
|
invalidCron: 无效的 cron 调度
|
|
5647
|
+
invalidCidr: "无效的 CIDR"
|
|
5648
|
+
invalidIP: "无效的 IP"
|
|
5643
5649
|
k8s:
|
|
5644
5650
|
name: 必须由小写字母数字或“-”组成,并且开头和结尾必须是字母数字(例如“my-name”或“123-abc”)。
|
|
5645
5651
|
identifier:
|
|
@@ -5776,6 +5782,7 @@ wm:
|
|
|
5776
5782
|
containerShell:
|
|
5777
5783
|
clear: 清除
|
|
5778
5784
|
containerName: "容器:{label}"
|
|
5785
|
+
failed: "无法打开容器 shell(所有 shell 命令均未成功)\n\r"
|
|
5779
5786
|
kubectlShell:
|
|
5780
5787
|
title: "Kubectl: {name}"
|
|
5781
5788
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import AzureCloudCreds from '@shell/cloud-credential/azure.vue';
|
|
3
|
+
|
|
4
|
+
const mockStore = {
|
|
5
|
+
getters: { 'i18n/t': jest.fn() },
|
|
6
|
+
dispatch: () => jest.fn()
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
describe('cloud credentials: Azure', () => {
|
|
10
|
+
const wrapper = mount(AzureCloudCreds, {
|
|
11
|
+
propsData: {
|
|
12
|
+
value: {
|
|
13
|
+
decodedData: {
|
|
14
|
+
environment: '',
|
|
15
|
+
subscriptionId: '',
|
|
16
|
+
clientId: '',
|
|
17
|
+
clientSecret: '',
|
|
18
|
+
},
|
|
19
|
+
setData: jest.fn()
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
mocks: { $store: mockStore }
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should pass all the correct fields when checking if credentials are valid', async() => {
|
|
26
|
+
const spyDispatch = jest.spyOn(mockStore, 'dispatch');
|
|
27
|
+
|
|
28
|
+
wrapper.setData({
|
|
29
|
+
value: {
|
|
30
|
+
decodedData: {
|
|
31
|
+
environment: 'my-env',
|
|
32
|
+
subscriptionId: 'my-sub-id',
|
|
33
|
+
clientId: 'my-c-id',
|
|
34
|
+
clientSecret: 'my-c-secret',
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
await wrapper.vm.test();
|
|
40
|
+
|
|
41
|
+
expect(spyDispatch).toHaveBeenCalledWith('management/request', {
|
|
42
|
+
data: {
|
|
43
|
+
environment: 'my-env',
|
|
44
|
+
subscriptionId: 'my-sub-id',
|
|
45
|
+
clientId: 'my-c-id',
|
|
46
|
+
clientSecret: 'my-c-secret',
|
|
47
|
+
},
|
|
48
|
+
method: 'POST',
|
|
49
|
+
redirectUnauthorized: false,
|
|
50
|
+
url: '/meta/aksCheckCredentials'
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -40,6 +40,7 @@ export default {
|
|
|
40
40
|
clientId,
|
|
41
41
|
clientSecret,
|
|
42
42
|
subscriptionId,
|
|
43
|
+
environment,
|
|
43
44
|
} = this.value.decodedData;
|
|
44
45
|
|
|
45
46
|
try {
|
|
@@ -50,6 +51,7 @@ export default {
|
|
|
50
51
|
clientId,
|
|
51
52
|
clientSecret,
|
|
52
53
|
subscriptionId,
|
|
54
|
+
environment,
|
|
53
55
|
},
|
|
54
56
|
redirectUnauthorized: false,
|
|
55
57
|
});
|
|
@@ -96,6 +98,7 @@ export default {
|
|
|
96
98
|
:searchable="false"
|
|
97
99
|
:required="true"
|
|
98
100
|
:label="t('cluster.credential.azure.environment.label')"
|
|
101
|
+
data-testid="azure-cloud-credentials-environment"
|
|
99
102
|
@input="value.setData('environment', $event)"
|
|
100
103
|
/>
|
|
101
104
|
</div>
|
|
@@ -106,6 +109,7 @@ export default {
|
|
|
106
109
|
type="text"
|
|
107
110
|
:mode="mode"
|
|
108
111
|
:required="true"
|
|
112
|
+
data-testid="azure-cloud-credentials-subscription-id"
|
|
109
113
|
@input="value.setData('subscriptionId', $event)"
|
|
110
114
|
/>
|
|
111
115
|
</div>
|
|
@@ -118,6 +122,7 @@ export default {
|
|
|
118
122
|
type="text"
|
|
119
123
|
:mode="mode"
|
|
120
124
|
:required="true"
|
|
125
|
+
data-testid="azure-cloud-credentials-client-id"
|
|
121
126
|
@input="value.setData('clientId', $event)"
|
|
122
127
|
/>
|
|
123
128
|
</div>
|
|
@@ -128,6 +133,7 @@ export default {
|
|
|
128
133
|
type="password"
|
|
129
134
|
:mode="mode"
|
|
130
135
|
:required="true"
|
|
136
|
+
data-testid="azure-cloud-credentials-client-secret"
|
|
131
137
|
@input="value.setData('clientSecret', $event)"
|
|
132
138
|
/>
|
|
133
139
|
</div>
|
|
@@ -99,15 +99,17 @@ export default {
|
|
|
99
99
|
<i :class="{icon: true, ['icon-'+growl.icon]: true}" />
|
|
100
100
|
</div>
|
|
101
101
|
<div class="growl-text">
|
|
102
|
-
<
|
|
102
|
+
<i
|
|
103
|
+
class="close hand icon icon-close"
|
|
104
|
+
@click="close(growl)"
|
|
105
|
+
/>
|
|
106
|
+
<div class="growl-text-title">
|
|
107
|
+
{{ growl.title }}
|
|
108
|
+
</div>
|
|
103
109
|
<p v-if="growl.message">
|
|
104
110
|
{{ growl.message }}
|
|
105
111
|
</p>
|
|
106
112
|
</div>
|
|
107
|
-
<i
|
|
108
|
-
class="close hand icon icon-close"
|
|
109
|
-
@click="close(growl)"
|
|
110
|
-
/>
|
|
111
113
|
</div>
|
|
112
114
|
</div>
|
|
113
115
|
</div>
|
|
@@ -135,7 +137,7 @@ export default {
|
|
|
135
137
|
width: 100%;
|
|
136
138
|
|
|
137
139
|
@media only screen and (min-width: map-get($breakpoints, '--viewport-7')) {
|
|
138
|
-
width:
|
|
140
|
+
width: 420px;
|
|
139
141
|
}
|
|
140
142
|
}
|
|
141
143
|
|
|
@@ -149,13 +151,15 @@ export default {
|
|
|
149
151
|
margin: 10px;
|
|
150
152
|
position: relative;
|
|
151
153
|
word-break: break-all;
|
|
152
|
-
|
|
153
|
-
.close {
|
|
154
|
-
padding: 5px;
|
|
155
|
-
}
|
|
154
|
+
box-shadow: 0 3px 5px 0px var(--shadow);
|
|
156
155
|
|
|
157
156
|
.icon-container {
|
|
158
157
|
align-self: center;
|
|
158
|
+
flex-basis: 10%;
|
|
159
|
+
padding: 10px 20px 10px 10px;
|
|
160
|
+
i {
|
|
161
|
+
font-size: 24px;
|
|
162
|
+
}
|
|
159
163
|
}
|
|
160
164
|
|
|
161
165
|
.growl-message {
|
|
@@ -164,28 +168,27 @@ export default {
|
|
|
164
168
|
&.growl-center {
|
|
165
169
|
align-items: center;
|
|
166
170
|
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
.growl-text {
|
|
170
|
-
flex-basis: 90%;
|
|
171
|
-
padding: 10px 10px 10px 0;
|
|
172
|
-
word-break: break-word;
|
|
173
|
-
white-space: normal;
|
|
174
|
-
|
|
175
|
-
> div {
|
|
176
|
-
font-size: 16px;
|
|
177
|
-
}
|
|
178
171
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
172
|
+
.growl-text {
|
|
173
|
+
position: relative;
|
|
174
|
+
flex-basis: 90%;
|
|
175
|
+
padding: 10px 10px 10px 0;
|
|
176
|
+
word-break: break-word;
|
|
177
|
+
white-space: normal;
|
|
178
|
+
|
|
179
|
+
.close {
|
|
180
|
+
position: absolute;
|
|
181
|
+
top: 12px;
|
|
182
|
+
right: 10px;
|
|
183
|
+
}
|
|
184
|
+
.growl-text-title {
|
|
185
|
+
font-size: 16px;
|
|
186
|
+
margin-bottom: 20px;
|
|
187
|
+
}
|
|
183
188
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
i {
|
|
188
|
-
font-size: 24px;
|
|
189
|
+
> P {
|
|
190
|
+
margin-top: 5px;
|
|
191
|
+
}
|
|
189
192
|
}
|
|
190
193
|
}
|
|
191
194
|
}
|
|
@@ -19,11 +19,11 @@ export default {
|
|
|
19
19
|
<div class="col span-6">
|
|
20
20
|
<ArrayList
|
|
21
21
|
:key="question.variable"
|
|
22
|
-
v-model="value
|
|
22
|
+
v-model="value"
|
|
23
23
|
:title="question.label"
|
|
24
24
|
:mode="mode"
|
|
25
|
-
:protip="false"
|
|
26
25
|
:disabled="disabled"
|
|
26
|
+
:protip="displayTooltip"
|
|
27
27
|
@input="update"
|
|
28
28
|
/>
|
|
29
29
|
</div>
|
|
@@ -9,18 +9,24 @@ export default {
|
|
|
9
9
|
</script>
|
|
10
10
|
|
|
11
11
|
<template>
|
|
12
|
-
<div
|
|
12
|
+
<div
|
|
13
|
+
:data-testid="`boolean-row-${question.variable}`"
|
|
14
|
+
class="row"
|
|
15
|
+
>
|
|
13
16
|
<div class="col span-6">
|
|
14
17
|
<Checkbox
|
|
15
18
|
:mode="mode"
|
|
16
19
|
:label="displayLabel"
|
|
17
20
|
:value="value"
|
|
18
21
|
:disabled="disabled"
|
|
22
|
+
:tooltip="displayTooltip"
|
|
23
|
+
:data-testid="`boolean-input-${question.variable}`"
|
|
19
24
|
@input="$emit('input', $event)"
|
|
20
25
|
/>
|
|
21
26
|
</div>
|
|
22
27
|
<div
|
|
23
28
|
v-if="showDescription"
|
|
29
|
+
:data-testid="`boolean-description-${question.variable}`"
|
|
24
30
|
class="col span-6 mt-10"
|
|
25
31
|
>
|
|
26
32
|
{{ displayDescription }}
|
|
@@ -4,7 +4,23 @@ import Question from './Question';
|
|
|
4
4
|
|
|
5
5
|
export default {
|
|
6
6
|
components: { LabeledSelect },
|
|
7
|
-
mixins: [Question]
|
|
7
|
+
mixins: [Question],
|
|
8
|
+
computed: {
|
|
9
|
+
options() {
|
|
10
|
+
const options = this.question.options;
|
|
11
|
+
|
|
12
|
+
if (Array.isArray(options)) {
|
|
13
|
+
return options;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return Object.entries(options).map(([key, value]) => {
|
|
17
|
+
return {
|
|
18
|
+
value: key,
|
|
19
|
+
label: value,
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
8
24
|
};
|
|
9
25
|
</script>
|
|
10
26
|
|
|
@@ -14,11 +30,14 @@ export default {
|
|
|
14
30
|
<LabeledSelect
|
|
15
31
|
:mode="mode"
|
|
16
32
|
:label="displayLabel"
|
|
17
|
-
:options="
|
|
33
|
+
:options="options"
|
|
18
34
|
:placeholder="question.description"
|
|
19
35
|
:required="question.required"
|
|
36
|
+
:multiple="question.multiple"
|
|
20
37
|
:value="value"
|
|
21
38
|
:disabled="disabled"
|
|
39
|
+
:tooltip="displayTooltip"
|
|
40
|
+
:searchable="question.searchable"
|
|
22
41
|
@input="$emit('input', $event)"
|
|
23
42
|
/>
|
|
24
43
|
</div>
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
import { LabeledInput } from '@components/Form/LabeledInput';
|
|
3
3
|
import Question from './Question';
|
|
4
4
|
|
|
5
|
-
// @TODO valid_chars, invalid_chars
|
|
6
|
-
|
|
7
5
|
export default {
|
|
8
6
|
components: { LabeledInput },
|
|
9
7
|
mixins: [Question]
|
|
@@ -11,7 +9,10 @@ export default {
|
|
|
11
9
|
</script>
|
|
12
10
|
|
|
13
11
|
<template>
|
|
14
|
-
<div
|
|
12
|
+
<div
|
|
13
|
+
:data-testid="`float-row-${question.variable}`"
|
|
14
|
+
class="row"
|
|
15
|
+
>
|
|
15
16
|
<div class="col span-6">
|
|
16
17
|
<LabeledInput
|
|
17
18
|
type="text"
|
|
@@ -21,11 +22,15 @@ export default {
|
|
|
21
22
|
:required="question.required"
|
|
22
23
|
:value="value"
|
|
23
24
|
:disabled="disabled"
|
|
25
|
+
:tooltip="displayTooltip"
|
|
26
|
+
:rules="rules"
|
|
27
|
+
:data-testid="`float-input-${question.variable}`"
|
|
24
28
|
@input="val = parseFloat($event); if ( !isNaN(val) ) { $emit('input', val) }"
|
|
25
29
|
/>
|
|
26
30
|
</div>
|
|
27
31
|
<div
|
|
28
32
|
v-if="showDescription"
|
|
33
|
+
:data-testid="`float-description-${question.variable}`"
|
|
29
34
|
class="col span-6 mt-10"
|
|
30
35
|
>
|
|
31
36
|
{{ question.description }}
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
import { LabeledInput } from '@components/Form/LabeledInput';
|
|
3
3
|
import Question from './Question';
|
|
4
4
|
|
|
5
|
-
// @TODO valid_chars, invalid_chars
|
|
6
|
-
|
|
7
5
|
export default {
|
|
8
6
|
components: { LabeledInput },
|
|
9
7
|
mixins: [Question]
|
|
@@ -11,7 +9,10 @@ export default {
|
|
|
11
9
|
</script>
|
|
12
10
|
|
|
13
11
|
<template>
|
|
14
|
-
<div
|
|
12
|
+
<div
|
|
13
|
+
:data-testid="`int-row-${question.variable}`"
|
|
14
|
+
class="row"
|
|
15
|
+
>
|
|
15
16
|
<div class="col span-6">
|
|
16
17
|
<LabeledInput
|
|
17
18
|
type="text"
|
|
@@ -21,11 +22,15 @@ export default {
|
|
|
21
22
|
:required="question.required"
|
|
22
23
|
:value="value"
|
|
23
24
|
:disabled="disabled"
|
|
25
|
+
:tooltip="displayTooltip"
|
|
26
|
+
:rules="rules"
|
|
27
|
+
:data-testid="`int-input-${question.variable}`"
|
|
24
28
|
@input="val = parseInt($event, 10); if ( !isNaN(val) ) { $emit('input', val) }"
|
|
25
29
|
/>
|
|
26
30
|
</div>
|
|
27
31
|
<div
|
|
28
32
|
v-if="showDescription"
|
|
33
|
+
:data-testid="`int-description-${question.variable}`"
|
|
29
34
|
class="col span-6 mt-10"
|
|
30
35
|
>
|
|
31
36
|
{{ displayDescription }}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { _EDIT } from '@shell/config/query-params';
|
|
2
|
+
import { validateChars, validateHostname, validateLength } from '@shell/utils/validators';
|
|
3
|
+
import { cronSchedule } from '@shell/utils/validators/cron-schedule';
|
|
4
|
+
import { isValidCIDR, isValidIP } from '@shell/utils/validators/cidr';
|
|
2
5
|
|
|
3
6
|
export default {
|
|
4
7
|
props: {
|
|
@@ -57,6 +60,75 @@ export default {
|
|
|
57
60
|
|
|
58
61
|
return this.$store.getters['i18n/withFallback'](`charts.${ this.chartName }."${ variable }".description`, null, this.question?.description);
|
|
59
62
|
},
|
|
63
|
+
|
|
64
|
+
displayTooltip() {
|
|
65
|
+
if (!this.question?.tooltip) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
const variable = this.question?.variable;
|
|
69
|
+
|
|
70
|
+
return this.$store.getters['i18n/withFallback'](`charts.${ this.chartName }."${ variable }".tooltip`, null, this.question?.tooltip);
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
rules() {
|
|
74
|
+
return [
|
|
75
|
+
(val) => {
|
|
76
|
+
let errors = [];
|
|
77
|
+
|
|
78
|
+
errors = validateChars(
|
|
79
|
+
val,
|
|
80
|
+
{
|
|
81
|
+
validChars: this.question.valid_chars,
|
|
82
|
+
invalidChars: this.question.invalid_chars
|
|
83
|
+
},
|
|
84
|
+
this.displayLabel,
|
|
85
|
+
this.$store.getters,
|
|
86
|
+
errors,
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
errors = validateLength(
|
|
90
|
+
val,
|
|
91
|
+
{
|
|
92
|
+
minLength: this.question?.min_length,
|
|
93
|
+
maxLenght: this.question?.max_length,
|
|
94
|
+
min: this.question?.min,
|
|
95
|
+
max: this.question?.max,
|
|
96
|
+
},
|
|
97
|
+
this.displayLabel,
|
|
98
|
+
this.$store.getters,
|
|
99
|
+
errors,
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
if (this.question.type === 'hostname') {
|
|
103
|
+
errors = validateHostname(
|
|
104
|
+
val,
|
|
105
|
+
this.displayLabel,
|
|
106
|
+
this.$store.getters,
|
|
107
|
+
{},
|
|
108
|
+
errors,
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (this.question.type === 'cron') {
|
|
113
|
+
cronSchedule(
|
|
114
|
+
val,
|
|
115
|
+
this.$store.getters,
|
|
116
|
+
errors,
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (this.question.type === 'cidr' && !isValidCIDR(val)) {
|
|
121
|
+
errors.push(this.$store.getters['i18n/t']('validation.invalidCidr'));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (this.question.type === 'ipaddr' && !isValidIP(val)) {
|
|
125
|
+
errors.push(this.$store.getters['i18n/t']('validation.invalidIP'));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return errors;
|
|
129
|
+
}
|
|
130
|
+
];
|
|
131
|
+
}
|
|
60
132
|
},
|
|
61
133
|
|
|
62
134
|
created() {
|
|
@@ -29,11 +29,12 @@ export default {
|
|
|
29
29
|
<div class="col span-12 mt-10">
|
|
30
30
|
<KeyValue
|
|
31
31
|
:key="question.variable"
|
|
32
|
-
v-model="value
|
|
32
|
+
v-model="value"
|
|
33
33
|
:title="question.label"
|
|
34
34
|
:mode="mode"
|
|
35
35
|
:protip="false"
|
|
36
36
|
:disabled="disabled"
|
|
37
|
+
:title-protip="displayTooltip"
|
|
37
38
|
@input="update"
|
|
38
39
|
/>
|
|
39
40
|
</div>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import RadioGroup from '@components/Form/Radio/RadioGroup.vue';
|
|
3
|
+
import Question from './Question';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
components: { RadioGroup },
|
|
7
|
+
mixins: [Question]
|
|
8
|
+
};
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<div class="row">
|
|
13
|
+
<div class="col span-6">
|
|
14
|
+
<RadioGroup
|
|
15
|
+
name="question.variable"
|
|
16
|
+
:mode="mode"
|
|
17
|
+
:labels="Array.isArray(question.options) ? question.options : Object.values(question.options)"
|
|
18
|
+
:options="Array.isArray(question.options) ? question.options : Object.keys(question.options)"
|
|
19
|
+
:value="value"
|
|
20
|
+
:disabled="disabled"
|
|
21
|
+
:label="displayLabel"
|
|
22
|
+
:tooltip="displayTooltip"
|
|
23
|
+
@input="$emit('input', $event)"
|
|
24
|
+
/>
|
|
25
|
+
</div>
|
|
26
|
+
<div
|
|
27
|
+
v-if="showDescription"
|
|
28
|
+
class="col span-6 mt-10"
|
|
29
|
+
>
|
|
30
|
+
{{ displayDescription }}
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
@@ -96,6 +96,7 @@ export default {
|
|
|
96
96
|
:placeholder="question.description"
|
|
97
97
|
:required="question.required"
|
|
98
98
|
:value="value"
|
|
99
|
+
:tooltip="displayTooltip"
|
|
99
100
|
@input="!$fetchState.pending && $emit('input', $event)"
|
|
100
101
|
/>
|
|
101
102
|
</div>
|
|
@@ -118,6 +119,7 @@ export default {
|
|
|
118
119
|
:placeholder="question.description"
|
|
119
120
|
:required="question.required"
|
|
120
121
|
:value="value"
|
|
122
|
+
:tooltip="displayTooltip"
|
|
121
123
|
@input="!$fetchState.pending && $emit('input', $event)"
|
|
122
124
|
/>
|
|
123
125
|
</div>
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
import { LabeledInput } from '@components/Form/LabeledInput';
|
|
3
3
|
import Question from './Question';
|
|
4
4
|
|
|
5
|
-
// @TODO valid_chars, invalid_chars
|
|
6
|
-
|
|
7
5
|
export default {
|
|
8
6
|
components: { LabeledInput },
|
|
9
7
|
mixins: [Question],
|
|
@@ -21,7 +19,10 @@ export default {
|
|
|
21
19
|
</script>
|
|
22
20
|
|
|
23
21
|
<template>
|
|
24
|
-
<div
|
|
22
|
+
<div
|
|
23
|
+
:data-testid="`string-row-${question.variable}`"
|
|
24
|
+
class="row"
|
|
25
|
+
>
|
|
25
26
|
<div class="col span-6">
|
|
26
27
|
<LabeledInput
|
|
27
28
|
:mode="mode"
|
|
@@ -31,11 +32,15 @@ export default {
|
|
|
31
32
|
:required="question.required"
|
|
32
33
|
:value="value"
|
|
33
34
|
:disabled="disabled"
|
|
35
|
+
:tooltip="displayTooltip"
|
|
36
|
+
:rules="rules"
|
|
37
|
+
:data-testid="`string-input-${question.variable}`"
|
|
34
38
|
@input="$emit('input', $event)"
|
|
35
39
|
/>
|
|
36
40
|
</div>
|
|
37
41
|
<div
|
|
38
42
|
v-if="showDescription"
|
|
43
|
+
:data-testid="`string-description-${question.variable}`"
|
|
39
44
|
class="col span-6 mt-10"
|
|
40
45
|
>
|
|
41
46
|
{{ displayDescription }}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import YamlEditor from '@shell/components/YamlEditor';
|
|
3
|
+
import Question from './Question';
|
|
4
|
+
import { _VIEW } from '@shell/config/query-params';
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
components: { YamlEditor },
|
|
8
|
+
mixins: [Question],
|
|
9
|
+
data() {
|
|
10
|
+
return { VIEW: _VIEW };
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<div
|
|
17
|
+
:data-testid="`yaml-row-${question.variable}`"
|
|
18
|
+
class="row"
|
|
19
|
+
>
|
|
20
|
+
<div class="col span-6">
|
|
21
|
+
<h3>
|
|
22
|
+
{{ displayLabel }}
|
|
23
|
+
<i
|
|
24
|
+
v-if="displayTooltip"
|
|
25
|
+
v-clean-tooltip="displayTooltip"
|
|
26
|
+
class="icon icon-info icon-lg"
|
|
27
|
+
/>
|
|
28
|
+
</h3>
|
|
29
|
+
<YamlEditor
|
|
30
|
+
class="yaml-editor mb-6"
|
|
31
|
+
:editor-mode="mode === VIEW ? 'VIEW_CODE' : 'EDIT_CODE'"
|
|
32
|
+
:disabled="disabled"
|
|
33
|
+
:value="value"
|
|
34
|
+
:data-testid="`yaml-input-${question.variable}`"
|
|
35
|
+
@input="$emit('input', $event)"
|
|
36
|
+
/>
|
|
37
|
+
</div>
|
|
38
|
+
<div
|
|
39
|
+
v-if="showDescription"
|
|
40
|
+
:data-testid="`yaml-description-${question.variable}`"
|
|
41
|
+
class="col span-6 mt-10"
|
|
42
|
+
>
|
|
43
|
+
{{ displayDescription }}
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</template>
|