@rancher/shell 3.0.8-rc.7 → 3.0.8-rc.9
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/brand/suse/dark/rancher-logo.svg +1 -64
- package/assets/translations/en-us.yaml +9 -1
- package/components/BackLink.vue +8 -0
- package/components/BannerGraphic.vue +1 -5
- package/components/BrandImage.vue +17 -6
- package/components/Cron/CronExpressionEditor.vue +1 -1
- package/components/Cron/CronExpressionEditorModal.vue +1 -1
- package/components/Drawer/Chrome.vue +2 -6
- package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +4 -9
- package/components/Drawer/ResourceDetailDrawer/YamlTab.vue +3 -8
- package/components/Drawer/ResourceDetailDrawer/composables.ts +3 -4
- package/components/Drawer/ResourceDetailDrawer/index.vue +4 -9
- package/components/Drawer/ResourceDetailDrawer/types.ts +17 -0
- package/components/Drawer/types.ts +3 -0
- package/components/PaginatedResourceTable.vue +2 -6
- package/components/Questions/__tests__/index.test.ts +159 -0
- package/components/Resource/Detail/Metadata/Annotations/index.vue +2 -2
- package/components/Resource/Detail/Metadata/Labels/index.vue +2 -2
- package/components/Resource/Detail/Metadata/composables.ts +9 -9
- package/components/Resource/Detail/Metadata/index.vue +3 -3
- package/components/Resource/Detail/TitleBar/composables.ts +2 -1
- package/components/Resource/Detail/composables.ts +12 -0
- package/components/Tabbed/__tests__/index.test.ts +86 -0
- package/components/auth/SelectPrincipal.vue +24 -6
- package/components/auth/__tests__/SelectPrincipal.test.ts +119 -0
- package/components/formatter/InternalExternalIP.vue +4 -1
- package/components/formatter/__tests__/InternalExternalIP.test.ts +1 -1
- package/components/nav/Header.vue +1 -2
- package/components/nav/TopLevelMenu.helper.ts +16 -6
- package/components/templates/standalone.vue +1 -1
- package/composables/useI18n.ts +10 -1
- package/config/__test__/uiplugins.test.ts +309 -0
- package/config/labels-annotations.js +1 -0
- package/config/product/explorer.js +3 -1
- package/config/router/routes.js +6 -2
- package/config/types.js +7 -0
- package/config/uiplugins.js +46 -2
- package/core/__test__/extension-manager-impl.test.js +236 -0
- package/core/extension-manager-impl.js +23 -6
- package/core/types-provisioning.ts +1 -1
- package/detail/provisioning.cattle.io.cluster.vue +1 -0
- package/dialog/DeveloperLoadExtensionDialog.vue +12 -3
- package/dialog/RollbackWorkloadDialog.vue +2 -5
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +2 -2
- package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -0
- package/edit/configmap.vue +1 -0
- package/edit/constraints.gatekeeper.sh.constraint/index.vue +1 -0
- package/edit/fleet.cattle.io.helmop.vue +6 -6
- package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
- package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +1 -0
- package/edit/logging-flow/index.vue +1 -0
- package/edit/logging.banzaicloud.io.output/index.vue +1 -0
- package/edit/management.cattle.io.fleetworkspace.vue +1 -1
- package/edit/management.cattle.io.project.vue +1 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +4 -1
- package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +2 -1
- package/edit/monitoring.coreos.com.prometheusrule/index.vue +1 -0
- package/edit/monitoring.coreos.com.receiver/index.vue +2 -1
- package/edit/monitoring.coreos.com.route.vue +1 -1
- package/edit/namespace.vue +1 -0
- package/edit/networking.istio.io.destinationrule/index.vue +1 -0
- package/edit/networking.k8s.io.ingress/index.vue +1 -0
- package/edit/networking.k8s.io.networkpolicy/PolicyRules.vue +1 -0
- package/edit/networking.k8s.io.networkpolicy/index.vue +1 -0
- package/edit/node.vue +1 -0
- package/edit/persistentvolume/index.vue +27 -22
- package/edit/persistentvolume/plugins/awsElasticBlockStore.vue +13 -14
- package/edit/persistentvolume/plugins/azureDisk.vue +49 -48
- package/edit/persistentvolume/plugins/azureFile.vue +15 -14
- package/edit/persistentvolume/plugins/cephfs.vue +15 -14
- package/edit/persistentvolume/plugins/cinder.vue +15 -14
- package/edit/persistentvolume/plugins/csi.vue +18 -16
- package/edit/persistentvolume/plugins/fc.vue +13 -14
- package/edit/persistentvolume/plugins/flexVolume.vue +15 -14
- package/edit/persistentvolume/plugins/flocker.vue +1 -3
- package/edit/persistentvolume/plugins/gcePersistentDisk.vue +13 -14
- package/edit/persistentvolume/plugins/glusterfs.vue +15 -14
- package/edit/persistentvolume/plugins/hostPath.vue +40 -39
- package/edit/persistentvolume/plugins/iscsi.vue +13 -14
- package/edit/persistentvolume/plugins/local.vue +1 -3
- package/edit/persistentvolume/plugins/longhorn.vue +23 -22
- package/edit/persistentvolume/plugins/nfs.vue +15 -14
- package/edit/persistentvolume/plugins/photonPersistentDisk.vue +1 -14
- package/edit/persistentvolume/plugins/portworxVolume.vue +15 -14
- package/edit/persistentvolume/plugins/quobyte.vue +15 -14
- package/edit/persistentvolume/plugins/rbd.vue +15 -14
- package/edit/persistentvolume/plugins/scaleIO.vue +15 -14
- package/edit/persistentvolume/plugins/storageos.vue +15 -14
- package/edit/persistentvolume/plugins/vsphereVolume.vue +1 -3
- package/edit/provisioning.cattle.io.cluster/rke2.vue +1 -0
- package/edit/secret/index.vue +1 -1
- package/edit/service.vue +1 -0
- package/edit/serviceaccount.vue +1 -0
- package/edit/storage.k8s.io.storageclass/index.vue +1 -0
- package/edit/workload/index.vue +2 -1
- package/edit/workload/mixins/workload.js +1 -1
- package/initialize/App.vue +4 -4
- package/initialize/install-plugins.js +17 -2
- package/machine-config/components/EC2Networking.vue +5 -2
- package/machine-config/components/__tests__/EC2Networking.test.ts +24 -0
- package/mixins/__tests__/brand.spec.ts +2 -2
- package/mixins/__tests__/chart.test.ts +21 -0
- package/mixins/brand.js +1 -7
- package/mixins/chart.js +7 -1
- package/mixins/create-edit-view/index.js +5 -0
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +112 -5
- package/models/management.cattle.io.cluster.js +21 -3
- package/models/provisioning.cattle.io.cluster.js +21 -9
- package/package.json +5 -4
- package/pages/auth/login.vue +1 -3
- package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +135 -0
- package/pages/c/_cluster/apps/charts/chart.vue +33 -15
- package/pages/c/_cluster/explorer/index.vue +8 -6
- package/pages/c/_cluster/manager/hostedprovider/index.vue +12 -6
- package/pages/c/_cluster/settings/brand.vue +1 -1
- package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +7 -0
- package/pages/c/_cluster/uiplugins/catalogs.vue +147 -0
- package/pages/c/_cluster/uiplugins/index.vue +126 -184
- package/pages/home.vue +5 -2
- package/pkg/dynamic-importer.lib.js +4 -0
- package/plugins/dashboard-client-init.js +3 -0
- package/plugins/dashboard-store/getters.js +18 -1
- package/plugins/dashboard-store/resource-class.js +4 -4
- package/plugins/i18n.js +8 -0
- package/plugins/steve/__tests__/steve-pagination-utils.test.ts +333 -0
- package/plugins/steve/steve-pagination-utils.ts +39 -20
- package/plugins/steve/subscribe.js +17 -9
- package/plugins/subscribe-events.ts +4 -2
- package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +6 -42
- package/rancher-components/Pill/RcStatusBadge/index.ts +0 -1
- package/rancher-components/Pill/RcStatusBadge/types.ts +1 -1
- package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +5 -28
- package/rancher-components/Pill/RcStatusIndicator/types.ts +2 -1
- package/rancher-components/Pill/types.ts +0 -1
- package/rancher-components/RcIcon/RcIcon.test.ts +51 -0
- package/rancher-components/RcIcon/RcIcon.vue +46 -0
- package/rancher-components/RcIcon/index.ts +1 -0
- package/rancher-components/RcIcon/types.ts +160 -0
- package/rancher-components/utils/status.test.ts +67 -0
- package/rancher-components/utils/status.ts +77 -0
- package/scripts/typegen.sh +1 -0
- package/store/action-menu.js +8 -0
- package/store/auth.js +3 -3
- package/store/catalog.js +6 -0
- package/store/index.js +36 -17
- package/store/prefs.js +4 -5
- package/store/type-map.js +3 -3
- package/store/wm.ts +4 -4
- package/types/shell/index.d.ts +39 -2
- package/types/store/__tests__/pagination.types.spec.ts +137 -0
- package/types/store/pagination.types.ts +157 -9
- package/types/store/subscribe-events.types.ts +8 -1
- package/types/store/subscribe.types.ts +1 -0
- package/utils/__tests__/provider.test.ts +98 -0
- package/utils/__tests__/selector-typed.test.ts +263 -0
- package/utils/__tests__/version.test.ts +19 -1
- package/utils/back-off.ts +3 -3
- package/utils/color.js +1 -1
- package/utils/dynamic-content/__tests__/info.test.ts +21 -9
- package/utils/dynamic-content/info.ts +44 -2
- package/utils/favicon.js +4 -4
- package/utils/pagination-wrapper.ts +12 -8
- package/utils/provider.ts +14 -0
- package/utils/selector-typed.ts +6 -2
- package/utils/version.js +15 -0
- package/plugins/nuxt-client-init.js +0 -3
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { DEVELOPER_LOAD_NAME_SUFFIX } from '@shell/core/extension-manager-impl';
|
|
2
|
+
|
|
3
|
+
// Mock external dependencies
|
|
4
|
+
jest.mock('@shell/store/type-map', () => ({ productsLoaded: jest.fn().mockReturnValue(true) }));
|
|
5
|
+
|
|
6
|
+
jest.mock('@shell/plugins/dashboard-store/model-loader', () => ({ clearModelCache: jest.fn() }));
|
|
7
|
+
|
|
8
|
+
jest.mock('@shell/config/uiplugins', () => ({ UI_PLUGIN_BASE_URL: '/api/v1/uiplugins' }));
|
|
9
|
+
|
|
10
|
+
jest.mock('@shell/plugins/clean-html', () => ({
|
|
11
|
+
addLinkInterceptor: jest.fn(),
|
|
12
|
+
removeLinkInterceptor: jest.fn(),
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
// Mock the Plugin class
|
|
16
|
+
jest.mock('@shell/core/plugin', () => {
|
|
17
|
+
return {
|
|
18
|
+
Plugin: jest.fn().mockImplementation((id) => ({
|
|
19
|
+
id,
|
|
20
|
+
name: id,
|
|
21
|
+
types: {},
|
|
22
|
+
uiConfig: {},
|
|
23
|
+
l10n: {},
|
|
24
|
+
modelExtensions: {},
|
|
25
|
+
stores: [],
|
|
26
|
+
locales: [],
|
|
27
|
+
routes: [],
|
|
28
|
+
validators: {},
|
|
29
|
+
uninstallHooks: [],
|
|
30
|
+
productNames: [],
|
|
31
|
+
})),
|
|
32
|
+
EXT_IDS: {
|
|
33
|
+
MODELS: 'models',
|
|
34
|
+
MODEL_EXTENSION: 'model-extension'
|
|
35
|
+
},
|
|
36
|
+
ExtensionPoint: { EDIT_YAML: 'edit-yaml' }
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Mock PluginRoutes
|
|
41
|
+
jest.mock('@shell/core/plugin-routes', () => {
|
|
42
|
+
return { PluginRoutes: jest.fn().mockImplementation(() => ({ addRoutes: jest.fn() })) };
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('extension Manager', () => {
|
|
46
|
+
let mockStore;
|
|
47
|
+
let mockApp;
|
|
48
|
+
let context;
|
|
49
|
+
|
|
50
|
+
// These variables will be assigned the fresh functions inside beforeEach
|
|
51
|
+
let initExtensionManager;
|
|
52
|
+
let getExtensionManager;
|
|
53
|
+
|
|
54
|
+
beforeEach(() => {
|
|
55
|
+
// singleton instance for every test run, preventing mock store leaks.
|
|
56
|
+
jest.resetModules();
|
|
57
|
+
|
|
58
|
+
// Re-require the System Under Test (SUT)
|
|
59
|
+
const extensionManagerModule = require('../extension-manager-impl');
|
|
60
|
+
|
|
61
|
+
initExtensionManager = extensionManagerModule.initExtensionManager;
|
|
62
|
+
getExtensionManager = extensionManagerModule.getExtensionManager;
|
|
63
|
+
|
|
64
|
+
jest.clearAllMocks();
|
|
65
|
+
|
|
66
|
+
// Setup Mock Context
|
|
67
|
+
mockStore = {
|
|
68
|
+
getters: { 'i18n/t': jest.fn() },
|
|
69
|
+
dispatch: jest.fn(),
|
|
70
|
+
commit: jest.fn(),
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
mockApp = { router: {} };
|
|
74
|
+
|
|
75
|
+
context = {
|
|
76
|
+
app: mockApp,
|
|
77
|
+
store: mockStore,
|
|
78
|
+
$axios: {},
|
|
79
|
+
redirect: jest.fn(),
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// Clean up DOM from previous tests
|
|
83
|
+
document.head.innerHTML = '';
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe('singleton Pattern', () => {
|
|
87
|
+
it('initializes and returns the same instance', () => {
|
|
88
|
+
const instance1 = initExtensionManager(context);
|
|
89
|
+
const instance2 = getExtensionManager();
|
|
90
|
+
const instance3 = initExtensionManager(context);
|
|
91
|
+
|
|
92
|
+
expect(instance1).toBeDefined();
|
|
93
|
+
expect(instance1).toBe(instance2);
|
|
94
|
+
expect(instance1).toBe(instance3);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe('registration (Dynamic)', () => {
|
|
99
|
+
it('registers and retrieves a dynamic component', () => {
|
|
100
|
+
const manager = initExtensionManager(context);
|
|
101
|
+
const mockFn = jest.fn();
|
|
102
|
+
|
|
103
|
+
manager.register('component', 'my-component', mockFn);
|
|
104
|
+
|
|
105
|
+
const retrieved = manager.getDynamic('component', 'my-component');
|
|
106
|
+
|
|
107
|
+
expect(retrieved).toBe(mockFn);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('unregisters a dynamic component', () => {
|
|
111
|
+
const manager = initExtensionManager(context);
|
|
112
|
+
const mockFn = jest.fn();
|
|
113
|
+
|
|
114
|
+
manager.register('component', 'my-component', mockFn);
|
|
115
|
+
manager.unregister('component', 'my-component');
|
|
116
|
+
|
|
117
|
+
const retrieved = manager.getDynamic('component', 'my-component');
|
|
118
|
+
|
|
119
|
+
expect(retrieved).toBeUndefined();
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe('loadPluginAsync (URL Generation)', () => {
|
|
124
|
+
let manager;
|
|
125
|
+
|
|
126
|
+
beforeEach(() => {
|
|
127
|
+
manager = initExtensionManager(context);
|
|
128
|
+
// Mock the internal loadAsync so we only test URL generation here
|
|
129
|
+
jest.spyOn(manager, 'loadAsync').mockImplementation().mockResolvedValue();
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('generates correct URL for standard plugin', async() => {
|
|
133
|
+
const pluginData = { name: 'elemental', version: '1.0.0' };
|
|
134
|
+
const expectedId = 'elemental-1.0.0';
|
|
135
|
+
const expectedUrl = `/api/v1/uiplugins/elemental/1.0.0/plugin/elemental-1.0.0.umd.min.js`;
|
|
136
|
+
|
|
137
|
+
await manager.loadPluginAsync(pluginData);
|
|
138
|
+
|
|
139
|
+
expect(manager.loadAsync).toHaveBeenCalledWith(expectedId, expectedUrl);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('handles "direct" metadata plugins', async() => {
|
|
143
|
+
const pluginData = {
|
|
144
|
+
name: 'direct-plugin',
|
|
145
|
+
version: '1.0.0',
|
|
146
|
+
endpoint: 'http://localhost:8000/plugin.js',
|
|
147
|
+
metadata: { direct: 'true' }
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
await manager.loadPluginAsync(pluginData);
|
|
151
|
+
|
|
152
|
+
expect(manager.loadAsync).toHaveBeenCalledWith('direct-plugin-1.0.0', 'http://localhost:8000/plugin.js');
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('removes developer suffix from ID but keeps it for internal logic', async() => {
|
|
156
|
+
const pluginData = {
|
|
157
|
+
name: `my-plugin${ DEVELOPER_LOAD_NAME_SUFFIX }`,
|
|
158
|
+
version: `1.0.0`
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
await manager.loadPluginAsync(pluginData);
|
|
162
|
+
|
|
163
|
+
// Expected ID passed to loadAsync should NOT have the suffix
|
|
164
|
+
const expectedIdWithoutSuffix = 'my-plugin-1.0.0';
|
|
165
|
+
|
|
166
|
+
expect(manager.loadAsync).toHaveBeenCalledWith(
|
|
167
|
+
expectedIdWithoutSuffix,
|
|
168
|
+
expect.any(String)
|
|
169
|
+
);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
describe('loadAsync (Script Injection)', () => {
|
|
174
|
+
let manager;
|
|
175
|
+
|
|
176
|
+
beforeEach(() => {
|
|
177
|
+
manager = initExtensionManager(context);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('resolves immediately if element already exists', async() => {
|
|
181
|
+
const id = 'existing-plugin';
|
|
182
|
+
const script = document.createElement('script');
|
|
183
|
+
|
|
184
|
+
script.id = id;
|
|
185
|
+
document.body.appendChild(script);
|
|
186
|
+
|
|
187
|
+
await expect(manager.loadAsync(id, 'url.js')).resolves.toBeUndefined();
|
|
188
|
+
|
|
189
|
+
document.body.removeChild(script);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('injects script tag and initializes plugin on load', async() => {
|
|
193
|
+
const pluginId = 'test-plugin';
|
|
194
|
+
const pluginUrl = 'http://test.com/plugin.js';
|
|
195
|
+
|
|
196
|
+
// Mock the window object to simulate the plugin loading into global scope
|
|
197
|
+
const mockPluginInit = jest.fn();
|
|
198
|
+
|
|
199
|
+
window[pluginId] = { default: mockPluginInit };
|
|
200
|
+
|
|
201
|
+
// Start the load
|
|
202
|
+
const loadPromise = manager.loadAsync(pluginId, pluginUrl);
|
|
203
|
+
|
|
204
|
+
// Find the injected script tag in the DOM
|
|
205
|
+
const script = document.head.querySelector(`script[id="${ pluginId }"]`);
|
|
206
|
+
|
|
207
|
+
expect(script).toBeTruthy();
|
|
208
|
+
expect(script.src).toBe(pluginUrl);
|
|
209
|
+
|
|
210
|
+
// Manually trigger the onload event
|
|
211
|
+
script.onload();
|
|
212
|
+
|
|
213
|
+
// Await the promise
|
|
214
|
+
await loadPromise;
|
|
215
|
+
|
|
216
|
+
// Assertions
|
|
217
|
+
expect(mockPluginInit).toHaveBeenCalledWith(expect.objectContaining({ id: pluginId }), expect.objectContaining({ ...context }));
|
|
218
|
+
expect(mockStore.dispatch).toHaveBeenCalledWith('uiplugins/addPlugin', expect.objectContaining({ id: pluginId }));
|
|
219
|
+
|
|
220
|
+
// Cleanup
|
|
221
|
+
delete window[pluginId];
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it('rejects if script load fails', async() => {
|
|
225
|
+
const pluginId = 'fail-plugin';
|
|
226
|
+
const loadPromise = manager.loadAsync(pluginId, 'bad-url.js');
|
|
227
|
+
|
|
228
|
+
const script = document.head.querySelector(`script[id="${ pluginId }"]`);
|
|
229
|
+
|
|
230
|
+
// Trigger error
|
|
231
|
+
script.onerror({ target: { src: 'bad-url.js' } });
|
|
232
|
+
|
|
233
|
+
await expect(loadPromise).rejects.toThrow('Failed to load script');
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
});
|
|
@@ -6,6 +6,8 @@ import { UI_PLUGIN_BASE_URL } from '@shell/config/uiplugins';
|
|
|
6
6
|
import { ExtensionPoint } from './types';
|
|
7
7
|
import { addLinkInterceptor, removeLinkInterceptor } from '@shell/plugins/clean-html';
|
|
8
8
|
|
|
9
|
+
export const DEVELOPER_LOAD_NAME_SUFFIX = '-developer-load';
|
|
10
|
+
|
|
9
11
|
let extensionManagerInstance;
|
|
10
12
|
|
|
11
13
|
const createExtensionManager = (context) => {
|
|
@@ -35,11 +37,11 @@ const createExtensionManager = (context) => {
|
|
|
35
37
|
*/
|
|
36
38
|
function instantiateModelExtension($plugin, clz) {
|
|
37
39
|
const context = {
|
|
38
|
-
dispatch:
|
|
39
|
-
getters:
|
|
40
|
-
t:
|
|
40
|
+
dispatch: store.dispatch,
|
|
41
|
+
getters: store.getters,
|
|
42
|
+
t: store.getters['i18n/t'],
|
|
41
43
|
$axios,
|
|
42
|
-
$plugin,
|
|
44
|
+
$extension: $plugin,
|
|
43
45
|
};
|
|
44
46
|
|
|
45
47
|
return new clz(context);
|
|
@@ -63,9 +65,18 @@ const createExtensionManager = (context) => {
|
|
|
63
65
|
// Load a plugin from a UI package
|
|
64
66
|
loadPluginAsync(plugin) {
|
|
65
67
|
const { name, version } = plugin;
|
|
66
|
-
|
|
68
|
+
let id = `${ name }-${ version }`;
|
|
67
69
|
let url;
|
|
68
70
|
|
|
71
|
+
// for a developer load, we need to remove the suffix applied
|
|
72
|
+
// otherwise the extension won't load correctly
|
|
73
|
+
// but with this at least we won't hit developer loaded cards find charts
|
|
74
|
+
// when they aren't supposed to
|
|
75
|
+
if (id.includes(DEVELOPER_LOAD_NAME_SUFFIX)) {
|
|
76
|
+
id = id.replace(DEVELOPER_LOAD_NAME_SUFFIX, '');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// this is where a developer load hits (direct=true, developer=true)
|
|
69
80
|
if (plugin?.metadata?.direct === 'true') {
|
|
70
81
|
url = plugin.endpoint;
|
|
71
82
|
} else {
|
|
@@ -455,7 +466,13 @@ const createExtensionManager = (context) => {
|
|
|
455
466
|
try {
|
|
456
467
|
const provisioner = context.$extension.getDynamic('provisioner', name);
|
|
457
468
|
|
|
458
|
-
|
|
469
|
+
const defaults = {
|
|
470
|
+
isCreate: false,
|
|
471
|
+
isEdit: false,
|
|
472
|
+
isView: false
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
return new provisioner({ ...defaults, ...context });
|
|
459
476
|
} catch (e) {
|
|
460
477
|
console.error('Error loading provisioner(s) from extensions', e); // eslint-disable-line no-console
|
|
461
478
|
}
|
|
@@ -578,6 +578,7 @@ export default {
|
|
|
578
578
|
// Hosted kubernetes providers with private endpoints need the registration tab
|
|
579
579
|
// https://github.com/rancher/dashboard/issues/6036
|
|
580
580
|
// https://github.com/rancher/dashboard/issues/4545
|
|
581
|
+
|
|
581
582
|
if ( this.value.isHostedKubernetesProvider && this.value.isPrivateHostedProvider && !this.isClusterReady ) {
|
|
582
583
|
return this.extDetailTabs.registration;
|
|
583
584
|
}
|
|
@@ -4,6 +4,7 @@ import { LabeledInput } from '@components/Form/LabeledInput';
|
|
|
4
4
|
import Checkbox from '@components/Form/Checkbox/Checkbox.vue';
|
|
5
5
|
import { UI_PLUGIN } from '@shell/config/types';
|
|
6
6
|
import { UI_PLUGIN_CHART_ANNOTATIONS, UI_PLUGIN_NAMESPACE } from '@shell/config/uiplugins';
|
|
7
|
+
import { DEVELOPER_LOAD_NAME_SUFFIX } from '@shell/core/extension-manager-impl';
|
|
7
8
|
|
|
8
9
|
export default {
|
|
9
10
|
emits: ['close'],
|
|
@@ -101,8 +102,16 @@ export default {
|
|
|
101
102
|
const parts = name.split('-');
|
|
102
103
|
|
|
103
104
|
if (parts.length >= 2) {
|
|
104
|
-
version
|
|
105
|
-
|
|
105
|
+
// fixing the name-version separation, especially in RC versions
|
|
106
|
+
// like: elemental-3.0.1-rc.1
|
|
107
|
+
// on capturing version it must be "digit + dot + digit" + rest of string
|
|
108
|
+
const regex = /^(?<name>.+?)-(?<version>\d+\.\d+.*)$/;
|
|
109
|
+
const match = name.match(regex);
|
|
110
|
+
|
|
111
|
+
if (match && match.groups) {
|
|
112
|
+
version = match.groups.version;
|
|
113
|
+
crdName = match.groups.name;
|
|
114
|
+
}
|
|
106
115
|
}
|
|
107
116
|
|
|
108
117
|
if (this.persist) {
|
|
@@ -114,7 +123,7 @@ export default {
|
|
|
114
123
|
},
|
|
115
124
|
spec: {
|
|
116
125
|
plugin: {
|
|
117
|
-
name: crdName
|
|
126
|
+
name: `${ crdName }${ DEVELOPER_LOAD_NAME_SUFFIX }`,
|
|
118
127
|
version,
|
|
119
128
|
endpoint: url,
|
|
120
129
|
noCache: true,
|
|
@@ -165,12 +165,9 @@ export default {
|
|
|
165
165
|
return option.label;
|
|
166
166
|
},
|
|
167
167
|
sizeDialog() {
|
|
168
|
-
const
|
|
169
|
-
const width = this.showDiff ? '85%' : '600px';
|
|
168
|
+
const modalWidth = this.showDiff ? '85%' : '600px';
|
|
170
169
|
|
|
171
|
-
|
|
172
|
-
dialogs[0].style.setProperty('width', width);
|
|
173
|
-
}
|
|
170
|
+
this.$store.commit('action-menu/updateModalData', [{ key: 'modalWidth', value: modalWidth }]);
|
|
174
171
|
},
|
|
175
172
|
sanitizeYaml(obj, path = '') {
|
|
176
173
|
const res = {};
|
|
@@ -243,7 +243,7 @@ describe.each([
|
|
|
243
243
|
|
|
244
244
|
await fleetSecretSelector.vm.$emit('update:value', ['secret2', 'secret3']);
|
|
245
245
|
|
|
246
|
-
expect(wrapper.vm.value.spec.
|
|
246
|
+
expect(wrapper.vm.value.spec.downstreamResources).toStrictEqual([{ name: 'secret2', kind: 'Secret' }, { name: 'secret3', kind: 'Secret' }]);
|
|
247
247
|
});
|
|
248
248
|
|
|
249
249
|
it('should update downstreamResources with new ConfigMaps when FleetConfigMapSelector emits update event', async() => {
|
|
@@ -260,6 +260,6 @@ describe.each([
|
|
|
260
260
|
|
|
261
261
|
await fleetConfigMapSelector.vm.$emit('update:value', ['configMap2', 'configMap3']);
|
|
262
262
|
|
|
263
|
-
expect(wrapper.vm.value.spec.
|
|
263
|
+
expect(wrapper.vm.value.spec.downstreamResources).toStrictEqual([{ name: 'configMap2', kind: 'ConfigMap' }, { name: 'configMap3', kind: 'ConfigMap' }]);
|
|
264
264
|
});
|
|
265
265
|
});
|
package/edit/configmap.vue
CHANGED
|
@@ -237,11 +237,11 @@ export default {
|
|
|
237
237
|
},
|
|
238
238
|
|
|
239
239
|
downstreamSecretsList() {
|
|
240
|
-
return (this.value.spec.
|
|
240
|
+
return (this.value.spec.downstreamResources || []).filter((r) => r.kind === 'Secret').map((r) => r.name);
|
|
241
241
|
},
|
|
242
242
|
|
|
243
243
|
downstreamConfigMapsList() {
|
|
244
|
-
return (this.value.spec.
|
|
244
|
+
return (this.value.spec.downstreamResources || []).filter((r) => r.kind === 'ConfigMap').map((r) => r.name);
|
|
245
245
|
},
|
|
246
246
|
},
|
|
247
247
|
|
|
@@ -446,14 +446,14 @@ export default {
|
|
|
446
446
|
updateDownstreamResources(kind, list) {
|
|
447
447
|
switch (kind) {
|
|
448
448
|
case 'Secret':
|
|
449
|
-
this.value.spec.
|
|
450
|
-
...(this.value.spec.
|
|
449
|
+
this.value.spec.downstreamResources = [
|
|
450
|
+
...(this.value.spec.downstreamResources || []).filter((r) => r.kind !== 'Secret'),
|
|
451
451
|
...(list || []).map((name) => ({ name, kind: 'Secret' })),
|
|
452
452
|
];
|
|
453
453
|
break;
|
|
454
454
|
case 'ConfigMap':
|
|
455
|
-
this.value.spec.
|
|
456
|
-
...(this.value.spec.
|
|
455
|
+
this.value.spec.downstreamResources = [
|
|
456
|
+
...(this.value.spec.downstreamResources || []).filter((r) => r.kind !== 'ConfigMap'),
|
|
457
457
|
...(list || []).map((name) => ({ name, kind: 'ConfigMap' })),
|
|
458
458
|
];
|
|
459
459
|
break;
|
|
@@ -204,7 +204,10 @@ export default {
|
|
|
204
204
|
@input="$emit('input', $event)"
|
|
205
205
|
/>
|
|
206
206
|
|
|
207
|
-
<Tabbed
|
|
207
|
+
<Tabbed
|
|
208
|
+
:use-hash="useTabbedHash"
|
|
209
|
+
:default-tab="defaultTab"
|
|
210
|
+
>
|
|
208
211
|
<Tab
|
|
209
212
|
:label="t('monitoring.route.label')"
|
|
210
213
|
:weight="1"
|
package/edit/namespace.vue
CHANGED