@rancher/shell 0.3.26 → 0.3.28

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/assets/translations/en-us.yaml +8 -23
  2. package/assets/translations/zh-hans.yaml +2 -26
  3. package/chart/gatekeeper.vue +2 -11
  4. package/chart/istio.vue +1 -10
  5. package/chart/logging/index.vue +2 -11
  6. package/chart/monitoring/index.vue +1 -9
  7. package/chart/rancher-backup/index.vue +1 -9
  8. package/components/AlertTable.vue +8 -6
  9. package/components/Carousel.vue +2 -1
  10. package/components/EmberPage.vue +2 -2
  11. package/components/EtcdInfoBanner.vue +12 -2
  12. package/components/GlobalRoleBindings.vue +10 -0
  13. package/components/GrafanaDashboard.vue +8 -3
  14. package/components/Wizard.vue +17 -1
  15. package/components/auth/RoleDetailEdit.vue +17 -1
  16. package/components/form/ArrayList.vue +20 -11
  17. package/components/form/__tests__/ArrayList.test.ts +44 -0
  18. package/components/formatter/ClusterProvider.vue +1 -18
  19. package/components/nav/Header.vue +5 -4
  20. package/components/nav/TopLevelMenu.vue +38 -15
  21. package/components/nav/WindowManager/ContainerLogs.vue +22 -19
  22. package/components/nav/__tests__/TopLevelMenu.test.ts +120 -0
  23. package/components/nav/__tests__/Type.test.ts +139 -0
  24. package/config/private-label.js +1 -1
  25. package/config/product/manager.js +0 -13
  26. package/config/settings.ts +0 -2
  27. package/config/types.js +0 -4
  28. package/core/types.ts +11 -4
  29. package/edit/management.cattle.io.project.vue +1 -52
  30. package/edit/management.cattle.io.setting.vue +31 -2
  31. package/edit/provisioning.cattle.io.cluster/Basics.vue +19 -107
  32. package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +1 -1
  33. package/edit/provisioning.cattle.io.cluster/__tests__/Basics.tests.ts +0 -3
  34. package/edit/provisioning.cattle.io.cluster/rke2.vue +3 -128
  35. package/edit/workload/mixins/workload.js +14 -4
  36. package/middleware/authenticated.js +4 -2
  37. package/models/__tests__/management.cattle.io.cluster.test.ts +19 -0
  38. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +90 -0
  39. package/models/cluster.x-k8s.io.machine.js +1 -1
  40. package/models/fleet.cattle.io.cluster.js +11 -1
  41. package/models/management.cattle.io.cluster.js +4 -0
  42. package/models/management.cattle.io.project.js +0 -36
  43. package/models/management.cattle.io.setting.js +11 -7
  44. package/models/provisioning.cattle.io.cluster.js +16 -4
  45. package/package.json +1 -1
  46. package/pages/auth/setup.vue +38 -1
  47. package/pages/c/_cluster/apps/charts/__tests__/install.helper.test.ts +2 -17
  48. package/pages/c/_cluster/apps/charts/index.vue +0 -15
  49. package/pages/c/_cluster/apps/charts/install.helpers.js +2 -13
  50. package/pages/c/_cluster/apps/charts/install.vue +1 -1
  51. package/pages/c/_cluster/auth/roles/index.vue +11 -1
  52. package/pages/c/_cluster/explorer/index.vue +7 -49
  53. package/pages/c/_cluster/manager/pages/_page.vue +4 -5
  54. package/pages/c/_cluster/monitoring/index.vue +26 -39
  55. package/pages/support/index.vue +1 -8
  56. package/promptRemove/management.cattle.io.project.vue +6 -9
  57. package/rancher-components/BadgeState/BadgeState.vue +1 -5
  58. package/rancher-components/Banner/Banner.test.ts +1 -51
  59. package/rancher-components/Banner/Banner.vue +53 -134
  60. package/rancher-components/Card/Card.vue +7 -24
  61. package/rancher-components/Form/Checkbox/Checkbox.test.ts +29 -20
  62. package/rancher-components/Form/Checkbox/Checkbox.vue +20 -45
  63. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +8 -2
  64. package/rancher-components/Form/LabeledInput/LabeledInput.vue +10 -22
  65. package/rancher-components/Form/Radio/RadioButton.vue +13 -30
  66. package/rancher-components/Form/Radio/RadioGroup.vue +7 -26
  67. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +6 -7
  68. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.test.ts +38 -25
  69. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +11 -23
  70. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +5 -19
  71. package/rancher-components/StringList/StringList.test.ts +49 -453
  72. package/rancher-components/StringList/StringList.vue +58 -92
  73. package/rancher-components/components/Form/Radio/RadioGroup.test.ts +30 -0
  74. package/rancher-components/components/Form/Radio/RadioGroup.vue +4 -0
  75. package/rancher-components/components/StringList/StringList.test.ts +270 -0
  76. package/rancher-components/components/StringList/StringList.vue +57 -18
  77. package/store/features.js +1 -0
  78. package/store/prefs.js +0 -3
  79. package/types/shell/index.d.ts +26 -17
  80. package/utils/__tests__/object.test.ts +67 -1
  81. package/utils/__tests__/version.test.ts +13 -23
  82. package/utils/cluster.js +1 -1
  83. package/utils/custom-validators.js +0 -2
  84. package/utils/error.js +16 -1
  85. package/utils/grafana.js +1 -2
  86. package/utils/monitoring.js +25 -1
  87. package/utils/object.js +4 -3
  88. package/utils/sort.js +1 -1
  89. package/utils/validators/formRules/__tests__/index.test.ts +49 -4
  90. package/utils/validators/formRules/index.ts +13 -10
  91. package/utils/validators/role-template.js +1 -1
  92. package/utils/validators/setting.js +6 -10
  93. package/utils/version.js +0 -13
  94. package/components/ChartPsp.vue +0 -76
  95. package/components/__tests__/ChartPsp.test.ts +0 -75
  96. package/components/formatter/__tests__/ClusterProvider.test.ts +0 -28
  97. package/rancher-components/Card/Card.test.ts +0 -37
  98. package/rancher-components/Form/Radio/RadioButton.test.ts +0 -31
  99. package/yarn-error.log +0 -200
