@rancher/shell 3.0.8-rc.8 → 3.0.8
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/impl/apis.ts +61 -0
- package/apis/index.ts +40 -0
- package/apis/intf/modal.ts +90 -0
- package/apis/intf/shell.ts +36 -0
- package/apis/intf/slide-in.ts +98 -0
- package/apis/intf/system.ts +41 -0
- package/apis/shell/__tests__/modal.test.ts +80 -0
- package/apis/shell/__tests__/notifications.test.ts +71 -0
- package/apis/shell/__tests__/slide-in.test.ts +54 -0
- package/apis/shell/__tests__/system.test.ts +129 -0
- package/apis/shell/index.ts +38 -0
- package/apis/shell/modal.ts +41 -0
- package/apis/shell/notifications.ts +65 -0
- package/apis/shell/slide-in.ts +33 -0
- package/apis/shell/system.ts +65 -0
- package/apis/vue-shim.d.ts +11 -0
- package/assets/brand/suse/dark/rancher-logo.svg +1 -64
- package/assets/styles/global/_tooltip.scss +6 -1
- package/assets/translations/en-us.yaml +14 -1
- package/components/ActionMenuShell.vue +3 -1
- package/components/BackLink.vue +8 -0
- package/components/BannerGraphic.vue +1 -5
- package/components/BrandImage.vue +17 -6
- package/components/Cron/CronExpressionEditor.vue +1 -1
- package/components/Cron/CronExpressionEditorModal.vue +1 -1
- package/components/CruResource.vue +8 -1
- package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +1 -0
- package/components/Drawer/ResourceDetailDrawer/__tests__/composables.test.ts +50 -1
- package/components/Drawer/ResourceDetailDrawer/composables.ts +19 -0
- package/components/Drawer/ResourceDetailDrawer/index.vue +4 -1
- package/components/Drawer/ResourceDetailDrawer/types.ts +2 -1
- package/components/LocaleSelector.vue +2 -2
- package/components/ModalManager.vue +11 -1
- package/components/Questions/__tests__/Yaml.test.ts +1 -1
- package/components/Questions/__tests__/index.test.ts +159 -0
- package/components/RelatedResources.vue +5 -0
- package/components/Resource/Detail/Metadata/Annotations/index.vue +2 -2
- package/components/Resource/Detail/Metadata/Labels/index.vue +2 -2
- package/components/Resource/Detail/Metadata/index.vue +3 -3
- package/components/Resource/Detail/ResourcePopover/index.vue +5 -1
- package/components/Resource/Detail/composables.ts +2 -2
- package/components/ResourceDetail/Masthead/latest.vue +23 -21
- package/components/ResourceDetail/index.vue +3 -0
- package/components/ResourceTable.vue +54 -21
- package/components/SlideInPanelManager.vue +16 -11
- package/components/SortableTable/THead.vue +2 -1
- package/components/SortableTable/index.vue +20 -2
- package/components/Tabbed/__tests__/index.test.ts +86 -0
- package/components/Tabbed/index.vue +37 -2
- package/components/__tests__/NamespaceFilter.test.ts +49 -0
- package/components/auth/SelectPrincipal.vue +28 -6
- package/components/auth/__tests__/SelectPrincipal.test.ts +119 -0
- package/components/auth/login/ldap.vue +3 -3
- package/components/fleet/FleetSecretSelector.vue +1 -1
- package/components/form/KeyValue.vue +1 -1
- package/components/form/NameNsDescription.vue +1 -1
- package/components/form/NodeScheduling.vue +2 -2
- package/components/form/ResourceTabs/composable.ts +2 -2
- package/components/form/ResourceTabs/index.vue +0 -2
- package/components/form/__tests__/NameNsDescription.test.ts +42 -0
- package/components/formatter/InternalExternalIP.vue +4 -1
- package/components/formatter/LinkName.vue +5 -0
- package/components/formatter/__tests__/InternalExternalIP.test.ts +1 -1
- package/components/nav/Group.vue +25 -7
- package/components/nav/Header.vue +1 -1
- package/components/nav/NamespaceFilter.vue +1 -0
- package/components/nav/Type.vue +17 -6
- package/components/nav/WindowManager/panels/TabBodyContainer.vue +1 -1
- package/components/nav/__tests__/Type.test.ts +59 -0
- package/components/templates/standalone.vue +1 -1
- package/composables/cruResource.ts +27 -0
- package/composables/focusTrap.ts +3 -1
- package/composables/resourceDetail.ts +15 -0
- package/composables/useI18n.ts +10 -1
- package/composables/useLabeledFormElement.ts +3 -4
- package/config/__test__/uiplugins.test.ts +309 -0
- package/config/labels-annotations.js +1 -0
- package/config/product/explorer.js +3 -1
- package/config/product/fleet.js +1 -1
- package/config/router/navigation-guards/clusters.js +3 -3
- package/config/router/navigation-guards/products.js +1 -1
- package/config/router/routes.js +7 -7
- package/config/types.js +7 -0
- package/config/uiplugins.js +46 -2
- package/core/__tests__/extension-manager-impl.test.js +437 -0
- package/core/extension-manager-impl.js +21 -25
- package/core/plugin-helpers.ts +2 -2
- package/core/plugin.ts +9 -1
- package/core/plugins-loader.js +2 -2
- package/core/types-provisioning.ts +5 -1
- package/core/types.ts +35 -0
- package/detail/provisioning.cattle.io.cluster.vue +9 -6
- package/dialog/DeveloperLoadExtensionDialog.vue +13 -4
- package/dialog/MoveNamespaceDialog.vue +20 -4
- package/dialog/RollbackWorkloadDialog.vue +2 -5
- package/dialog/SearchDialog.vue +1 -0
- package/dialog/__tests__/MoveNamespaceDialog.test.ts +249 -0
- package/directives/__tests__/clean-tooltip.test.ts +298 -0
- package/directives/clean-tooltip.ts +234 -0
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +2 -2
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +100 -3
- package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -0
- package/edit/configmap.vue +1 -0
- package/edit/constraints.gatekeeper.sh.constraint/index.vue +1 -0
- package/edit/fleet.cattle.io.helmop.vue +11 -6
- package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
- package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +1 -0
- package/edit/logging-flow/index.vue +1 -0
- package/edit/logging.banzaicloud.io.output/index.vue +1 -0
- package/edit/management.cattle.io.fleetworkspace.vue +1 -1
- package/edit/management.cattle.io.project.vue +1 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +4 -1
- package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +2 -1
- package/edit/monitoring.coreos.com.prometheusrule/index.vue +1 -0
- package/edit/monitoring.coreos.com.receiver/index.vue +2 -1
- package/edit/monitoring.coreos.com.route.vue +1 -1
- package/edit/namespace.vue +1 -0
- package/edit/networking.istio.io.destinationrule/index.vue +1 -0
- package/edit/networking.k8s.io.ingress/index.vue +1 -0
- package/edit/networking.k8s.io.networkpolicy/PolicyRules.vue +1 -0
- package/edit/networking.k8s.io.networkpolicy/index.vue +1 -0
- package/edit/node.vue +1 -0
- package/edit/persistentvolume/index.vue +27 -22
- package/edit/persistentvolume/plugins/awsElasticBlockStore.vue +13 -14
- package/edit/persistentvolume/plugins/azureDisk.vue +49 -48
- package/edit/persistentvolume/plugins/azureFile.vue +15 -14
- package/edit/persistentvolume/plugins/cephfs.vue +15 -14
- package/edit/persistentvolume/plugins/cinder.vue +15 -14
- package/edit/persistentvolume/plugins/csi.vue +18 -16
- package/edit/persistentvolume/plugins/fc.vue +13 -14
- package/edit/persistentvolume/plugins/flexVolume.vue +15 -14
- package/edit/persistentvolume/plugins/flocker.vue +1 -3
- package/edit/persistentvolume/plugins/gcePersistentDisk.vue +13 -14
- package/edit/persistentvolume/plugins/glusterfs.vue +15 -14
- package/edit/persistentvolume/plugins/hostPath.vue +40 -39
- package/edit/persistentvolume/plugins/iscsi.vue +13 -14
- package/edit/persistentvolume/plugins/local.vue +1 -3
- package/edit/persistentvolume/plugins/longhorn.vue +23 -22
- package/edit/persistentvolume/plugins/nfs.vue +15 -14
- package/edit/persistentvolume/plugins/photonPersistentDisk.vue +1 -14
- package/edit/persistentvolume/plugins/portworxVolume.vue +15 -14
- package/edit/persistentvolume/plugins/quobyte.vue +15 -14
- package/edit/persistentvolume/plugins/rbd.vue +15 -14
- package/edit/persistentvolume/plugins/scaleIO.vue +15 -14
- package/edit/persistentvolume/plugins/storageos.vue +15 -14
- package/edit/persistentvolume/plugins/vsphereVolume.vue +1 -3
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +21 -21
- package/edit/provisioning.cattle.io.cluster/index.vue +5 -5
- package/edit/provisioning.cattle.io.cluster/rke2.vue +9 -8
- package/edit/resources.cattle.io.restore.vue +1 -1
- package/edit/secret/index.vue +1 -1
- package/edit/service.vue +1 -0
- package/edit/serviceaccount.vue +1 -0
- package/edit/storage.k8s.io.storageclass/index.vue +1 -0
- package/edit/workload/Job.vue +2 -2
- package/edit/workload/index.vue +2 -1
- package/edit/workload/mixins/workload.js +1 -1
- package/initialize/App.vue +4 -4
- package/initialize/install-plugins.js +19 -5
- package/machine-config/azure.vue +1 -1
- package/machine-config/components/GCEImage.vue +1 -1
- package/mixins/__tests__/brand.spec.ts +2 -2
- package/mixins/brand.js +1 -7
- package/mixins/create-edit-view/index.js +5 -0
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +128 -5
- package/models/chart.js +70 -74
- package/models/management.cattle.io.cluster.js +21 -3
- package/models/provisioning.cattle.io.cluster.js +31 -11
- package/package.json +11 -10
- package/pages/auth/login.vue +4 -6
- package/pages/auth/setup.vue +1 -1
- package/pages/auth/verify.vue +3 -3
- package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +135 -0
- package/pages/c/_cluster/apps/charts/chart.vue +33 -15
- package/pages/c/_cluster/apps/charts/index.vue +122 -24
- package/pages/c/_cluster/apps/charts/install.vue +33 -0
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +1 -1
- package/pages/c/_cluster/explorer/index.vue +8 -6
- package/pages/c/_cluster/fleet/index.vue +4 -7
- package/pages/c/_cluster/manager/hostedprovider/index.vue +12 -6
- package/pages/c/_cluster/settings/brand.vue +1 -1
- package/pages/c/_cluster/settings/index.vue +5 -0
- package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +7 -0
- package/pages/c/_cluster/uiplugins/catalogs.vue +147 -0
- package/pages/c/_cluster/uiplugins/index.vue +126 -184
- package/pkg/auto-import.js +3 -3
- package/pkg/dynamic-importer.lib.js +1 -1
- package/pkg/import.js +1 -1
- package/plugins/__tests__/mutations.tests.ts +179 -0
- package/plugins/dashboard-client-init.js +3 -0
- package/plugins/dashboard-store/getters.js +19 -2
- package/plugins/dashboard-store/model-loader.js +1 -1
- package/plugins/dashboard-store/mutations.js +23 -2
- package/plugins/dashboard-store/resource-class.js +11 -5
- package/plugins/i18n.js +8 -0
- package/plugins/plugin.js +2 -2
- package/plugins/steve/__tests__/steve-pagination-utils.test.ts +506 -0
- package/plugins/steve/steve-class.js +1 -1
- package/plugins/steve/steve-pagination-utils.ts +131 -47
- package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +1 -1
- package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +6 -42
- package/rancher-components/Pill/RcStatusBadge/index.ts +0 -1
- package/rancher-components/Pill/RcStatusBadge/types.ts +1 -1
- package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +5 -28
- package/rancher-components/Pill/RcStatusIndicator/types.ts +2 -1
- package/rancher-components/Pill/types.ts +0 -1
- package/rancher-components/RcDropdown/useDropdownContext.ts +2 -4
- package/rancher-components/RcIcon/RcIcon.test.ts +51 -0
- package/rancher-components/RcIcon/RcIcon.vue +46 -0
- package/rancher-components/RcIcon/index.ts +1 -0
- package/rancher-components/RcIcon/types.ts +160 -0
- package/rancher-components/RcItemCard/RcItemCard.vue +1 -1
- package/rancher-components/utils/status.test.ts +67 -0
- package/rancher-components/utils/status.ts +77 -0
- package/scripts/publish-shell.sh +25 -0
- package/scripts/typegen.sh +1 -0
- package/store/__tests__/catalog.test.ts +1 -1
- package/store/__tests__/type-map.test.ts +164 -2
- package/store/action-menu.js +8 -0
- package/store/auth.js +25 -13
- package/store/catalog.js +6 -0
- package/store/i18n.js +3 -3
- package/store/index.js +8 -6
- package/store/notifications.ts +2 -0
- package/store/prefs.js +6 -7
- package/store/type-map.js +17 -7
- package/store/wm.ts +4 -4
- package/types/internal-api/shell/modal.d.ts +6 -6
- package/types/notifications/index.ts +126 -15
- package/types/rancher/index.d.ts +9 -0
- package/types/shell/index.d.ts +54 -3
- package/types/store/__tests__/pagination.types.spec.ts +137 -0
- package/types/store/pagination.types.ts +157 -9
- package/types/vue-shim.d.ts +5 -4
- package/utils/__tests__/provider.test.ts +98 -0
- package/utils/__tests__/router.test.js +238 -0
- package/utils/__tests__/selector-typed.test.ts +263 -0
- package/utils/cluster.js +4 -1
- package/utils/color.js +1 -1
- package/utils/dynamic-content/__tests__/info.test.ts +6 -0
- package/utils/dynamic-content/info.ts +43 -0
- package/utils/favicon.js +4 -4
- package/utils/fleet.ts +8 -1
- package/utils/pagination-utils.ts +2 -2
- package/utils/pagination-wrapper.ts +1 -1
- package/utils/provider.ts +14 -0
- package/utils/router.js +50 -0
- package/utils/selector-typed.ts +6 -2
- package/utils/unit-tests/pagination-utils.spec.ts +8 -8
- package/vue.config.js +3 -3
- package/composables/useExtensionManager.ts +0 -17
- package/core/plugins.js +0 -38
- package/directives/clean-tooltip.js +0 -32
- package/plugins/internal-api/index.ts +0 -37
- package/plugins/internal-api/shared/base-api.ts +0 -13
- package/plugins/internal-api/shell/shell.api.ts +0 -108
- package/plugins/nuxt-client-init.js +0 -3
- package/types/internal-api/shell/growl.d.ts +0 -25
- 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
|
+
});
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { labelSelectorToSelector } from '@shell/utils/selector-typed';
|
|
2
|
+
import { KubeLabelSelector } from '@shell/types/kube/kube-api';
|
|
3
|
+
|
|
4
|
+
describe('selector-typed', () => {
|
|
5
|
+
describe('labelSelectorToSelector', () => {
|
|
6
|
+
describe('empty label selectors', () => {
|
|
7
|
+
it('should return empty string for undefined label selector', () => {
|
|
8
|
+
const result = labelSelectorToSelector(undefined);
|
|
9
|
+
|
|
10
|
+
expect(result).toBe('');
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should return empty string for label selector with no matchLabels and no matchExpressions', () => {
|
|
14
|
+
const labelSelector: KubeLabelSelector = {};
|
|
15
|
+
const result = labelSelectorToSelector(labelSelector);
|
|
16
|
+
|
|
17
|
+
expect(result).toBe('');
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should return empty string for label selector with empty matchLabels', () => {
|
|
21
|
+
const labelSelector: KubeLabelSelector = { matchLabels: {} };
|
|
22
|
+
const result = labelSelectorToSelector(labelSelector);
|
|
23
|
+
|
|
24
|
+
expect(result).toBe('');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should return empty string for label selector with empty matchExpressions', () => {
|
|
28
|
+
const labelSelector: KubeLabelSelector = { matchExpressions: [] };
|
|
29
|
+
const result = labelSelectorToSelector(labelSelector);
|
|
30
|
+
|
|
31
|
+
expect(result).toBe('');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should return empty string for label selector with both empty matchLabels and matchExpressions', () => {
|
|
35
|
+
const labelSelector: KubeLabelSelector = {
|
|
36
|
+
matchLabels: {},
|
|
37
|
+
matchExpressions: []
|
|
38
|
+
};
|
|
39
|
+
const result = labelSelectorToSelector(labelSelector);
|
|
40
|
+
|
|
41
|
+
expect(result).toBe('');
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('matchLabels conversion', () => {
|
|
46
|
+
it('should convert single matchLabel to selector string', () => {
|
|
47
|
+
const labelSelector: KubeLabelSelector = { matchLabels: { app: 'nginx' } };
|
|
48
|
+
const result = labelSelectorToSelector(labelSelector);
|
|
49
|
+
|
|
50
|
+
expect(result).toBe('app=nginx');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should convert multiple matchLabels to comma-separated selector string', () => {
|
|
54
|
+
const labelSelector: KubeLabelSelector = {
|
|
55
|
+
matchLabels: {
|
|
56
|
+
app: 'nginx',
|
|
57
|
+
version: 'v1.0',
|
|
58
|
+
env: 'production'
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const result = labelSelectorToSelector(labelSelector);
|
|
62
|
+
|
|
63
|
+
expect(result).toBe('app=nginx,version=v1.0,env=production');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should handle matchLabels with special characters', () => {
|
|
67
|
+
const labelSelector: KubeLabelSelector = { matchLabels: { 'app.kubernetes.io/name': 'my-app' } };
|
|
68
|
+
const result = labelSelectorToSelector(labelSelector);
|
|
69
|
+
|
|
70
|
+
expect(result).toBe('app.kubernetes.io/name=my-app');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should handle matchLabels with numeric values', () => {
|
|
74
|
+
const labelSelector: KubeLabelSelector = { matchLabels: { tier: '3' } };
|
|
75
|
+
const result = labelSelectorToSelector(labelSelector);
|
|
76
|
+
|
|
77
|
+
expect(result).toBe('tier=3');
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe('matchExpressions conversion with In operator', () => {
|
|
82
|
+
it('should convert matchExpression with In operator and single value to equality selector', () => {
|
|
83
|
+
const labelSelector: KubeLabelSelector = {
|
|
84
|
+
matchExpressions: [
|
|
85
|
+
{
|
|
86
|
+
key: 'app',
|
|
87
|
+
operator: 'In',
|
|
88
|
+
values: ['nginx']
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
};
|
|
92
|
+
const result = labelSelectorToSelector(labelSelector);
|
|
93
|
+
|
|
94
|
+
expect(result).toBe('app=nginx');
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should convert matchExpression with In operator and multiple values to in() selector', () => {
|
|
98
|
+
const labelSelector: KubeLabelSelector = {
|
|
99
|
+
matchExpressions: [
|
|
100
|
+
{
|
|
101
|
+
key: 'env',
|
|
102
|
+
operator: 'In',
|
|
103
|
+
values: ['dev', 'staging', 'prod']
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
};
|
|
107
|
+
const result = labelSelectorToSelector(labelSelector);
|
|
108
|
+
|
|
109
|
+
expect(result).toBe('env in (dev,staging,prod)');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should convert multiple matchExpressions with In operator', () => {
|
|
113
|
+
const labelSelector: KubeLabelSelector = {
|
|
114
|
+
matchExpressions: [
|
|
115
|
+
{
|
|
116
|
+
key: 'app',
|
|
117
|
+
operator: 'In',
|
|
118
|
+
values: ['nginx']
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
key: 'env',
|
|
122
|
+
operator: 'In',
|
|
123
|
+
values: ['dev', 'staging']
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
};
|
|
127
|
+
const result = labelSelectorToSelector(labelSelector);
|
|
128
|
+
|
|
129
|
+
expect(result).toBe('app=nginx,env in (dev,staging)');
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('should handle matchExpression with empty values array for In operator', () => {
|
|
133
|
+
const labelSelector: KubeLabelSelector = {
|
|
134
|
+
matchExpressions: [
|
|
135
|
+
{
|
|
136
|
+
key: 'app',
|
|
137
|
+
operator: 'In',
|
|
138
|
+
values: []
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
};
|
|
142
|
+
const result = labelSelectorToSelector(labelSelector);
|
|
143
|
+
|
|
144
|
+
// With empty values array, it should create an in() with no values
|
|
145
|
+
expect(result).toBe('app in ()');
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe('combined matchLabels and matchExpressions', () => {
|
|
150
|
+
it('should combine matchLabels and matchExpressions with single values', () => {
|
|
151
|
+
const labelSelector: KubeLabelSelector = {
|
|
152
|
+
matchLabels: { tier: 'frontend' },
|
|
153
|
+
matchExpressions: [
|
|
154
|
+
{
|
|
155
|
+
key: 'env',
|
|
156
|
+
operator: 'In',
|
|
157
|
+
values: ['prod']
|
|
158
|
+
}
|
|
159
|
+
]
|
|
160
|
+
};
|
|
161
|
+
const result = labelSelectorToSelector(labelSelector);
|
|
162
|
+
|
|
163
|
+
expect(result).toBe('tier=frontend,env=prod');
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should combine multiple matchLabels and matchExpressions', () => {
|
|
167
|
+
const labelSelector: KubeLabelSelector = {
|
|
168
|
+
matchLabels: {
|
|
169
|
+
tier: 'frontend',
|
|
170
|
+
version: 'v2'
|
|
171
|
+
},
|
|
172
|
+
matchExpressions: [
|
|
173
|
+
{
|
|
174
|
+
key: 'env',
|
|
175
|
+
operator: 'In',
|
|
176
|
+
values: ['dev', 'staging']
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
key: 'region',
|
|
180
|
+
operator: 'In',
|
|
181
|
+
values: ['us-west-1']
|
|
182
|
+
}
|
|
183
|
+
]
|
|
184
|
+
};
|
|
185
|
+
const result = labelSelectorToSelector(labelSelector);
|
|
186
|
+
|
|
187
|
+
expect(result).toBe('tier=frontend,version=v2,env in (dev,staging),region=us-west-1');
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('should combine matchLabels with multiple matchExpressions using in() notation', () => {
|
|
191
|
+
const labelSelector: KubeLabelSelector = {
|
|
192
|
+
matchLabels: { 'app.kubernetes.io/name': 'myapp' },
|
|
193
|
+
matchExpressions: [
|
|
194
|
+
{
|
|
195
|
+
key: 'env',
|
|
196
|
+
operator: 'In',
|
|
197
|
+
values: ['dev', 'test', 'prod']
|
|
198
|
+
}
|
|
199
|
+
]
|
|
200
|
+
};
|
|
201
|
+
const result = labelSelectorToSelector(labelSelector);
|
|
202
|
+
|
|
203
|
+
expect(result).toBe('app.kubernetes.io/name=myapp,env in (dev,test,prod)');
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
describe('unsupported operators', () => {
|
|
208
|
+
it('should throw error for NotIn operator', () => {
|
|
209
|
+
const labelSelector: KubeLabelSelector = {
|
|
210
|
+
matchExpressions: [
|
|
211
|
+
{
|
|
212
|
+
key: 'env',
|
|
213
|
+
operator: 'NotIn',
|
|
214
|
+
values: ['prod']
|
|
215
|
+
}
|
|
216
|
+
]
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
expect(() => labelSelectorToSelector(labelSelector)).toThrow('Unsupported matchExpression found when converting to selector string.');
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
describe('edge cases', () => {
|
|
224
|
+
it('should handle matchExpression with In operator but undefined values', () => {
|
|
225
|
+
const labelSelector: KubeLabelSelector = {
|
|
226
|
+
matchExpressions: [
|
|
227
|
+
{
|
|
228
|
+
key: 'app',
|
|
229
|
+
operator: 'In',
|
|
230
|
+
values: undefined
|
|
231
|
+
}
|
|
232
|
+
]
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
// When values is undefined, the function throws an error
|
|
236
|
+
expect(() => labelSelectorToSelector(labelSelector)).toThrow('Unsupported matchExpression found when converting to selector string.');
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it('should preserve order of matchLabels and matchExpressions', () => {
|
|
240
|
+
const labelSelector: KubeLabelSelector = {
|
|
241
|
+
matchLabels: {
|
|
242
|
+
first: 'value1',
|
|
243
|
+
second: 'value2'
|
|
244
|
+
},
|
|
245
|
+
matchExpressions: [
|
|
246
|
+
{
|
|
247
|
+
key: 'third',
|
|
248
|
+
operator: 'In',
|
|
249
|
+
values: ['value3']
|
|
250
|
+
}
|
|
251
|
+
]
|
|
252
|
+
};
|
|
253
|
+
const result = labelSelectorToSelector(labelSelector);
|
|
254
|
+
|
|
255
|
+
// matchLabels come before matchExpressions
|
|
256
|
+
expect(result).toContain('first=value1');
|
|
257
|
+
expect(result).toContain('second=value2');
|
|
258
|
+
expect(result).toContain('third=value3');
|
|
259
|
+
expect(result.indexOf('first')).toBeLessThan(result.indexOf('third'));
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
});
|
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) {
|
package/utils/color.js
CHANGED
|
@@ -13,7 +13,7 @@ Primary color classes from _light.scss
|
|
|
13
13
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
import Color from 'color';
|
|
17
17
|
|
|
18
18
|
export function createCssVars(color, theme = 'light', name = 'primary') {
|
|
19
19
|
const contrastOpts = theme === 'light' ? LIGHT_CONTRAST_COLORS : DARK_CONTRAST_COLORS;
|
|
@@ -97,6 +97,7 @@ describe('systemInfoProvider', () => {
|
|
|
97
97
|
}),
|
|
98
98
|
'management/schemaFor': jest.fn(),
|
|
99
99
|
localCluster: mockClusters.find((c) => c.id === 'local') || null,
|
|
100
|
+
'features/get': jest.fn(() => 'abc'),
|
|
100
101
|
};
|
|
101
102
|
|
|
102
103
|
(version.getVersionData as jest.Mock).mockReturnValue({
|
|
@@ -129,6 +130,7 @@ describe('systemInfoProvider', () => {
|
|
|
129
130
|
expect(qs).toContain('bl=en-US');
|
|
130
131
|
expect(qs).toContain('bs=1024x768');
|
|
131
132
|
expect(qs).toContain('ss=1920x1080');
|
|
133
|
+
expect(qs).toContain('ff-usc=abc');
|
|
132
134
|
});
|
|
133
135
|
|
|
134
136
|
it('should handle missing or partial data gracefully', () => {
|
|
@@ -161,6 +163,9 @@ describe('systemInfoProvider', () => {
|
|
|
161
163
|
mockGetters['uiplugins/plugins'] = null; // No plugins
|
|
162
164
|
mockGetters['auth/principalId'] = null; // No user
|
|
163
165
|
mockGetters['localCluster'] = null; // No clusters
|
|
166
|
+
mockGetters['features/get'] = () => {
|
|
167
|
+
throw new Error('unknown feature');
|
|
168
|
+
};
|
|
164
169
|
|
|
165
170
|
const infoProvider = new SystemInfoProvider(mockGetters, {});
|
|
166
171
|
const qs = infoProvider.buildQueryString();
|
|
@@ -177,6 +182,7 @@ describe('systemInfoProvider', () => {
|
|
|
177
182
|
expect(qs).not.toContain('lnc=');
|
|
178
183
|
expect(qs).not.toContain('xkn=');
|
|
179
184
|
expect(qs).not.toContain('xcc=');
|
|
185
|
+
expect(qs).not.toContain('ff-usc=');
|
|
180
186
|
});
|
|
181
187
|
|
|
182
188
|
it('should handle getAll returning undefined when types are not registered', () => {
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { SETTING } from '@shell/config/settings';
|
|
11
11
|
import { getVersionData } from '@shell/config/version';
|
|
12
12
|
import { SettingsInfo } from '@shell/utils/dynamic-content/types';
|
|
13
|
+
import { STEVE_CACHE } from '@shell/store/features';
|
|
13
14
|
|
|
14
15
|
const QS_VERSION = 'v1'; // Include a version number in the query string in case we want to version the set of params we are sending
|
|
15
16
|
const UNKNOWN = 'unknown';
|
|
@@ -26,6 +27,29 @@ const SUSE_EXTENSIONS = [
|
|
|
26
27
|
'virtual-clusters'
|
|
27
28
|
];
|
|
28
29
|
|
|
30
|
+
type FeatureFlagInfos = {
|
|
31
|
+
[id: string]: {
|
|
32
|
+
/**
|
|
33
|
+
* Query param, in format `ff-<param>`
|
|
34
|
+
*/
|
|
35
|
+
param: string,
|
|
36
|
+
/**
|
|
37
|
+
* The actual value used by the UI, roughly spec.value || status.default
|
|
38
|
+
*/
|
|
39
|
+
value: string,
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Explicit ff's to send
|
|
45
|
+
*/
|
|
46
|
+
const ffs: FeatureFlagInfos = {
|
|
47
|
+
[STEVE_CACHE]: {
|
|
48
|
+
param: 'usc',
|
|
49
|
+
value: '',
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
29
53
|
/**
|
|
30
54
|
* System information that is collected and which can then be encoded into a query string in the dyanmic content request
|
|
31
55
|
*/
|
|
@@ -47,6 +71,7 @@ type SystemInfo = {
|
|
|
47
71
|
browserSize: string;
|
|
48
72
|
screenSize: string;
|
|
49
73
|
language: string;
|
|
74
|
+
featureFlags: FeatureFlagInfos
|
|
50
75
|
};
|
|
51
76
|
|
|
52
77
|
/**
|
|
@@ -131,6 +156,19 @@ export class SystemInfoProvider {
|
|
|
131
156
|
const screenSize = `${ window.screen?.width || '?' }x${ window.screen?.height || '?' }`;
|
|
132
157
|
const browserSize = `${ window.innerWidth }x${ window.innerHeight }`;
|
|
133
158
|
|
|
159
|
+
const safeFfs = Object.entries(ffs).reduce((res, [id, ff]) => {
|
|
160
|
+
try {
|
|
161
|
+
res[id] = {
|
|
162
|
+
param: ff.param,
|
|
163
|
+
value: getters['features/get'](id),
|
|
164
|
+
};
|
|
165
|
+
} catch (e) {
|
|
166
|
+
console.debug(`Cannot include Feature Flag "${ id }" in dynamic feature request: `, e); // eslint-disable-line no-console
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return res;
|
|
170
|
+
}, {} as FeatureFlagInfos);
|
|
171
|
+
|
|
134
172
|
return {
|
|
135
173
|
systemUUID,
|
|
136
174
|
userHash,
|
|
@@ -146,6 +184,7 @@ export class SystemInfoProvider {
|
|
|
146
184
|
screenSize,
|
|
147
185
|
browserSize,
|
|
148
186
|
language: window.navigator?.language,
|
|
187
|
+
featureFlags: safeFfs,
|
|
149
188
|
};
|
|
150
189
|
}
|
|
151
190
|
|
|
@@ -213,6 +252,10 @@ export class SystemInfoProvider {
|
|
|
213
252
|
params.push(`ss=${ systemData.screenSize }`);
|
|
214
253
|
}
|
|
215
254
|
|
|
255
|
+
Object.values(systemData.featureFlags).forEach((ff) => {
|
|
256
|
+
params.push(`ff-` + `${ ff.param }=${ ff.value }`);
|
|
257
|
+
});
|
|
258
|
+
|
|
216
259
|
return params.join('&');
|
|
217
260
|
}
|
|
218
261
|
}
|
package/utils/favicon.js
CHANGED
|
@@ -9,17 +9,17 @@ export function haveSetFavIcon() {
|
|
|
9
9
|
|
|
10
10
|
export function setFavIcon(store) {
|
|
11
11
|
const res = store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.FAVICON);
|
|
12
|
-
const brandSetting = store.getters['management/
|
|
12
|
+
const brandSetting = store.getters['management/brand'];
|
|
13
13
|
const link = findIconLink(document.head.getElementsByTagName('link'));
|
|
14
14
|
|
|
15
15
|
if (link) {
|
|
16
16
|
let brandImage;
|
|
17
17
|
|
|
18
|
-
if (brandSetting
|
|
18
|
+
if (brandSetting === 'suse') {
|
|
19
19
|
brandImage = require('~shell/assets/brand/suse/favicon.png');
|
|
20
|
-
} else if (brandSetting
|
|
20
|
+
} else if (brandSetting === 'csp') {
|
|
21
21
|
brandImage = require('~shell/assets/brand/csp/favicon.png');
|
|
22
|
-
} else if (brandSetting
|
|
22
|
+
} else if (brandSetting === 'harvester') {
|
|
23
23
|
brandImage = require('~shell/assets/brand/harvester/favicon.png');
|
|
24
24
|
}
|
|
25
25
|
|
package/utils/fleet.ts
CHANGED
|
@@ -184,7 +184,7 @@ class Fleet {
|
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
detailLocation(r: Resource, mgmtClusterName: string): any {
|
|
187
|
-
|
|
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
|
/**
|