@rancher/shell 3.0.8-rc.9 → 3.0.9-rc.1

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 (154) hide show
  1. package/apis/impl/apis.ts +61 -0
  2. package/apis/index.ts +40 -0
  3. package/apis/intf/modal.ts +128 -0
  4. package/apis/intf/shell.ts +36 -0
  5. package/apis/intf/slide-in.ts +100 -0
  6. package/apis/intf/system.ts +41 -0
  7. package/apis/shell/__tests__/modal.test.ts +80 -0
  8. package/apis/shell/__tests__/notifications.test.ts +71 -0
  9. package/apis/shell/__tests__/slide-in.test.ts +90 -0
  10. package/apis/shell/__tests__/system.test.ts +129 -0
  11. package/apis/shell/index.ts +38 -0
  12. package/apis/shell/modal.ts +41 -0
  13. package/apis/shell/notifications.ts +65 -0
  14. package/apis/shell/slide-in.ts +37 -0
  15. package/apis/shell/system.ts +65 -0
  16. package/apis/vue-shim.d.ts +11 -0
  17. package/assets/styles/global/_tooltip.scss +6 -1
  18. package/assets/translations/en-us.yaml +5 -0
  19. package/components/ActionMenuShell.vue +3 -1
  20. package/components/CruResource.vue +8 -1
  21. package/components/Drawer/ResourceDetailDrawer/__tests__/composables.test.ts +50 -1
  22. package/components/Drawer/ResourceDetailDrawer/composables.ts +19 -0
  23. package/components/Drawer/ResourceDetailDrawer/index.vue +3 -1
  24. package/components/LocaleSelector.vue +2 -2
  25. package/components/ModalManager.vue +11 -1
  26. package/components/Questions/__tests__/Yaml.test.ts +1 -1
  27. package/components/RelatedResources.vue +5 -0
  28. package/components/Resource/Detail/ResourcePopover/index.vue +5 -1
  29. package/components/ResourceDetail/Masthead/latest.vue +23 -21
  30. package/components/ResourceDetail/index.vue +3 -0
  31. package/components/ResourceTable.vue +54 -21
  32. package/components/SlideInPanelManager.vue +16 -11
  33. package/components/SortableTable/THead.vue +2 -1
  34. package/components/SortableTable/index.vue +20 -2
  35. package/components/Tabbed/index.vue +37 -2
  36. package/components/__tests__/NamespaceFilter.test.ts +49 -0
  37. package/components/auth/SelectPrincipal.vue +4 -0
  38. package/components/auth/login/ldap.vue +3 -3
  39. package/components/fleet/FleetSecretSelector.vue +1 -1
  40. package/components/form/KeyValue.vue +1 -1
  41. package/components/form/NameNsDescription.vue +1 -1
  42. package/components/form/NodeScheduling.vue +2 -2
  43. package/components/form/ResourceTabs/composable.ts +2 -2
  44. package/components/form/ResourceTabs/index.vue +0 -2
  45. package/components/form/__tests__/NameNsDescription.test.ts +42 -0
  46. package/components/formatter/LinkName.vue +5 -0
  47. package/components/nav/Group.vue +25 -7
  48. package/components/nav/Header.vue +1 -1
  49. package/components/nav/NamespaceFilter.vue +1 -0
  50. package/components/nav/Type.vue +17 -6
  51. package/components/nav/WindowManager/panels/TabBodyContainer.vue +1 -1
  52. package/components/nav/__tests__/Type.test.ts +59 -0
  53. package/composables/cruResource.ts +27 -0
  54. package/composables/focusTrap.ts +3 -1
  55. package/composables/resourceDetail.ts +15 -0
  56. package/composables/useLabeledFormElement.ts +3 -4
  57. package/config/product/fleet.js +1 -1
  58. package/config/router/navigation-guards/clusters.js +3 -3
  59. package/config/router/navigation-guards/products.js +1 -1
  60. package/config/router/routes.js +1 -5
  61. package/core/__tests__/extension-manager-impl.test.js +437 -0
  62. package/core/extension-manager-impl.js +6 -27
  63. package/core/plugin-helpers.ts +2 -2
  64. package/core/plugin.ts +9 -1
  65. package/core/plugins-loader.js +2 -2
  66. package/core/types-provisioning.ts +4 -0
  67. package/core/types.ts +35 -0
  68. package/detail/catalog.cattle.io.app.vue +1 -0
  69. package/detail/provisioning.cattle.io.cluster.vue +8 -6
  70. package/dialog/DeveloperLoadExtensionDialog.vue +1 -1
  71. package/dialog/MoveNamespaceDialog.vue +20 -4
  72. package/dialog/SearchDialog.vue +1 -0
  73. package/dialog/__tests__/MoveNamespaceDialog.test.ts +249 -0
  74. package/directives/__tests__/clean-tooltip.test.ts +298 -0
  75. package/directives/clean-tooltip.ts +234 -0
  76. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +2 -2
  77. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +98 -1
  78. package/edit/fleet.cattle.io.helmop.vue +5 -0
  79. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +21 -21
  80. package/edit/provisioning.cattle.io.cluster/index.vue +5 -5
  81. package/edit/provisioning.cattle.io.cluster/rke2.vue +8 -8
  82. package/edit/resources.cattle.io.restore.vue +1 -1
  83. package/edit/workload/Job.vue +2 -2
  84. package/edit/workload/__tests__/index.test.ts +123 -85
  85. package/edit/workload/index.vue +2 -2
  86. package/edit/workload/mixins/workload.js +19 -1
  87. package/initialize/install-plugins.js +4 -5
  88. package/machine-config/azure.vue +1 -1
  89. package/machine-config/components/GCEImage.vue +1 -1
  90. package/mixins/__tests__/brand.spec.ts +18 -13
  91. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +16 -0
  92. package/models/chart.js +70 -74
  93. package/models/management.cattle.io.cluster.js +1 -1
  94. package/models/provisioning.cattle.io.cluster.js +11 -3
  95. package/package.json +7 -7
  96. package/pages/auth/login.vue +3 -3
  97. package/pages/auth/setup.vue +1 -1
  98. package/pages/auth/verify.vue +3 -3
  99. package/pages/c/_cluster/apps/charts/index.vue +122 -24
  100. package/pages/c/_cluster/apps/charts/install.vue +33 -0
  101. package/pages/c/_cluster/explorer/__tests__/index.test.ts +1 -1
  102. package/pages/c/_cluster/fleet/index.vue +7 -10
  103. package/pages/c/_cluster/settings/index.vue +5 -0
  104. package/pkg/auto-import.js +3 -3
  105. package/pkg/dynamic-importer.lib.js +1 -1
  106. package/pkg/import.js +1 -1
  107. package/plugins/__tests__/mutations.tests.ts +179 -0
  108. package/plugins/dashboard-store/getters.js +1 -1
  109. package/plugins/dashboard-store/model-loader.js +1 -1
  110. package/plugins/dashboard-store/mutations.js +23 -2
  111. package/plugins/dashboard-store/resource-class.js +8 -3
  112. package/plugins/plugin.js +2 -2
  113. package/plugins/steve/__tests__/steve-pagination-utils.test.ts +301 -128
  114. package/plugins/steve/mutations.js +9 -0
  115. package/plugins/steve/steve-class.js +1 -1
  116. package/plugins/steve/steve-pagination-utils.ts +108 -43
  117. package/plugins/steve/subscribe.js +23 -2
  118. package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
  119. package/rancher-components/Form/LabeledInput/LabeledInput.vue +1 -1
  120. package/rancher-components/RcDropdown/useDropdownContext.ts +2 -4
  121. package/rancher-components/RcItemCard/RcItemCard.vue +1 -1
  122. package/scripts/publish-shell.sh +25 -0
  123. package/store/__tests__/catalog.test.ts +1 -1
  124. package/store/__tests__/type-map.test.ts +164 -2
  125. package/store/auth.js +23 -11
  126. package/store/i18n.js +3 -3
  127. package/store/index.js +5 -3
  128. package/store/notifications.ts +2 -0
  129. package/store/prefs.js +2 -2
  130. package/store/type-map.js +17 -7
  131. package/types/internal-api/shell/modal.d.ts +6 -6
  132. package/types/notifications/index.ts +126 -15
  133. package/types/rancher/index.d.ts +9 -0
  134. package/types/shell/index.d.ts +16 -1
  135. package/types/store/dashboard-store.types.ts +29 -7
  136. package/types/vue-shim.d.ts +5 -4
  137. package/utils/__tests__/router.test.js +238 -0
  138. package/utils/cluster.js +4 -1
  139. package/utils/cspAdaptor.ts +32 -14
  140. package/utils/fleet.ts +8 -1
  141. package/utils/pagination-utils.ts +2 -2
  142. package/utils/pagination-wrapper.ts +4 -4
  143. package/utils/router.js +50 -0
  144. package/utils/unit-tests/pagination-utils.spec.ts +8 -8
  145. package/vue.config.js +3 -3
  146. package/composables/useExtensionManager.ts +0 -17
  147. package/core/__test__/extension-manager-impl.test.js +0 -236
  148. package/core/plugins.js +0 -38
  149. package/directives/clean-tooltip.js +0 -32
  150. package/plugins/internal-api/index.ts +0 -37
  151. package/plugins/internal-api/shared/base-api.ts +0 -13
  152. package/plugins/internal-api/shell/shell.api.ts +0 -108
  153. package/types/internal-api/shell/growl.d.ts +0 -25
  154. package/types/internal-api/shell/slideIn.d.ts +0 -15
