@rancher/shell 3.0.8-rc.10 → 3.0.8-rc.12

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 (44) hide show
  1. package/components/ResourceTable.vue +1 -1
  2. package/components/SortableTable/index.vue +1 -1
  3. package/components/auth/login/ldap.vue +3 -3
  4. package/components/form/NodeScheduling.vue +2 -2
  5. package/components/nav/Group.vue +9 -2
  6. package/components/nav/Header.vue +1 -1
  7. package/components/nav/Type.vue +8 -3
  8. package/components/nav/__tests__/Type.test.ts +59 -0
  9. package/config/router/navigation-guards/clusters.js +3 -3
  10. package/config/router/navigation-guards/products.js +1 -1
  11. package/core/extension-manager-impl.js +5 -5
  12. package/core/plugin-helpers.ts +2 -2
  13. package/core/plugins-loader.js +2 -2
  14. package/core/types-provisioning.ts +4 -0
  15. package/detail/provisioning.cattle.io.cluster.vue +6 -6
  16. package/dialog/DeveloperLoadExtensionDialog.vue +1 -1
  17. package/dialog/SearchDialog.vue +1 -0
  18. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +21 -21
  19. package/edit/provisioning.cattle.io.cluster/index.vue +5 -5
  20. package/edit/provisioning.cattle.io.cluster/rke2.vue +8 -8
  21. package/models/management.cattle.io.cluster.js +1 -1
  22. package/models/provisioning.cattle.io.cluster.js +1 -1
  23. package/package.json +3 -3
  24. package/pages/auth/login.vue +3 -3
  25. package/pages/auth/setup.vue +1 -1
  26. package/pages/auth/verify.vue +3 -3
  27. package/pkg/auto-import.js +3 -3
  28. package/pkg/dynamic-importer.lib.js +1 -1
  29. package/pkg/import.js +1 -1
  30. package/plugins/dashboard-store/getters.js +1 -1
  31. package/plugins/dashboard-store/model-loader.js +1 -1
  32. package/plugins/dashboard-store/resource-class.js +6 -2
  33. package/plugins/plugin.js +2 -2
  34. package/plugins/steve/steve-class.js +1 -1
  35. package/store/__tests__/catalog.test.ts +1 -1
  36. package/store/auth.js +1 -1
  37. package/store/i18n.js +3 -3
  38. package/store/index.js +5 -3
  39. package/store/type-map.js +4 -4
  40. package/types/shell/index.d.ts +1 -0
  41. package/utils/pagination-utils.ts +2 -2
  42. package/utils/pagination-wrapper.ts +1 -1
  43. package/utils/unit-tests/pagination-utils.spec.ts +8 -8
  44. package/vue.config.js +3 -3
