@rancher/shell 3.0.12-rc.5 → 3.0.12-rc.6
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/apis/intf/resources-api/resource-base.ts +42 -2
- package/apis/intf/resources-api/resource-instance.ts +101 -0
- package/apis/intf/resources-api/resources-api.ts +177 -23
- package/apis/intf/resources.ts +8 -6
- package/apis/resources/__tests__/resources-api-class.test.ts +309 -28
- package/apis/resources/resources-api-class.ts +232 -43
- package/assets/images/providers/traefik.png +0 -0
- package/assets/translations/en-us.yaml +10 -4
- package/chart/__tests__/rancher-monitoring-dashboards-index.test.ts +269 -0
- package/chart/rancher-monitoring-dashboards/index.vue +155 -0
- package/cloud-credential/__tests__/generic.test.ts +132 -0
- package/cloud-credential/generic.vue +33 -3
- package/components/EtcdInfoBanner.vue +2 -12
- package/components/GrafanaDashboard.vue +2 -8
- package/components/Resource/Detail/Masthead/__tests__/index.test.ts +68 -14
- package/components/Resource/Detail/Masthead/index.vue +8 -3
- package/components/form/Security.vue +1 -1
- package/components/formatter/Translate.vue +22 -1
- package/components/nav/Group.vue +5 -10
- package/components/nav/TopLevelMenu.vue +1 -30
- package/components/nav/__tests__/Group.test.ts +61 -0
- package/config/labels-annotations.js +1 -0
- package/config/table-headers.js +5 -2
- package/core/__tests__/plugin-products-apply.test.ts +787 -0
- package/core/__tests__/plugin-products-extend.test.ts +189 -0
- package/core/__tests__/plugin-products-helpers.test.ts +81 -78
- package/core/__tests__/plugin-products-new.test.ts +389 -0
- package/core/__tests__/plugin-products-scenarios.test.ts +980 -0
- package/core/__tests__/plugin-products-side-menu.test.ts +1935 -0
- package/core/plugin-products-base.ts +201 -93
- package/core/plugin-products-extending.ts +1 -1
- package/core/plugin-products-external.ts +380 -0
- package/core/plugin-products-helpers.ts +28 -24
- package/core/plugin-products-internal.ts +207 -0
- package/core/plugin-products-top-level.ts +10 -5
- package/core/plugin-products-type-guards.ts +17 -6
- package/core/plugin-products.ts +5 -7
- package/core/plugin-types.ts +1 -389
- package/core/plugin.ts +10 -11
- package/core/types.ts +6 -202
- package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +52 -0
- package/detail/pod.vue +1 -1
- package/detail/provisioning.cattle.io.cluster.vue +0 -2
- package/edit/auth/AuthProviderWarningBanners.vue +12 -0
- package/edit/auth/__tests__/AuthProviderWarningBanners.test.ts +10 -1
- package/edit/auth/__tests__/azuread.test.ts +1 -0
- package/edit/auth/__tests__/github.test.ts +1 -0
- package/edit/auth/__tests__/oidc.test.ts +1 -0
- package/edit/auth/__tests__/saml.test.ts +1 -0
- package/edit/auth/ldap/__tests__/index.test.ts +1 -0
- package/edit/provisioning.cattle.io.cluster/index.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/rke2.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +2 -2
- package/list/management.cattle.io.user.vue +24 -5
- package/list/utils/management.cattle.io.cluster.utils.ts +1 -1
- package/machine-config/__tests__/generic.test.ts +163 -0
- package/machine-config/components/EC2Networking.vue +31 -7
- package/machine-config/components/__tests__/EC2Networking.test.ts +38 -15
- package/machine-config/generic.vue +32 -5
- package/mixins/resource-fetch.js +1 -1
- package/models/__tests__/rke-machine.cattle.io.vmwarevspheremachinetemplate.test.ts +22 -0
- package/models/pod.js +12 -10
- package/models/rke-machine.cattle.io.vmwarevspheremachinetemplate.js +9 -0
- package/package.json +1 -1
- package/pages/auth/login.vue +1 -1
- package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +110 -0
- package/pages/c/_cluster/apps/charts/install.vue +29 -0
- package/pages/c/_cluster/auth/config/index.vue +11 -4
- package/pages/c/_cluster/monitoring/index.vue +6 -1
- package/plugins/dashboard-store/resource-class.js +10 -3
- package/plugins/steve/__tests__/steve-class-resource-api.test.ts +147 -0
- package/plugins/steve/steve-class.js +43 -0
- package/plugins/steve/subscribe.js +11 -0
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +115 -0
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +83 -3
- package/store/__tests__/auth.test.ts +18 -0
- package/store/__tests__/notifications.test.ts +466 -1
- package/store/__tests__/ui-context.test.ts +255 -0
- package/store/auth.js +11 -1
- package/store/features.js +1 -0
- package/store/plugins.js +6 -0
- package/types/rancher/steve.api.ts +2 -2
- package/types/shell/index.d.ts +58 -0
- package/types/store/dashboard-store.types.ts +2 -2
- package/types/store/type-map.ts +262 -1
- package/utils/async.ts +2 -0
- package/utils/grafana.js +2 -17
- package/utils/monitoring.js +38 -1
- package/core/__tests__/plugin-products.test.ts +0 -4694
|
@@ -1,10 +1,4 @@
|
|
|
1
1
|
import { IExtension } from '@shell/core/types';
|
|
2
|
-
import {
|
|
3
|
-
ProductChild, ProductMetadata,
|
|
4
|
-
ResourcePageConfiguration, CustomPageConfiguration,
|
|
5
|
-
ProductChildCustomPage, VueRouteComponent,
|
|
6
|
-
OverviewPageRoutingMetadata
|
|
7
|
-
} from '@shell/core/plugin-types';
|
|
8
2
|
import EmptyProductPage from '@shell/components/EmptyProductPage.vue';
|
|
9
3
|
import pluginProductsHelpers from '@shell/core/plugin-products-helpers';
|
|
10
4
|
import {
|
|
@@ -13,7 +7,36 @@ import {
|
|
|
13
7
|
isProductChildWithType,
|
|
14
8
|
hasNameProperty,
|
|
15
9
|
hasTypeProperty,
|
|
10
|
+
isProductConfigInternal,
|
|
16
11
|
} from '@shell/core/plugin-products-type-guards';
|
|
12
|
+
import {
|
|
13
|
+
ProductChild, ProductChildCustomPage, ProductChildGroup, ProductChildResourcePage, ProductMetadata, ProductMetadataSinglePage
|
|
14
|
+
} from '@shell/core/plugin-products-external';
|
|
15
|
+
import { TypeMapConfigureType, TypeMapProduct, TypeMapVirtualType } from '@shell/types/store/type-map';
|
|
16
|
+
import { ProductChildCustomPageInternal, ProductChildResourcePageInternal, ProductMetadataInternal } from '@shell/core/plugin-products-internal';
|
|
17
|
+
import { RouteRecordRaw } from 'vue-router';
|
|
18
|
+
import { RouteRecordRawWithParams } from '@shell/core/plugin-types';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* What's the point of this?
|
|
22
|
+
*
|
|
23
|
+
* Example
|
|
24
|
+
* `applyIfDefined(this.product?.label, () => typeMapProduct.label = this.product?.label); `
|
|
25
|
+
*
|
|
26
|
+
* If the property is defined we apply it to the object
|
|
27
|
+
* - this avoids verbose objects filled with `: undefined` (which fail unit tests)
|
|
28
|
+
* - { a: undefined, b: undefined, c: true} vs { c: true}
|
|
29
|
+
*
|
|
30
|
+
* Caller supplied direct object.property values
|
|
31
|
+
* - this ensure any further refactoring can happen automatically
|
|
32
|
+
* - type failures are very visible
|
|
33
|
+
* - both above would be lost if we had this as a cleaner but generic function(obj, targetPathString, targetValue)
|
|
34
|
+
*/
|
|
35
|
+
const applyIfDefined = function(value: any, apply: () => void) {
|
|
36
|
+
if (value !== undefined) {
|
|
37
|
+
apply();
|
|
38
|
+
}
|
|
39
|
+
};
|
|
17
40
|
|
|
18
41
|
/**
|
|
19
42
|
* Base class for product registration in extensions
|
|
@@ -22,7 +45,7 @@ import {
|
|
|
22
45
|
export abstract class BasePluginProduct {
|
|
23
46
|
protected name!: string;
|
|
24
47
|
|
|
25
|
-
protected product?: ProductMetadata;
|
|
48
|
+
protected product?: ProductMetadata | ProductMetadataSinglePage;
|
|
26
49
|
|
|
27
50
|
protected addedResourceRoutes = false;
|
|
28
51
|
|
|
@@ -86,13 +109,6 @@ export abstract class BasePluginProduct {
|
|
|
86
109
|
}
|
|
87
110
|
}
|
|
88
111
|
|
|
89
|
-
/**
|
|
90
|
-
* Generates data for group overview page routing
|
|
91
|
-
*/
|
|
92
|
-
protected generateMetadataForGroupOverviewPageRouting(name: string, component: VueRouteComponent): OverviewPageRoutingMetadata {
|
|
93
|
-
return { name, component };
|
|
94
|
-
}
|
|
95
|
-
|
|
96
112
|
/**
|
|
97
113
|
* This is where we register the product and its children via the DSL
|
|
98
114
|
*/
|
|
@@ -143,20 +159,18 @@ export abstract class BasePluginProduct {
|
|
|
143
159
|
return;
|
|
144
160
|
}
|
|
145
161
|
|
|
146
|
-
const itemGroup = item;
|
|
162
|
+
const itemGroup = item as ProductChildGroup;
|
|
147
163
|
const groupName = parentGroupName ? `${ productName }-${ parentGroupName }-${ itemGroup.name }` : `${ productName }-${ itemGroup.name }`;
|
|
148
164
|
|
|
149
165
|
// Map the user's friendly group name to the resolved internal name
|
|
150
166
|
// so that moveToGroup can translate friendly names automatically
|
|
151
167
|
this.groupNameMap.set(itemGroup.name, groupName);
|
|
152
168
|
|
|
153
|
-
if (!Array.isArray(itemGroup.children)) {
|
|
169
|
+
if (!Array.isArray(itemGroup.sideMenu.children)) {
|
|
154
170
|
this.surfaceError('Children defined for group are not in an array format');
|
|
155
|
-
|
|
156
|
-
return;
|
|
157
171
|
}
|
|
158
172
|
|
|
159
|
-
const navNames = this.getIDsForGroupsOrBasicTypes(groupName, itemGroup.children);
|
|
173
|
+
const navNames = this.getIDsForGroupsOrBasicTypes(groupName, itemGroup.sideMenu.children);
|
|
160
174
|
|
|
161
175
|
// Build the full hierarchical path with :: separators for the store's _ensureGroup function
|
|
162
176
|
// For example: "explorer-root::explorer-root-group1" tells the store to nest group1 inside root
|
|
@@ -175,7 +189,7 @@ export abstract class BasePluginProduct {
|
|
|
175
189
|
basicType(navNames, hierarchicalPath);
|
|
176
190
|
|
|
177
191
|
// register virtualTypes/configureTypes for each child item
|
|
178
|
-
itemGroup.children.forEach((subItem: ProductChild) => {
|
|
192
|
+
itemGroup.sideMenu.children.forEach((subItem: ProductChild) => {
|
|
179
193
|
const currentGroupName = parentGroupName ? `${ parentGroupName }-${ itemGroup.name }` : itemGroup.name;
|
|
180
194
|
|
|
181
195
|
this.configurePageItem(productName, subItem, currentGroupName);
|
|
@@ -196,8 +210,8 @@ export abstract class BasePluginProduct {
|
|
|
196
210
|
}
|
|
197
211
|
|
|
198
212
|
// group weight
|
|
199
|
-
if (itemGroup.weight) {
|
|
200
|
-
weightGroup(groupName, itemGroup.weight, true);
|
|
213
|
+
if (itemGroup.sideMenu?.weight) {
|
|
214
|
+
weightGroup(groupName, itemGroup.sideMenu?.weight, true);
|
|
201
215
|
}
|
|
202
216
|
|
|
203
217
|
// group label
|
|
@@ -221,31 +235,50 @@ export abstract class BasePluginProduct {
|
|
|
221
235
|
const firstConfig = this.config[0];
|
|
222
236
|
|
|
223
237
|
if (isProductChildGroup(firstConfig)) {
|
|
238
|
+
const config = firstConfig as ProductChildGroup;
|
|
239
|
+
|
|
224
240
|
// First config item is a group
|
|
225
|
-
if (
|
|
226
|
-
const entryChild =
|
|
241
|
+
if (config.sideMenu.children.length > 0) {
|
|
242
|
+
const entryChild = config.sideMenu.children[0];
|
|
227
243
|
|
|
228
|
-
if (!
|
|
244
|
+
if (!config.component) {
|
|
229
245
|
// Group without component - route to first child
|
|
230
246
|
if (isProductChildWithType(entryChild)) {
|
|
231
|
-
|
|
247
|
+
const entry = entryChild as ProductChildResourcePage;
|
|
248
|
+
|
|
249
|
+
defaultRoute = pluginProductsHelpers.generateConfigureTypeRoute(this.name, entry, { omitPath: true, extendProduct: !this.isNewProduct });
|
|
232
250
|
} else if (isProductChildWithComponent(entryChild)) {
|
|
233
|
-
|
|
251
|
+
const entry = entryChild as ProductChildCustomPage;
|
|
252
|
+
|
|
253
|
+
defaultRoute = pluginProductsHelpers.generateVirtualTypeRoute(this.name, entry.name, {
|
|
254
|
+
omitPath: true, extendProduct: !this.isNewProduct, component: entry.component
|
|
255
|
+
});
|
|
234
256
|
}
|
|
235
257
|
} else {
|
|
258
|
+
// generateMetadataForGroupOverviewPageRouting
|
|
236
259
|
// Group with component - route to the group overview page (which will render the group's component and side-menu)
|
|
237
|
-
defaultRoute = pluginProductsHelpers.generateVirtualTypeRoute(this.name,
|
|
260
|
+
defaultRoute = pluginProductsHelpers.generateVirtualTypeRoute(this.name, firstConfig.name, {
|
|
261
|
+
omitPath: true, extendProduct: !this.isNewProduct, component: firstConfig.component
|
|
262
|
+
});
|
|
238
263
|
}
|
|
239
264
|
} else if (firstConfig.component) {
|
|
240
265
|
// Group with component but no children - route to the group page itself
|
|
241
|
-
defaultRoute = pluginProductsHelpers.generateVirtualTypeRoute(this.name,
|
|
266
|
+
defaultRoute = pluginProductsHelpers.generateVirtualTypeRoute(this.name, firstConfig.name, {
|
|
267
|
+
omitPath: true, extendProduct: !this.isNewProduct, component: firstConfig.component
|
|
268
|
+
});
|
|
242
269
|
}
|
|
243
270
|
} else if (isProductChildWithType(firstConfig)) {
|
|
244
271
|
// Simple configureType page (resource page)
|
|
245
|
-
|
|
272
|
+
const config = firstConfig as ProductChildResourcePage;
|
|
273
|
+
|
|
274
|
+
defaultRoute = pluginProductsHelpers.generateConfigureTypeRoute(this.name, config, { omitPath: true, extendProduct: !this.isNewProduct });
|
|
246
275
|
} else if (isProductChildWithComponent(firstConfig)) {
|
|
247
276
|
// Simple virtual type page (custom page)
|
|
248
|
-
|
|
277
|
+
const config = firstConfig as ProductChildCustomPage;
|
|
278
|
+
|
|
279
|
+
defaultRoute = pluginProductsHelpers.generateVirtualTypeRoute(this.name, config.name, {
|
|
280
|
+
omitPath: true, extendProduct: !this.isNewProduct, component: config.component
|
|
281
|
+
});
|
|
249
282
|
}
|
|
250
283
|
} else if (this.isNewProduct) {
|
|
251
284
|
// this is the "to" route for a simple page product (no config items)
|
|
@@ -253,18 +286,63 @@ export abstract class BasePluginProduct {
|
|
|
253
286
|
basicType(names);
|
|
254
287
|
}
|
|
255
288
|
|
|
256
|
-
|
|
257
|
-
product({
|
|
289
|
+
const typeMapProduct: TypeMapProduct = {
|
|
258
290
|
showClusterSwitcher: false,
|
|
259
291
|
extendable: false,
|
|
260
|
-
...this.product,
|
|
292
|
+
// ...this.product,
|
|
261
293
|
category: 'global',
|
|
262
294
|
to: defaultRoute,
|
|
263
|
-
icon:
|
|
295
|
+
icon: 'extension',
|
|
264
296
|
version: 2,
|
|
265
297
|
inStore: 'management',
|
|
266
298
|
name: this.name,
|
|
267
|
-
}
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
if (this.product) {
|
|
302
|
+
// ProductMetadata
|
|
303
|
+
|
|
304
|
+
applyIfDefined(this.product?.label, () => typeMapProduct.label = this.product?.label); // eslint-disable-line no-return-assign
|
|
305
|
+
applyIfDefined(this.product?.labelKey, () => typeMapProduct.labelKey = this.product?.labelKey); // eslint-disable-line no-return-assign
|
|
306
|
+
|
|
307
|
+
applyIfDefined(this.product?.enable?.ifFeature, () => typeMapProduct.ifFeature = this.product?.enable?.ifFeature); // eslint-disable-line no-return-assign
|
|
308
|
+
applyIfDefined(this.product?.enable?.ifHave, () => typeMapProduct.ifHave = this.product?.enable?.ifHave); // eslint-disable-line no-return-assign
|
|
309
|
+
applyIfDefined(this.product?.enable?.ifHaveGroup, () => typeMapProduct.ifHaveGroup = this.product?.enable?.ifHaveGroup); // eslint-disable-line no-return-assign
|
|
310
|
+
applyIfDefined(this.product?.enable?.ifHaveType, () => typeMapProduct.ifHaveType = this.product?.enable?.ifHaveType); // eslint-disable-line no-return-assign
|
|
311
|
+
applyIfDefined(this.product?.enable?.ifNotHaveType, () => typeMapProduct.ifNotHaveType = this.product?.enable?.ifNotHaveType); // eslint-disable-line no-return-assign
|
|
312
|
+
|
|
313
|
+
applyIfDefined(this.product?.resources?.hideSystemResources, () => typeMapProduct.hideSystemResources = this.product?.resources?.hideSystemResources); // eslint-disable-line no-return-assign
|
|
314
|
+
typeMapProduct.inStore = this.product.resources?.store ?? 'management';
|
|
315
|
+
|
|
316
|
+
applyIfDefined(this.product?.extendable, () => typeMapProduct.extendable = this.product?.extendable); // eslint-disable-line no-return-assign
|
|
317
|
+
|
|
318
|
+
applyIfDefined(this.product?.appHeader?.hideCopyConfig, () => typeMapProduct.hideCopyConfig = this.product?.appHeader?.hideCopyConfig); // eslint-disable-line no-return-assign
|
|
319
|
+
applyIfDefined(this.product?.appHeader?.hideKubeConfig, () => typeMapProduct.hideKubeConfig = this.product?.appHeader?.hideKubeConfig); // eslint-disable-line no-return-assign
|
|
320
|
+
applyIfDefined(this.product?.appHeader?.hideKubeShell, () => typeMapProduct.hideKubeShell = this.product?.appHeader?.hideKubeShell); // eslint-disable-line no-return-assign
|
|
321
|
+
applyIfDefined(this.product?.appHeader?.showClusterInfo, () => typeMapProduct.showClusterSwitcher = this.product?.appHeader?.showClusterInfo); // eslint-disable-line no-return-assign
|
|
322
|
+
applyIfDefined(this.product?.appHeader?.showNamespaceFilter, () => typeMapProduct.showNamespaceFilter = this.product?.appHeader?.showNamespaceFilter); // eslint-disable-line no-return-assign
|
|
323
|
+
applyIfDefined(this.product?.appHeader?.icon, () => typeMapProduct.iconHeader = this.product?.appHeader?.icon); // eslint-disable-line no-return-assign
|
|
324
|
+
|
|
325
|
+
applyIfDefined(this.product?.sideBar?.weight, () => typeMapProduct.weight = this.product?.sideBar?.weight); // eslint-disable-line no-return-assign
|
|
326
|
+
typeMapProduct.icon = this.product?.sideBar?.icon?.name ?? 'extension';
|
|
327
|
+
applyIfDefined(this.product?.sideBar?.icon?.svg, () => typeMapProduct.svg = this.product?.sideBar?.icon?.svg); // eslint-disable-line no-return-assign
|
|
328
|
+
|
|
329
|
+
// ProductMetadataAddInternal
|
|
330
|
+
if (isProductConfigInternal(this.product)) {
|
|
331
|
+
const poI = this.product as ProductMetadataInternal;
|
|
332
|
+
|
|
333
|
+
applyIfDefined(poI.category, () => typeMapProduct.category = poI.category); // eslint-disable-line no-return-assign
|
|
334
|
+
applyIfDefined(poI?.appHeader?.hideNamespaceLocation, () => typeMapProduct.hideNamespaceLocation = poI?.appHeader?.hideNamespaceLocation); // eslint-disable-line no-return-assign
|
|
335
|
+
applyIfDefined(poI?.sideMenu?.renameGroups, () => typeMapProduct.renameGroups = poI?.sideMenu?.renameGroups); // eslint-disable-line no-return-assign
|
|
336
|
+
applyIfDefined(poI?.sideMenu?.ignoreGroups, () => typeMapProduct.ignoreGroups = poI?.sideMenu?.ignoreGroups); // eslint-disable-line no-return-assign
|
|
337
|
+
applyIfDefined(poI?.sideMenu?.moveToGroup, () => typeMapProduct.moveToGroup = poI?.sideMenu?.moveToGroup); // eslint-disable-line no-return-assign
|
|
338
|
+
|
|
339
|
+
applyIfDefined(poI?.appHeader?.showWorkspaceSwitcher, () => typeMapProduct.showWorkspaceSwitcher = poI?.appHeader?.showWorkspaceSwitcher); // eslint-disable-line no-return-assign
|
|
340
|
+
applyIfDefined(poI?.removable, () => typeMapProduct.removable = poI?.removable); // eslint-disable-line no-return-assign
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// register the product via DSL
|
|
345
|
+
product(typeMapProduct);
|
|
268
346
|
}
|
|
269
347
|
|
|
270
348
|
/**
|
|
@@ -276,47 +354,51 @@ export abstract class BasePluginProduct {
|
|
|
276
354
|
mapGroup, ignoreGroup, moveType, basicType
|
|
277
355
|
} = this.DSLMethods;
|
|
278
356
|
|
|
279
|
-
if (this.product
|
|
280
|
-
this.product
|
|
281
|
-
mapGroup(mapping.groupSelector, mapping.newName);
|
|
282
|
-
});
|
|
283
|
-
}
|
|
357
|
+
if (this.product && isProductConfigInternal(this.product)) {
|
|
358
|
+
const productConfigInternal = this.product as ProductMetadataInternal;
|
|
284
359
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
ignoreGroup(ignore.groupSelector);
|
|
291
|
-
}
|
|
292
|
-
});
|
|
293
|
-
}
|
|
360
|
+
if (productConfigInternal?.sideMenu?.renameGroups?.length) {
|
|
361
|
+
productConfigInternal?.sideMenu?.renameGroups.forEach((mapping) => {
|
|
362
|
+
mapGroup(mapping.groupSelector, mapping.newName);
|
|
363
|
+
});
|
|
364
|
+
}
|
|
294
365
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
366
|
+
if (productConfigInternal?.sideMenu?.ignoreGroups?.length) {
|
|
367
|
+
productConfigInternal?.sideMenu?.ignoreGroups.forEach((ignore) => {
|
|
368
|
+
if (ignore.condition) {
|
|
369
|
+
ignoreGroup(ignore.groupSelector, ignore.condition);
|
|
370
|
+
} else {
|
|
371
|
+
ignoreGroup(ignore.groupSelector);
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
}
|
|
298
375
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
376
|
+
if (productConfigInternal?.sideMenu?.moveToGroup?.length) {
|
|
377
|
+
productConfigInternal?.sideMenu?.moveToGroup.forEach((move) => {
|
|
378
|
+
const resolvedGroup = this.groupNameMap.get(move.groupName);
|
|
302
379
|
|
|
303
|
-
|
|
380
|
+
if (!resolvedGroup) {
|
|
381
|
+
this.surfaceError(`moveToGroup target group "${ move.groupName }" not found. Available groups: ${ Array.from(this.groupNameMap.keys()).join(', ') }`);
|
|
382
|
+
}
|
|
304
383
|
|
|
305
|
-
|
|
306
|
-
this.surfaceError(`moveToGroup entryId "${ move.entryId }" not found. Available pages: ${ Array.from(this.pageIdMap.keys()).join(', ') }`);
|
|
307
|
-
}
|
|
384
|
+
const resolvedPageId = this.pageIdMap.get(move.entryId);
|
|
308
385
|
|
|
309
|
-
|
|
310
|
-
|
|
386
|
+
if (!resolvedPageId) {
|
|
387
|
+
this.surfaceError(`moveToGroup entryId "${ move.entryId }" not found. Available pages: ${ Array.from(this.pageIdMap.keys()).join(', ') }`);
|
|
388
|
+
}
|
|
311
389
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
const isResourceType = resolvedPageId === move.entryId;
|
|
390
|
+
// Re-register via basicType to move the page in the nav tree (basic view mode)
|
|
391
|
+
basicType([resolvedPageId], resolvedGroup);
|
|
315
392
|
|
|
316
|
-
|
|
317
|
-
moveType
|
|
318
|
-
|
|
319
|
-
|
|
393
|
+
// Also register via moveType for non-basic view modes (e.g. "in use" mode).
|
|
394
|
+
// moveType uses regex matching against schema IDs, so it only works for resource types.
|
|
395
|
+
const isResourceType = resolvedPageId === move.entryId;
|
|
396
|
+
|
|
397
|
+
if (isResourceType) {
|
|
398
|
+
moveType(move.entryId, resolvedGroup, move.weight);
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
}
|
|
320
402
|
}
|
|
321
403
|
}
|
|
322
404
|
|
|
@@ -343,12 +425,12 @@ export abstract class BasePluginProduct {
|
|
|
343
425
|
this.registeredPageNames.add(finalName);
|
|
344
426
|
this.pageIdMap.set(item.name, finalName);
|
|
345
427
|
|
|
346
|
-
const virtualTypeConfig:
|
|
428
|
+
const virtualTypeConfig: TypeMapVirtualType = {
|
|
347
429
|
label: item.label,
|
|
348
430
|
labelKey: item.labelKey,
|
|
349
431
|
namespaced: false,
|
|
350
432
|
name: finalName,
|
|
351
|
-
weight: item.weight, // ordering is done here and not via "weightType"
|
|
433
|
+
weight: item.sideMenu?.weight, // ordering is done here and not via "weightType"
|
|
352
434
|
};
|
|
353
435
|
|
|
354
436
|
// if the item with COMPONENT has children then it's a GROUP virtualType, so set "exact" and "overview" to "true"
|
|
@@ -357,12 +439,24 @@ export abstract class BasePluginProduct {
|
|
|
357
439
|
virtualTypeConfig.exact = true;
|
|
358
440
|
virtualTypeConfig.overview = true;
|
|
359
441
|
// Pass group metadata as pageChild so the route gets a unique path segment (e.g. /product/c/:cluster/groupName)
|
|
360
|
-
virtualTypeConfig.route = pluginProductsHelpers.generateVirtualTypeRoute(parentName,
|
|
442
|
+
virtualTypeConfig.route = pluginProductsHelpers.generateVirtualTypeRoute(parentName, item.name, { extendProduct: !this.isNewProduct, component: item.component });
|
|
361
443
|
} else {
|
|
362
|
-
virtualTypeConfig.route = pluginProductsHelpers.generateVirtualTypeRoute(parentName, item, { extendProduct: !this.isNewProduct });
|
|
444
|
+
virtualTypeConfig.route = pluginProductsHelpers.generateVirtualTypeRoute(parentName, item.name, { extendProduct: !this.isNewProduct, component: item.component });
|
|
363
445
|
}
|
|
364
446
|
|
|
365
|
-
|
|
447
|
+
if (isProductChildWithComponent(item)) {
|
|
448
|
+
const itemCustomPage:ProductChildCustomPageInternal = item as ProductChildCustomPageInternal;
|
|
449
|
+
|
|
450
|
+
// virtualTypeConfig.component = itemCustomPage.component;
|
|
451
|
+
applyIfDefined(itemCustomPage.enable?.ifHave, () => virtualTypeConfig.ifHave = itemCustomPage.enable?.ifHave); // eslint-disable-line no-return-assign
|
|
452
|
+
applyIfDefined(itemCustomPage.enable?.ifFeature, () => virtualTypeConfig.ifFeature = itemCustomPage.enable?.ifFeature); // eslint-disable-line no-return-assign
|
|
453
|
+
applyIfDefined(itemCustomPage.enable?.ifHaveType, () => virtualTypeConfig.ifHaveType = itemCustomPage.enable?.ifHaveType); // eslint-disable-line no-return-assign
|
|
454
|
+
applyIfDefined(itemCustomPage.enable?.ifHaveVerb, () => virtualTypeConfig.ifHaveVerb = itemCustomPage.enable?.ifHaveVerb); // eslint-disable-line no-return-assign
|
|
455
|
+
|
|
456
|
+
applyIfDefined(itemCustomPage.resource?.namespaced, () => virtualTypeConfig.namespaced = itemCustomPage.resource?.namespaced); // eslint-disable-line no-return-assign
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
virtualType(virtualTypeConfig);
|
|
366
460
|
} else if (isProductChildWithType(item)) {
|
|
367
461
|
// Page with a "type" specified maps to a configureType
|
|
368
462
|
const typeValue = item.type;
|
|
@@ -372,39 +466,53 @@ export abstract class BasePluginProduct {
|
|
|
372
466
|
this.surfaceError(`Duplicate resource type "${ typeValue }" - each resource type must be unique within a product`);
|
|
373
467
|
}
|
|
374
468
|
|
|
469
|
+
const itemRP: ProductChildResourcePageInternal = item as ProductChildResourcePageInternal;
|
|
470
|
+
|
|
375
471
|
this.registeredPageNames.add(typeValue);
|
|
376
472
|
this.pageIdMap.set(typeValue, typeValue);
|
|
377
473
|
|
|
378
474
|
const route = pluginProductsHelpers.generateConfigureTypeRoute(parentName, item, { extendProduct: !this.isNewProduct });
|
|
379
475
|
|
|
380
|
-
const configureTypeConfig:
|
|
381
|
-
isCreatable: true,
|
|
382
|
-
isEditable: true,
|
|
383
|
-
isRemovable: true,
|
|
384
|
-
canYaml: true,
|
|
476
|
+
const configureTypeConfig: TypeMapConfigureType = {
|
|
477
|
+
isCreatable: itemRP.can?.create ?? true,
|
|
478
|
+
isEditable: itemRP.can?.edit ?? true,
|
|
479
|
+
isRemovable: itemRP.can?.create ?? true,
|
|
480
|
+
canYaml: itemRP.can?.yaml ?? true,
|
|
385
481
|
customRoute: route
|
|
386
482
|
};
|
|
387
483
|
|
|
388
|
-
|
|
389
|
-
|
|
484
|
+
applyIfDefined(itemRP.listConfig?.listGroups, () => configureTypeConfig.listGroups = itemRP.listConfig?.listGroups); // eslint-disable-line no-return-assign
|
|
485
|
+
applyIfDefined(itemRP.listConfig?.listGroupsWillOverride, () => configureTypeConfig.listGroupsWillOverride = itemRP.listConfig?.listGroupsWillOverride); // eslint-disable-line no-return-assign
|
|
486
|
+
applyIfDefined(itemRP.listConfig?.subTypes, () => configureTypeConfig.subTypes = itemRP.listConfig?.subTypes); // eslint-disable-line no-return-assign
|
|
487
|
+
|
|
488
|
+
if (itemRP.listConfig?.localHeaders || itemRP.listConfig?.headers) {
|
|
489
|
+
headers(item.type, itemRP.listConfig?.localHeaders, itemRP.listConfig?.headers);
|
|
390
490
|
}
|
|
391
491
|
|
|
392
|
-
if (
|
|
393
|
-
mapType(item.type,
|
|
492
|
+
if (itemRP.label) {
|
|
493
|
+
mapType(item.type, itemRP.label);
|
|
394
494
|
}
|
|
395
495
|
|
|
396
|
-
if (
|
|
496
|
+
if (itemRP.sideMenu?.hideFromNav) {
|
|
397
497
|
ignoreType(item.type);
|
|
398
498
|
}
|
|
399
499
|
|
|
400
|
-
if (
|
|
500
|
+
if (itemRP.listConfig?.hideBulkActions) {
|
|
401
501
|
hideBulkActions(item.type, true);
|
|
402
502
|
}
|
|
403
503
|
|
|
404
|
-
|
|
504
|
+
applyIfDefined(item.views?.list?.createLabelKey, () => configureTypeConfig.listCreateButtonLabelKey = item.views?.list?.createLabelKey); // eslint-disable-line no-return-assign
|
|
505
|
+
configureTypeConfig.showState = item.display?.showState ?? true;
|
|
506
|
+
configureTypeConfig.showAge = item.display?.showAge ?? true;
|
|
507
|
+
configureTypeConfig.showConfigView = item.views?.detail?.showConfigView ?? true;
|
|
508
|
+
configureTypeConfig.showListMasthead = item.views?.list?.showListMasthead ?? true;
|
|
509
|
+
configureTypeConfig.resourceEditMasthead = item.views?.createEdit?.showMasthead ?? true;
|
|
510
|
+
configureTypeConfig.localOnly = item.sideMenu?.localOnly ?? false;
|
|
511
|
+
|
|
512
|
+
configureType(typeValue, configureTypeConfig);
|
|
405
513
|
|
|
406
|
-
if (
|
|
407
|
-
weightType(typeValue,
|
|
514
|
+
if (itemRP.sideMenu?.weight !== undefined) {
|
|
515
|
+
weightType(typeValue, itemRP.sideMenu?.weight, true);
|
|
408
516
|
}
|
|
409
517
|
}
|
|
410
518
|
}
|
|
@@ -421,7 +529,7 @@ export abstract class BasePluginProduct {
|
|
|
421
529
|
this.surfaceError('Group items cannot have a "type" property - only custom pages can have groups.');
|
|
422
530
|
}
|
|
423
531
|
|
|
424
|
-
let route;
|
|
532
|
+
let route: RouteRecordRaw | RouteRecordRawWithParams;
|
|
425
533
|
|
|
426
534
|
if (!child.component) {
|
|
427
535
|
// Create minimal page object for route generation
|
|
@@ -431,23 +539,23 @@ export abstract class BasePluginProduct {
|
|
|
431
539
|
component: EmptyProductPage
|
|
432
540
|
};
|
|
433
541
|
|
|
434
|
-
route = pluginProductsHelpers.generateVirtualTypeRoute(parentName, pageForRoute, { extendProduct: !this.isNewProduct });
|
|
542
|
+
route = pluginProductsHelpers.generateVirtualTypeRoute(parentName, pageForRoute.name, { extendProduct: !this.isNewProduct });
|
|
435
543
|
} else {
|
|
436
|
-
route = pluginProductsHelpers.generateVirtualTypeRoute(parentName,
|
|
544
|
+
route = pluginProductsHelpers.generateVirtualTypeRoute(parentName, child.name, { component: child.component, extendProduct: !this.isNewProduct });
|
|
437
545
|
}
|
|
438
546
|
|
|
439
547
|
// add the route for the group page/parent
|
|
440
548
|
plugin.addRoute(route);
|
|
441
549
|
|
|
442
550
|
// add children routes
|
|
443
|
-
this.addRoutes(plugin, `${ parentName }`, child.children);
|
|
551
|
+
this.addRoutes(plugin, `${ parentName }`, child.sideMenu.children);
|
|
444
552
|
} else if (isProductChildWithComponent(child)) {
|
|
445
553
|
// virtualType page
|
|
446
554
|
if (hasTypeProperty(child)) {
|
|
447
555
|
this.surfaceError('Custom pages cannot have a "type" property - only resource pages can use "type".');
|
|
448
556
|
}
|
|
449
557
|
|
|
450
|
-
const route = pluginProductsHelpers.generateVirtualTypeRoute(parentName, child, { component: child.component, extendProduct: !this.isNewProduct });
|
|
558
|
+
const route = pluginProductsHelpers.generateVirtualTypeRoute(parentName, child.name, { component: child.component, extendProduct: !this.isNewProduct });
|
|
451
559
|
|
|
452
560
|
plugin.addRoute(route);
|
|
453
561
|
} else if (isProductChildWithType(child)) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { IExtension } from '@shell/core/types';
|
|
2
|
-
import { ProductChild, StandardProductName } from '@shell/core/plugin-types';
|
|
3
2
|
import EmptyProductPage from '@shell/components/EmptyProductPage.vue';
|
|
4
3
|
import { BasePluginProduct } from '@shell/core/plugin-products-base';
|
|
4
|
+
import { ProductChild, StandardProductName } from '@shell/core/plugin-products-external';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Represents extending an existing standard product
|