@@ -1,484 +1,80 @@
1
- /* eslint-disable jest/no-hooks */
2
- import { mount, Wrapper } from '@vue/test-utils';
1
+ import { mount } from '@vue/test-utils';
3
2
  import { StringList } from './index';
4
3
 
5
- describe('stringList.vue', () => {
6
- let wrapper: Wrapper<InstanceType<typeof StringList>>;
4
+ describe('StringList.vue', () => {
7
5
 
8
- beforeEach(() => {
9
- wrapper = mount(StringList, { propsData: { items: [] } });
10
- });
11
-
12
- describe('list box', () => {
13
- it('is empty', () => {
14
- const box = wrapper.find('[data-testid="div-string-list-box"]').element as HTMLElement;
15
-
16
- expect(box.children).toHaveLength(0);
17
- });
18
-
19
- it('show multiple items', async() => {
20
- const items = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k'];
21
-
22
- await wrapper.setProps({ items });
23
-
24
- const elements = wrapper.findAll('[data-testid^="div-item"]');
25
-
26
- expect(elements).toHaveLength(10);
27
- });
28
-
29
- it('double click triggers inline edit mode', async() => {
30
- const items = ['test'];
31
-
32
- await wrapper.setProps({ items });
33
-
34
- const item = wrapper.find('[data-testid="div-item-test"]');
35
-
36
- await item.trigger('dblclick');
37
-
38
- const inputField = wrapper.find('[data-testid^="item-edit"]');
39
-
40
- expect(inputField.element).toBeDefined();
41
- });
42
-
43
- it('double click on empty space triggers create mode', async() => {
44
- await wrapper.setProps({ items: [] });
45
-
46
- // double click on empty space
47
- const box = wrapper.find('[data-testid="div-string-list-box"]');
48
-
49
- await box.trigger('dblclick');
50
-
51
- const inputField = wrapper.find('[data-testid="item-create"]');
52
-
53
- expect(inputField.element).toBeDefined();
54
- });
55
-
56
- it('select item when click on it', async() => {
57
- const items = ['test'];
58
-
59
- await wrapper.setProps({ items });
60
-
61
- // select item
62
- const item = wrapper.find('[data-testid^="div-item"]');
63
-
64
- await item.trigger('mousedown');
65
-
66
- expect(item.element.className).toContain('selected');
67
- });
68
-
69
- it('double click to edit item not allowed when readonly', async() => {
70
- const items = ['test'];
71
-
72
- await wrapper.setProps({
73
- items,
74
- readonly: true,
75
- });
76
-
77
- const item = wrapper.find('[data-testid="div-item-test"]');
78
-
79
- await item.trigger('dblclick');
80
-
81
- const inputField = wrapper.find('[data-testid^="item-edit"]');
82
-
83
- expect(inputField.element).toBeUndefined();
6
+ it('is empty', () => {
7
+ const wrapper = mount(StringList, {
8
+ propsData: { items: [] },
84
9
  });
10
+ const box = wrapper.find('[data-testid="div-string-list-box"]').element as HTMLElement;
85
11
 
86
- it('double click on empty space to create item not allowed when readonly', async() => {
87
- await wrapper.setProps({
88
- items: [],
89
- readonly: true,
90
- });
91
-
92
- // double click on empty space
93
- const box = wrapper.find('[data-testid="div-string-list-box"]');
94
-
95
- await box.trigger('dblclick');
96
-
97
- const inputField = wrapper.find('[data-testid="item-create"]');
98
-
99
- expect(inputField.element).toBeUndefined();
100
- });
101
-
102
- it('select item not allowed when readonly', async() => {
103
- const items = ['test'];
104
-
105
- await wrapper.setProps({
106
- items,
107
- readonly: true,
108
- });
109
-
110
- // select item
111
- const item = wrapper.find('[data-testid^="div-item"]');
112
-
113
- await item.trigger('mousedown');
114
-
115
- expect(item.element.className).not.toContain('selected');
116
- });
117
-
118
- it('emit type:item event', async() => {
119
- // activate create mode
120
- await wrapper.setData({ isCreateItem: true });
121
-
122
- const inputField = wrapper.find('[data-testid="item-create"]');
123
-
124
- // set input value to 'F'
125
- await inputField.setValue('F');
126
- await wrapper.vm.$nextTick();
127
-
128
- const emitted = (wrapper.emitted('type:item') || [])[0][0][0];
129
-
130
- expect(emitted).toBe('F');
131
- });
12
+ expect(box.children.length).toBe(0);
132
13
  });
133
14
 
134
- describe('buttons', () => {
135
- it('are visible by default', () => {
136
- const actionButtons = wrapper.find('[data-testid="div-action-buttons"]');
137
-
138
- expect(actionButtons.element).toBeDefined();
139
- });
140
-
141
- it('are hidden when is view-only mode', async() => {
142
- await wrapper.setProps({ readonly: true });
143
- const actionButtons = wrapper.find('[data-testid="div-action-buttons"]');
144
-
145
- expect(actionButtons.element).toBeUndefined();
15
+ it('is showing one element', () => {
16
+ const wrapper = mount(StringList, {
17
+ propsData: { items: ['test'] },
146
18
  });
19
+ const box = wrapper.find('.string-list-box').element as HTMLElement;
147
20
 
148
- describe('add button', () => {
149
- it('is enabled by default', () => {
150
- const addButton = wrapper.find('[data-testid="button-add"]')?.element as HTMLButtonElement;
151
-
152
- expect(addButton.disabled).toBe(false);
153
- });
154
-
155
- it('show the input field when is clicked', async() => {
156
- // click add button
157
- const addButton = wrapper.find('[data-testid="button-add"]');
158
-
159
- await addButton.trigger('click');
160
-
161
- const inputField = wrapper.find('[data-testid="item-create"]');
162
-
163
- expect(inputField.element).toBeDefined();
164
- });
165
-
166
- it('is disabled when create mode is active', async() => {
167
- // click add button
168
- const addButton = wrapper.find('[data-testid="button-add"]');
169
-
170
- await addButton.trigger('click');
171
-
172
- wrapper.find('[data-testid="item-create"]');
173
-
174
- const buttonElem = addButton.element as HTMLButtonElement;
175
-
176
- expect(buttonElem.disabled).toBe(true);
177
- });
178
- });
179
-
180
- describe('remove button', () => {
181
- it('is disabled by default', () => {
182
- const removeButton = wrapper.find('[data-testid="button-remove"]');
183
- const buttonElem = removeButton.element as HTMLButtonElement;
184
-
185
- expect(buttonElem.disabled).toBe(true);
186
- });
187
-
188
- it('is enabled when create mode is active', async() => {
189
- // click add button
190
- const addButton = wrapper.find('[data-testid="button-add"]');
191
-
192
- await addButton.trigger('click');
193
-
194
- const removeButton = wrapper.find('[data-testid="button-remove"]');
195
- const buttonElem = removeButton.element as HTMLButtonElement;
196
-
197
- expect(buttonElem.disabled).toBe(false);
198
- });
199
-
200
- it('is enabled when edit mode is active', async() => {
201
- const items = ['test'];
202
-
203
- await wrapper.setProps({ items });
204
-
205
- // activate edit mode
206
- await wrapper.setData({ editedItem: 'test' });
207
-
208
- const removeButton = wrapper.find('[data-testid="button-remove"]');
209
- const buttonElem = removeButton.element as HTMLButtonElement;
210
-
211
- expect(buttonElem.disabled).toBe(false);
212
- });
213
-
214
- it('is enabled when an item is selected', async() => {
215
- const items = ['test'];
216
-
217
- await wrapper.setProps({ items });
218
-
219
- // select item
220
- await wrapper.setData({ selected: 'test' });
221
-
222
- // click remove button
223
- const removeButton = wrapper.find('[data-testid="button-remove"]');
224
- const buttonElem = removeButton.element as HTMLButtonElement;
225
-
226
- expect(buttonElem.disabled).toBe(false);
227
- });
228
-
229
- it('removes items when an item is selected', async() => {
230
- const items = ['a'];
231
-
232
- await wrapper.setProps({ items });
233
-
234
- // select item
235
- await wrapper.setData({ selected: 'a' });
236
-
237
- // click remove button
238
- const removeButton = wrapper.find('[data-testid="button-remove"]');
239
-
240
- await removeButton.trigger('mousedown');
241
-
242
- await wrapper.vm.$nextTick();
243
-
244
- const itemsCount = (wrapper.emitted('change') || [])[0][0].length;
245
-
246
- expect(itemsCount).toBe(0);
247
- });
248
-
249
- it('deactivates create mode', async() => {
250
- // activate create mode
251
- await wrapper.setData({ isCreateItem: true });
252
-
253
- // click remove button
254
- const removeButton = wrapper.find('[data-testid="button-remove"]');
255
-
256
- await removeButton.trigger('mousedown');
257
-
258
- const inputField = await wrapper.find('[data-testid="item-create"]');
259
-
260
- expect(inputField.element).toBeUndefined();
261
- });
262
-
263
- it('deactivates edit mode', async() => {
264
- const items = ['test'];
265
-
266
- await wrapper.setProps({ items });
267
-
268
- // activate edit mode
269
- await wrapper.setData({ editedItem: 'test' });
270
-
271
- // click remove button
272
- const removeButton = wrapper.find('[data-testid="button-remove"]');
273
-
274
- await removeButton.trigger('mousedown');
275
-
276
- const inputField = wrapper.find('[data-testid^="item-edit"]');
277
-
278
- expect(inputField.element).toBeUndefined();
279
- });
280
- });
21
+ expect(box.children.length).toBe(1);
281
22
  });
282
23
 
283
- describe('list edit', () => {
284
- const validItem = ' item name ';
285
- const emptyItem = ' ';
286
-
287
- it('save a new item in create mode by pressing Enter key', async() => {
288
- // activate create mode
289
- await wrapper.setData({ isCreateItem: true });
290
-
291
- // type item name
292
- const inputField = wrapper.find('[data-testid="item-create"]');
293
-
294
- await inputField.setValue(validItem);
295
-
296
- // press enter
297
- await inputField.trigger('keydown.enter');
298
- await wrapper.vm.$nextTick();
299
-
300
- const emitted = (wrapper.emitted('change') || [])[0][0][0];
301
-
302
- expect(emitted).toBe(validItem.trim());
303
- });
304
-
305
- it('save item in edit mode by pressing Enter key', async() => {
306
- const items = ['test'];
307
-
308
- await wrapper.setProps({ items });
309
-
310
- // activate edit mode
311
- await wrapper.setData({ editedItem: 'test' });
312
- const inputField = wrapper.find('[data-testid^="item-edit"]');
313
-
314
- // edit item name
315
- await inputField.setValue(validItem);
316
-
317
- // press enter
318
- await inputField.trigger('keydown.enter');
319
- await wrapper.vm.$nextTick();
320
-
321
- const emitted = (wrapper.emitted('change') || [])[0][0][0];
322
-
323
- expect(emitted).toBe(validItem.trim());
24
+ it('action-buttons are visible', () => {
25
+ const wrapper = mount(StringList, {
26
+ propsData: { items: ['test'] },
324
27
  });
28
+ const actionButtons = wrapper.find('[data-testid="div-action-buttons"]').element as HTMLElement;
325
29
 
326
- it('reject a new item in create mode when item name is empty', async() => {
327
- // activate create mode
328
- await wrapper.setData({ isCreateItem: true });
329
-
330
- // type item name
331
- const inputField = wrapper.find('[data-testid="item-create"]');
332
-
333
- await inputField.setValue(emptyItem);
334
-
335
- // press enter
336
- await inputField.trigger('keydown.enter');
337
- await wrapper.vm.$nextTick();
338
-
339
- expect(wrapper.emitted('change')).toBeFalsy();
340
- });
341
-
342
- it('reject a new item in create mode when item name is duplicate', async() => {
343
- const items = ['test'];
344
-
345
- await wrapper.setProps({ items });
346
-
347
- // activate create mode
348
- await wrapper.setData({ isCreateItem: true });
349
-
350
- // type item name
351
- const inputField = wrapper.find('[data-testid="item-create"]');
352
-
353
- await inputField.setValue('test');
354
-
355
- // press enter
356
- await inputField.trigger('keydown.enter');
357
- await wrapper.vm.$nextTick();
358
-
359
- expect(wrapper.emitted('change')).toBeFalsy();
360
- });
361
-
362
- it('reject an item in edit mode when item name is empty', async() => {
363
- const items = ['test'];
364
-
365
- await wrapper.setProps({ items });
366
-
367
- // activate edit mode
368
- await wrapper.setData({ editedItem: 'test' });
369
- const inputField = wrapper.find('[data-testid^="item-edit"]');
370
-
371
- // edit item name
372
- await inputField.setValue(emptyItem);
373
-
374
- // press enter
375
- await inputField.trigger('keydown.enter');
376
- await wrapper.vm.$nextTick();
30
+ expect(actionButtons).not.toBe(undefined);
31
+ });
377
32
 
378
- expect(wrapper.emitted('change')).toBeFalsy();
33
+ it('action-buttons are hidden when is view-only mode', () => {
34
+ const wrapper = mount(StringList, {
35
+ propsData: {
36
+ items: ['test'],
37
+ readonly: true,
38
+ },
379
39
  });
40
+ const actionButtons = wrapper.find('[data-testid="div-action-buttons"]').element as HTMLElement;
380
41
 
381
- it('reject an item in edit mode when item name is duplicate', async() => {
382
- const items = ['test', 'test-1'];
383
-
384
- await wrapper.setProps({ items });
385
-
386
- // activate edit mode
387
- await wrapper.setData({ editedItem: 'test' });
388
- const inputField = wrapper.find('[data-testid^="item-edit"]');
389
-
390
- // edit item name
391
- await inputField.setValue('test-1');
392
-
393
- // press enter
394
- await inputField.trigger('keydown.enter');
395
- await wrapper.vm.$nextTick();
396
-
397
- expect(wrapper.emitted('change')).toBeFalsy();
398
- });
42
+ expect(actionButtons).toBe(undefined);
399
43
  });
400
44
 
401
- describe('errors handling', () => {
402
- it('show duplicate warning icon when errorMessages is defined', async() => {
403
- const items = ['test'];
45
+ it('show new item when "items" property change', async () => {
46
+ const items = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k'];
404
47
 
405
- await wrapper.setProps({
48
+ const wrapper = mount(StringList, {
49
+ propsData: {
406
50
  items,
407
- errorMessages: { duplicate: 'error, item is duplicate.' },
408
- });
409
-
410
- // activate edit mode
411
- await wrapper.setData({ isCreateItem: true });
412
-
413
- // type item name
414
- const inputField = wrapper.find('[data-testid="item-create"]');
415
-
416
- await inputField.setValue('test');
417
-
418
- const icon = wrapper.find('[data-testid="i-warning-icon"]');
419
-
420
- expect(icon.element).toBeDefined();
51
+ },
421
52
  });
53
+ const elements = wrapper.findAll('[data-testid^="div-item"]');
422
54
 
423
- it('show duplicate warning message when errorMessages is defined', async() => {
424
- const items = ['test'];
55
+ expect(elements.length).toBe(10);
425
56
 
426
- await wrapper.setProps({
427
- items,
428
- errorMessages: { duplicate: 'error, item is duplicate.' },
429
- });
430
-
431
- // activate edit mode
432
- await wrapper.setData({ isCreateItem: true });
433
-
434
- // type item name
435
- const inputField = wrapper.find('[data-testid="item-create"]');
436
-
437
- await inputField.setValue('test');
438
-
439
- const message = wrapper.find('[data-testid^="span-error-message"]');
440
-
441
- expect(message.element).toBeDefined();
442
- });
443
-
444
- it('emit duplicate errors', async() => {
445
- const items = ['test'];
446
-
447
- await wrapper.setProps({ items });
448
-
449
- // activate edit mode
450
- await wrapper.setData({ isCreateItem: true });
451
-
452
- // type item name
453
- const inputField = wrapper.find('[data-testid="item-create"]');
57
+ await wrapper.setProps({ items: [ ...items, 'new' ] });
454
58
 
455
- await inputField.setValue('test');
59
+ const newElements = wrapper.findAll('[data-testid^="div-item"]');
60
+ expect(newElements.length).toBe(11);
61
+ });
456
62
 
457
- const isDuplicate = (wrapper.emitted('errors') || [])[0][0].duplicate;
63
+ it('remove item when "items" property change', async () => {
64
+ const items = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k'];
458
65
 
459
- expect(isDuplicate).toBe(true);
66
+ const wrapper = mount(StringList, {
67
+ propsData: {
68
+ items,
69
+ },
460
70
  });
71
+ const elements = wrapper.findAll('[data-testid^="div-item"]');
72
+ expect(elements.length).toBe(10);
461
73
 
462
- it('emit duplicate errors, reset error', async() => {
463
- const items = ['test'];
464
-
465
- await wrapper.setProps({ items });
466
-
467
- // activate edit mode
468
- await wrapper.setData({ isCreateItem: true });
469
-
470
- // type item name
471
- const inputField = wrapper.find('[data-testid="item-create"]');
74
+ await wrapper.setProps({ items: [ ...items.filter(f => f !== 'a') ] });
472
75
 
473
- // emit duplicate errors
474
- await inputField.setValue('test');
475
-
476
- // it is not duplicate, reset duplicate error -> emit false
477
- await inputField.setValue('test-1');
478
-
479
- const isDuplicate = (wrapper.emitted('errors') || [])[0][0].duplicate;
480
-
481
- expect(isDuplicate).toBe(false);
482
- });
76
+ const newElements = wrapper.findAll('[data-testid^="div-item"]');
77
+ expect(newElements.length).toBe(9);
483
78
  });
79
+
484
80
  });