@@ -316,7 +316,7 @@ export default {
316
316
 
317
317
  // add custom table columns provided by the extensions ExtensionPoint.TABLE_COL hook
318
318
  // gate it so that we prevent errors on older versions of dashboard
319
- if (this.$store.$plugin?.getUIConfig) {
319
+ if (this.$store.$extension?.getUIConfig) {
320
320
  // { column: TableColumn, paginationColumn: PaginationTableColumn }[]
321
321
  const extensionCols = getApplicableExtensionEnhancements(this, ExtensionPoint.TABLE_COL, TableColumnLocation.RESOURCE, this.$route);
322
322
 
@@ -765,7 +765,7 @@ export default {
765
765
  needRef = true;
766
766
  } else {
767
767
  // Check if we have a formatter from a plugin
768
- const pluginFormatter = this.$plugin?.getDynamic('formatters', c.formatter);
768
+ const pluginFormatter = this.$extension?.getDynamic('formatters', c.formatter);
769
769
 
770
770
  if (pluginFormatter) {
771
771
  component = defineAsyncComponent(pluginFormatter);
@@ -34,9 +34,9 @@ export default {
34
34
  });
35
35
 
36
36
  await loadPlugins({
37
- app: this.$store.app,
38
- store: this.$store,
39
- $plugin: this.$store.$plugin
37
+ app: this.$store.app,
38
+ store: this.$store,
39
+ $extension: this.$store.$extension,
40
40
  });
41
41
 
42
42
  buttonCb(true);
@@ -181,7 +181,7 @@ export default {
181
181
  :options="selectNodeOptions"
182
182
  :mode="mode"
183
183
  :data-testid="'node-scheduling-selectNode'"
184
- @input="update"
184
+ @update:value="update"
185
185
  />
186
186
  </div>
187
187
  <template v-if="selectNode === 'nodeSelector'">
@@ -205,7 +205,7 @@ export default {
205
205
  v-model:value="nodeAffinity"
206
206
  :mode="mode"
207
207
  :data-testid="'node-scheduling-nodeAffinity'"
208
- @input="update"
208
+ @update:value="update"
209
209
  />
210
210
  </template>
211
211
  </div>
@@ -41,6 +41,11 @@ export default {
41
41
  fixedOpen: {
42
42
  type: Boolean,
43
43
  default: false,
44
+ },
45
+
46
+ highlightRoute: {
47
+ type: Boolean,
48
+ default: true,
44
49
  }
45
50
  },
46
51
 
@@ -233,7 +238,7 @@ export default {
233
238
  <template>
234
239
  <div
235
240
  class="accordion"
236
- :class="{[`depth-${depth}`]: true, 'expanded': isExpanded, 'has-children': hasChildren, 'group-highlight': isGroupActive }"
241
+ :class="{[`depth-${depth}`]: true, 'expanded': isExpanded, 'has-children': hasChildren, 'group-highlight': highlightRoute && isGroupActive }"
237
242
  >
238
243
  <div
239
244
  v-if="showHeader || (!onlyHasOverview && canCollapse)"
@@ -242,7 +247,7 @@ export default {
242
247
  <div
243
248
  v-if="showHeader"
244
249
  class="header"
245
- :class="{'active': isOverview, 'noHover': !canCollapse || fixedOpen}"
250
+ :class="{'active': highlightRoute && isOverview, 'noHover': !canCollapse || fixedOpen}"
246
251
  role="button"
247
252
  :tabindex="fixedOpen ? -1 : 0"
248
253
  :aria-label="group.labelDisplay || group.label || ''"
@@ -311,6 +316,7 @@ export default {
311
316
  :can-collapse="canCollapse"
312
317
  :group="child"
313
318
  :fixed-open="fixedOpen"
319
+ :highlight-route="highlightRoute"
314
320
  @selected="groupSelected($event)"
315
321
  @expand="expandGroup($event)"
316
322
  @close="close($event)"
@@ -322,6 +328,7 @@ export default {
322
328
  :is-root="depth == 0 && !showHeader"
323
329
  :type="child"
324
330
  :depth="depth"
331
+ :highlight-route="highlightRoute"
325
332
  @selected="selectType($event)"
326
333
  />
327
334
  </template>
@@ -254,7 +254,7 @@ export default {
254
254
  this.extensionHeaderActions = getApplicableExtensionEnhancements(this, ExtensionPoint.ACTION, ActionLocation.HEADER, neu);
255
255
  this.updateExtensionActionsEnabled();
256
256
 
257
- this.navHeaderRight = this.$plugin?.getDynamic('component', 'NavHeaderRight');
257
+ this.navHeaderRight = this.$extension?.getDynamic('component', 'NavHeaderRight');
258
258
  }
259
259
  },
260
260
  immediate: true,
@@ -27,6 +27,11 @@ export default {
27
27
  type: Number,
28
28
  default: 0,
29
29
  },
30
+
31
+ highlightRoute: {
32
+ type: Boolean,
33
+ default: true,
34
+ },
30
35
  },
31
36
 
32
37
  data() {
@@ -121,12 +126,12 @@ export default {
121
126
  >
122
127
  <li
123
128
  class="child nav-type"
124
- :class="{'root': isRoot, [`depth-${depth}`]: true, 'router-link-active': isActive, 'router-link-exact-active': isExactActive}"
129
+ :class="{'root': isRoot, [`depth-${depth}`]: true, 'router-link-active': highlightRoute && isActive, 'router-link-exact-active': highlightRoute && isExactActive}"
125
130
  @click="navigate"
126
131
  @keypress.enter="navigate"
127
132
  >
128
133
  <TabTitle
129
- v-if="isExactActive"
134
+ v-if="highlightRoute && isExactActive"
130
135
  :show-child="false"
131
136
  >
132
137
  {{ type.labelKey ? t(type.labelKey) : (type.labelDisplay || type.label) }}
@@ -136,7 +141,7 @@ export default {
136
141
  :aria-label="type.labelKey ? t(type.labelKey) : (type.labelDisplay || type.label)"
137
142
  :href="href"
138
143
  class="type-link"
139
- :aria-current="isActive ? 'page' : undefined"
144
+ :aria-current="highlightRoute && isActive ? 'page' : undefined"
140
145
  @click="selectType(); navigate($event);"
141
146
  @mouseenter="setNear(true)"
142
147
  @mouseleave="setNear(false)"
@@ -250,6 +250,65 @@ describe('component: Type', () => {
250
250
  });
251
251
  });
252
252
 
253
+ describe('should respect highlightRoute prop', () => {
254
+ it('should not use active class when highlightRoute is false even if route is active', () => {
255
+ const wrapper = shallowMount(Type as any, {
256
+ props: { type: defaultRouteTypeProp, highlightRoute: false },
257
+
258
+ global: {
259
+ directives: { cleanHtml: (identity) => identity },
260
+
261
+ mocks: {
262
+ $store: storeMock, $router: routerMock, $route: routeMock
263
+ },
264
+ stubs: { routerLink: createChildRenderingRouterLinkStub() },
265
+ },
266
+ });
267
+
268
+ const elementWithSelector = wrapper.find(`.${ activeClass }`);
269
+
270
+ expect(elementWithSelector.exists()).toBe(false);
271
+ });
272
+
273
+ it('should not use exact active class when highlightRoute is false even if route is exact active', () => {
274
+ const wrapper = shallowMount(Type as any, {
275
+ props: { type: defaultRouteTypeProp, highlightRoute: false },
276
+
277
+ global: {
278
+ directives: { cleanHtml: (identity) => identity },
279
+
280
+ mocks: {
281
+ $store: storeMock, $router: routerMock, $route: routeMock
282
+ },
283
+ stubs: { routerLink: createChildRenderingRouterLinkStub({ isExactActive: true }) },
284
+ },
285
+ });
286
+
287
+ const elementWithSelector = wrapper.find(`.${ exactActiveClass }`);
288
+
289
+ expect(elementWithSelector.exists()).toBe(false);
290
+ });
291
+
292
+ it('should use active class when highlightRoute is true (default) and route is active', () => {
293
+ const wrapper = shallowMount(Type as any, {
294
+ props: { type: defaultRouteTypeProp, highlightRoute: true },
295
+
296
+ global: {
297
+ directives: { cleanHtml: (identity) => identity },
298
+
299
+ mocks: {
300
+ $store: storeMock, $router: routerMock, $route: routeMock
301
+ },
302
+ stubs: { routerLink: createChildRenderingRouterLinkStub() },
303
+ },
304
+ });
305
+
306
+ const elementWithSelector = wrapper.find(`.${ activeClass }`);
307
+
308
+ expect(elementWithSelector.exists()).toBe(true);
309
+ });
310
+ });
311
+
253
312
  describe('should handle the favorite icon appropriately', () => {
254
313
  it('should show favorite icon if mouse is over and type is favorite', async() => {
255
314
  const wrapper = shallowMount(Type as any, {
@@ -30,12 +30,12 @@ export async function loadClusters(to, from, next, { store }) {
30
30
  const oldPkg = getPackageFromRoute(from);
31
31
  const oldProduct = getProductFromRoute(from);
32
32
 
33
- // TODO: Replace all references to store.$plugin.
33
+ // TODO: Replace all references to store.$extension.
34
34
  // Unfortunately the initialization code has circular dependencies between creating
35
35
  // the router and creating the store that will need to be untangled before this can be tackled.
36
36
 
37
37
  // Leave an old pkg where we weren't before?
38
- const oldPkgPlugin = oldPkg ? Object.values(store.$plugin.getPlugins()).find((p) => p.name === oldPkg) : null;
38
+ const oldPkgPlugin = oldPkg ? Object.values(store.$extension.getPlugins()).find((p) => p.name === oldPkg) : null;
39
39
 
40
40
  if (oldPkg && oldPkg !== pkg ) {
41
41
  // Execute anything optional the plugin wants to. For example resetting it's store to remove data
@@ -53,7 +53,7 @@ export async function loadClusters(to, from, next, { store }) {
53
53
  ];
54
54
 
55
55
  // Entering a new package where we weren't before?
56
- const newPkgPlugin = pkg ? Object.values(store.$plugin.getPlugins()).find((p) => p.name === pkg) : null;
56
+ const newPkgPlugin = pkg ? Object.values(store.$extension.getPlugins()).find((p) => p.name === pkg) : null;
57
57
 
58
58
  // Note - We can't block on oldPkg !== newPkg because on a fresh load the `from` route equals the `to` route
59
59
  if (pkg && (oldPkg !== pkg || from.fullPath === to.fullPath)) {
@@ -9,7 +9,7 @@ export async function loadProducts(to, from, next, { store }) {
9
9
  // GC should be notified of route change before any find/get request is made that might be used for that page
10
10
  store.dispatch('gcRouteChanged', to);
11
11
 
12
- await applyProducts(store, store.$plugin);
12
+ await applyProducts(store, store.$extension);
13
13
  setProduct(store, to);
14
14
  next();
15
15
  }
@@ -35,13 +35,13 @@ const createExtensionManager = (context) => {
35
35
  /**
36
36
  * When an extension adds a model extension, it provides the class - we will instantiate that class and store and use that
37
37
  */
38
- function instantiateModelExtension($plugin, clz) {
38
+ function instantiateModelExtension($extension, clz) {
39
39
  const context = {
40
- dispatch: store.dispatch,
41
- getters: store.getters,
42
- t: store.getters['i18n/t'],
40
+ dispatch: store.dispatch,
41
+ getters: store.getters,
42
+ t: store.getters['i18n/t'],
43
43
  $axios,
44
- $extension: $plugin,
44
+ $extension,
45
45
  };
46
46
 
47
47
  return new clz(context);
@@ -147,8 +147,8 @@ export function getApplicableExtensionEnhancements<T>(
147
147
  const extensionEnhancements: T[] = [];
148
148
 
149
149
  // gate it so that we prevent errors on older versions of dashboard
150
- if (pluginCtx.$plugin?.getUIConfig) {
151
- const actions = pluginCtx.$plugin.getUIConfig(actionType, uiArea);
150
+ if (pluginCtx.$extension?.getUIConfig) {
151
+ const actions = pluginCtx.$extension.getUIConfig(actionType, uiArea);
152
152
 
153
153
  actions.forEach((action: any, i: number) => {
154
154
  if (checkExtensionRouteBinding(currRoute, action.locationConfig, context || {})) {
@@ -13,10 +13,10 @@ export default function({
13
13
  store,
14
14
  $axios,
15
15
  redirect,
16
- $plugin,
16
+ $extension,
17
17
  }, inject) {
18
18
  if (dynamicLoader) {
19
- dynamicLoader.default($plugin);
19
+ dynamicLoader.default($extension);
20
20
  }
21
21
 
22
22
  // The libraries we build have Vue externalised, so we need to expose Vue as a global for
@@ -60,6 +60,10 @@ export interface ClusterProvisionerContext {
60
60
  * Used to make http requests
61
61
  */
62
62
  axios: any,
63
+ /**
64
+ * [Deprecated] Definition of the extension
65
+ */
66
+ $plugin: any,
63
67
  /**
64
68
  * Definition of the extension
65
69
  */
@@ -96,15 +96,15 @@ export default {
96
96
  await this.value.waitForProvisioner();
97
97
 
98
98
  // Support for the 'provisioner' extension
99
- const extClass = this.$plugin.getDynamic('provisioner', this.value.machineProvider);
99
+ const extClass = this.$extension.getDynamic('provisioner', this.value.machineProvider);
100
100
 
101
101
  if (extClass) {
102
102
  this.extProvider = new extClass({
103
- dispatch: this.$store.dispatch,
104
- getters: this.$store.getters,
105
- axios: this.$store.$axios,
106
- $plugin: this.$store.app.$plugin,
107
- $t: this.t
103
+ dispatch: this.$store.dispatch,
104
+ getters: this.$store.getters,
105
+ axios: this.$store.$axios,
106
+ $extension: this.$store.app.$extension,
107
+ $t: this.t
108
108
  });
109
109
 
110
110
  this.extDetailTabs = {
@@ -145,7 +145,7 @@ export default {
145
145
  }
146
146
  }
147
147
 
148
- this.$plugin.loadAsync(name, url).then(() => {
148
+ this.$extension.loadAsync(name, url).then(() => {
149
149
  this.closeDialog(true);
150
150
 
151
151
  this.$store.dispatch('growl/success', {
@@ -106,6 +106,7 @@ export default {
106
106
  :group="g"
107
107
  :can-collapse="false"
108
108
  :fixed-open="true"
109
+ :highlight-route="false"
109
110
  @close="$emit('close')"
110
111
  >
111
112
  <template #accordion>
@@ -112,8 +112,8 @@ describe('component: rke2', () => {
112
112
  global: {
113
113
  mocks: {
114
114
  ...defaultMocks,
115
- $store: { dispatch: () => jest.fn(), getters: defaultGetters },
116
- $plugin: { getDynamic: jest.fn(() => undefined ) }
115
+ $store: { dispatch: () => jest.fn(), getters: defaultGetters },
116
+ $extension: { getDynamic: jest.fn(() => undefined ) }
117
117
  },
118
118
 
119
119
  stubs: defaultStubs,
@@ -143,8 +143,8 @@ describe('component: rke2', () => {
143
143
  global: {
144
144
  mocks: {
145
145
  ...defaultMocks,
146
- $store: { dispatch: () => jest.fn(), getters: defaultGetters },
147
- $plugin: { getDynamic: jest.fn(() => undefined ) },
146
+ $store: { dispatch: () => jest.fn(), getters: defaultGetters },
147
+ $extension: { getDynamic: jest.fn(() => undefined ) },
148
148
  },
149
149
 
150
150
  stubs: defaultStubs,
@@ -174,8 +174,8 @@ describe('component: rke2', () => {
174
174
  global: {
175
175
  mocks: {
176
176
  ...defaultMocks,
177
- $store: { dispatch: () => jest.fn(), getters: defaultGetters },
178
- $plugin: { getDynamic: jest.fn(() => undefined ) },
177
+ $store: { dispatch: () => jest.fn(), getters: defaultGetters },
178
+ $extension: { getDynamic: jest.fn(() => undefined ) },
179
179
  },
180
180
 
181
181
  stubs: defaultStubs,
@@ -231,7 +231,7 @@ describe('component: rke2', () => {
231
231
  },
232
232
  getters: defaultGetters
233
233
  },
234
- $plugin: { getDynamic: jest.fn(() => undefined ) },
234
+ $extension: { getDynamic: jest.fn(() => undefined ) },
235
235
  },
236
236
 
237
237
  stubs: defaultStubs,
@@ -275,7 +275,7 @@ describe('component: rke2', () => {
275
275
  'management/findAll': () => ([]),
276
276
  }
277
277
  },
278
- $plugin: { getDynamic: jest.fn(() => undefined ) },
278
+ $extension: { getDynamic: jest.fn(() => undefined ) },
279
279
  },
280
280
 
281
281
  stubs: defaultStubs,
@@ -324,7 +324,7 @@ describe('component: rke2', () => {
324
324
  'management/findAll': () => ([]),
325
325
  }
326
326
  },
327
- $plugin: { getDynamic: jest.fn(() => undefined ) },
327
+ $extension: { getDynamic: jest.fn(() => undefined ) },
328
328
  },
329
329
 
330
330
  stubs: defaultStubs,
@@ -369,8 +369,8 @@ describe('component: rke2', () => {
369
369
  global: {
370
370
  mocks: {
371
371
  ...defaultMocks,
372
- $store: { dispatch: () => jest.fn(), getters: defaultGetters },
373
- $plugin: { getDynamic: jest.fn(() => undefined ) },
372
+ $store: { dispatch: () => jest.fn(), getters: defaultGetters },
373
+ $extension: { getDynamic: jest.fn(() => undefined ) },
374
374
  },
375
375
  stubs: defaultStubs
376
376
  }
@@ -409,8 +409,8 @@ describe('component: rke2', () => {
409
409
  global: {
410
410
  mocks: {
411
411
  ...defaultMocks,
412
- $store: { dispatch: () => jest.fn(), getters: defaultGetters },
413
- $plugin: { getDynamic: jest.fn(() => undefined ) },
412
+ $store: { dispatch: () => jest.fn(), getters: defaultGetters },
413
+ $extension: { getDynamic: jest.fn(() => undefined ) },
414
414
  },
415
415
  stubs: defaultStubs
416
416
  }
@@ -441,8 +441,8 @@ describe('component: rke2', () => {
441
441
  global: {
442
442
  mocks: {
443
443
  ...defaultMocks,
444
- $store: { dispatch: () => jest.fn(), getters: defaultGetters },
445
- $plugin: { getDynamic: jest.fn(() => undefined ) },
444
+ $store: { dispatch: () => jest.fn(), getters: defaultGetters },
445
+ $extension: { getDynamic: jest.fn(() => undefined ) },
446
446
  },
447
447
  stubs: defaultStubs
448
448
  }
@@ -489,8 +489,8 @@ describe('component: rke2', () => {
489
489
  global: {
490
490
  mocks: {
491
491
  ...defaultMocks,
492
- $store: { dispatch: () => jest.fn(), getters: defaultGetters },
493
- $plugin: { getDynamic: jest.fn(() => undefined ) },
492
+ $store: { dispatch: () => jest.fn(), getters: defaultGetters },
493
+ $extension: { getDynamic: jest.fn(() => undefined ) },
494
494
  },
495
495
  stubs: defaultStubs
496
496
  }
@@ -536,8 +536,8 @@ describe('component: rke2', () => {
536
536
  global: {
537
537
  mocks: {
538
538
  ...defaultMocks,
539
- $store: { dispatch: () => jest.fn(), getters: defaultGetters },
540
- $plugin: { getDynamic: jest.fn(() => undefined ) },
539
+ $store: { dispatch: () => jest.fn(), getters: defaultGetters },
540
+ $extension: { getDynamic: jest.fn(() => undefined ) },
541
541
  },
542
542
  stubs: defaultStubs
543
543
  }
@@ -600,8 +600,8 @@ describe('component: rke2', () => {
600
600
  global: {
601
601
  mocks: {
602
602
  ...defaultMocks,
603
- $store: { dispatch: () => jest.fn(), getters: defaultGetters },
604
- $plugin: { getDynamic: jest.fn(() => undefined ) },
603
+ $store: { dispatch: () => jest.fn(), getters: defaultGetters },
604
+ $extension: { getDynamic: jest.fn(() => undefined ) },
605
605
  },
606
606
 
607
607
  stubs: defaultStubs,
@@ -332,9 +332,9 @@ export default {
332
332
  // Keeping this for non Rancher-managed kontainer drivers
333
333
  this.kontainerDrivers.filter((x) => (isImport ? x.showImport : x.showCreate)).forEach((obj) => {
334
334
  if ( vueKontainerTypes.includes(obj.driverName) ) {
335
- addType(this.$plugin, obj.driverName, 'hosted', false);
335
+ addType(this.$extension, obj.driverName, 'hosted', false);
336
336
  } else {
337
- addType(this.$plugin, obj.driverName, 'hosted', false, (isImport ? obj.emberImportPath : obj.emberCreatePath));
337
+ addType(this.$extension, obj.driverName, 'hosted', false, (isImport ? obj.emberImportPath : obj.emberCreatePath));
338
338
  }
339
339
  });
340
340
  if (!isImport) {
@@ -351,7 +351,7 @@ export default {
351
351
 
352
352
  // If Elemental is installed, then add the elemental cluster provider
353
353
  if (isElementalActive) {
354
- addType(this.$plugin, ELEMENTAL_CLUSTER_PROVIDER, 'custom2', false);
354
+ addType(this.$extension, ELEMENTAL_CLUSTER_PROVIDER, 'custom2', false);
355
355
  }
356
356
 
357
357
  // Only add the RKE2 options if RKE2 is enabled
@@ -359,10 +359,10 @@ export default {
359
359
  machineTypes.forEach((type) => {
360
360
  const id = type.spec.displayName || type.id;
361
361
 
362
- addType(this.$plugin, id, _RKE2, false, null, undefined, type);
362
+ addType(this.$extension, id, _RKE2, false, null, undefined, type);
363
363
  });
364
364
 
365
- addType(this.$plugin, 'custom', 'custom2', false);
365
+ addType(this.$extension, 'custom', 'custom2', false);
366
366
  }
367
367
  }
368
368
  // Add from extensions
@@ -502,7 +502,7 @@ export default {
502
502
  * 2) Override via hardcoded setting
503
503
  */
504
504
  cloudCredentialsOverride() {
505
- const cloudCredential = this.$plugin.getDynamic('cloud-credential', this.provider);
505
+ const cloudCredential = this.$extension.getDynamic('cloud-credential', this.provider);
506
506
 
507
507
  if (cloudCredential === undefined) {
508
508
  return CLOUD_CREDENTIAL_OVERRIDE[this.provider];
@@ -527,16 +527,16 @@ export default {
527
527
  * Extension provider where being provisioned by an extension
528
528
  */
529
529
  extensionProvider() {
530
- const extClass = this.$plugin.getDynamic('provisioner', this.provider);
530
+ const extClass = this.$extension.getDynamic('provisioner', this.provider);
531
531
 
532
532
  if (extClass) {
533
533
  return new extClass({
534
- dispatch: this.$store.dispatch,
535
- getters: this.$store.getters,
536
- axios: this.$store.$axios,
537
- $plugin: this.$store.app.$plugin,
538
- $t: this.t,
539
- isCreate: this.isCreate
534
+ dispatch: this.$store.dispatch,
535
+ getters: this.$store.getters,
536
+ axios: this.$store.$axios,
537
+ $extension: this.$store.app.$extension,
538
+ $t: this.t,
539
+ isCreate: this.isCreate
540
540
  });
541
541
  }
542
542
 
@@ -255,7 +255,7 @@ export default class MgmtCluster extends SteveModel {
255
255
  dispatch: this.$dispatch,
256
256
  getters: this.$getters,
257
257
  axios: this.$axios,
258
- $extension: this.$plugin,
258
+ $extension: this.$extension,
259
259
  t: (...args) => this.t.apply(this, args),
260
260
  };
261
261
 
@@ -277,7 +277,7 @@ export default class ProvCluster extends SteveModel {
277
277
  dispatch: this.$dispatch,
278
278
  getters: this.$getters,
279
279
  axios: this.$axios,
280
- $extension: this.$plugin,
280
+ $extension: this.$extension,
281
281
  t: (...args) => this.t.apply(this, args),
282
282
  };
283
283
 
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@rancher/shell",
3
- "version": "3.0.8-rc.10",
3
+ "version": "3.0.8-rc.12",
4
4
  "description": "Rancher Dashboard Shell",
5
- "repository": "https://github.com/rancherlabs/dashboard",
5
+ "repository": "https://github.com/rancher/dashboard",
6
6
  "license": "Apache-2.0",
7
7
  "author": "SUSE",
8
8
  "private": false,
@@ -140,7 +140,7 @@
140
140
  "vuedraggable": "4.1.0",
141
141
  "vuex": "4.1.0",
142
142
  "webpack-bundle-analyzer": "4.10.2",
143
- "webpack-virtual-modules": "0.4.3",
143
+ "webpack-virtual-modules": "0.6.2",
144
144
  "worker-loader": "3.0.8",
145
145
  "xterm-addon-canvas": "0.5.0",
146
146
  "xterm-addon-fit": "0.8.0",
@@ -315,9 +315,9 @@ export default {
315
315
  // so we manually load them here - other SSO auth providers bounce out and back to the Dashboard, so on the bounce-back
316
316
  // the plugins will load via the boot-time plugin
317
317
  await loadPlugins({
318
- app: this.$store.app,
319
- store: this.$store,
320
- $plugin: this.$store.$plugin
318
+ app: this.$store.app,
319
+ store: this.$store,
320
+ $extension: this.$store.$extension,
321
321
  });
322
322
 
323
323
  if (this.firstLogin || user[0]?.mustChangePassword) {
@@ -209,7 +209,7 @@ export default {
209
209
  const promises = [];
210
210
 
211
211
  try {
212
- await applyProducts(this.$store, this.$plugin);
212
+ await applyProducts(this.$store, this.$extension);
213
213
  await this.$store.dispatch('loadManagement');
214
214
 
215
215
  if ( this.mustChangePassword ) {
@@ -119,9 +119,9 @@ export default {
119
119
 
120
120
  // Load plugins
121
121
  await loadPlugins({
122
- app: this.$store.app,
123
- store: this.$store,
124
- $plugin: this.$store.$plugin
122
+ app: this.$store.app,
123
+ store: this.$store,
124
+ $extension: this.$store.$extension,
125
125
  });
126
126
 
127
127
  this.$router.replace(backTo);
@@ -15,7 +15,7 @@ function registerFile(file, type, pkg, f) {
15
15
  const importType = (f === 'models') ? 'require' : 'import';
16
16
  const chunkName = (f === 'l10n') ? '' : `/* webpackChunkName: "${ f }" */`;
17
17
 
18
- return ` $plugin.register('${ f }', '${ type }', () => ${ importType }(${ chunkName }'${ pkg }/${ f }/${ file }'));\n`;
18
+ return ` $extension.register('${ f }', '${ type }', () => ${ importType }(${ chunkName }'${ pkg }/${ f }/${ file }'));\n`;
19
19
  }
20
20
 
21
21
  function register(file, pkg, f) {
@@ -29,7 +29,7 @@ function register(file, pkg, f) {
29
29
  // This ensures that the webpackChunkName is respected (require.context does not support this) - so when build as a library
30
30
  // the code splitting will be respected
31
31
  function generateTypeImport(pkg, dir) {
32
- let content = 'export function importTypes($plugin) { \n';
32
+ let content = 'export function importTypes($extension) { \n';
33
33
 
34
34
  // Auto-import if the folder exists
35
35
  contextFolders.forEach((f) => {
@@ -77,7 +77,7 @@ function generateTypeImport(pkg, dir) {
77
77
  // and then restart the dev server for it to be picked up.
78
78
  function generateDynamicTypeImport(pkg, dir) {
79
79
  const template = fs.readFileSync(path.join(__dirname, 'import.js'), { encoding: 'utf8' });
80
- let content = 'export function importTypes($plugin) { \n';
80
+ let content = 'export function importTypes($extension) { \n';
81
81
 
82
82
  // Auto-import if the folder exists
83
83
  contextFolders.forEach((f) => {
@@ -41,7 +41,7 @@ export function listProducts() {
41
41
  return [];
42
42
  }
43
43
 
44
- export function loadProduct(name, $plugin) {
44
+ export function loadProduct(name, $extension) {
45
45
  return () => undefined;
46
46
  }
47
47
 
package/pkg/import.js CHANGED
@@ -6,5 +6,5 @@ _NAME.forEach((f) => {
6
6
 
7
7
  name = name.substr(0, ext);
8
8
 
9
- $plugin.register('DIR', name, () => REQUIRE(CHUNK`BASE/DIR/${ name }EXT`)); // eslint-disable-line no-undef
9
+ $extension.register('DIR', name, () => REQUIRE(CHUNK`BASE/DIR/${ name }EXT`)); // eslint-disable-line no-undef
10
10
  });
@@ -543,7 +543,7 @@ export default {
543
543
  const store = state.config.namespace;
544
544
  const resource = id || context ? { id, context } : null;
545
545
 
546
- return paginationUtils.isEnabled({ rootGetters, $plugin: rootState.$plugin }, { store, resource });
546
+ return paginationUtils.isEnabled({ rootGetters, $extension: rootState.$extension }, { store, resource });
547
547
  },
548
548
 
549
549
  /**
@@ -13,7 +13,7 @@ function find(cache, type, rootState) {
13
13
  }
14
14
 
15
15
  try {
16
- const pluginModel = rootState.$plugin.getDynamic('models', type);
16
+ const pluginModel = rootState.$extension.getDynamic('models', type);
17
17
  let base;
18
18
 
19
19
  if (!pluginModel) {
@@ -610,7 +610,11 @@ export default class Resource {
610
610
  }
611
611
 
612
612
  get '$plugin'() {
613
- return this.$ctx.rootState?.$plugin;
613
+ return this.$ctx.rootState?.$extension;
614
+ }
615
+
616
+ get '$extension'() {
617
+ return this.$ctx.rootState?.$extension;
614
618
  }
615
619
 
616
620
  get customValidationRules() {
@@ -1777,7 +1781,7 @@ export default class Resource {
1777
1781
  CustomValidators[validatorName](pathValue, this.$rootGetters, errors, validatorArgs, displayKey, data);
1778
1782
  } else if (!isEmpty(validatorName) && !validatorExists) {
1779
1783
  // Check if validator is imported from plugin
1780
- const pluginValidator = this.$rootState.$plugin?.getValidator(validatorName);
1784
+ const pluginValidator = this.$rootState.$extension?.getValidator(validatorName);
1781
1785
 
1782
1786
  if (pluginValidator) {
1783
1787
  pluginValidator(pathValue, this.$rootGetters, errors, validatorArgs, displayKey, data);
package/plugins/plugin.js CHANGED
@@ -44,7 +44,7 @@ export default async function(context) {
44
44
  const res = await allHashSettled(fetches);
45
45
 
46
46
  // Initialize the built-in extensions now - this is now done here so that built-in extensions get the same, correct environment data (version etc)
47
- context.$plugin.loadBuiltinExtensions();
47
+ context.$extension.loadBuiltinExtensions();
48
48
 
49
49
  if (res.plugins?.status === 'rejected') {
50
50
  throw new Error(res.reason);
@@ -60,7 +60,7 @@ export default async function(context) {
60
60
  const shouldNotLoad = shouldNotLoadPlugin(plugin, { rancherVersion, kubeVersion }, context.store.getters['uiplugins/plugins'] || []); // Error key string or boolean
61
61
 
62
62
  if (!shouldNotLoad) {
63
- hash[plugin.name] = context.$plugin.loadPluginAsync(plugin);
63
+ hash[plugin.name] = context.$extension.loadPluginAsync(plugin);
64
64
  } else {
65
65
  context.store.dispatch('uiplugins/setError', { name: plugin.name, error: shouldNotLoad });
66
66
  }
@@ -47,7 +47,7 @@ export default class SteveModel extends HybridModel {
47
47
  * Get all model extensions for this model
48
48
  */
49
49
  get modelExtensions() {
50
- return this.$plugin.getDynamic(EXT_IDS.MODEL_EXTENSION, this.type) || [];
50
+ return this.$extension.getDynamic(EXT_IDS.MODEL_EXTENSION, this.type) || [];
51
51
  }
52
52
 
53
53
  cleanForSave(data, forNew) {
@@ -88,7 +88,7 @@ describe('catalog', () => {
88
88
  }
89
89
  },
90
90
  state: {
91
- $plugin: { getDynamic: () => require(`@shell/models/chart`) },
91
+ $extension: { getDynamic: () => require(`@shell/models/chart`) },
92
92
  [catalogStoreName]: { } as { [key: string]: any},
93
93
  },
94
94
  getters: {
package/store/auth.js CHANGED
@@ -402,7 +402,7 @@ export const actions = {
402
402
  }
403
403
 
404
404
  // Unload plugins - we will load again on login
405
- await rootState.$plugin.logout();
405
+ await rootState.$extension.logout();
406
406
 
407
407
  let logoutAction = '';
408
408
  const data = {};
package/store/i18n.js CHANGED
@@ -285,8 +285,8 @@ export const actions = {
285
285
  return;
286
286
  }
287
287
 
288
- const lastLoad = rootState.$plugin?.lastLoad;
289
- const i18nExt = rootState.$plugin?.getDynamic('l10n', locale);
288
+ const lastLoad = rootState.$extension?.lastLoad;
289
+ const i18nExt = rootState.$extension?.getDynamic('l10n', locale);
290
290
  const reload = lastLoaded < lastLoad;
291
291
 
292
292
  lastLoaded = lastLoad;
@@ -314,7 +314,7 @@ export const actions = {
314
314
 
315
315
  // load all of the default locales from the plugins for fallback
316
316
  if (locale !== DEFAULT_LOCALE) {
317
- const defaultI18nExt = rootState.$plugin?.getDynamic('l10n', DEFAULT_LOCALE);
317
+ const defaultI18nExt = rootState.$extension?.getDynamic('l10n', DEFAULT_LOCALE);
318
318
 
319
319
  if (defaultI18nExt && defaultI18nExt.length) {
320
320
  defaultI18nExt.forEach((fn) => {
package/store/index.js CHANGED
@@ -233,7 +233,7 @@ const updateActiveNamespaceCache = (state, activeNamespaceCache) => {
233
233
  * Are we in the vai enabled world where mgmt clusters are paginated?
234
234
  */
235
235
  const paginateClusters = ({ rootGetters, state }) => {
236
- return paginationUtils.isEnabled({ rootGetters, $plugin: state.$plugin }, { store: 'management', resource: { id: MANAGEMENT.CLUSTER, context: 'side-bar' } });
236
+ return paginationUtils.isEnabled({ rootGetters, $extension: state.$extension }, { store: 'management', resource: { id: MANAGEMENT.CLUSTER, context: 'side-bar' } });
237
237
  };
238
238
 
239
239
  export const state = () => {
@@ -262,6 +262,7 @@ export const state = () => {
262
262
  $router: markRaw({}),
263
263
  $route: markRaw({}),
264
264
  $plugin: markRaw({}),
265
+ $extension: markRaw({}),
265
266
  showWorkspaceSwitcher: true,
266
267
  localCluster: null,
267
268
  };
@@ -775,6 +776,7 @@ export const mutations = {
775
776
  },
776
777
 
777
778
  setPlugin(state, pluginDefinition) {
779
+ state.$extension = markRaw(pluginDefinition || {});
778
780
  state.$plugin = markRaw(pluginDefinition || {});
779
781
  },
780
782
 
@@ -1195,7 +1197,7 @@ export const actions = {
1195
1197
 
1196
1198
  store.dispatch('gcStopIntervals');
1197
1199
 
1198
- Object.values(this.$plugin.getPlugins()).forEach((p) => {
1200
+ Object.values(this.$extension.getPlugins()).forEach((p) => {
1199
1201
  if (p.onLogOut) {
1200
1202
  p.onLogOut(store);
1201
1203
  }
@@ -1254,7 +1256,7 @@ export const actions = {
1254
1256
  dashboardClientInit({ dispatch, commit, rootState }, context) {
1255
1257
  commit('setRouter', context.app.router);
1256
1258
  commit('setRoute', context.route);
1257
- commit('setPlugin', context.app.$plugin);
1259
+ commit('setPlugin', context.app.$extension);
1258
1260
 
1259
1261
  dispatch('management/rehydrateSubscribe');
1260
1262
  dispatch('cluster/rehydrateSubscribe');
package/store/type-map.js CHANGED
@@ -365,7 +365,7 @@ export function DSL(store, product, module = 'type-map') {
365
365
 
366
366
  let called = false;
367
367
 
368
- export async function applyProducts(store, $plugin) {
368
+ export async function applyProducts(store, $extension) {
369
369
  if (called) {
370
370
  return;
371
371
  }
@@ -379,7 +379,7 @@ export async function applyProducts(store, $plugin) {
379
379
  }
380
380
  }
381
381
  // Load the products from all plugins
382
- $plugin.loadProducts();
382
+ $extension.loadProducts();
383
383
  }
384
384
 
385
385
  export function productsLoaded() {
@@ -2026,7 +2026,7 @@ function hasCustom(state, rootState, kind, key, fallback) {
2026
2026
  }
2027
2027
 
2028
2028
  // Check to see if the custom kind is provided by a plugin (ignore booleans)
2029
- const pluginComponent = rootState.$plugin.getDynamic(kind, key);
2029
+ const pluginComponent = rootState.$extension.getDynamic(kind, key);
2030
2030
 
2031
2031
  if (typeof pluginComponent !== 'boolean' && !!pluginComponent) {
2032
2032
  cache[key] = true;
@@ -2046,7 +2046,7 @@ function hasCustom(state, rootState, kind, key, fallback) {
2046
2046
  }
2047
2047
 
2048
2048
  function loadExtension(rootState, kind, key, fallback) {
2049
- const ext = rootState.$plugin.getDynamic(kind, key);
2049
+ const ext = rootState.$extension.getDynamic(kind, key);
2050
2050
 
2051
2051
  if (ext) {
2052
2052
  if (typeof ext === 'function') {
@@ -3255,6 +3255,7 @@ export default class Resource {
3255
3255
  get $state(): any;
3256
3256
  get $rootState(): any;
3257
3257
  get $plugin(): any;
3258
+ get $extension(): any;
3258
3259
  get customValidationRules(): any[];
3259
3260
  get _key(): any;
3260
3261
  get schema(): any;
@@ -165,7 +165,7 @@ class PaginationUtils {
165
165
  /**
166
166
  * Is pagination enabled at a global level or for a specific resource
167
167
  */
168
- isEnabled({ rootGetters, $plugin }: any, enabledFor: PaginationResourceContext) {
168
+ isEnabled({ rootGetters, $extension }: any, enabledFor: PaginationResourceContext) {
169
169
  // Cache must be enabled to support pagination api
170
170
  if (!this.isSteveCacheEnabled({ rootGetters })) {
171
171
  return false;
@@ -184,7 +184,7 @@ class PaginationUtils {
184
184
  }
185
185
 
186
186
  // Does an extension say this type is enabled?
187
- const plugin = $plugin as ExtensionManager;
187
+ const plugin = $extension as ExtensionManager;
188
188
  const paginationExtensionPoints = plugin.getAll()[EXT_IDS.SERVER_SIDE_PAGINATION_RESOURCES];
189
189
 
190
190
  if (paginationExtensionPoints) {
@@ -69,7 +69,7 @@ class PaginationWrapper<T extends object> {
69
69
  this.classify = formatResponse?.classify || false;
70
70
  this.reactive = formatResponse?.reactive || false;
71
71
 
72
- this.isEnabled = paginationUtils.isEnabled({ rootGetters: $store.getters, $plugin: this.$store.$plugin }, enabledFor);
72
+ this.isEnabled = paginationUtils.isEnabled({ rootGetters: $store.getters, $extension: this.$store.$extension }, enabledFor);
73
73
  }
74
74
 
75
75
  async request({ pagination, forceWatch }: {
@@ -163,14 +163,14 @@ describe('pagination-utils', () => {
163
163
 
164
164
  it('should return false if steve cache is disabled', () => {
165
165
  mockRootGetters['features/get'].mockImplementation((feature: string) => feature === STEVE_CACHE ? false : undefined);
166
- const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $plugin: mockPlugin }, enabledFor);
166
+ const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $extension: mockPlugin }, enabledFor);
167
167
 
168
168
  expect(result).toBe(false);
169
169
  });
170
170
 
171
171
  it('should return false if pagination settings are not defined', () => {
172
172
  jest.spyOn(paginationUtils, 'getSettings').mockReturnValue(undefined);
173
- const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $plugin: mockPlugin }, enabledFor);
173
+ const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $extension: mockPlugin }, enabledFor);
174
174
 
175
175
  expect(result).toBe(false);
176
176
 
@@ -189,7 +189,7 @@ describe('pagination-utils', () => {
189
189
  return null;
190
190
  });
191
191
 
192
- const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $plugin: mockPlugin }, undefined as unknown as PaginationResourceContext);
192
+ const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $extension: mockPlugin }, undefined as unknown as PaginationResourceContext);
193
193
 
194
194
  expect(result).toBe(false);
195
195
  });
@@ -200,7 +200,7 @@ describe('pagination-utils', () => {
200
200
 
201
201
  mockPlugin.getAll.mockReturnValue({ [EXT_IDS.SERVER_SIDE_PAGINATION_RESOURCES]: { 'my-ext': () => extensionSettings } });
202
202
 
203
- const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $plugin: mockPlugin }, enabledFor);
203
+ const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $extension: mockPlugin }, enabledFor);
204
204
 
205
205
  expect(result).toBe(true);
206
206
  });
@@ -215,7 +215,7 @@ describe('pagination-utils', () => {
215
215
  // Mocking PAGINATION_SETTINGS_STORE_DEFAULTS behavior
216
216
  jest.spyOn(paginationUtils, 'getStoreDefault').mockReturnValue(defaultSettings);
217
217
 
218
- const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $plugin: mockPlugin }, enabledFor);
218
+ const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $extension: mockPlugin }, enabledFor);
219
219
 
220
220
  expect(result).toBe(true);
221
221
  });
@@ -235,7 +235,7 @@ describe('pagination-utils', () => {
235
235
  // Mocking PAGINATION_SETTINGS_STORE_DEFAULTS behavior
236
236
  jest.spyOn(paginationUtils, 'getStoreDefault').mockReturnValue({ cluster: { resources: { enableAll: true } } });
237
237
 
238
- const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $plugin: mockPlugin }, enabledFor);
238
+ const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $extension: mockPlugin }, enabledFor);
239
239
 
240
240
  expect(result).toBe(true);
241
241
  });
@@ -255,7 +255,7 @@ describe('pagination-utils', () => {
255
255
  return null;
256
256
  });
257
257
 
258
- const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $plugin: mockPlugin }, enabledFor);
258
+ const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $extension: mockPlugin }, enabledFor);
259
259
 
260
260
  expect(result).toBe(true);
261
261
  });
@@ -275,7 +275,7 @@ describe('pagination-utils', () => {
275
275
  return null;
276
276
  });
277
277
 
278
- const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $plugin: mockPlugin }, enabledFor);
278
+ const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $extension: mockPlugin }, enabledFor);
279
279
 
280
280
  expect(result).toBe(false);
281
281
  });
package/vue.config.js CHANGED
@@ -323,16 +323,16 @@ const getVirtualModules = (dir, includePkg) => {
323
323
 
324
324
  // Package file must have rancher field to be a plugin
325
325
  if (includePkg(name) && library.rancher) {
326
- reqs += `$plugin.registerBuiltinExtension('${ name }', require(\'~/pkg/${ name }\')); `;
326
+ reqs += `$extension.registerBuiltinExtension('${ name }', require(\'~/pkg/${ name }\')); `;
327
327
  }
328
328
  });
329
329
  }
330
330
 
331
331
  Object.keys(librariesIndex).forEach((i) => {
332
- reqs += `$plugin.loadAsync('${ i }', '/pkg/${ i }/${ librariesIndex[i] }');`;
332
+ reqs += `$extension.loadAsync('${ i }', '/pkg/${ i }/${ librariesIndex[i] }');`;
333
333
  });
334
334
 
335
- return new VirtualModulesPlugin({ 'node_modules/@rancher/dynamic.js': `export default function ($plugin) { ${ reqs } };` });
335
+ return new VirtualModulesPlugin({ 'node_modules/@rancher/dynamic.js': `export default function ($extension) { ${ reqs } };` });
336
336
  };
337
337
 
338
338
  const getAutoImport = () => new webpack.NormalModuleReplacementPlugin(/^@rancher\/auto-import$/, (resource) => {