@@ -0,0 +1,238 @@
1
+ import { findRouteDefinitionByName, filterLocationValidParams } from '@shell/utils/router';
2
+
3
+ describe('findRouteDefinitionByName', () => {
4
+ const createMockRouter = (routes) => ({ getRoutes: () => routes });
5
+
6
+ it('should find a route by its name', () => {
7
+ const routes = [
8
+ { name: 'home', path: '/' },
9
+ { name: 'about', path: '/about' },
10
+ { name: 'c-cluster', path: '/c/:cluster' },
11
+ ];
12
+ const router = createMockRouter(routes);
13
+
14
+ const result = findRouteDefinitionByName(router, 'about');
15
+
16
+ expect(result).toStrictEqual({ name: 'about', path: '/about' });
17
+ });
18
+
19
+ it('should return the first matching route when name exists', () => {
20
+ const routes = [
21
+ { name: 'c-cluster-explorer', path: '/c/:cluster/explorer' },
22
+ { name: 'c-cluster-apps', path: '/c/:cluster/apps' },
23
+ ];
24
+ const router = createMockRouter(routes);
25
+
26
+ const result = findRouteDefinitionByName(router, 'c-cluster-explorer');
27
+
28
+ expect(result).toStrictEqual({ name: 'c-cluster-explorer', path: '/c/:cluster/explorer' });
29
+ });
30
+
31
+ it('should return undefined when route name is not found', () => {
32
+ const routes = [
33
+ { name: 'home', path: '/' },
34
+ { name: 'about', path: '/about' },
35
+ ];
36
+ const router = createMockRouter(routes);
37
+
38
+ const result = findRouteDefinitionByName(router, 'nonexistent');
39
+
40
+ expect(result).toBeUndefined();
41
+ });
42
+
43
+ it('should return undefined when routes array is empty', () => {
44
+ const router = createMockRouter([]);
45
+
46
+ const result = findRouteDefinitionByName(router, 'any-route');
47
+
48
+ expect(result).toBeUndefined();
49
+ });
50
+
51
+ it('should handle routes with additional properties', () => {
52
+ const routes = [
53
+ {
54
+ name: 'c-cluster-product-resource',
55
+ path: '/c/:cluster/:product/:resource',
56
+ meta: { requiresAuthentication: true },
57
+ props: true,
58
+ },
59
+ ];
60
+ const router = createMockRouter(routes);
61
+
62
+ const result = findRouteDefinitionByName(router, 'c-cluster-product-resource');
63
+
64
+ expect(result).toStrictEqual(routes[0]);
65
+ });
66
+
67
+ it('should match exact route names only', () => {
68
+ const routes = [
69
+ { name: 'c-cluster', path: '/c/:cluster' },
70
+ { name: 'c-cluster-explorer', path: '/c/:cluster/explorer' },
71
+ ];
72
+ const router = createMockRouter(routes);
73
+
74
+ const result = findRouteDefinitionByName(router, 'c-cluster');
75
+
76
+ expect(result).toStrictEqual({ name: 'c-cluster', path: '/c/:cluster' });
77
+ expect(result.name).not.toBe('c-cluster-explorer');
78
+ });
79
+ });
80
+
81
+ describe('filterLocationValidParams', () => {
82
+ const createMockRouter = (routes) => ({ getRoutes: () => routes });
83
+
84
+ it('should filter out params not in route path', () => {
85
+ const routes = [
86
+ { name: 'c-cluster', path: '/c/:cluster' },
87
+ ];
88
+ const router = createMockRouter(routes);
89
+ const routeRecord = {
90
+ name: 'c-cluster',
91
+ params: {
92
+ cluster: 'local',
93
+ product: 'explorer',
94
+ },
95
+ };
96
+
97
+ const result = filterLocationValidParams(router, routeRecord);
98
+
99
+ expect(result.params).toStrictEqual({ cluster: 'local' });
100
+ expect(result.params.product).toBeUndefined();
101
+ });
102
+
103
+ it('should keep all params when all are valid', () => {
104
+ const routes = [
105
+ { name: 'c-cluster-product-resource', path: '/c/:cluster/:product/:resource' },
106
+ ];
107
+ const router = createMockRouter(routes);
108
+ const routeRecord = {
109
+ name: 'c-cluster-product-resource',
110
+ params: {
111
+ cluster: 'local',
112
+ product: 'explorer',
113
+ resource: 'pods',
114
+ },
115
+ };
116
+
117
+ const result = filterLocationValidParams(router, routeRecord);
118
+
119
+ expect(result.params).toStrictEqual({
120
+ cluster: 'local',
121
+ product: 'explorer',
122
+ resource: 'pods',
123
+ });
124
+ });
125
+
126
+ it('should preserve other properties on routeRecord', () => {
127
+ const routes = [
128
+ { name: 'c-cluster', path: '/c/:cluster' },
129
+ ];
130
+ const router = createMockRouter(routes);
131
+ const routeRecord = {
132
+ name: 'c-cluster',
133
+ params: { cluster: 'local' },
134
+ query: { mode: 'edit' },
135
+ hash: '#section',
136
+ };
137
+
138
+ const result = filterLocationValidParams(router, routeRecord);
139
+
140
+ expect(result.query).toStrictEqual({ mode: 'edit' });
141
+ expect(result.hash).toBe('#section');
142
+ expect(result.name).toBe('c-cluster');
143
+ });
144
+
145
+ it('should return routeRecord unchanged when routeRecord is null', () => {
146
+ const router = createMockRouter([]);
147
+
148
+ const result = filterLocationValidParams(router, null);
149
+
150
+ expect(result).toBeNull();
151
+ });
152
+
153
+ it('should return routeRecord unchanged when routeRecord is undefined', () => {
154
+ const router = createMockRouter([]);
155
+
156
+ const result = filterLocationValidParams(router, undefined);
157
+
158
+ expect(result).toBeUndefined();
159
+ });
160
+
161
+ it('should return routeRecord unchanged when name is missing', () => {
162
+ const router = createMockRouter([]);
163
+ const routeRecord = { params: { cluster: 'local' } };
164
+
165
+ const result = filterLocationValidParams(router, routeRecord);
166
+
167
+ expect(result).toStrictEqual(routeRecord);
168
+ });
169
+
170
+ it('should return routeRecord unchanged when params is missing', () => {
171
+ const router = createMockRouter([]);
172
+ const routeRecord = { name: 'c-cluster' };
173
+
174
+ const result = filterLocationValidParams(router, routeRecord);
175
+
176
+ expect(result).toStrictEqual(routeRecord);
177
+ });
178
+
179
+ it('should return routeRecord unchanged when route definition is not found', () => {
180
+ const routes = [
181
+ { name: 'home', path: '/' },
182
+ ];
183
+ const router = createMockRouter(routes);
184
+ const routeRecord = {
185
+ name: 'nonexistent-route',
186
+ params: { cluster: 'local' },
187
+ };
188
+
189
+ const result = filterLocationValidParams(router, routeRecord);
190
+
191
+ expect(result).toStrictEqual(routeRecord);
192
+ });
193
+
194
+ it('should return empty params when no params are valid', () => {
195
+ const routes = [
196
+ { name: 'home', path: '/' },
197
+ ];
198
+ const router = createMockRouter(routes);
199
+ const routeRecord = {
200
+ name: 'home',
201
+ params: {
202
+ cluster: 'local',
203
+ product: 'explorer',
204
+ },
205
+ };
206
+
207
+ const result = filterLocationValidParams(router, routeRecord);
208
+
209
+ expect(result.params).toStrictEqual({});
210
+ });
211
+
212
+ it('should handle optional params in path', () => {
213
+ const routes = [
214
+ { name: 'c-cluster-product-resource-id', path: '/c/:cluster/:product/:resource/:id?' },
215
+ ];
216
+ const router = createMockRouter(routes);
217
+ const routeRecord = {
218
+ name: 'c-cluster-product-resource-id',
219
+ params: {
220
+ cluster: 'local',
221
+ product: 'explorer',
222
+ resource: 'pods',
223
+ id: 'my-pod',
224
+ extra: 'should-be-removed',
225
+ },
226
+ };
227
+
228
+ const result = filterLocationValidParams(router, routeRecord);
229
+
230
+ expect(result.params).toStrictEqual({
231
+ cluster: 'local',
232
+ product: 'explorer',
233
+ resource: 'pods',
234
+ id: 'my-pod',
235
+ });
236
+ expect(result.params.extra).toBeUndefined();
237
+ });
238
+ });
package/utils/cluster.js CHANGED
@@ -242,7 +242,7 @@ export function filterOutDeprecatedPatchVersions(allVersions, currentVersion) {
242
242
  return filteredVersions;
243
243
  }
