dashboard-shell-shell 3.0.5-test.16 → 3.0.5-test.18
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/zh-hans.yaml +2 -1
- package/components/Drawer/ResourceDetailDrawer/index.vue +3 -3
- package/components/GlobalRoleBindings.vue +48 -55
- package/components/Resource/Detail/TitleBar/composables.ts +16 -1
- package/components/Resource/Detail/TitleBar/index.vue +1 -1
- package/components/breadcrumb/index.vue +9 -202
- package/components/form/ArrayList.vue +2 -2
- package/components/form/ChangePassword.vue +1 -1
- package/components/form/KeyValue.vue +6 -6
- package/components/form/Members/ClusterMembershipEditor.vue +1 -1
- package/components/form/Members/ClusterPermissionsEditor.vue +5 -5
- package/components/form/Members/MembershipEditor.vue +2 -2
- package/components/form/ResourceQuota/Namespace.vue +4 -4
- package/components/form/ResourceQuota/NamespaceRow.vue +11 -9
- package/components/form/ResourceQuota/Project.vue +4 -4
- package/components/form/ResourceQuota/ProjectRow.vue +36 -30
- package/components/nav/Type.vue +2 -2
- package/package.json +1 -1
- package/pages/auth/setup.vue +35 -16
- package/scripts/publish-shell.sh +1 -1
- package/utils/errorTranslate.json +94 -1
|
@@ -593,6 +593,7 @@ assignTo:
|
|
|
593
593
|
workspace: 工作空间
|
|
594
594
|
|
|
595
595
|
stateLabel:
|
|
596
|
+
Locked: 锁定
|
|
596
597
|
Bound: 已绑定
|
|
597
598
|
Running: 运行中
|
|
598
599
|
Off: 关闭
|
|
@@ -671,7 +672,7 @@ buttonLabel:
|
|
|
671
672
|
Errors:
|
|
672
673
|
changePassword:
|
|
673
674
|
Password must be at least 12 characters: 密码至少为12个字符
|
|
674
|
-
invalid current password: 当前的密码输入错误
|
|
675
|
+
"invalid current password": 当前的密码输入错误
|
|
675
676
|
|
|
676
677
|
|
|
677
678
|
asyncButton:
|
|
@@ -3,7 +3,7 @@ import Drawer from '@shell/components/Drawer/Chrome.vue';
|
|
|
3
3
|
import { useI18n } from '@shell/composables/useI18n';
|
|
4
4
|
import { useStore } from 'vuex';
|
|
5
5
|
import Tabbed from '@shell/components/Tabbed/index.vue';
|
|
6
|
-
import YamlTab, { Props as YamlProps } from '@shell/components/Drawer/ResourceDetailDrawer/YamlTab.vue';
|
|
6
|
+
// import YamlTab, { Props as YamlProps } from '@shell/components/Drawer/ResourceDetailDrawer/YamlTab.vue';
|
|
7
7
|
import { useDefaultConfigTabProps, useDefaultYamlTabProps } from '@shell/components/Drawer/ResourceDetailDrawer/composables';
|
|
8
8
|
import ConfigTab from '@shell/components/Drawer/ResourceDetailDrawer/ConfigTab.vue';
|
|
9
9
|
import { computed, ref } from 'vue';
|
|
@@ -87,10 +87,10 @@ const canEdit = computed(() => {
|
|
|
87
87
|
v-if="configTabProps"
|
|
88
88
|
v-bind="configTabProps"
|
|
89
89
|
/>
|
|
90
|
-
<YamlTab
|
|
90
|
+
<!-- <YamlTab
|
|
91
91
|
v-if="yamlTabProps"
|
|
92
92
|
v-bind="yamlTabProps"
|
|
93
|
-
/>
|
|
93
|
+
/> -->
|
|
94
94
|
</Tabbed>
|
|
95
95
|
</template>
|
|
96
96
|
<template #additional-actions>
|
|
@@ -108,12 +108,7 @@ export default {
|
|
|
108
108
|
} catch (e) { }
|
|
109
109
|
},
|
|
110
110
|
data() {
|
|
111
|
-
|
|
112
|
-
const topLevelPermissions = sessionStorage.getItem('TOPLEVELPERMISSIONS') || ''
|
|
113
|
-
|
|
114
111
|
return {
|
|
115
|
-
topLevelPermissions,
|
|
116
|
-
|
|
117
112
|
// This not only identifies global roles but the order here is the order we want to display them in the UI
|
|
118
113
|
globalPermissions: [
|
|
119
114
|
'admin',
|
|
@@ -333,62 +328,60 @@ export default {
|
|
|
333
328
|
|
|
334
329
|
<div v-else>
|
|
335
330
|
<form v-if="selectedRoles">
|
|
336
|
-
<
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
331
|
+
<div
|
|
332
|
+
v-for="(sortedRole, roleType) in sortedRoles"
|
|
333
|
+
:key="roleType"
|
|
334
|
+
class="role-group mb-10"
|
|
335
|
+
>
|
|
336
|
+
<Card
|
|
337
|
+
v-if="Object.keys(sortedRole).length"
|
|
338
|
+
:show-highlight-border="false"
|
|
339
|
+
:show-actions="false"
|
|
341
340
|
>
|
|
342
|
-
<
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
<template v-slot:title>
|
|
348
|
-
<div class="type-title">
|
|
349
|
-
<h3>{{ t(`rbac.globalRoles.types.${roleType}.label`) }}</h3>
|
|
350
|
-
<div class="type-description">
|
|
351
|
-
{{ t(`rbac.globalRoles.types.${roleType}.description`, { isUser }) }}
|
|
352
|
-
</div>
|
|
341
|
+
<template v-slot:title>
|
|
342
|
+
<div class="type-title">
|
|
343
|
+
<h3>{{ t(`rbac.globalRoles.types.${roleType}.label`) }}</h3>
|
|
344
|
+
<div class="type-description">
|
|
345
|
+
{{ t(`rbac.globalRoles.types.${roleType}.description`, { isUser }) }}
|
|
353
346
|
</div>
|
|
354
|
-
</
|
|
355
|
-
|
|
347
|
+
</div>
|
|
348
|
+
</template>
|
|
349
|
+
<template v-slot:body>
|
|
350
|
+
<div
|
|
351
|
+
class="checkbox-section"
|
|
352
|
+
:class="'checkbox-section--' + roleType"
|
|
353
|
+
>
|
|
356
354
|
<div
|
|
357
|
-
|
|
358
|
-
:
|
|
355
|
+
v-for="(role, i) in sortedRoles[roleType]"
|
|
356
|
+
:key="i"
|
|
357
|
+
class="checkbox mb-10 mr-10"
|
|
359
358
|
>
|
|
360
|
-
<
|
|
361
|
-
v-
|
|
362
|
-
:
|
|
363
|
-
|
|
359
|
+
<Checkbox
|
|
360
|
+
v-model:value="selectedRoles"
|
|
361
|
+
:value-when-true="role.id"
|
|
362
|
+
:disabled="!!assignOnlyRoles[role.id]"
|
|
363
|
+
:label="role.nameDisplay"
|
|
364
|
+
:description="role.descriptionDisplay"
|
|
365
|
+
:mode="mode"
|
|
366
|
+
:data-testId="'grb-checkbox-' + role.id"
|
|
367
|
+
@update:value="checkboxChanged"
|
|
364
368
|
>
|
|
365
|
-
<
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
>
|
|
375
|
-
|
|
376
|
-
<div class="checkbox-label-slot">
|
|
377
|
-
<span class="checkbox-label">{{ role.nameDisplay }}</span>
|
|
378
|
-
<i
|
|
379
|
-
v-if="!!assignOnlyRoles[role.id]"
|
|
380
|
-
v-clean-tooltip="t('rbac.globalRoles.assignOnlyRole')"
|
|
381
|
-
class="checkbox-info icon icon-info icon-lg"
|
|
382
|
-
/>
|
|
383
|
-
</div>
|
|
384
|
-
</template>
|
|
385
|
-
</Checkbox>
|
|
386
|
-
</div>
|
|
369
|
+
<template #label>
|
|
370
|
+
<div class="checkbox-label-slot">
|
|
371
|
+
<span class="checkbox-label">{{ role.nameDisplay }}</span>
|
|
372
|
+
<i
|
|
373
|
+
v-if="!!assignOnlyRoles[role.id]"
|
|
374
|
+
v-clean-tooltip="t('rbac.globalRoles.assignOnlyRole')"
|
|
375
|
+
class="checkbox-info icon icon-info icon-lg"
|
|
376
|
+
/>
|
|
377
|
+
</div>
|
|
378
|
+
</template>
|
|
379
|
+
</Checkbox>
|
|
387
380
|
</div>
|
|
388
|
-
</
|
|
389
|
-
</
|
|
390
|
-
</
|
|
391
|
-
</
|
|
381
|
+
</div>
|
|
382
|
+
</template>
|
|
383
|
+
</Card>
|
|
384
|
+
</div>
|
|
392
385
|
</form>
|
|
393
386
|
</div>
|
|
394
387
|
</template>
|
|
@@ -14,7 +14,22 @@ export const useDefaultTitleBarProps = (resource: any, resourceSubtype?: Ref<str
|
|
|
14
14
|
const resourceSubtypeValue = toValue(resourceSubtype);
|
|
15
15
|
const currentStore = store.getters['currentStore'](resourceValue.type);
|
|
16
16
|
const schema = store.getters[`${ currentStore }/schemaFor`](resourceValue.type);
|
|
17
|
-
|
|
17
|
+
let resourceTypeLabel = resourceValue.parentNameOverride || store.getters['type-map/labelFor'](schema);
|
|
18
|
+
|
|
19
|
+
// 转换为中文
|
|
20
|
+
const displayName_zh_hans: Record<string, string> = {
|
|
21
|
+
'GlobalRole': '全局角色',
|
|
22
|
+
'RoleTemplate': '集群角色',
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (displayName_zh_hans[resourceTypeLabel]) {
|
|
26
|
+
resourceTypeLabel = displayName_zh_hans[resourceTypeLabel]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (resourceTypeLabel == '集群角色' && (route.query?.roleContext == 'NAMESPACE' || resource?.parentLocationOverride?.hash == '#NAMESPACE')) {
|
|
30
|
+
resourceTypeLabel = '项目或资源组角色'
|
|
31
|
+
}
|
|
32
|
+
|
|
18
33
|
const resourceName = resourceSubtypeValue ? `${ resourceSubtypeValue } - ${ resourceValue.nameDisplay }` : resourceValue.nameDisplay;
|
|
19
34
|
const resourceTo = resourceValue.listLocation || {
|
|
20
35
|
name: 'c-cluster-product-resource',
|
|
@@ -1,54 +1,18 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import { Banner } from '@components/Banner';
|
|
3
2
|
import { get } from '@shell/utils/object';;
|
|
4
|
-
import {
|
|
5
|
-
AS, _DETAIL, _CONFIG, _YAML, MODE, _CREATE, _EDIT, _VIEW, _UNFLAG, _GRAPH
|
|
6
|
-
} from '@shell/config/query-params';
|
|
7
|
-
import { ExtensionPoint, PanelLocation } from '@shell/core/types';
|
|
8
3
|
import { useRuntimeFlag } from '@shell/composables/useRuntimeFlag';
|
|
9
4
|
import { useStore } from 'vuex';
|
|
10
5
|
|
|
11
|
-
// i18n-uses resourceDetail.header.*
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Resource Detail Masthead component.
|
|
15
|
-
*
|
|
16
|
-
* ToDo: this component seem to be picking up a lot of logic from special cases, could be simplified down to parameters and then customized per use-case via wrapper component
|
|
17
|
-
*/
|
|
18
6
|
export default {
|
|
19
7
|
|
|
20
|
-
name: '
|
|
8
|
+
name: 'MastheadBreadcrumb',
|
|
21
9
|
|
|
22
10
|
components: {
|
|
23
|
-
// BadgeState,
|
|
24
|
-
Banner,
|
|
25
11
|
},
|
|
26
12
|
props: {
|
|
27
|
-
|
|
28
|
-
type: Object,
|
|
29
|
-
default: () => {
|
|
30
|
-
return {};
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
|
|
34
|
-
mode: {
|
|
35
|
-
type: String,
|
|
36
|
-
default: 'view'
|
|
37
|
-
},
|
|
38
|
-
|
|
39
|
-
realMode: {
|
|
40
|
-
type: String,
|
|
41
|
-
default: 'view'
|
|
42
|
-
},
|
|
43
|
-
|
|
44
|
-
as: {
|
|
13
|
+
resourceTypeLabel: {
|
|
45
14
|
type: String,
|
|
46
|
-
default:
|
|
47
|
-
},
|
|
48
|
-
|
|
49
|
-
storeOverride: {
|
|
50
|
-
type: String,
|
|
51
|
-
default: null,
|
|
15
|
+
default: ''
|
|
52
16
|
},
|
|
53
17
|
|
|
54
18
|
resource: {
|
|
@@ -56,15 +20,10 @@ export default {
|
|
|
56
20
|
default: null,
|
|
57
21
|
},
|
|
58
22
|
|
|
59
|
-
|
|
60
|
-
type: String,
|
|
61
|
-
default: null,
|
|
62
|
-
},
|
|
63
|
-
|
|
64
|
-
parentRouteOverride: {
|
|
23
|
+
realMode: {
|
|
65
24
|
type: String,
|
|
66
|
-
default:
|
|
67
|
-
}
|
|
25
|
+
default: 'view',
|
|
26
|
+
}
|
|
68
27
|
|
|
69
28
|
},
|
|
70
29
|
|
|
@@ -77,82 +36,10 @@ export default {
|
|
|
77
36
|
|
|
78
37
|
data() {
|
|
79
38
|
return {
|
|
80
|
-
DETAIL_VIEW: _DETAIL,
|
|
81
|
-
extensionType: ExtensionPoint.PANEL,
|
|
82
|
-
extensionLocation: PanelLocation.DETAILS_MASTHEAD,
|
|
83
|
-
Svg: require('~shell/assets/images/API.svg')
|
|
84
39
|
};
|
|
85
40
|
},
|
|
86
41
|
|
|
87
42
|
computed: {
|
|
88
|
-
dev() {
|
|
89
|
-
return this.$store.getters['prefs/dev'];
|
|
90
|
-
},
|
|
91
|
-
|
|
92
|
-
schema() {
|
|
93
|
-
const inStore = this.storeOverride || this.$store.getters['currentStore'](this.resource);
|
|
94
|
-
|
|
95
|
-
return this.$store.getters[`${ inStore }/schemaFor`]( this.resource );
|
|
96
|
-
},
|
|
97
|
-
|
|
98
|
-
isProjectHelmChart() {
|
|
99
|
-
return this.schema?.id === HELM.PROJECTHELMCHART;
|
|
100
|
-
},
|
|
101
|
-
|
|
102
|
-
shouldHifenize() {
|
|
103
|
-
return (this.mode === 'view' || this.mode === 'edit') && this.resourceSubtype?.length && this.value?.nameDisplay?.length;
|
|
104
|
-
},
|
|
105
|
-
|
|
106
|
-
parent() {
|
|
107
|
-
const displayName = this.value?.parentNameOverride || this.$store.getters['type-map/labelFor'](this.schema);
|
|
108
|
-
const product = this.$store.getters['currentProduct'].name;
|
|
109
|
-
|
|
110
|
-
const defaultLocation = {
|
|
111
|
-
name: 'c-cluster-product-resource',
|
|
112
|
-
params: {
|
|
113
|
-
resource: this.resource,
|
|
114
|
-
product,
|
|
115
|
-
}
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
const location = this.value?.parentLocationOverride || defaultLocation;
|
|
119
|
-
|
|
120
|
-
if (this.parentRouteOverride) {
|
|
121
|
-
location.name = this.parentRouteOverride;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const typeOptions = this.$store.getters[`type-map/optionsFor`]( this.resource );
|
|
125
|
-
|
|
126
|
-
// 转换为中文
|
|
127
|
-
const displayName_zh_hans = {
|
|
128
|
-
'GlobalRole': '全局角色',
|
|
129
|
-
'RoleTemplate': '集群角色',
|
|
130
|
-
}
|
|
131
|
-
if (displayName_zh_hans[displayName]) {
|
|
132
|
-
displayName = displayName_zh_hans[displayName]
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (displayName == '集群角色' && (this.$route.query?.roleContext == 'NAMESPACE' || location.hash == '#NAMESPACE')) {
|
|
136
|
-
displayName = '项目或资源组角色'
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const out = {
|
|
140
|
-
displayName, location, ...typeOptions
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
return out;
|
|
144
|
-
},
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
displayName() {
|
|
148
|
-
let displayName = this.value.nameDisplay;
|
|
149
|
-
|
|
150
|
-
if (this.isProjectHelmChart) {
|
|
151
|
-
displayName = this.value.projectDisplayName;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return this.shouldHifenize ? ` - ${ displayName }` : displayName;
|
|
155
|
-
},
|
|
156
43
|
|
|
157
44
|
demoDisplay() {
|
|
158
45
|
|
|
@@ -177,12 +64,6 @@ export default {
|
|
|
177
64
|
return partsEn;
|
|
178
65
|
},
|
|
179
66
|
|
|
180
|
-
location() {
|
|
181
|
-
const { parent } = this;
|
|
182
|
-
|
|
183
|
-
return parent?.location;
|
|
184
|
-
},
|
|
185
|
-
|
|
186
67
|
},
|
|
187
68
|
|
|
188
69
|
methods: {
|
|
@@ -206,7 +87,7 @@ export default {
|
|
|
206
87
|
<span>/</span>
|
|
207
88
|
</span>
|
|
208
89
|
<span class="excram-last-name">
|
|
209
|
-
{{ (realMode === 'view'? '查看': realMode === 'edit' ? '编辑':'创建') +
|
|
90
|
+
{{ (realMode === 'view'? '查看': realMode === 'edit' ? '编辑':'创建') + resourceTypeLabel }}
|
|
210
91
|
</span>
|
|
211
92
|
</div>
|
|
212
93
|
</div>
|
|
@@ -215,71 +96,6 @@ export default {
|
|
|
215
96
|
|
|
216
97
|
<style lang='scss' scoped>
|
|
217
98
|
|
|
218
|
-
HEADER {
|
|
219
|
-
margin: 0;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
.primaryheader {
|
|
223
|
-
display: flex;
|
|
224
|
-
flex-direction: row;
|
|
225
|
-
align-items: center;
|
|
226
|
-
font-size:14px;
|
|
227
|
-
height: 50px;
|
|
228
|
-
|
|
229
|
-
h1 {
|
|
230
|
-
margin: 0;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
.subheader{
|
|
235
|
-
display: flex;
|
|
236
|
-
flex-direction: row;
|
|
237
|
-
color: var(--input-label);
|
|
238
|
-
& > * {
|
|
239
|
-
margin: 5px 20px 5px 0px;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
.live-data {
|
|
243
|
-
color: var(--body-text)
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
.state-banner {
|
|
248
|
-
margin: 3px 0 0 0;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
.masthead-state {
|
|
252
|
-
font-size: initial;
|
|
253
|
-
display: inline-block;
|
|
254
|
-
position: relative;
|
|
255
|
-
/* top: -2px; */
|
|
256
|
-
font-size: 12px;
|
|
257
|
-
margin-left: 5px;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
.masthead-istio {
|
|
261
|
-
.icon {
|
|
262
|
-
vertical-align: middle;
|
|
263
|
-
color: var(--primary);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
.left-right-split {
|
|
268
|
-
display: grid;
|
|
269
|
-
align-items: center;
|
|
270
|
-
|
|
271
|
-
.left-half {
|
|
272
|
-
grid-column: 1;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
.right-half {
|
|
276
|
-
grid-column: 2;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
.resource-external {
|
|
281
|
-
font-size: 18px;
|
|
282
|
-
}
|
|
283
99
|
.excram-list{
|
|
284
100
|
font-size: 14px;
|
|
285
101
|
margin-bottom: 20px;
|
|
@@ -287,10 +103,7 @@ export default {
|
|
|
287
103
|
.excram-last-name{
|
|
288
104
|
color: var(--link);
|
|
289
105
|
}
|
|
290
|
-
|
|
291
|
-
color: #d7d7d7;
|
|
292
|
-
margin: 0px 10px;
|
|
293
|
-
}
|
|
106
|
+
|
|
294
107
|
.detailIcon-span{
|
|
295
108
|
width: 24px;
|
|
296
109
|
height: 24px;
|
|
@@ -306,11 +119,5 @@ export default {
|
|
|
306
119
|
left: 4px;
|
|
307
120
|
top: -2px;
|
|
308
121
|
}
|
|
309
|
-
|
|
310
|
-
display: flex;
|
|
311
|
-
align-items: center;
|
|
312
|
-
}
|
|
313
|
-
.detailIcon-span-title{
|
|
314
|
-
font-weight: bold;
|
|
315
|
-
}
|
|
122
|
+
|
|
316
123
|
</style>
|
|
@@ -265,7 +265,7 @@ export default {
|
|
|
265
265
|
>
|
|
266
266
|
|
|
267
267
|
<div class="row">
|
|
268
|
-
<div class="col">
|
|
268
|
+
<div style="width: 100%;" class="col">
|
|
269
269
|
<div
|
|
270
270
|
v-if="title"
|
|
271
271
|
class="clearfix"
|
|
@@ -289,7 +289,7 @@ export default {
|
|
|
289
289
|
</slot>
|
|
290
290
|
</div>
|
|
291
291
|
</div>
|
|
292
|
-
<div class="col">
|
|
292
|
+
<div style="width: 100%;" class="col">
|
|
293
293
|
<div>
|
|
294
294
|
<template v-if="rows.length">
|
|
295
295
|
<div
|
|
@@ -392,10 +392,10 @@ export default {
|
|
|
392
392
|
|
|
393
393
|
rows = rows.map((item) => {
|
|
394
394
|
if (item.key.includes('harvester')) {
|
|
395
|
-
item.key = item.key
|
|
395
|
+
item.key = item.key?.replace('harvester', 'cloud');
|
|
396
396
|
}
|
|
397
397
|
if (item.value.includes('harvester')) {
|
|
398
|
-
item.value = item.value
|
|
398
|
+
item.value = item.value?.replace('harvester', 'cloud');
|
|
399
399
|
}
|
|
400
400
|
|
|
401
401
|
return item;
|
|
@@ -411,8 +411,8 @@ export default {
|
|
|
411
411
|
[this.valueName]: value,
|
|
412
412
|
};
|
|
413
413
|
|
|
414
|
-
obj.key = obj.key
|
|
415
|
-
obj.value = obj.value
|
|
414
|
+
obj.key = obj.key?.replace('harvester', 'cloud');
|
|
415
|
+
obj.value = obj.value?.replace('harvester', 'cloud');
|
|
416
416
|
obj.binary = false;
|
|
417
417
|
obj.canEncode = this.handleBase64;
|
|
418
418
|
obj.supported = true;
|
|
@@ -494,8 +494,8 @@ export default {
|
|
|
494
494
|
// let value = (row[valueName] || '');
|
|
495
495
|
// const key = (row[keyName] || '').trim();
|
|
496
496
|
|
|
497
|
-
const key = (row[keyName]
|
|
498
|
-
let value = (row[valueName]
|
|
497
|
+
const key = (row[keyName]?.replace('cloud', 'harvester') || '').trim();
|
|
498
|
+
let value = (row[valueName]?.replace('cloud', 'harvester') || '').trim();
|
|
499
499
|
|
|
500
500
|
if (value && typeOf(value) === 'object') {
|
|
501
501
|
out[key] = JSON.parse(JSON.stringify(value));
|
|
@@ -161,11 +161,11 @@ export default {
|
|
|
161
161
|
value: 'member'
|
|
162
162
|
},
|
|
163
163
|
...customRoles,
|
|
164
|
-
{
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
164
|
+
// {
|
|
165
|
+
// label: this.t('members.clusterPermissions.custom.label'),
|
|
166
|
+
// description: this.t('members.clusterPermissions.custom.description'),
|
|
167
|
+
// value: 'custom'
|
|
168
|
+
// }
|
|
169
169
|
];
|
|
170
170
|
},
|
|
171
171
|
principal() {
|
|
@@ -170,7 +170,7 @@ export default {
|
|
|
170
170
|
>
|
|
171
171
|
<template #column-headers>
|
|
172
172
|
<div class="box mb-0">
|
|
173
|
-
<div class="column-headers row" style="width:
|
|
173
|
+
<div class="column-headers row" style="width: calc(100% - 100px);">
|
|
174
174
|
<div class="col span-6">
|
|
175
175
|
<label class="text-label">{{ t('membershipEditor.user') }}</label>
|
|
176
176
|
</div>
|
|
@@ -181,7 +181,7 @@ export default {
|
|
|
181
181
|
</div>
|
|
182
182
|
</template>
|
|
183
183
|
<template #columns="{row, i}">
|
|
184
|
-
<div class="columns row">
|
|
184
|
+
<div style="width: 100%;" class="columns row">
|
|
185
185
|
<div class="col span-6">
|
|
186
186
|
<Principal
|
|
187
187
|
:value="row.value.principalId"
|
|
@@ -72,13 +72,13 @@ export default {
|
|
|
72
72
|
<template>
|
|
73
73
|
<div>
|
|
74
74
|
<div class="headers mb-10">
|
|
75
|
-
<div style="width:
|
|
75
|
+
<div style="width: 450px;">
|
|
76
76
|
<label>{{ t('resourceQuota.headers.resourceType') }}</label>
|
|
77
77
|
</div>
|
|
78
|
-
<div style="width:
|
|
78
|
+
<div style="width: 450px;">
|
|
79
79
|
<label>{{ t('resourceQuota.headers.projectResourceAvailability') }}</label>
|
|
80
80
|
</div>
|
|
81
|
-
<div style="width:
|
|
81
|
+
<div style="width: 450px;">
|
|
82
82
|
<label>{{ t('resourceQuota.headers.limit') }}</label>
|
|
83
83
|
</div>
|
|
84
84
|
</div>
|
|
@@ -101,7 +101,7 @@ export default {
|
|
|
101
101
|
.headers {
|
|
102
102
|
display: flex;
|
|
103
103
|
flex-direction: row;
|
|
104
|
-
justify-content:
|
|
104
|
+
justify-content: left;
|
|
105
105
|
align-items: center;
|
|
106
106
|
border-bottom: 1px solid var(--border);
|
|
107
107
|
height: 30px;
|
|
@@ -175,13 +175,15 @@ export default {
|
|
|
175
175
|
v-if="typeOption"
|
|
176
176
|
class="rowNew"
|
|
177
177
|
>
|
|
178
|
-
<
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
178
|
+
<div style="width: 450px;">
|
|
179
|
+
<Select
|
|
180
|
+
:mode="mode"
|
|
181
|
+
:value="type"
|
|
182
|
+
:disabled="true"
|
|
183
|
+
:options="types"
|
|
184
|
+
/>
|
|
185
|
+
</div>
|
|
186
|
+
<div style="width: 450px;" class="resource-availability">
|
|
185
187
|
<PercentageBar
|
|
186
188
|
v-clean-tooltip="tooltip"
|
|
187
189
|
class="percentage-bar"
|
|
@@ -190,7 +192,7 @@ export default {
|
|
|
190
192
|
:color-stops="{'100': '--primary'}"
|
|
191
193
|
/>
|
|
192
194
|
</div>
|
|
193
|
-
<div style="width:
|
|
195
|
+
<div style="width: 450px;">
|
|
194
196
|
<UnitInput
|
|
195
197
|
:value="value.limit[type]"
|
|
196
198
|
:mode="mode"
|
|
@@ -212,7 +214,7 @@ export default {
|
|
|
212
214
|
.rowNew {
|
|
213
215
|
margin-bottom: 10px;
|
|
214
216
|
display: flex;
|
|
215
|
-
justify-content:
|
|
217
|
+
justify-content: left;
|
|
216
218
|
|
|
217
219
|
& > * {
|
|
218
220
|
width: 400px;
|
|
@@ -57,14 +57,14 @@ export default {
|
|
|
57
57
|
</script>
|
|
58
58
|
<template>
|
|
59
59
|
<div>
|
|
60
|
-
<div style="justify-content:
|
|
61
|
-
<div style="width:
|
|
60
|
+
<div style="justify-content: left;" class="headers mb-10">
|
|
61
|
+
<div style="width: 450px;">
|
|
62
62
|
<label>{{ t('resourceQuota.headers.resourceType') }}</label>
|
|
63
63
|
</div>
|
|
64
|
-
<div style="width:
|
|
64
|
+
<div style="width: 450px;">
|
|
65
65
|
<label>{{ t('resourceQuota.headers.projectLimit') }}</label>
|
|
66
66
|
</div>
|
|
67
|
-
<div style="width:
|
|
67
|
+
<div style="width: 450px;">
|
|
68
68
|
<label>{{ t('resourceQuota.headers.namespaceDefaultLimit') }}</label>
|
|
69
69
|
</div>
|
|
70
70
|
</div>
|
|
@@ -72,41 +72,47 @@ export default {
|
|
|
72
72
|
v-if="typeOption"
|
|
73
73
|
class="rowNew"
|
|
74
74
|
>
|
|
75
|
-
<
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
75
|
+
<div style="width: 450px;">
|
|
76
|
+
<Select
|
|
77
|
+
:value="type"
|
|
78
|
+
:mode="mode"
|
|
79
|
+
:options="types"
|
|
80
|
+
data-testid="projectrow-type-input"
|
|
81
|
+
@update:value="updateType($event)"
|
|
82
|
+
/>
|
|
83
|
+
</div>
|
|
84
|
+
<div style="width: 450px;">
|
|
85
|
+
<UnitInput
|
|
86
|
+
:value="resourceQuotaLimit[type]"
|
|
87
|
+
:mode="mode"
|
|
88
|
+
:placeholder="typeOption.placeholder"
|
|
89
|
+
:increment="typeOption.increment"
|
|
90
|
+
:input-exponent="typeOption.inputExponent"
|
|
91
|
+
:base-unit="typeOption.baseUnit"
|
|
92
|
+
:output-modifier="true"
|
|
93
|
+
data-testid="projectrow-project-quota-input"
|
|
94
|
+
@update:value="updateQuotaLimit('resourceQuota', type, $event)"
|
|
95
|
+
/>
|
|
96
|
+
</div>
|
|
97
|
+
<div style="width: 450px;">
|
|
98
|
+
<UnitInput
|
|
99
|
+
:value="namespaceDefaultResourceQuotaLimit[type]"
|
|
100
|
+
:mode="mode"
|
|
101
|
+
:placeholder="typeOption.placeholder"
|
|
102
|
+
:increment="typeOption.increment"
|
|
103
|
+
:input-exponent="typeOption.inputExponent"
|
|
104
|
+
:base-unit="typeOption.baseUnit"
|
|
105
|
+
:output-modifier="true"
|
|
106
|
+
data-testid="projectrow-namespace-quota-input"
|
|
107
|
+
@update:value="updateQuotaLimit('namespaceDefaultResourceQuota', type, $event)"
|
|
108
|
+
/>
|
|
109
|
+
</div>
|
|
104
110
|
</div>
|
|
105
111
|
</template>
|
|
106
112
|
|
|
107
113
|
<style lang='scss' scoped>
|
|
108
114
|
.rowNew {
|
|
109
115
|
display: flex;
|
|
110
|
-
justify-content:
|
|
116
|
+
justify-content: left;
|
|
111
117
|
}
|
|
112
118
|
</style>
|
package/components/nav/Type.vue
CHANGED
|
@@ -141,7 +141,7 @@ export default {
|
|
|
141
141
|
<a
|
|
142
142
|
role="link"
|
|
143
143
|
:aria-label="type.labelKey ? t(type.labelKey) : (type.labelDisplay || type.label)"
|
|
144
|
-
:href="href"
|
|
144
|
+
:href="href.replace(/harvester/g, 'cloud')"
|
|
145
145
|
class="type-link"
|
|
146
146
|
:aria-current="isActive ? 'page' : undefined"
|
|
147
147
|
@click="selectType(); navigate($event);"
|
|
@@ -199,7 +199,7 @@ export default {
|
|
|
199
199
|
>
|
|
200
200
|
<a
|
|
201
201
|
role="link"
|
|
202
|
-
:href="type.link"
|
|
202
|
+
:href="type.link.replace(/harvester/g, 'cloud')"
|
|
203
203
|
:target="type.target"
|
|
204
204
|
rel="noopener noreferrer nofollow"
|
|
205
205
|
:aria-label="type.label"
|
package/package.json
CHANGED
package/pages/auth/setup.vue
CHANGED
|
@@ -21,6 +21,7 @@ import FormValidation from '@shell/mixins/form-validation';
|
|
|
21
21
|
import isUrl from 'is-url';
|
|
22
22
|
import { isLocalhost } from '@shell/utils/validators/setting';
|
|
23
23
|
import Loading from '@shell/components/Loading';
|
|
24
|
+
import { copyTextToClipboard } from '@shell/utils/clipboard';
|
|
24
25
|
|
|
25
26
|
const calcIsFirstLogin = (store) => {
|
|
26
27
|
const firstLoginSetting = store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.FIRST_LOGIN);
|
|
@@ -259,6 +260,14 @@ export default {
|
|
|
259
260
|
this.$router.replace('/');
|
|
260
261
|
},
|
|
261
262
|
|
|
263
|
+
copyPassword(val) {
|
|
264
|
+
copyTextToClipboard(val).then(() => {
|
|
265
|
+
console.log('复制成功')
|
|
266
|
+
}).catch(() => {
|
|
267
|
+
console.log('复制失败')
|
|
268
|
+
});
|
|
269
|
+
},
|
|
270
|
+
|
|
262
271
|
onServerUrlChange(value) {
|
|
263
272
|
this.serverUrl = value.trim();
|
|
264
273
|
},
|
|
@@ -324,13 +333,14 @@ export default {
|
|
|
324
333
|
>
|
|
325
334
|
<div class="mb-20">
|
|
326
335
|
<RadioGroup
|
|
336
|
+
class="setupRadioGroupCls"
|
|
327
337
|
v-model:value="useRandom"
|
|
328
338
|
data-testid="setup-password-mode"
|
|
329
339
|
name="password-mode"
|
|
330
340
|
:options="passwordOptions"
|
|
331
341
|
/>
|
|
332
342
|
</div>
|
|
333
|
-
<div class="mb-20">
|
|
343
|
+
<div class="setup_radom-password mb-20">
|
|
334
344
|
<LabeledInput
|
|
335
345
|
v-if="useRandom"
|
|
336
346
|
ref="password"
|
|
@@ -347,13 +357,9 @@ export default {
|
|
|
347
357
|
>
|
|
348
358
|
<div
|
|
349
359
|
class="addon"
|
|
350
|
-
style="padding:
|
|
360
|
+
style="padding: 4px 0px 0px;"
|
|
351
361
|
>
|
|
352
|
-
<
|
|
353
|
-
:aria-label="t('setup.copyRandom')"
|
|
354
|
-
:text="password"
|
|
355
|
-
class="btn-sm"
|
|
356
|
-
/>
|
|
362
|
+
<a @click="copyPassword(password)" href="javascript:;">复制</a>
|
|
357
363
|
</div>
|
|
358
364
|
</template>
|
|
359
365
|
</LabeledInput>
|
|
@@ -367,15 +373,17 @@ export default {
|
|
|
367
373
|
:required="true"
|
|
368
374
|
/>
|
|
369
375
|
</div>
|
|
370
|
-
<
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
376
|
+
<div class="setup_radom-password">
|
|
377
|
+
<Password
|
|
378
|
+
v-show="!useRandom"
|
|
379
|
+
v-model:value.trim="confirm"
|
|
380
|
+
autocomplete="new-password"
|
|
381
|
+
data-testid="setup-password-confirm"
|
|
382
|
+
class="setup-password"
|
|
383
|
+
:label="t('setup.confirmPassword')"
|
|
384
|
+
:required="true"
|
|
385
|
+
/>
|
|
386
|
+
</div>
|
|
379
387
|
</template>
|
|
380
388
|
|
|
381
389
|
<template v-if="isFirstLogin">
|
|
@@ -467,6 +475,16 @@ export default {
|
|
|
467
475
|
</template>
|
|
468
476
|
|
|
469
477
|
<style lang="scss" scoped>
|
|
478
|
+
.setup_radom-password {
|
|
479
|
+
:deep(.label-input-all) LABEL {
|
|
480
|
+
color: #fff;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
.setupRadioGroupCls {
|
|
484
|
+
:deep(.radio-label) {
|
|
485
|
+
color: #fff;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
470
488
|
.principal {
|
|
471
489
|
display: block;
|
|
472
490
|
background: var(--box-bg);
|
|
@@ -538,6 +556,7 @@ export default {
|
|
|
538
556
|
}
|
|
539
557
|
|
|
540
558
|
.setup-title {
|
|
559
|
+
color: #fff;
|
|
541
560
|
:deep() code {
|
|
542
561
|
font-size: 12px;
|
|
543
562
|
padding: 0;
|
package/scripts/publish-shell.sh
CHANGED
|
@@ -1,5 +1,98 @@
|
|
|
1
1
|
{
|
|
2
2
|
"translations": [
|
|
3
|
+
{
|
|
4
|
+
"pattern": "role is locked and cannot be assigned",
|
|
5
|
+
"replacement": "角色已被锁定,不能再分配"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"pattern": "invalid current password",
|
|
9
|
+
"replacement": "重复密码无效"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"pattern": "spec\\.template\\.spec\\.podaffinity\\.requiredduringschedulingignoredduringexecution\\[(\\d+)\\]\\.topologykey: required value: can not be empty[\\s\\S]*?regex used for validation is '([^']+)'",
|
|
13
|
+
"replacement": "拓扑键不能为空",
|
|
14
|
+
"flags": "gi"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"pattern": "pcidevice ([^\\s]+) has no iommugroup available",
|
|
18
|
+
"replacement": "PCI 设备 '$1' 没有可用的 IOMMU 组",
|
|
19
|
+
"flags": "gi"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"pattern": "invalidbodycontent 422: failed to parse totalsnapshotsizequota: quantities must match the regular expression '\\^\\(\\[\\+\\-\\]\\?\\[0-9\\.\\]\\+\\)\\(\\[eeinumkkmgtp\\]\\*\\[\\-\\+\\]\\?\\[0-9\\]\\*\\)\\$'",
|
|
23
|
+
"replacement": "快照配额不能为空",
|
|
24
|
+
"flags": "gi"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"pattern": "secrets \"([^\"]+)\" already exists",
|
|
28
|
+
"replacement": "密钥 \"$1\" 已存在",
|
|
29
|
+
"flags": "gi"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"pattern": "backup target is invalid",
|
|
33
|
+
"replacement": "备份目标无效",
|
|
34
|
+
"flags": "gi"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"pattern": "failed to list objects with param:[\\s\\S]*?server gave http response to https client",
|
|
38
|
+
"replacement": "列举对象失败:服务器返回 HTTP 响应,但客户端使用 HTTPS,请检查协议配置",
|
|
39
|
+
"flags": "gi"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"pattern": "clusternetwork\\.network\\.harvesterhci\\.io \"([^\"]+)\" is invalid: metadata\\.name: invalid value: \"([^\"]*)\": a lowercase rfc 1123 subdomain must consist of lower case alphanumeric characters, '-' or '\\.', and must start and end with an alphanumeric character",
|
|
43
|
+
"replacement": "集群网络名称 '$1' 无效:须符合 RFC 1123 子域名规则,只能使用小写字母、数字、'-' 或 '.',且以字母或数字开头和结尾",
|
|
44
|
+
"flags": "gi"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"pattern": "loadbalancer\\.loadbalancer\\.harvesterhci\\.io \"([^\"]+)\" is invalid: \\[spec\\.listeners\\[(\\d+)\\]\\.(backendport|port): required value[^\\]]*\\]",
|
|
48
|
+
"replacement": "负载均衡器 '$1' 配置无效:第 $2 个监听器的 $3 为必填项",
|
|
49
|
+
"flags": "gi"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"pattern": "can't delete cluster network (\\S+) because vlanconfig\\(s\\) \\[(.*?)\\] under this clusternetwork are still existing",
|
|
53
|
+
"replacement": "无法删除集群网络 '$1',因其下仍存在 VLAN 配置 [$2]",
|
|
54
|
+
"flags": "gi"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"pattern": "value: (\\d+) must be in range \\[1 \\.\\. (\\d+)\\]",
|
|
58
|
+
"replacement": "值 $1 超出范围,必须在 1–$2 之间",
|
|
59
|
+
"flags": "gi"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"pattern": "can't delete vlanconfig (\\S+) because it is blocked by vm\\(s\\) ([^/]+)/(\\S+) which must be stopped at first",
|
|
63
|
+
"replacement": "无法删除 VLAN 配置 '$1':需先停止虚拟机 '$2/$3'",
|
|
64
|
+
"flags": "gi"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"pattern": "cannot find nfs path",
|
|
68
|
+
"replacement": "无法找到 NFS 路径",
|
|
69
|
+
"flags": "gi"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"pattern": "get \"([^\"]+)\": unsupported protocol scheme \"\"",
|
|
73
|
+
"replacement": "url 无效",
|
|
74
|
+
"flags": "gi"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"pattern": "cannot mount nfs ([^\\s]+)[\\s\\S]*?no such file or directory[\\s\\S]*?cannot mount using nfsv4",
|
|
78
|
+
"replacement": "备份存储的端点无法访问",
|
|
79
|
+
"flags": "gi"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"pattern": "can't create nad ([^/]+)/([^\\s]+) because the gateway ([^\\s]+) is invalid",
|
|
83
|
+
"replacement": "无法创建虚拟网络 '$1/$2',因为网关 '$3' 无效",
|
|
84
|
+
"flags": "gi"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"pattern": "can't create nad ([^/]+)/([^\\s]+) because the cidr ([^\\s]+) is invalid",
|
|
88
|
+
"replacement": "无法创建虚拟网络 '$1/$2',因为 CIDR '$3' 无效",
|
|
89
|
+
"flags": "gi"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"pattern": "no matching backup found for url ([^\\s]+) and backing image ([^\\s]+)",
|
|
93
|
+
"replacement": "未找到与 URL $1 和镜像 $2 匹配的备份",
|
|
94
|
+
"flags": "gi"
|
|
95
|
+
},
|
|
3
96
|
{
|
|
4
97
|
"pattern": "take virtual machine snapshot ([^\\s]+) successfully\\.",
|
|
5
98
|
"replacement": "虚拟机快照 '$1' 创建成功。",
|
|
@@ -87,7 +180,7 @@
|
|
|
87
180
|
},
|
|
88
181
|
{
|
|
89
182
|
"pattern": "validation failed in api: vpc.kubeovn.io \"([^\"]*)\" is invalid: metadata\\.name: invalid value: \"([^\"]*)\": a lowercase rfc 1123 subdomain must consist of lower case alphanumeric characters, '-' or '\\.', and must start and end with an alphanumeric character \\(e\\.g\\..*?\\)",
|
|
90
|
-
"replacement": "
|
|
183
|
+
"replacement": "校验失败:VPC 名称 \"$1\" 不符合 RFC 1123 子域名规则,只能使用小写字母、数字、'-' 或 '.',且必须以字母/数字开头和结尾",
|
|
91
184
|
"flags": "gi"
|
|
92
185
|
},
|
|
93
186
|
{
|