@rancher/shell 0.3.23 → 0.3.25
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/styles/base/_variables.scss +1 -0
- package/assets/styles/themes/_dark.scss +1 -0
- package/assets/styles/themes/_light.scss +6 -5
- package/assets/translations/en-us.yaml +44 -17
- package/assets/translations/zh-hans.yaml +2 -2
- package/components/ClusterIconMenu.vue +143 -0
- package/components/CruResource.vue +7 -1
- package/components/ExplorerProjectsNamespaces.vue +11 -1
- package/components/FixedBanner.vue +17 -1
- package/components/Loading.vue +1 -1
- package/components/Markdown.vue +1 -1
- package/components/Questions/__tests__/Yaml.test.ts +3 -2
- package/components/SideNav.vue +1 -1
- package/components/SortableTable/index.vue +3 -2
- package/components/auth/RoleDetailEdit.vue +15 -2
- package/components/auth/login/saml.vue +12 -1
- package/components/form/LabeledSelect.vue +12 -5
- package/components/form/Members/ClusterPermissionsEditor.vue +1 -1
- package/components/form/Members/MembershipEditor.vue +6 -1
- package/components/form/SelectOrCreateAuthSecret.vue +7 -0
- package/components/form/__tests__/KeyValue.test.ts +6 -3
- package/components/form/__tests__/LabeledSelect.test.ts +18 -0
- package/components/formatter/PodsUsage.vue +11 -36
- package/components/formatter/PrincipalGroupBindings.vue +8 -5
- package/components/formatter/__tests__/PodsUsage.test.ts +36 -19
- package/components/nav/Group.vue +62 -34
- package/components/nav/Header.vue +13 -6
- package/components/nav/Pinned.vue +47 -0
- package/components/nav/TopLevelMenu.vue +673 -325
- package/components/nav/Type.vue +88 -8
- package/config/home-links.js +1 -1
- package/config/product/istio.js +15 -5
- package/config/router.js +3 -9
- package/config/table-headers.js +5 -6
- package/config/uiplugins.js +1 -0
- package/core/plugin-helpers.js +3 -0
- package/core/types.ts +6 -1
- package/creators/app/files/.vscode/settings.json +0 -1
- package/creators/pkg/init +2 -2
- package/detail/__tests__/autoscaling.horizontalpodautoscaler.test.ts +118 -0
- package/detail/autoscaling.horizontalpodautoscaler/index.vue +4 -4
- package/detail/provisioning.cattle.io.cluster.vue +7 -5
- package/edit/__tests__/management.cattle.io.clusterroletemplatebinding.test.ts +58 -0
- package/edit/__tests__/namespace.test.ts +5 -3
- package/edit/fleet.cattle.io.gitrepo.vue +43 -15
- package/edit/logging.banzaicloud.io.output/index.vue +7 -0
- package/edit/management.cattle.io.clusterroletemplatebinding.vue +3 -11
- package/edit/namespace.vue +8 -4
- package/edit/provisioning.cattle.io.cluster/Basics.vue +662 -0
- package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +9 -8
- package/edit/provisioning.cattle.io.cluster/DrainOptions.vue +13 -8
- package/edit/provisioning.cattle.io.cluster/MachinePool.vue +11 -2
- package/edit/provisioning.cattle.io.cluster/MemberRoles.vue +40 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/Basics.tests.ts +237 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/CustomCommand.tests.ts +71 -23
- package/edit/provisioning.cattle.io.cluster/__tests__/DrainOptions.test.ts +52 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +65 -142
- package/edit/provisioning.cattle.io.cluster/rke2.vue +253 -582
- package/edit/workload/storage/ContainerMountPaths.vue +7 -5
- package/edit/workload/storage/__tests__/Storage.test.ts +2 -2
- package/edit/workload/storage/persistentVolumeClaim/__tests__/persistentvolumeclaim.test.ts +36 -0
- package/edit/workload/storage/persistentVolumeClaim/persistentvolumeclaim.vue +15 -7
- package/initialize/App.js +2 -0
- package/initialize/client.js +63 -51
- package/initialize/index.js +7 -5
- package/layouts/default.vue +10 -2
- package/layouts/home.vue +6 -2
- package/layouts/plain.vue +9 -2
- package/list/fleet.cattle.io.cluster.vue +2 -2
- package/list/management.cattle.io.feature.vue +1 -1
- package/machine-config/amazonec2.vue +1 -0
- package/machine-config/vmwarevsphere.vue +48 -7
- package/mixins/brand.js +0 -8
- package/mixins/child-hook.js +2 -2
- package/mixins/create-edit-view/impl.js +3 -3
- package/mixins/fetch.client.js +3 -3
- package/models/__tests__/management.cattle.io.node.ts +96 -0
- package/models/__tests__/node.ts +74 -0
- package/models/cluster/node.js +6 -5
- package/models/cluster.x-k8s.io.machinedeployment.js +2 -2
- package/models/management.cattle.io.cluster.js +22 -1
- package/models/management.cattle.io.clusterroletemplatebinding.js +3 -3
- package/models/management.cattle.io.globalrole.js +17 -2
- package/models/management.cattle.io.node.js +6 -4
- package/models/management.cattle.io.projectroletemplatebinding.js +3 -3
- package/models/management.cattle.io.roletemplate.js +17 -2
- package/package.json +2 -6
- package/pages/__tests__/prefs.test.ts +1 -1
- package/pages/about.vue +2 -0
- package/pages/auth/setup.vue +5 -4
- package/pages/c/_cluster/explorer/ConfigBadge.vue +1 -0
- package/pages/c/_cluster/monitoring/index.vue +8 -3
- package/pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue +9 -66
- package/pages/c/_cluster/uiplugins/CatalogList/CatalogUninstallDialog.vue +182 -0
- package/pages/c/_cluster/uiplugins/CatalogList/index.vue +15 -32
- package/pages/c/_cluster/uiplugins/UninstallDialog.vue +8 -46
- package/pages/c/_cluster/uiplugins/index.vue +64 -64
- package/pages/diagnostic.vue +0 -39
- package/pages/home.vue +1 -1
- package/pages/prefs.vue +3 -13
- package/plugins/dashboard-store/normalize.js +4 -4
- package/plugins/dashboard-store/resource-class.js +1 -1
- package/plugins/int-number.js +5 -2
- package/plugins/positive-int-number.js +19 -0
- package/plugins/steve/__tests__/getters.spec.ts +15 -0
- package/plugins/steve/getters.js +22 -10
- package/public/index.html +4 -2
- package/rancher-components/BadgeState/BadgeState.vue +5 -1
- package/rancher-components/Banner/Banner.test.ts +51 -1
- package/rancher-components/Banner/Banner.vue +134 -53
- package/rancher-components/Card/Card.test.ts +37 -0
- package/rancher-components/Card/Card.vue +24 -7
- package/rancher-components/Form/Checkbox/Checkbox.test.ts +20 -29
- package/rancher-components/Form/Checkbox/Checkbox.vue +45 -20
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +2 -8
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +22 -10
- package/rancher-components/Form/Radio/RadioButton.test.ts +31 -0
- package/rancher-components/Form/Radio/RadioButton.vue +30 -13
- package/rancher-components/Form/Radio/RadioGroup.vue +26 -7
- package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +7 -6
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.test.ts +25 -38
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +23 -11
- package/rancher-components/LabeledTooltip/LabeledTooltip.vue +19 -5
- package/rancher-components/StringList/StringList.test.ts +453 -49
- package/rancher-components/StringList/StringList.vue +92 -58
- package/scripts/extension/parse-tag-name +0 -0
- package/store/index.js +4 -0
- package/store/prefs.js +4 -4
- package/store/type-map.js +2 -16
- package/types/shell/index.d.ts +26 -14
- package/utils/__tests__/cluster.test.ts +55 -0
- package/utils/__tests__/object.test.ts +21 -2
- package/utils/__tests__/sort.test.ts +61 -0
- package/utils/cluster.js +47 -1
- package/utils/object.js +12 -5
- package/utils/string.js +12 -0
- package/utils/validators/formRules/__tests__/index.test.ts +13 -1
- package/utils/validators/formRules/index.ts +4 -0
- package/utils/validators/role-template.js +9 -1
- package/utils/version.js +1 -1
- package/vue.config.js +1 -4
- package/yarn-error.log +200 -0
- package/content/docs/en-us/getting-started.md +0 -224
- package/content/docs/en-us/whats-new.md +0 -29
- package/content/docs/zh-hans/getting-started.md +0 -224
- package/content/docs/zh-hans/whats-new.md +0 -28
- package/pages/docs/_doc.vue +0 -345
- package/pages/docs/toc.js +0 -27
- package/plugins/console.js +0 -34
|
@@ -30,9 +30,9 @@ const CLASS = {
|
|
|
30
30
|
* Manage a list of strings
|
|
31
31
|
*/
|
|
32
32
|
export default Vue.extend({
|
|
33
|
-
components: { LabeledInput },
|
|
34
33
|
|
|
35
|
-
name:
|
|
34
|
+
name: 'StringList',
|
|
35
|
+
components: { LabeledInput },
|
|
36
36
|
|
|
37
37
|
props: {
|
|
38
38
|
/**
|
|
@@ -85,11 +85,11 @@ export default Vue.extend({
|
|
|
85
85
|
},
|
|
86
86
|
data() {
|
|
87
87
|
return {
|
|
88
|
-
value:
|
|
89
|
-
selected:
|
|
90
|
-
|
|
91
|
-
isCreateItem:
|
|
92
|
-
errors:
|
|
88
|
+
value: null as string | null,
|
|
89
|
+
selected: null as string | null,
|
|
90
|
+
editedItem: null as string | null,
|
|
91
|
+
isCreateItem: false,
|
|
92
|
+
errors: { duplicate: false } as Record<Error, boolean>
|
|
93
93
|
};
|
|
94
94
|
},
|
|
95
95
|
|
|
@@ -100,8 +100,8 @@ export default Vue.extend({
|
|
|
100
100
|
*/
|
|
101
101
|
errorMessagesArray(): string[] {
|
|
102
102
|
return (Object.keys(this.errors) as Error[])
|
|
103
|
-
.filter(f =>
|
|
104
|
-
.map(k => this.errorMessages[k]);
|
|
103
|
+
.filter((f) => this.errors[f] && this.errorMessages[f])
|
|
104
|
+
.map((k) => this.errorMessages[k]);
|
|
105
105
|
},
|
|
106
106
|
},
|
|
107
107
|
|
|
@@ -113,23 +113,35 @@ export default Vue.extend({
|
|
|
113
113
|
this.toggleEditMode(false);
|
|
114
114
|
this.toggleCreateMode(false);
|
|
115
115
|
},
|
|
116
|
+
value(val) {
|
|
117
|
+
this.$emit('type:item', val);
|
|
118
|
+
},
|
|
119
|
+
errors: {
|
|
120
|
+
handler(val) {
|
|
121
|
+
this.$emit('errors', val);
|
|
122
|
+
},
|
|
123
|
+
deep: true
|
|
124
|
+
}
|
|
116
125
|
},
|
|
117
126
|
|
|
118
127
|
methods: {
|
|
119
128
|
onChange(value: string) {
|
|
120
129
|
this.value = value;
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
130
|
+
|
|
131
|
+
const items = [
|
|
132
|
+
...this.items,
|
|
133
|
+
this.value
|
|
134
|
+
];
|
|
135
|
+
|
|
124
136
|
this.toggleError(
|
|
125
137
|
'duplicate',
|
|
126
|
-
|
|
127
|
-
this.isCreateItem ? INPUT.create : INPUT.edit
|
|
138
|
+
hasDuplicatedStrings(items, this.caseSensitive),
|
|
139
|
+
this.isCreateItem ? INPUT.create : INPUT.edit
|
|
128
140
|
);
|
|
129
141
|
},
|
|
130
142
|
|
|
131
143
|
onSelect(item: string) {
|
|
132
|
-
if (this.isCreateItem || this.
|
|
144
|
+
if (this.readonly || this.isCreateItem || this.editedItem === item) {
|
|
133
145
|
return;
|
|
134
146
|
}
|
|
135
147
|
this.selected = item;
|
|
@@ -160,7 +172,7 @@ export default Vue.extend({
|
|
|
160
172
|
},
|
|
161
173
|
|
|
162
174
|
onClickEmptyBody() {
|
|
163
|
-
if (!this.isCreateItem && !this.
|
|
175
|
+
if (!this.isCreateItem && !this.editedItem) {
|
|
164
176
|
this.toggleCreateMode(true);
|
|
165
177
|
}
|
|
166
178
|
},
|
|
@@ -176,38 +188,43 @@ export default Vue.extend({
|
|
|
176
188
|
|
|
177
189
|
return;
|
|
178
190
|
}
|
|
179
|
-
if (this.
|
|
191
|
+
if (this.editedItem) {
|
|
192
|
+
this.deleteAndSelectNext(this.editedItem);
|
|
180
193
|
this.toggleEditMode(false);
|
|
181
194
|
|
|
182
195
|
return;
|
|
183
196
|
}
|
|
184
197
|
if (this.selected) {
|
|
185
|
-
|
|
198
|
+
this.deleteAndSelectNext(this.selected);
|
|
199
|
+
}
|
|
200
|
+
},
|
|
186
201
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
202
|
+
deleteAndSelectNext(currItem: string) {
|
|
203
|
+
const index = findStringIndex(this.items, currItem, false);
|
|
204
|
+
|
|
205
|
+
if (index !== -1) {
|
|
206
|
+
/**
|
|
207
|
+
* Select the next item in the list.
|
|
208
|
+
*/
|
|
209
|
+
const item = (this.items[index + 1] || this.items[index - 1]);
|
|
192
210
|
|
|
193
|
-
|
|
194
|
-
|
|
211
|
+
this.onSelect(item);
|
|
212
|
+
this.setFocus(item);
|
|
195
213
|
|
|
196
|
-
|
|
197
|
-
}
|
|
214
|
+
this.deleteItem(this.items[index]);
|
|
198
215
|
}
|
|
199
216
|
},
|
|
200
217
|
|
|
201
218
|
setFocus(refId: string) {
|
|
202
|
-
this.$nextTick(() => this.getElemByRef(refId)?.focus());
|
|
219
|
+
this.$nextTick(() => (this.getElemByRef(refId) as Vue & HTMLElement)?.focus());
|
|
203
220
|
},
|
|
204
221
|
|
|
205
222
|
/**
|
|
206
223
|
* Move scrollbar when the selected item is over the top or bottom side of the box
|
|
207
224
|
*/
|
|
208
225
|
moveScrollbar(arrow: Arrow, value?: number) {
|
|
209
|
-
const box = this.getElemByRef(BOX);
|
|
210
|
-
const item = this.getElemByRef(this.selected || '');
|
|
226
|
+
const box = this.getElemByRef(BOX) as HTMLElement;
|
|
227
|
+
const item = this.getElemByRef(this.selected || '') as HTMLElement;
|
|
211
228
|
|
|
212
229
|
if (box && item && item.className.includes(CLASS.item)) {
|
|
213
230
|
const boxRect = box.getClientRects()[0];
|
|
@@ -229,13 +246,14 @@ export default Vue.extend({
|
|
|
229
246
|
*/
|
|
230
247
|
toggleError(type: Error, val: boolean, refId?: string) {
|
|
231
248
|
this.errors[type] = val;
|
|
249
|
+
|
|
232
250
|
if (refId) {
|
|
233
251
|
this.toggleErrorClass(refId, val);
|
|
234
252
|
}
|
|
235
253
|
},
|
|
236
254
|
|
|
237
255
|
toggleErrorClass(refId: string, val: boolean) {
|
|
238
|
-
const input = this.getElemByRef(refId)?.$el;
|
|
256
|
+
const input = (this.getElemByRef(refId) as Vue)?.$el;
|
|
239
257
|
|
|
240
258
|
if (input) {
|
|
241
259
|
if (val) {
|
|
@@ -250,7 +268,11 @@ export default Vue.extend({
|
|
|
250
268
|
* Show/Hide the input line to create new item
|
|
251
269
|
*/
|
|
252
270
|
toggleCreateMode(show: boolean) {
|
|
271
|
+
if (this.readonly) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
253
274
|
if (show) {
|
|
275
|
+
this.toggleEditMode(false);
|
|
254
276
|
this.value = '';
|
|
255
277
|
|
|
256
278
|
this.isCreateItem = true;
|
|
@@ -268,31 +290,34 @@ export default Vue.extend({
|
|
|
268
290
|
* Show/Hide the in-line editing to edit an existing item
|
|
269
291
|
*/
|
|
270
292
|
toggleEditMode(show: boolean, item?: string) {
|
|
293
|
+
if (this.readonly) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
271
296
|
if (show) {
|
|
272
297
|
this.toggleCreateMode(false);
|
|
273
|
-
this.value = this.
|
|
298
|
+
this.value = this.editedItem;
|
|
274
299
|
|
|
275
|
-
this.
|
|
300
|
+
this.editedItem = item || '';
|
|
276
301
|
this.setFocus(INPUT.edit);
|
|
277
302
|
} else {
|
|
278
303
|
this.value = null;
|
|
279
304
|
this.toggleError('duplicate', false);
|
|
280
305
|
this.onSelectLeave();
|
|
281
306
|
|
|
282
|
-
this.
|
|
307
|
+
this.editedItem = null;
|
|
283
308
|
}
|
|
284
309
|
},
|
|
285
310
|
|
|
286
311
|
getElemByRef(id: string) {
|
|
287
312
|
const ref = this.$refs[id];
|
|
288
313
|
|
|
289
|
-
return
|
|
314
|
+
return Array.isArray(ref) ? ref[0] : ref;
|
|
290
315
|
},
|
|
291
316
|
|
|
292
317
|
/**
|
|
293
318
|
* Create a new item and insert in the items list
|
|
294
319
|
*/
|
|
295
|
-
saveItem() {
|
|
320
|
+
saveItem(closeInput = true) {
|
|
296
321
|
const value = this.value?.trim();
|
|
297
322
|
|
|
298
323
|
if (value) {
|
|
@@ -301,21 +326,20 @@ export default Vue.extend({
|
|
|
301
326
|
value,
|
|
302
327
|
];
|
|
303
328
|
|
|
304
|
-
if (hasDuplicatedStrings(items, this.caseSensitive)) {
|
|
305
|
-
this.
|
|
306
|
-
|
|
307
|
-
return;
|
|
329
|
+
if (!hasDuplicatedStrings(items, this.caseSensitive)) {
|
|
330
|
+
this.updateItems(items);
|
|
308
331
|
}
|
|
332
|
+
}
|
|
309
333
|
|
|
310
|
-
|
|
334
|
+
if (closeInput) {
|
|
335
|
+
this.toggleCreateMode(false);
|
|
311
336
|
}
|
|
312
|
-
this.toggleCreateMode(false);
|
|
313
337
|
},
|
|
314
338
|
|
|
315
339
|
/**
|
|
316
340
|
* Update an existing item in the items list
|
|
317
341
|
*/
|
|
318
|
-
updateItem(item: string) {
|
|
342
|
+
updateItem(item: string, closeInput = true) {
|
|
319
343
|
const value = this.value?.trim();
|
|
320
344
|
|
|
321
345
|
if (value) {
|
|
@@ -326,22 +350,21 @@ export default Vue.extend({
|
|
|
326
350
|
items[index] = value;
|
|
327
351
|
}
|
|
328
352
|
|
|
329
|
-
if (hasDuplicatedStrings(items, this.caseSensitive)) {
|
|
330
|
-
this.
|
|
331
|
-
|
|
332
|
-
return;
|
|
353
|
+
if (!hasDuplicatedStrings(items, this.caseSensitive)) {
|
|
354
|
+
this.updateItems(items);
|
|
333
355
|
}
|
|
356
|
+
}
|
|
334
357
|
|
|
335
|
-
|
|
358
|
+
if (closeInput) {
|
|
359
|
+
this.toggleEditMode(false);
|
|
336
360
|
}
|
|
337
|
-
this.toggleEditMode(false);
|
|
338
361
|
},
|
|
339
362
|
|
|
340
363
|
/**
|
|
341
364
|
* Remove an item from items list
|
|
342
365
|
*/
|
|
343
366
|
deleteItem(item?: string) {
|
|
344
|
-
const items = this.items.filter(f => f !== item);
|
|
367
|
+
const items = this.items.filter((f) => f !== item);
|
|
345
368
|
|
|
346
369
|
this.updateItems(items);
|
|
347
370
|
},
|
|
@@ -387,19 +410,20 @@ export default Vue.extend({
|
|
|
387
410
|
@blur="onSelectLeave(item)"
|
|
388
411
|
>
|
|
389
412
|
<span
|
|
390
|
-
v-if="!
|
|
413
|
+
v-if="!editedItem || editedItem !== item"
|
|
391
414
|
class="label static"
|
|
392
415
|
>
|
|
393
416
|
{{ item }}
|
|
394
417
|
</span>
|
|
395
418
|
<LabeledInput
|
|
396
|
-
v-if="
|
|
419
|
+
v-if="editedItem && editedItem === item"
|
|
397
420
|
ref="item-edit"
|
|
421
|
+
:data-testid="`item-edit-${item}`"
|
|
398
422
|
class="edit-input static"
|
|
399
423
|
:value="value != null ? value : item"
|
|
400
424
|
@input="onChange($event)"
|
|
401
|
-
@blur.prevent="
|
|
402
|
-
@keydown.native.enter="updateItem(item)"
|
|
425
|
+
@blur.prevent="updateItem(item)"
|
|
426
|
+
@keydown.native.enter="updateItem(item, !errors.duplicate)"
|
|
403
427
|
/>
|
|
404
428
|
</div>
|
|
405
429
|
<div
|
|
@@ -408,12 +432,14 @@ export default Vue.extend({
|
|
|
408
432
|
>
|
|
409
433
|
<LabeledInput
|
|
410
434
|
ref="item-create"
|
|
435
|
+
data-testid="item-create"
|
|
411
436
|
class="create-input static"
|
|
412
437
|
type="text"
|
|
413
438
|
:value="value"
|
|
414
439
|
:placeholder="placeholder"
|
|
415
440
|
@input="onChange($event)"
|
|
416
|
-
@
|
|
441
|
+
@blur.prevent="saveItem"
|
|
442
|
+
@keydown.native.enter="saveItem(!errors.duplicate)"
|
|
417
443
|
/>
|
|
418
444
|
</div>
|
|
419
445
|
</div>
|
|
@@ -427,25 +453,32 @@ export default Vue.extend({
|
|
|
427
453
|
class="action-buttons"
|
|
428
454
|
>
|
|
429
455
|
<button
|
|
456
|
+
data-testid="button-remove"
|
|
430
457
|
class="btn btn-sm role-tertiary remove-button"
|
|
431
|
-
:disabled="!selected && !isCreateItem && !
|
|
458
|
+
:disabled="!selected && !isCreateItem && !editedItem"
|
|
432
459
|
@mousedown.prevent="onClickMinusButton"
|
|
433
460
|
>
|
|
434
461
|
<span class="icon icon-minus icon-sm" />
|
|
435
462
|
</button>
|
|
436
463
|
<button
|
|
464
|
+
data-testid="button-add"
|
|
437
465
|
class="btn btn-sm role-tertiary add-button"
|
|
438
|
-
:disabled="isCreateItem"
|
|
466
|
+
:disabled="isCreateItem || editedItem"
|
|
439
467
|
@click.prevent="onClickPlusButton"
|
|
440
468
|
>
|
|
441
469
|
<span class="icon icon-plus icon-sm" />
|
|
442
470
|
</button>
|
|
443
471
|
</div>
|
|
444
472
|
<div class="messages">
|
|
445
|
-
<i
|
|
473
|
+
<i
|
|
474
|
+
v-if="errorMessagesArray.length > 0"
|
|
475
|
+
data-testid="i-warning-icon"
|
|
476
|
+
class="icon icon-warning icon-lg"
|
|
477
|
+
/>
|
|
446
478
|
<span
|
|
447
479
|
v-for="(msg, idx) in errorMessagesArray"
|
|
448
480
|
:key="idx"
|
|
481
|
+
:data-testid="`span-error-message-${msg}`"
|
|
449
482
|
class="error"
|
|
450
483
|
>
|
|
451
484
|
{{ idx > 0 ? '; ' : '' }}
|
|
@@ -499,6 +532,7 @@ export default Vue.extend({
|
|
|
499
532
|
width: auto;
|
|
500
533
|
user-select: none;
|
|
501
534
|
overflow: hidden;
|
|
535
|
+
white-space: no-wrap;
|
|
502
536
|
text-overflow: ellipsis;
|
|
503
537
|
padding-top: 1px;
|
|
504
538
|
}
|
|
File without changes
|
package/store/index.js
CHANGED
|
@@ -568,6 +568,10 @@ export const getters = {
|
|
|
568
568
|
return getters['isSingleProduct'] && cluster.isHarvester && !getters['isRancherInHarvester'];
|
|
569
569
|
},
|
|
570
570
|
|
|
571
|
+
showTopLevelMenu(getters) {
|
|
572
|
+
return getters['isRancherInHarvester'] || getters['isMultiCluster'] || !getters['isSingleProduct'];
|
|
573
|
+
},
|
|
574
|
+
|
|
571
575
|
targetRoute(state) {
|
|
572
576
|
return state.targetRoute;
|
|
573
577
|
},
|
package/store/prefs.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { SETTING } from '@shell/config/settings';
|
|
2
2
|
import { MANAGEMENT, STEVE } from '@shell/config/types';
|
|
3
3
|
import { clone } from '@shell/utils/object';
|
|
4
|
-
import
|
|
4
|
+
import Vue from 'vue';
|
|
5
5
|
|
|
6
6
|
const definitions = {};
|
|
7
7
|
/**
|
|
@@ -54,6 +54,7 @@ export const NAMESPACE_FILTERS = create('ns-by-cluster', {}, { parseJSON });
|
|
|
54
54
|
export const WORKSPACE = create('workspace', '');
|
|
55
55
|
export const EXPANDED_GROUPS = create('open-groups', ['cluster', 'policy', 'rbac', 'serviceDiscovery', 'storage', 'workload'], { parseJSON });
|
|
56
56
|
export const FAVORITE_TYPES = create('fav-type', [], { parseJSON });
|
|
57
|
+
export const PINNED_CLUSTERS = create('pinned-clusters', [], { parseJSON });
|
|
57
58
|
export const GROUP_RESOURCES = create('group-by', 'namespace');
|
|
58
59
|
export const DIFF = create('diff', 'unified', { options: ['unified', 'split'] });
|
|
59
60
|
export const THEME = create('theme', 'auto', {
|
|
@@ -115,8 +116,7 @@ export const PROVISIONER = create('provisioner', _RKE2, { options: [_RKE1, _RKE2
|
|
|
115
116
|
export const PSP_DEPRECATION_BANNER = create('hide-psp-deprecation-banner', false, { parseJSON });
|
|
116
117
|
|
|
117
118
|
// Maximum number of clusters to show in the slide-in menu
|
|
118
|
-
export const MENU_MAX_CLUSTERS =
|
|
119
|
-
|
|
119
|
+
export const MENU_MAX_CLUSTERS = 10;
|
|
120
120
|
// Prompt for confirm when scaling down node pool in GUI and save the pref
|
|
121
121
|
export const SCALE_POOL_PROMPT = create('scale-pool-prompt', null, { parseJSON });
|
|
122
122
|
// --------------------
|
package/store/type-map.js
CHANGED
|
@@ -593,18 +593,8 @@ export const getters = {
|
|
|
593
593
|
}
|
|
594
594
|
|
|
595
595
|
const label = typeObj.labelKey ? rootGetters['i18n/t'](typeObj.labelKey) || typeObj.label : typeObj.label;
|
|
596
|
-
const virtual = !!typeObj.virtual;
|
|
597
|
-
let icon = typeObj.icon;
|
|
598
596
|
|
|
599
|
-
|
|
600
|
-
if ( namespaced ) {
|
|
601
|
-
icon = 'folder';
|
|
602
|
-
} else {
|
|
603
|
-
icon = 'globe';
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
const labelDisplay = highlightLabel(label, icon, typeObj.count, typeObj.schema);
|
|
597
|
+
const labelDisplay = highlightLabel(label, typeObj.count, typeObj.schema);
|
|
608
598
|
|
|
609
599
|
if ( !labelDisplay ) {
|
|
610
600
|
// Search happens in highlight and returns null if not found
|
|
@@ -711,7 +701,7 @@ export const getters = {
|
|
|
711
701
|
return group;
|
|
712
702
|
}
|
|
713
703
|
|
|
714
|
-
function highlightLabel(original,
|
|
704
|
+
function highlightLabel(original, count, schema) {
|
|
715
705
|
let label = escapeHtml(original);
|
|
716
706
|
|
|
717
707
|
if ( searchRegex ) {
|
|
@@ -735,10 +725,6 @@ export const getters = {
|
|
|
735
725
|
}
|
|
736
726
|
}
|
|
737
727
|
|
|
738
|
-
if ( icon ) {
|
|
739
|
-
label = `<i class="icon icon-fw icon-${ icon }"></i>${ label }`;
|
|
740
|
-
}
|
|
741
|
-
|
|
742
728
|
return label;
|
|
743
729
|
}
|
|
744
730
|
};
|
package/types/shell/index.d.ts
CHANGED
|
@@ -2049,8 +2049,8 @@ declare namespace _default {
|
|
|
2049
2049
|
namespace methods {
|
|
2050
2050
|
function done(): any;
|
|
2051
2051
|
function done(): any;
|
|
2052
|
-
function conflict(): any
|
|
2053
|
-
function conflict(): any
|
|
2052
|
+
function conflict(): Promise<any>;
|
|
2053
|
+
function conflict(): Promise<any>;
|
|
2054
2054
|
function save(buttonDone: any, url: any, depth?: number): any;
|
|
2055
2055
|
function save(buttonDone: any, url: any, depth?: number): any;
|
|
2056
2056
|
function actuallySave(url: any): Promise<void>;
|
|
@@ -2069,7 +2069,7 @@ declare var _default: import("vue/types/vue").ExtendedVue<Vue<Record<string, any
|
|
|
2069
2069
|
errors: any[];
|
|
2070
2070
|
}, {
|
|
2071
2071
|
done(): any;
|
|
2072
|
-
conflict(): any
|
|
2072
|
+
conflict(): Promise<any>;
|
|
2073
2073
|
save(buttonDone: any, url: any, depth?: number): any;
|
|
2074
2074
|
actuallySave(url: any): Promise<void>;
|
|
2075
2075
|
setErrors(errors: any): void;
|
|
@@ -2407,7 +2407,7 @@ export const SELF: "__[[SELF]]__";
|
|
|
2407
2407
|
declare module '@shell/plugins/dashboard-store/normalize' {
|
|
2408
2408
|
export function keyFieldFor(type: any): string;
|
|
2409
2409
|
export function normalizeType(type: any): any;
|
|
2410
|
-
export function handleConflict(initialValueJSON: any, value: any, liveValue: any, rootGetters: any, store: any): false | any[]
|
|
2410
|
+
export function handleConflict(initialValueJSON: any, value: any, liveValue: any, rootGetters: any, store: any, storeNamespace: any): Promise<false | any[]>;
|
|
2411
2411
|
export const KEY_FIELD_FOR: {
|
|
2412
2412
|
[x: number]: string;
|
|
2413
2413
|
default: string;
|
|
@@ -2836,6 +2836,7 @@ export const NAMESPACE_FILTERS: any;
|
|
|
2836
2836
|
export const WORKSPACE: any;
|
|
2837
2837
|
export const EXPANDED_GROUPS: any;
|
|
2838
2838
|
export const FAVORITE_TYPES: any;
|
|
2839
|
+
export const PINNED_CLUSTERS: any;
|
|
2839
2840
|
export const GROUP_RESOURCES: any;
|
|
2840
2841
|
export const DIFF: any;
|
|
2841
2842
|
export const THEME: any;
|
|
@@ -2868,7 +2869,7 @@ export const _RKE1: "rke1";
|
|
|
2868
2869
|
export const _RKE2: "rke2";
|
|
2869
2870
|
export const PROVISIONER: any;
|
|
2870
2871
|
export const PSP_DEPRECATION_BANNER: any;
|
|
2871
|
-
export const MENU_MAX_CLUSTERS:
|
|
2872
|
+
export const MENU_MAX_CLUSTERS: 10;
|
|
2872
2873
|
export const SCALE_POOL_PROMPT: any;
|
|
2873
2874
|
export function state(): {
|
|
2874
2875
|
cookiesLoaded: boolean;
|
|
@@ -3052,6 +3053,14 @@ export function filterOnlyKubernetesClusters(mgmtClusters: any, store: any): any
|
|
|
3052
3053
|
export function isHarvesterCluster(mgmtCluster: any): boolean;
|
|
3053
3054
|
export function isHarvesterSatisfiesVersion(version?: string): any;
|
|
3054
3055
|
export function filterHiddenLocalCluster(mgmtClusters: any, store: any): any;
|
|
3056
|
+
/**
|
|
3057
|
+
* Shortens an input string based on the number of segments it contains.
|
|
3058
|
+
* @param {string} input - The input string to be shortened.
|
|
3059
|
+
* @returns {string} - The shortened string.
|
|
3060
|
+
* @example smallIdentifier('local') => 'lcl'
|
|
3061
|
+
* @example smallIdentifier('word-wide-web') => 'www'
|
|
3062
|
+
*/
|
|
3063
|
+
export function abbreviateClusterName(input: string): string;
|
|
3055
3064
|
}
|
|
3056
3065
|
|
|
3057
3066
|
// @shell/utils/color
|
|
@@ -3605,35 +3614,35 @@ export namespace KEY {
|
|
|
3605
3614
|
}
|
|
3606
3615
|
}
|
|
3607
3616
|
|
|
3608
|
-
// @shell/utils/poller
|
|
3617
|
+
// @shell/utils/poller-sequential
|
|
3609
3618
|
|
|
3610
|
-
declare module '@shell/utils/poller' {
|
|
3611
|
-
export default class
|
|
3619
|
+
declare module '@shell/utils/poller-sequential' {
|
|
3620
|
+
export default class PollerSequential {
|
|
3612
3621
|
constructor(fn: any, pollRateMs: any, maxRetries?: number);
|
|
3613
3622
|
fn: any;
|
|
3614
3623
|
pollRateMs: any;
|
|
3615
3624
|
maxRetries: number;
|
|
3616
|
-
|
|
3625
|
+
timeoutId: any;
|
|
3617
3626
|
tryCount: number;
|
|
3618
3627
|
start(): void;
|
|
3619
3628
|
stop(): void;
|
|
3629
|
+
_poll(): void;
|
|
3620
3630
|
_intervalMethod(): Promise<void>;
|
|
3621
3631
|
}
|
|
3622
3632
|
}
|
|
3623
3633
|
|
|
3624
|
-
// @shell/utils/poller
|
|
3634
|
+
// @shell/utils/poller
|
|
3625
3635
|
|
|
3626
|
-
declare module '@shell/utils/poller
|
|
3627
|
-
export default class
|
|
3636
|
+
declare module '@shell/utils/poller' {
|
|
3637
|
+
export default class Poller {
|
|
3628
3638
|
constructor(fn: any, pollRateMs: any, maxRetries?: number);
|
|
3629
3639
|
fn: any;
|
|
3630
3640
|
pollRateMs: any;
|
|
3631
3641
|
maxRetries: number;
|
|
3632
|
-
|
|
3642
|
+
intervalId: any;
|
|
3633
3643
|
tryCount: number;
|
|
3634
3644
|
start(): void;
|
|
3635
3645
|
stop(): void;
|
|
3636
|
-
_poll(): void;
|
|
3637
3646
|
_intervalMethod(): Promise<void>;
|
|
3638
3647
|
}
|
|
3639
3648
|
}
|
|
@@ -3908,6 +3917,9 @@ export function splitObjectPath(path: any): any;
|
|
|
3908
3917
|
export function joinObjectPath(ary: any): string;
|
|
3909
3918
|
export function shortenedImage(image: any): any;
|
|
3910
3919
|
export function isIpv4(ip: any): boolean;
|
|
3920
|
+
export function sanitizeKey(k: any): any;
|
|
3921
|
+
export function sanitizeValue(v: any): any;
|
|
3922
|
+
export function sanitizeIP(v: any): any;
|
|
3911
3923
|
export namespace CHARSET {
|
|
3912
3924
|
export { num as NUMERIC };
|
|
3913
3925
|
export const NO_VOWELS: string;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { abbreviateClusterName } from '@shell/utils/cluster';
|
|
2
|
+
|
|
3
|
+
describe('fx: abbreviateClusterName', () => {
|
|
4
|
+
it.each([
|
|
5
|
+
['local', 'lcl'],
|
|
6
|
+
['world-wide-web', 'www'],
|
|
7
|
+
['a', 'a'],
|
|
8
|
+
['ab', 'ab'],
|
|
9
|
+
['abc', 'abc'],
|
|
10
|
+
['', ''],
|
|
11
|
+
['1', '1'],
|
|
12
|
+
['12', '12'],
|
|
13
|
+
['123', '123'],
|
|
14
|
+
['a1', 'a1'],
|
|
15
|
+
['aa1', 'aa1'],
|
|
16
|
+
['aaa1', 'aa1'],
|
|
17
|
+
['a-b', 'a-b'],
|
|
18
|
+
['1-2', '1-2'],
|
|
19
|
+
['a-b-c', 'abc'],
|
|
20
|
+
['abc-def-ghi', 'adg'],
|
|
21
|
+
['abcd-efgh', 'adh'],
|
|
22
|
+
['a-bc', 'abc'],
|
|
23
|
+
['ab-c', 'abc'],
|
|
24
|
+
['ab-cd', 'abd'],
|
|
25
|
+
['a-bcd', 'abd'],
|
|
26
|
+
['abc-d', 'acd'],
|
|
27
|
+
['0123-4567-89ab-cdef', '048'],
|
|
28
|
+
['0123-4567-89ab-cdef-ghij', '048'],
|
|
29
|
+
['0123-4567-8901-2345', '048'],
|
|
30
|
+
['0123-4567-8901-2345-6789', '048'],
|
|
31
|
+
['a1b', 'a1b'],
|
|
32
|
+
['a1b2', 'a1b'],
|
|
33
|
+
['ab12cd34', 'a1c'],
|
|
34
|
+
['test-cluster-one', 'tco'],
|
|
35
|
+
['test-cluster-1', 'tc1'],
|
|
36
|
+
['customer-support-team-1', 'cst'],
|
|
37
|
+
['customer-support-team-one', 'cst'],
|
|
38
|
+
['customer-support-team-prod', 'cst'],
|
|
39
|
+
['customer-support-team-dev', 'cst'],
|
|
40
|
+
['customer-support-team-prod-1', 'cst'],
|
|
41
|
+
['customer-support-team-dev-1', 'cst'],
|
|
42
|
+
['customer-support-team-prod-2', 'cst'],
|
|
43
|
+
['customer-support-team-dev-2', 'cst'],
|
|
44
|
+
|
|
45
|
+
['s322', 's32'],
|
|
46
|
+
['sowmya2', 'sa2'],
|
|
47
|
+
['sowmya4', 'sa4'],
|
|
48
|
+
['sowmya', 'sma'],
|
|
49
|
+
['sowmyatest4', 'st4'],
|
|
50
|
+
])('should evaluate %p as %p', (value, expected) => {
|
|
51
|
+
const result = abbreviateClusterName(value);
|
|
52
|
+
|
|
53
|
+
expect(result).toStrictEqual(expected);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
-
clone, get, getter, isEmpty, toDictionary
|
|
2
|
+
clone, get, getter, isEmpty, toDictionary, remove
|
|
3
3
|
} from '@shell/utils/object';
|
|
4
4
|
|
|
5
5
|
describe('fx: get', () => {
|
|
@@ -129,7 +129,7 @@ describe('fx: isEmpty', () => {
|
|
|
129
129
|
});
|
|
130
130
|
});
|
|
131
131
|
|
|
132
|
-
describe('
|
|
132
|
+
describe('fx: toDictionary', () => {
|
|
133
133
|
it('should return a dictionary from an array', () => {
|
|
134
134
|
const array = ['a', 'b', 'c'];
|
|
135
135
|
const asd = (value: string) => value.toUpperCase();
|
|
@@ -142,3 +142,22 @@ describe('fX: toDictionary', () => {
|
|
|
142
142
|
expect(result).toStrictEqual(expectation);
|
|
143
143
|
});
|
|
144
144
|
});
|
|
145
|
+
|
|
146
|
+
describe('fx: remove', () => {
|
|
147
|
+
it.each([
|
|
148
|
+
[{}, '', {}],
|
|
149
|
+
[{}, 'not_there', {}],
|
|
150
|
+
[{}, 'not.there.again', {}],
|
|
151
|
+
[{ level1: true }, 'level1', {}],
|
|
152
|
+
[{ level1: true }, 'not_there', { level1: true }],
|
|
153
|
+
[{ level1: { level2: true } }, 'level1.level2', { level1: { } }],
|
|
154
|
+
[{ level1: { level2: true, other: true } }, 'level1.level2', { level1: { other: true } }],
|
|
155
|
+
[{ level1: { level2: true }, other: true }, 'level1.level2', { level1: { }, other: true }],
|
|
156
|
+
[{ level1: { level2: true }, other: true }, 'not_there.level1.level2', { level1: { level2: true }, other: true }],
|
|
157
|
+
[{ level1: { level2: true }, other: true }, 'level1', { other: true }],
|
|
158
|
+
])('should evaluate %p as %p', (obj, path, expected) => {
|
|
159
|
+
const result = remove(obj, path);
|
|
160
|
+
|
|
161
|
+
expect(result).toStrictEqual(expected);
|
|
162
|
+
});
|
|
163
|
+
});
|