244
244
 
245
- export function getAllOptionsAfterCurrentVersion(store, versions, currentVersion, defaultVersion) {
245
+ export function getAllOptionsAfterCurrentVersion(store, versions, currentVersion, defaultVersion, manual = false) {
246
246
  const out = (versions || []).filter((obj) => !!obj.serverArgs).map((obj) => {
247
247
  let disabled = false;
248
248
  let experimental = false;
@@ -260,6 +260,9 @@ export function getAllOptionsAfterCurrentVersion(store, versions, currentVersion
260
260
 
261
261
  if (isCurrentVersion) {
262
262
  label = `${ label } ${ store.getters['i18n/t']('cluster.kubernetesVersion.current') }`;
263
+ if (manual) {
264
+ label = `${ label } ${ store.getters['i18n/t']('cluster.kubernetesVersion.manual') }`;
265
+ }
263
266
  }
264
267
 
265
268
  if (experimental) {
@@ -1,12 +1,13 @@
1
1
  // For testing these could be changed to something like...
2
2
 
3
3
  import { CATALOG } from '@shell/config/types';
4
+ import { ActionFindPageArgs, ActionFindPageTransientResponse } from '@shell/types/store/dashboard-store.types';
4
5
  import { FilterArgs, PaginationFilterField, PaginationParamFilter } from '@shell/types/store/pagination.types';
5
6
  import { VuexStore } from '@shell/types/store/vuex';
6
7
 
7
8
  const CSP_ADAPTER_APPS = ['rancher-csp-adapter', 'rancher-csp-billing-adapter'];
8
9
  // For testing above line could be replaced with below line...
9
- // const cspAdaptorApp = ['rancher-webhooka', 'rancher-webhook'];
10
+ // const CSP_ADAPTER_APPS = ['rancher-webhooka', 'rancher-webhook'];
10
11
 
11
12
  /**
12
13
  * Helpers in order to
@@ -16,27 +17,44 @@ class CspAdapterUtils {
16
17
  return $store.getters[`management/paginationEnabled`]({ id: CATALOG.APP, context: 'branding' });
17
18
  }
18
19
 
19
- static fetchCspAdaptorApp($store: VuexStore): Promise<any> {
20
+ private static apps?: any[] = undefined;
21
+ public static resetState() {
22
+ this.apps = undefined;
23
+ }
24
+
25
+ static async fetchCspAdaptorApp($store: VuexStore): Promise<any> {
26
+ if (this.apps) {
27
+ return this.apps;
28
+ }
29
+
20
30
  // For the login page, the schemas won't be loaded - we don't need the apps in this case
21
31
  if ($store.getters['management/canList'](CATALOG.APP)) {
22
32
  if (CspAdapterUtils.canPagination($store)) {
23
33
  // Restrict the amount of apps we need to fetch
24
- return $store.dispatch('management/findPage', {
34
+ const opt: ActionFindPageArgs = {
35
+ pagination: new FilterArgs({
36
+ filters: PaginationParamFilter.createMultipleFields(CSP_ADAPTER_APPS.map(
37
+ (t) => new PaginationFilterField({
38
+ field: 'metadata.name',
39
+ value: t,
40
+ })
41
+ )),
42
+ }),
43
+ watch: false,
44
+ transient: true
45
+ };
46
+
47
+ const resp: ActionFindPageTransientResponse = await $store.dispatch('management/findPage', {
25
48
  type: CATALOG.APP,
26
- opt: { // Of type ActionFindPageArgs
27
- pagination: new FilterArgs({
28
- filters: PaginationParamFilter.createMultipleFields(CSP_ADAPTER_APPS.map(
29
- (t) => new PaginationFilterField({
30
- field: 'metadata.name',
31
- value: t,
32
- })
33
- )),
34
- })
35
- }
49
+ opt
36
50
  });
51
+
52
+ this.apps = resp.data;
53
+ } else {
54
+ this.apps = await $store.dispatch('management/findAll', { type: CATALOG.APP });
37
55
  }
38
56
 
39
- return $store.dispatch('management/findAll', { type: CATALOG.APP });
57
+ return this.apps;
40
58
  }
41
59
 
42
60
  return Promise.resolve([]);
package/utils/fleet.ts CHANGED
@@ -184,7 +184,7 @@ class Fleet {
184
184
  }
185
185
 
186
186
  detailLocation(r: Resource, mgmtClusterName: string): any {
187
- return mapStateToEnum(r.state) === STATES_ENUM.MISSING ? undefined : {
187
+ const location = mapStateToEnum(r.state) === STATES_ENUM.MISSING ? undefined : {
188
188
  name: `c-cluster-product-resource${ r.namespace ? '-namespace' : '' }-id`,
189
189
  params: {
190
190
  product: EXPLORER_NAME,
@@ -194,6 +194,13 @@ class Fleet {
194
194
  id: r.name,
195
195
  },
196
196
  };
197
+
198
+ // Having an undefined param can yield a console warning like [Vue Router warn]: Discarded invalid param(s) "namespace" when navigating
199
+ if (location && !location.params.namespace) {
200
+ delete location.params.namespace;
201
+ }
202
+
203
+ return location;
197
204
  }
198
205
 
199
206
  /**
@@ -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) {
@@ -1,7 +1,7 @@
1
1
  import paginationUtils from '@shell/utils/pagination-utils';
2
2
  import { PaginationArgs, PaginationResourceContext } from '@shell/types/store/pagination.types';
3
3
  import { VuexStore } from '@shell/types/store/vuex';
4
- import { ActionFindPageArgs, ActionFindPageTransientResult } from '@shell/types/store/dashboard-store.types';
4
+ import { ActionFindPageArgs, ActionFindPageTransientResponse } from '@shell/types/store/dashboard-store.types';
5
5
  import { STEVE_WATCH_EVENT_TYPES, STEVE_WATCH_MODE } from '@shell/types/store/subscribe.types';
6
6
  import { Reactive, reactive } from 'vue';
7
7
  import { STEVE_UNWATCH_EVENT_PARAMS, STEVE_WATCH_EVENT_LISTENER_CALLBACK, STEVE_WATCH_EVENT_PARAMS, STEVE_WATCH_EVENT_PARAMS_COMMON } from '@shell/types/store/subscribe-events.types';
@@ -30,7 +30,7 @@ interface Args {
30
30
  }
31
31
  }
32
32
 
33
- interface Result<T> extends Omit<ActionFindPageTransientResult<T>, 'data'> {
33
+ interface Result<T> extends Omit<ActionFindPageTransientResponse<T>, 'data'> {
34
34
  data: Reactive<T[]>
35
35
  }
36
36
 
@@ -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 }: {
@@ -86,7 +86,7 @@ class PaginationWrapper<T extends object> {
86
86
  };
87
87
 
88
88
  // Fetch
89
- const out: ActionFindPageTransientResult<T> = await this.$store.dispatch(`${ this.enabledFor.store }/findPage`, { opt, type: this.enabledFor.resource?.id });
89
+ const out: ActionFindPageTransientResponse<T> = await this.$store.dispatch(`${ this.enabledFor.store }/findPage`, { opt, type: this.enabledFor.resource?.id });
90
90
 
91
91
  // Watch
92
92
  const firstTime = !this.steveWatchParams;
package/utils/router.js CHANGED
@@ -117,3 +117,53 @@ export function findMeta(route, key) {
117
117
 
118
118
  return undefined;
119
119
  }
120
+
121
+ /**
122
+ * Find a route definition given a routeName
123
+ * @param {*} router VueRouter instance
124
+ * @param {*} routeName the name we want to look up
125
+ * @returns the route definition or undefined if it wasn't found
126
+ */
127
+ export function findRouteDefinitionByName(router, routeName) {
128
+ const routes = router.getRoutes();
129
+
130
+ return routes.find((r) => r.name === routeName);
131
+ }
132
+
133
+ /**
134
+ * Looks for the route definition and then ensures there's only valid params
135
+ * @param {*} router VueRouter instance
136
+ * @param {*} routeRecord an object conforming to the Route Record interface
137
+ * @returns the passed in routeLocation with only valid params.
138
+ */
139
+ export function filterLocationValidParams(router, routeRecord) {
140
+ if (!routeRecord || !routeRecord.name || !routeRecord.params) {
141
+ console.warn('filterLocationValidParams received invalid arguments'); // eslint-disable-line no-console
142
+
143
+ return routeRecord;
144
+ }
145
+
146
+ const routeDefinition = findRouteDefinitionByName(router, routeRecord.name);
147
+
148
+ if (!routeDefinition) {
149
+ console.warn('Could not find a route definition given the routeRecord', routeRecord); // eslint-disable-line no-console
150
+
151
+ return routeRecord;
152
+ }
153
+
154
+ const specifiedParams = routeRecord.params;
155
+ const validParams = {};
156
+
157
+ Object.entries(specifiedParams).forEach(([key, value]) => {
158
+ const pathParam = `:${ key }`;
159
+
160
+ if (routeDefinition.path.includes(pathParam)) {
161
+ validParams[key] = value;
162
+ }
163
+ });
164
+
165
+ return {
166
+ ...routeRecord,
167
+ params: validParams
168
+ };
169
+ }
@@ -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) => {
@@ -1,17 +0,0 @@
1
- import { ExtensionManager } from '@shell/types/extension-manager';
2
- import { getExtensionManager } from '@shell/core/extension-manager-impl';
3
-
4
- /**
5
- * Provides access to the registered extension manager instance. Used within Vue
6
- * components or other composables that require extension functionality.
7
- * @returns The extension manager instance
8
- */
9
- export const useExtensionManager = (): ExtensionManager => {
10
- const extension = getExtensionManager();
11
-
12
- if (!extension) {
13
- throw new Error('useExtensionManager must be called after the extensionManager has been initialized');
14
- }
15
-
16
- return extension;
17
- };