@rancher/shell 3.0.6 → 3.0.7
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/images/pl/dark/rancher-logo.svg +131 -44
- package/assets/images/pl/rancher-logo.svg +120 -44
- package/assets/styles/base/_basic.scss +2 -2
- package/assets/styles/base/_color-classic.scss +51 -0
- package/assets/styles/base/_color.scss +3 -3
- package/assets/styles/base/_mixins.scss +1 -1
- package/assets/styles/base/_variables-classic.scss +47 -0
- package/assets/styles/global/_button.scss +49 -17
- package/assets/styles/global/_form.scss +1 -1
- package/assets/styles/themes/_dark.scss +4 -0
- package/assets/styles/themes/_light.scss +3 -69
- package/assets/styles/themes/_modern.scss +194 -50
- package/assets/styles/vendor/vue-select.scss +1 -2
- package/assets/translations/en-us.yaml +33 -21
- package/components/ClusterIconMenu.vue +1 -1
- package/components/ClusterProviderIcon.vue +1 -1
- package/components/CodeMirror.vue +1 -1
- package/components/IconOrSvg.vue +40 -29
- package/components/ResourceDetail/index.vue +1 -0
- package/components/SortableTable/sorting.js +3 -1
- package/components/Tabbed/index.vue +5 -5
- package/components/form/ResourceTabs/index.vue +37 -18
- package/components/form/SecretSelector.vue +6 -2
- package/components/nav/Group.vue +29 -9
- package/components/nav/Header.vue +6 -8
- package/components/nav/NamespaceFilter.vue +1 -1
- package/components/nav/TopLevelMenu.helper.ts +47 -20
- package/components/nav/TopLevelMenu.vue +44 -14
- package/components/nav/Type.vue +0 -5
- package/components/nav/__tests__/TopLevelMenu.test.ts +2 -0
- package/config/pagination-table-headers.js +10 -2
- package/config/product/explorer.js +4 -3
- package/config/table-headers.js +9 -0
- package/core/plugin.ts +18 -6
- package/core/types.ts +8 -0
- package/detail/provisioning.cattle.io.cluster.vue +1 -0
- package/dialog/InstallExtensionDialog.vue +71 -45
- package/dialog/UninstallExtensionDialog.vue +2 -1
- package/dialog/__tests__/InstallExtensionDialog.test.ts +111 -0
- package/edit/auth/oidc.vue +86 -16
- package/mixins/__tests__/chart.test.ts +1 -1
- package/mixins/chart.js +1 -1
- package/models/event.js +7 -0
- package/models/provisioning.cattle.io.cluster.js +9 -0
- package/package.json +1 -1
- package/pages/c/_cluster/explorer/EventsTable.vue +3 -6
- package/pages/c/_cluster/settings/performance.vue +1 -1
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +159 -62
- package/pages/c/_cluster/uiplugins/__tests__/PluginInfoPanel.test.ts +102 -0
- package/pages/c/_cluster/uiplugins/__tests__/{index.spec.ts → index.test.ts} +121 -55
- package/pages/c/_cluster/uiplugins/index.vue +110 -94
- package/plugins/__tests__/subscribe.events.test.ts +194 -0
- package/plugins/dashboard-store/actions.js +3 -0
- package/plugins/dashboard-store/getters.js +1 -1
- package/plugins/dashboard-store/resource-class.js +3 -3
- package/plugins/steve/__tests__/subscribe.spec.ts +27 -24
- package/plugins/steve/index.js +18 -10
- package/plugins/steve/mutations.js +2 -2
- package/plugins/steve/resourceWatcher.js +2 -2
- package/plugins/steve/steve-pagination-utils.ts +12 -9
- package/plugins/steve/subscribe.js +113 -85
- package/plugins/subscribe-events.ts +211 -0
- package/rancher-components/BadgeState/BadgeState.vue +8 -6
- package/rancher-components/Banner/Banner.vue +2 -1
- package/rancher-components/Form/Checkbox/Checkbox.vue +3 -3
- package/rancher-components/Form/Radio/RadioButton.vue +3 -3
- package/store/index.js +12 -22
- package/types/extension-manager.ts +8 -1
- package/types/resources/settings.d.ts +24 -17
- package/types/shell/index.d.ts +352 -335
- package/types/store/subscribe-events.types.ts +70 -0
- package/types/store/subscribe.types.ts +6 -22
- package/utils/pagination-utils.ts +87 -28
- package/utils/pagination-wrapper.ts +6 -8
- package/utils/sort.js +5 -0
- package/utils/unit-tests/pagination-utils.spec.ts +283 -0
- package/utils/validators/formRules/__tests__/index.test.ts +7 -0
- package/utils/validators/formRules/index.ts +2 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { shallowMount } from '@vue/test-utils';
|
|
1
|
+
import { shallowMount, VueWrapper } from '@vue/test-utils';
|
|
2
2
|
import UiPluginsPage from '@shell/pages/c/_cluster/uiplugins/index.vue';
|
|
3
|
+
import { UI_PLUGIN_NAMESPACE } from '@shell/config/uiplugins';
|
|
3
4
|
|
|
4
5
|
const t = (key: string, args: Object) => {
|
|
5
6
|
if (args) {
|
|
@@ -10,11 +11,16 @@ const t = (key: string, args: Object) => {
|
|
|
10
11
|
};
|
|
11
12
|
|
|
12
13
|
describe('page: UI plugins/Extensions', () => {
|
|
13
|
-
let wrapper
|
|
14
|
+
let wrapper: VueWrapper<any>;
|
|
14
15
|
|
|
15
16
|
const mountComponent = (mocks = {}) => {
|
|
16
17
|
const store = {
|
|
17
|
-
getters:
|
|
18
|
+
getters: {
|
|
19
|
+
'prefs/get': jest.fn(),
|
|
20
|
+
'catalog/rawCharts': [],
|
|
21
|
+
'uiplugins/plugins': [],
|
|
22
|
+
'uiplugins/errors': {},
|
|
23
|
+
},
|
|
18
24
|
dispatch: () => Promise.resolve(),
|
|
19
25
|
};
|
|
20
26
|
|
|
@@ -57,8 +63,7 @@ describe('page: UI plugins/Extensions', () => {
|
|
|
57
63
|
};
|
|
58
64
|
const actions = wrapper.vm.getPluginActions(plugin);
|
|
59
65
|
|
|
60
|
-
expect(actions).
|
|
61
|
-
expect(actions[0].action).toBe('uninstall');
|
|
66
|
+
expect(actions.find((action: any) => action.action === 'uninstall')).toBeDefined();
|
|
62
67
|
});
|
|
63
68
|
|
|
64
69
|
it('should not return uninstall action for a builtin plugin', () => {
|
|
@@ -70,10 +75,10 @@ describe('page: UI plugins/Extensions', () => {
|
|
|
70
75
|
};
|
|
71
76
|
const actions = wrapper.vm.getPluginActions(plugin);
|
|
72
77
|
|
|
73
|
-
expect(actions.some((
|
|
78
|
+
expect(actions.some((action: any) => action.action === 'uninstall')).toBe(false);
|
|
74
79
|
});
|
|
75
80
|
|
|
76
|
-
it('should return
|
|
81
|
+
it('should return upgrade action for an installed plugin with an upgrade', () => {
|
|
77
82
|
const plugin = {
|
|
78
83
|
installed: true,
|
|
79
84
|
installableVersions: [],
|
|
@@ -82,33 +87,35 @@ describe('page: UI plugins/Extensions', () => {
|
|
|
82
87
|
};
|
|
83
88
|
const actions = wrapper.vm.getPluginActions(plugin);
|
|
84
89
|
|
|
85
|
-
expect(actions.some((
|
|
90
|
+
expect(actions.some((action: any) => action.action === 'upgrade')).toBe(true);
|
|
86
91
|
});
|
|
87
92
|
|
|
88
|
-
it('should return
|
|
93
|
+
it('should return downgrade action for an installed plugin with older installable versions', () => {
|
|
89
94
|
const plugin = {
|
|
90
95
|
installed: true,
|
|
91
96
|
installableVersions: [{ version: '1.0.0' }, { version: '0.9.0' }],
|
|
92
97
|
builtin: false,
|
|
93
98
|
upgrade: null,
|
|
99
|
+
installedVersion: '1.0.0',
|
|
94
100
|
};
|
|
95
101
|
const actions = wrapper.vm.getPluginActions(plugin);
|
|
96
102
|
|
|
97
|
-
expect(actions.some((
|
|
103
|
+
expect(actions.some((action: any) => action.action === 'downgrade')).toBe(true);
|
|
98
104
|
});
|
|
99
105
|
|
|
100
|
-
it('should return all applicable actions', () => {
|
|
106
|
+
it('should return all applicable actions (upgrade, downgrade, uninstall)', () => {
|
|
101
107
|
const plugin = {
|
|
102
108
|
installed: true,
|
|
103
|
-
installableVersions: [{ version: '1.1.0' }, { version: '1.0.0' }],
|
|
109
|
+
installableVersions: [{ version: '1.1.0' }, { version: '1.0.0' }, { version: '0.9.0' }],
|
|
104
110
|
builtin: false,
|
|
105
111
|
upgrade: '1.1.0',
|
|
112
|
+
installedVersion: '1.0.0',
|
|
106
113
|
};
|
|
107
114
|
const actions = wrapper.vm.getPluginActions(plugin);
|
|
108
115
|
|
|
109
|
-
expect(actions.map((
|
|
110
|
-
expect(actions.map((
|
|
111
|
-
expect(actions.map((
|
|
116
|
+
expect(actions.map((action: any) => action.action)).toContain('uninstall');
|
|
117
|
+
expect(actions.map((action: any) => action.action)).toContain('upgrade');
|
|
118
|
+
expect(actions.map((action: any) => action.action)).toContain('downgrade');
|
|
112
119
|
});
|
|
113
120
|
});
|
|
114
121
|
|
|
@@ -120,43 +127,39 @@ describe('page: UI plugins/Extensions', () => {
|
|
|
120
127
|
expect(items[0].label).toBe('v1.0.0');
|
|
121
128
|
});
|
|
122
129
|
|
|
123
|
-
it('should include upgrade availability in tooltip', () => {
|
|
124
|
-
const plugin = { displayVersionLabel: 'v1.0.0', upgrade: 'v1.1.0' };
|
|
125
|
-
const items = wrapper.vm.getSubHeaderItems(plugin);
|
|
126
|
-
|
|
127
|
-
expect(items[0].labelTooltip).toBe('plugins.upgradeAvailableTooltip with {"version":"v1.1.0"}');
|
|
128
|
-
});
|
|
129
|
-
|
|
130
130
|
it('should show installing status', () => {
|
|
131
131
|
const plugin = { displayVersionLabel: 'v1.0.0', installing: 'install' };
|
|
132
132
|
const items = wrapper.vm.getSubHeaderItems(plugin);
|
|
133
133
|
|
|
134
|
-
expect(items).
|
|
135
|
-
expect(items[1].label).toBe('plugins.labels.installing');
|
|
134
|
+
expect(items.find((item: any) => item.label === 'plugins.labels.installing')).toBeDefined();
|
|
136
135
|
});
|
|
137
136
|
|
|
138
137
|
it('should show uninstalling status', () => {
|
|
139
138
|
const plugin = { displayVersionLabel: 'v1.0.0', installing: 'uninstall' };
|
|
140
139
|
const items = wrapper.vm.getSubHeaderItems(plugin);
|
|
141
140
|
|
|
142
|
-
expect(items).
|
|
143
|
-
|
|
141
|
+
expect(items.find((item: any) => item.label === 'plugins.labels.uninstalling')).toBeDefined();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('should show upgrading status', () => {
|
|
145
|
+
const plugin = { displayVersionLabel: 'v1.0.0', installing: 'upgrade' };
|
|
146
|
+
const items = wrapper.vm.getSubHeaderItems(plugin);
|
|
147
|
+
|
|
148
|
+
expect(items.find((item: any) => item.label === 'plugins.labels.upgrading')).toBeDefined();
|
|
144
149
|
});
|
|
145
150
|
|
|
146
|
-
it('should show
|
|
147
|
-
const plugin = { displayVersionLabel: 'v1.0.0', installing: '
|
|
151
|
+
it('should show downgrading status', () => {
|
|
152
|
+
const plugin = { displayVersionLabel: 'v1.0.0', installing: 'downgrade' };
|
|
148
153
|
const items = wrapper.vm.getSubHeaderItems(plugin);
|
|
149
154
|
|
|
150
|
-
expect(items).
|
|
151
|
-
expect(items[1].label).toBe('plugins.labels.updating');
|
|
155
|
+
expect(items.find((item: any) => item.label === 'plugins.labels.downgrading')).toBeDefined();
|
|
152
156
|
});
|
|
153
157
|
|
|
154
|
-
it('should
|
|
155
|
-
const plugin = {
|
|
158
|
+
it('should include date info', () => {
|
|
159
|
+
const plugin = { created: '2023-01-01T00:00:00Z' };
|
|
156
160
|
const items = wrapper.vm.getSubHeaderItems(plugin);
|
|
157
161
|
|
|
158
|
-
expect(items).
|
|
159
|
-
expect(items[1].label).toBe('plugins.labels.rollingBack');
|
|
162
|
+
expect(items.find((item: any) => item.icon === 'icon-refresh-alt')).toBeDefined();
|
|
160
163
|
});
|
|
161
164
|
});
|
|
162
165
|
|
|
@@ -200,13 +203,16 @@ describe('page: UI plugins/Extensions', () => {
|
|
|
200
203
|
});
|
|
201
204
|
|
|
202
205
|
describe('getStatuses', () => {
|
|
203
|
-
it('should return "installed" status for installed, non-builtin plugins', () => {
|
|
206
|
+
it('should return "installed" status with version for installed, non-builtin plugins', () => {
|
|
204
207
|
const plugin = {
|
|
205
|
-
installed:
|
|
208
|
+
installed: true,
|
|
209
|
+
builtin: false,
|
|
210
|
+
installing: false,
|
|
211
|
+
installedVersion: '1.2.3',
|
|
206
212
|
};
|
|
207
213
|
const statuses = wrapper.vm.getStatuses(plugin);
|
|
208
214
|
|
|
209
|
-
expect(statuses[0].tooltip.
|
|
215
|
+
expect(statuses[0].tooltip.text).toBe('generic.installed (1.2.3)');
|
|
210
216
|
});
|
|
211
217
|
|
|
212
218
|
it('should return "upgradeable" status for plugins with an upgrade', () => {
|
|
@@ -250,14 +256,15 @@ describe('page: UI plugins/Extensions', () => {
|
|
|
250
256
|
it('should combine deprecated and other errors in tooltip', () => {
|
|
251
257
|
const plugin = { chart: { deprecated: true }, helmError: true };
|
|
252
258
|
const statuses = wrapper.vm.getStatuses(plugin);
|
|
253
|
-
const warningStatus = statuses.find((
|
|
259
|
+
const warningStatus = statuses.find((status: any) => status.icon === 'icon-alert-alt');
|
|
254
260
|
|
|
255
261
|
expect(warningStatus.tooltip.text).toBe('generic.deprecated. generic.error: plugins.helmError');
|
|
256
262
|
});
|
|
257
263
|
});
|
|
258
264
|
|
|
259
265
|
describe('watch: helmOps', () => {
|
|
260
|
-
let wrapper
|
|
266
|
+
let wrapper: VueWrapper<any>;
|
|
267
|
+
let updatePluginInstallStatusMock: jest.Mock;
|
|
261
268
|
|
|
262
269
|
beforeEach(() => {
|
|
263
270
|
const store = {
|
|
@@ -265,9 +272,10 @@ describe('page: UI plugins/Extensions', () => {
|
|
|
265
272
|
'prefs/get': jest.fn(),
|
|
266
273
|
'catalog/rawCharts': {},
|
|
267
274
|
'uiplugins/plugins': [],
|
|
268
|
-
'uiplugins/errors': {}
|
|
275
|
+
'uiplugins/errors': {},
|
|
276
|
+
'features/get': () => true,
|
|
269
277
|
},
|
|
270
|
-
dispatch: () => Promise.resolve(),
|
|
278
|
+
dispatch: () => Promise.resolve(true),
|
|
271
279
|
};
|
|
272
280
|
|
|
273
281
|
wrapper = shallowMount(UiPluginsPage, {
|
|
@@ -277,42 +285,100 @@ describe('page: UI plugins/Extensions', () => {
|
|
|
277
285
|
t,
|
|
278
286
|
},
|
|
279
287
|
stubs: { ActionMenu: { template: '<div />' } }
|
|
288
|
+
},
|
|
289
|
+
computed: {
|
|
290
|
+
// Override the computed property for this test suite
|
|
291
|
+
available: () => [
|
|
292
|
+
{ name: 'plugin1' },
|
|
293
|
+
{ name: 'plugin2' },
|
|
294
|
+
{ name: 'plugin3' },
|
|
295
|
+
{ name: 'plugin4' },
|
|
296
|
+
],
|
|
297
|
+
hasMenuActions: () => true,
|
|
298
|
+
menuActions: () => []
|
|
280
299
|
}
|
|
281
300
|
});
|
|
301
|
+
|
|
302
|
+
updatePluginInstallStatusMock = jest.fn();
|
|
303
|
+
wrapper.vm.updatePluginInstallStatus = updatePluginInstallStatusMock;
|
|
304
|
+
|
|
305
|
+
// Set the 'installing' status on the component instance
|
|
306
|
+
wrapper.vm.installing = {
|
|
307
|
+
plugin1: 'install',
|
|
308
|
+
plugin2: 'downgrade',
|
|
309
|
+
plugin3: 'uninstall',
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
// Reset errors
|
|
313
|
+
wrapper.vm.errors = {};
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
it('should update status for an active operation', async() => {
|
|
317
|
+
const helmOps = [{
|
|
318
|
+
namespace: UI_PLUGIN_NAMESPACE,
|
|
319
|
+
status: { releaseName: 'plugin1', action: 'install' },
|
|
320
|
+
metadata: { creationTimestamp: '1', state: { transitioning: true } }
|
|
321
|
+
}];
|
|
322
|
+
|
|
323
|
+
wrapper.vm.helmOps = helmOps;
|
|
324
|
+
await wrapper.vm.$nextTick();
|
|
325
|
+
|
|
326
|
+
expect(updatePluginInstallStatusMock).toHaveBeenCalledWith('plugin1', 'install');
|
|
282
327
|
});
|
|
283
328
|
|
|
284
|
-
it('should
|
|
285
|
-
const
|
|
329
|
+
it('should not update status for an upgrade op when a downgrade was initiated', async() => {
|
|
330
|
+
const helmOps = [{
|
|
331
|
+
namespace: UI_PLUGIN_NAMESPACE,
|
|
332
|
+
status: { releaseName: 'plugin2', action: 'upgrade' },
|
|
333
|
+
metadata: { creationTimestamp: '1', state: { transitioning: true } }
|
|
334
|
+
}];
|
|
286
335
|
|
|
287
|
-
wrapper.vm.
|
|
288
|
-
wrapper.vm
|
|
336
|
+
wrapper.vm.helmOps = helmOps;
|
|
337
|
+
await wrapper.vm.$nextTick();
|
|
289
338
|
|
|
339
|
+
// It should not be called with 'upgrade' for plugin2
|
|
340
|
+
expect(updatePluginInstallStatusMock).not.toHaveBeenCalledWith('plugin2', 'upgrade');
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it('should clear status for a completed uninstall operation', async() => {
|
|
290
344
|
const helmOps = [{
|
|
291
|
-
|
|
292
|
-
status:
|
|
345
|
+
namespace: UI_PLUGIN_NAMESPACE,
|
|
346
|
+
status: { releaseName: 'plugin3', action: 'uninstall' },
|
|
347
|
+
metadata: { creationTimestamp: '1', state: { transitioning: false } }
|
|
293
348
|
}];
|
|
294
349
|
|
|
295
350
|
wrapper.vm.helmOps = helmOps;
|
|
296
351
|
await wrapper.vm.$nextTick();
|
|
297
352
|
|
|
298
|
-
expect(
|
|
353
|
+
expect(updatePluginInstallStatusMock).toHaveBeenCalledWith('plugin3', false);
|
|
299
354
|
});
|
|
300
355
|
|
|
301
|
-
it('should
|
|
302
|
-
const
|
|
356
|
+
it('should set error and clear status for a failed operation', async() => {
|
|
357
|
+
const helmOps = [{
|
|
358
|
+
namespace: UI_PLUGIN_NAMESPACE,
|
|
359
|
+
status: { releaseName: 'plugin1', action: 'install' },
|
|
360
|
+
metadata: { creationTimestamp: '1', state: { transitioning: false, error: true } }
|
|
361
|
+
}];
|
|
362
|
+
|
|
363
|
+
wrapper.vm.helmOps = helmOps;
|
|
364
|
+
await wrapper.vm.$nextTick();
|
|
303
365
|
|
|
304
|
-
wrapper.vm.
|
|
305
|
-
|
|
366
|
+
expect(wrapper.vm.errors.plugin1).toBe(true);
|
|
367
|
+
expect(updatePluginInstallStatusMock).toHaveBeenCalledWith('plugin1', false);
|
|
368
|
+
});
|
|
306
369
|
|
|
370
|
+
it('should clear status for plugins with no active operation', async() => {
|
|
307
371
|
const helmOps = [{
|
|
308
|
-
|
|
309
|
-
status:
|
|
372
|
+
namespace: UI_PLUGIN_NAMESPACE,
|
|
373
|
+
status: { releaseName: 'plugin1', action: 'install' },
|
|
374
|
+
metadata: { creationTimestamp: '1', state: { transitioning: true } }
|
|
310
375
|
}];
|
|
311
376
|
|
|
312
377
|
wrapper.vm.helmOps = helmOps;
|
|
313
378
|
await wrapper.vm.$nextTick();
|
|
314
379
|
|
|
315
|
-
|
|
380
|
+
// plugin4 has no op, so its status should be cleared
|
|
381
|
+
expect(updatePluginInstallStatusMock).toHaveBeenCalledWith('plugin4', false);
|
|
316
382
|
});
|
|
317
383
|
});
|
|
318
384
|
});
|