@rancher/shell 0.4.0 → 0.5.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.
- package/assets/images/providers/ovhcloudmks.svg +122 -0
- package/assets/images/providers/ovhcloudpubliccloud.svg +122 -0
- package/assets/styles/global/_layout.scss +99 -0
- package/assets/translations/en-us.yaml +30 -5
- package/assets/translations/zh-hans.yaml +1 -1
- package/babel.config.js +7 -1
- package/chart/monitoring/alerting/index.vue +7 -21
- package/chart/monitoring/grafana/index.vue +55 -0
- package/chart/monitoring/index.vue +51 -17
- package/chart/monitoring/prometheus/index.vue +37 -43
- package/chart/rancher-backup/index.vue +2 -1
- package/cloud-credential/azure.vue +4 -17
- package/components/Certificates.vue +164 -0
- package/components/CodeMirror.vue +19 -21
- package/components/CruResource.vue +1 -0
- package/components/EtcdInfoBanner.vue +1 -1
- package/components/ExplorerProjectsNamespaces.vue +25 -1
- package/components/IconOrSvg.vue +1 -1
- package/components/LandingPagePreference.vue +1 -4
- package/components/Questions/index.vue +1 -1
- package/components/ResourceDetail/Masthead.vue +16 -3
- package/components/ResourceTable.vue +14 -2
- package/components/ResourceYaml.vue +5 -0
- package/components/SideNav.vue +1 -1
- package/components/SingleClusterInfo.vue +1 -4
- package/components/Tabbed/index.vue +12 -0
- package/components/fleet/FleetRepos.vue +62 -27
- package/components/fleet/FleetResources.vue +6 -1
- package/components/form/ArrayListSelect.vue +10 -0
- package/components/form/KeyValue.vue +4 -0
- package/components/form/LabeledSelect.vue +4 -0
- package/components/formatter/Checked.vue +11 -3
- package/components/formatter/FleetClusterSummaryGraph.vue +27 -0
- package/components/formatter/FleetSummaryGraph.vue +23 -11
- package/components/formatter/LiveDuration.vue +1 -1
- package/components/formatter/PercentageBar.vue +1 -1
- package/components/formatter/__tests__/Checked.test.ts +19 -0
- package/components/nav/Group.vue +2 -2
- package/components/nav/Header.vue +0 -1
- package/components/nav/TopLevelMenu.vue +36 -6
- package/components/nav/Type.vue +1 -3
- package/components/nav/WindowManager/ContainerLogs.vue +101 -3
- package/components/nav/WindowManager/ContainerShell.vue +6 -1
- package/components/nav/WindowManager/__tests__/ContainerLogs.test.ts +186 -0
- package/components/nav/WindowManager/index.vue +11 -10
- package/components/nav/__tests__/TopLevelMenu.test.ts +33 -0
- package/components/nav/__tests__/Type.test.ts +1 -1
- package/components/nuxt/nuxt-child.js +14 -78
- package/components/nuxt/nuxt.js +1 -1
- package/{layouts → components/templates}/blank.vue +1 -1
- package/{layouts → components/templates}/default.vue +8 -98
- package/{layouts → components/templates}/error.vue +10 -19
- package/{layouts → components/templates}/home.vue +4 -1
- package/{layouts → components/templates}/plain.vue +4 -1
- package/{layouts → components/templates}/standalone.vue +1 -1
- package/{layouts → components/templates}/unauthenticated.vue +1 -1
- package/composables/useCompactInput.ts +20 -0
- package/composables/useLabeledFormElement.ts +138 -0
- package/config/harvester-manager-types.js +2 -0
- package/config/private-label.js +22 -0
- package/config/product/explorer.js +3 -0
- package/config/product/fleet.js +6 -1
- package/config/product/manager.js +8 -2
- package/config/query-params.js +1 -0
- package/config/router.js +385 -364
- package/config/settings.ts +1 -0
- package/config/store.js +1 -1
- package/config/system-namespaces.js +3 -0
- package/config/table-headers.js +47 -0
- package/core/plugin-routes.ts +56 -114
- package/core/plugin.ts +16 -10
- package/core/plugins-loader.js +7 -9
- package/core/plugins.js +0 -3
- package/creators/app/files/.gitlab-ci.yml +1 -1
- package/detail/fleet.cattle.io.cluster.vue +11 -1
- package/detail/provisioning.cattle.io.cluster.vue +4 -3
- package/dialog/ScaleMachineDownDialog.vue +34 -17
- package/edit/__tests__/service.test.ts +89 -0
- package/edit/auth/googleoauth.vue +1 -5
- package/edit/catalog.cattle.io.clusterrepo.vue +18 -0
- package/edit/cloudcredential.vue +2 -0
- package/edit/configmap.vue +2 -1
- package/edit/networking.k8s.io.networkpolicy/__tests__/PolicyRuleTarget.spec.ts +1 -1
- package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +15 -7
- package/edit/provisioning.cattle.io.cluster/__tests__/Advanced.test.ts +112 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +473 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/{CustomCommand.tests.ts → CustomCommand.test.ts} +4 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/DrainOptions.test.ts +1 -1
- package/edit/provisioning.cattle.io.cluster/__tests__/index.test.ts +73 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +7 -1
- package/edit/provisioning.cattle.io.cluster/__tests__/utils/cluster.ts +386 -0
- package/edit/provisioning.cattle.io.cluster/import.vue +2 -2
- package/edit/provisioning.cattle.io.cluster/index.vue +92 -36
- package/edit/provisioning.cattle.io.cluster/rke2.vue +171 -583
- package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +137 -0
- package/edit/provisioning.cattle.io.cluster/tabs/Advanced.vue +157 -0
- package/edit/provisioning.cattle.io.cluster/{Basics.vue → tabs/Basics.vue} +94 -19
- package/edit/provisioning.cattle.io.cluster/{MachinePool.vue → tabs/MachinePool.vue} +1 -0
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +135 -0
- package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +189 -0
- package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +144 -0
- package/edit/provisioning.cattle.io.cluster/tabs/upgrade/index.vue +76 -0
- package/edit/service.vue +12 -0
- package/edit/workload/mixins/workload.js +1 -1
- package/initialize/App.js +25 -71
- package/initialize/client.js +21 -162
- package/initialize/index.js +27 -123
- package/list/management.cattle.io.feature.vue +1 -7
- package/list/node.vue +1 -0
- package/machine-config/__tests__/vmwarevsphere.test.ts +100 -21
- package/machine-config/vmwarevsphere.vue +73 -51
- package/middleware/authenticated.js +10 -17
- package/mixins/auth-config.js +2 -7
- package/mixins/brand.js +29 -41
- package/mixins/labeled-form-element.ts +6 -1
- package/models/__tests__/management.cattle.io.node.ts +85 -0
- package/models/__tests__/management.cattle.io.nodepool.ts +83 -0
- package/models/__tests__/namespace.test.ts +49 -9
- package/models/__tests__/workload.test.ts +91 -0
- package/models/cluster/node.js +4 -4
- package/models/cluster.x-k8s.io.machinedeployment.js +14 -0
- package/models/fleet.cattle.io.cluster.js +4 -0
- package/models/fleet.cattle.io.gitrepo.js +56 -13
- package/models/management.cattle.io.kontainerdriver.js +1 -1
- package/models/management.cattle.io.node.js +18 -14
- package/models/management.cattle.io.nodepool.js +17 -0
- package/models/namespace.js +1 -1
- package/models/pod.js +20 -0
- package/models/provisioning.cattle.io.cluster.js +20 -3
- package/models/secret.js +117 -18
- package/models/workload.js +16 -0
- package/models/workload.service.js +18 -0
- package/package.json +10 -9
- package/pages/about.vue +0 -1
- package/pages/account/create-key.vue +0 -1
- package/pages/account/index.vue +0 -1
- package/pages/auth/login.vue +0 -1
- package/pages/auth/logout.vue +0 -2
- package/pages/auth/setup.vue +0 -4
- package/pages/auth/verify.vue +14 -8
- package/pages/c/_cluster/apps/charts/install.vue +4 -4
- package/pages/c/_cluster/apps/index.vue +0 -2
- package/pages/c/_cluster/auth/index.vue +0 -2
- package/pages/c/_cluster/ecm/index.vue +0 -2
- package/pages/c/_cluster/explorer/index.vue +28 -2
- package/pages/c/_cluster/fleet/index.vue +1 -1
- package/pages/c/_cluster/index.vue +0 -2
- package/pages/c/_cluster/settings/banners.vue +0 -2
- package/pages/c/_cluster/settings/brand.vue +0 -2
- package/pages/c/_cluster/settings/index.vue +0 -2
- package/pages/c/_cluster/settings/links.vue +0 -1
- package/pages/c/_cluster/settings/performance.vue +0 -1
- package/pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue +2 -1
- package/pages/c/_cluster/uiplugins/CatalogList/index.vue +10 -46
- package/pages/c/_cluster/uiplugins/index.vue +0 -2
- package/pages/diagnostic.vue +1 -2
- package/pages/fail-whale.vue +0 -1
- package/pages/prefs.vue +0 -1
- package/pages/support/index.vue +2 -8
- package/pkg/auto-import.js +1 -1
- package/plugins/axios.js +0 -36
- package/plugins/back-button.js +3 -5
- package/plugins/codemirror-loader.js +1 -1
- package/plugins/codemirror.js +41 -0
- package/plugins/dashboard-store/__tests__/{mutations.spec.ts → mutations.test.ts} +1 -1
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +49 -0
- package/plugins/dashboard-store/__tests__/utils/store-mocks.ts +7 -0
- package/plugins/dashboard-store/actions.js +30 -4
- package/plugins/dashboard-store/classify.js +1 -18
- package/plugins/dashboard-store/getters.js +10 -5
- package/plugins/dashboard-store/index.js +0 -12
- package/plugins/dashboard-store/mutations.js +0 -4
- package/plugins/dashboard-store/resource-class.js +59 -18
- package/plugins/steve/__tests__/steve-class.spec.ts +59 -0
- package/plugins/steve/__tests__/utils/steve-mocks.ts +31 -0
- package/plugins/steve/getters.js +4 -1
- package/plugins/steve/norman-class.js +19 -0
- package/plugins/steve/steve-class.js +22 -0
- package/plugins/steve/subscribe.js +4 -10
- package/rancher-components/Accordion/Accordion.test.ts +45 -0
- package/rancher-components/Accordion/Accordion.vue +85 -0
- package/rancher-components/Accordion/index.ts +1 -0
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +19 -2
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +12 -1
- package/rancher-components/Form/Radio/RadioButton.test.ts +7 -3
- package/rancher-components/Form/Radio/RadioGroup.test.ts +30 -0
- package/rancher-components/Form/Radio/RadioGroup.vue +4 -0
- package/rancher-components/StringList/StringList.test.ts +270 -0
- package/rancher-components/StringList/StringList.vue +57 -18
- package/rancher-components/components/Accordion/Accordion.test.ts +45 -0
- package/rancher-components/components/Accordion/Accordion.vue +85 -0
- package/rancher-components/components/Accordion/index.ts +1 -0
- package/rancher-components/components/Form/LabeledInput/LabeledInput.test.ts +19 -2
- package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +4 -1
- package/scripts/.gitlab/workflows/build-extension-catalog.gitlab-ci.yml +50 -0
- package/scripts/extension/parse-tag-name +2 -2
- package/scripts/publish-shell.sh +10 -0
- package/scripts/test-plugins-build.sh +85 -9
- package/server/har-file.js +183 -0
- package/store/catalog.js +1 -1
- package/store/features.js +1 -0
- package/store/i18n.js +11 -0
- package/store/index.js +10 -11
- package/store/prefs.js +33 -35
- package/store/type-map.js +8 -7
- package/tsconfig.json +35 -9
- package/tsconfig.paths.json +18 -0
- package/types/shell/index.d.ts +345 -214
- package/utils/__tests__/create-yaml.test.ts +60 -0
- package/utils/axios.js +0 -19
- package/utils/azure.js +24 -0
- package/utils/create-yaml.js +17 -10
- package/utils/monitoring.js +1 -1
- package/utils/nuxt.js +18 -39
- package/utils/object.js +14 -0
- package/utils/router.scrollBehavior.js +12 -14
- package/utils/time.js +1 -1
- package/utils/url.ts +1 -1
- package/vue.config.js +23 -2
- package/.DS_Store +0 -0
- package/assets/images/providers/aks-black.svg +0 -28
- package/assets/images/providers/aks.svg +0 -31
- package/edit/provisioning.cattle.io.cluster/__tests__/Basics.tests.ts +0 -234
- package/initialize/layouts.ts +0 -26
- package/mixins/fetch.server.js +0 -73
- package/pages/c/index.vue +0 -9
- package/pages/rio/mesh.vue +0 -508
- package/plugins/transitions.js +0 -4
- package/scripts/.DS_Store +0 -0
- package/scripts/verdaccio.log +0 -205
- package/tsconfig.default.json +0 -46
- package/yarn-error.log +0 -200
- /package/components/form/__tests__/{NameNsDescription.ts → NameNsDescription.test.ts} +0 -0
- /package/edit/networking.k8s.io.networkpolicy/__tests__/utils/{selectors.ts → selectors.test.ts} +0 -0
- /package/edit/provisioning.cattle.io.cluster/{AgentConfiguration.vue → tabs/AgentConfiguration.vue} +0 -0
- /package/edit/provisioning.cattle.io.cluster/{MemberRoles.vue → tabs/MemberRoles.vue} +0 -0
- /package/edit/provisioning.cattle.io.cluster/{S3Config.vue → tabs/etcd/S3Config.vue} +0 -0
- /package/edit/provisioning.cattle.io.cluster/{ACE.vue → tabs/networking/ACE.vue} +0 -0
- /package/edit/provisioning.cattle.io.cluster/{RegistryConfigs.vue → tabs/registries/RegistryConfigs.vue} +0 -0
- /package/edit/provisioning.cattle.io.cluster/{RegistryMirrors.vue → tabs/registries/RegistryMirrors.vue} +0 -0
- /package/edit/provisioning.cattle.io.cluster/{DrainOptions.vue → tabs/upgrade/DrainOptions.vue} +0 -0
- /package/plugins/dashboard-store/__tests__/{actions.spec.ts → actions.test.ts} +0 -0
- /package/plugins/dashboard-store/__tests__/{getters.spec.ts → getters.test.ts} +0 -0
package/config/settings.ts
CHANGED
|
@@ -77,6 +77,7 @@ export const SETTING = {
|
|
|
77
77
|
FAVICON: 'ui-favicon',
|
|
78
78
|
UI_PERFORMANCE: 'ui-performance',
|
|
79
79
|
UI_CUSTOM_LINKS: 'ui-custom-links',
|
|
80
|
+
UI_SUPPORTED_K8S_VERSIONS: 'ui-k8s-supported-versions-range',
|
|
80
81
|
/**
|
|
81
82
|
* Allow the backend to force a light/dark theme. Used in non-rancher world and results in the theme used
|
|
82
83
|
* both pre and post log in. If not present defaults to the usual process
|
package/config/store.js
CHANGED
package/config/table-headers.js
CHANGED
|
@@ -706,6 +706,29 @@ export const FLEET_SUMMARY = {
|
|
|
706
706
|
width: 100,
|
|
707
707
|
};
|
|
708
708
|
|
|
709
|
+
export const FLEET_REPO_CLUSTER_SUMMARY = {
|
|
710
|
+
name: 'clusterSummary',
|
|
711
|
+
labelKey: 'tableHeaders.clusterResources',
|
|
712
|
+
value: 'status.resourceCounts',
|
|
713
|
+
sort: false,
|
|
714
|
+
search: false,
|
|
715
|
+
formatter: 'FleetClusterSummaryGraph',
|
|
716
|
+
align: 'center',
|
|
717
|
+
width: 100,
|
|
718
|
+
};
|
|
719
|
+
|
|
720
|
+
export const FLEET_REPO_PER_CLUSTER_STATE = {
|
|
721
|
+
name: 'perClusterState',
|
|
722
|
+
labelKey: 'tableHeaders.repoPerClusterState',
|
|
723
|
+
tooltip: 'tableHeaders.repoPerClusterStateTooltip',
|
|
724
|
+
sort: ['stateSort', 'nameSort'],
|
|
725
|
+
width: 100,
|
|
726
|
+
default: 'unknown',
|
|
727
|
+
formatter: 'BadgeStateFormatter',
|
|
728
|
+
formatterOpts: { arbitrary: true }
|
|
729
|
+
|
|
730
|
+
};
|
|
731
|
+
|
|
709
732
|
export const APP_SUMMARY = {
|
|
710
733
|
name: 'summary',
|
|
711
734
|
labelKey: 'tableHeaders.resources',
|
|
@@ -971,6 +994,30 @@ export const FLEET_BUNDLE_TYPE = {
|
|
|
971
994
|
width: 100,
|
|
972
995
|
};
|
|
973
996
|
|
|
997
|
+
export const FLEET_REPO_CLUSTERS_READY = {
|
|
998
|
+
name: 'clustersReady',
|
|
999
|
+
labelKey: 'tableHeaders.clustersReady',
|
|
1000
|
+
value: 'status.readyClusters',
|
|
1001
|
+
sort: 'status.readyClusters',
|
|
1002
|
+
search: false,
|
|
1003
|
+
};
|
|
1004
|
+
|
|
1005
|
+
export const FLEET_REPO_TARGET = {
|
|
1006
|
+
name: 'target',
|
|
1007
|
+
labelKey: 'tableHeaders.target',
|
|
1008
|
+
value: 'targetInfo.modeDisplay',
|
|
1009
|
+
sort: ['targetInfo.modeDisplay', 'targetInfo.cluster', 'targetInfo.clusterGroup'],
|
|
1010
|
+
|
|
1011
|
+
};
|
|
1012
|
+
|
|
1013
|
+
export const FLEET_REPO = {
|
|
1014
|
+
name: 'repo',
|
|
1015
|
+
labelKey: 'tableHeaders.repo',
|
|
1016
|
+
value: 'repoDisplay',
|
|
1017
|
+
sort: 'repoDisplay',
|
|
1018
|
+
search: ['spec.repo', 'status.commit'],
|
|
1019
|
+
};
|
|
1020
|
+
|
|
974
1021
|
export const UI_PLUGIN_CATALOG = [
|
|
975
1022
|
{
|
|
976
1023
|
name: 'state',
|
package/core/plugin-routes.ts
CHANGED
|
@@ -6,20 +6,8 @@ interface RouteInfo {
|
|
|
6
6
|
route: RouteConfig;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
interface RouteInstallInfo {
|
|
10
|
-
plugin: string;
|
|
11
|
-
route: RouteConfig;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
type RouteInstallHistory = {
|
|
15
|
-
[route: string]: RouteInstallInfo[]
|
|
16
|
-
}
|
|
17
|
-
|
|
18
9
|
export class PluginRoutes {
|
|
19
10
|
router: Router;
|
|
20
|
-
pluginRoutes: RouteConfig[] = [];
|
|
21
|
-
|
|
22
|
-
replacedRoutes: RouteInstallHistory = {};
|
|
23
11
|
|
|
24
12
|
constructor(router: Router) {
|
|
25
13
|
this.router = router;
|
|
@@ -34,70 +22,25 @@ export class PluginRoutes {
|
|
|
34
22
|
});
|
|
35
23
|
}
|
|
36
24
|
|
|
37
|
-
|
|
38
|
-
public uninstall(plugin: any) {
|
|
39
|
-
// List of routes we need to restore
|
|
40
|
-
const restore: RouteInfo[] = [];
|
|
41
|
-
|
|
42
|
-
Object.keys(this.replacedRoutes).forEach((routeName) => {
|
|
43
|
-
const info = this.replacedRoutes[routeName];
|
|
44
|
-
|
|
45
|
-
for (let index = 0; index < info.length; index++) {
|
|
46
|
-
const savedRoute = info[index];
|
|
47
|
-
|
|
48
|
-
if (savedRoute.plugin === plugin.id) {
|
|
49
|
-
// The plugin that is being uninstalled replaced an existing route that we will restore
|
|
50
|
-
if (index === 0) {
|
|
51
|
-
// Need to restore the previous route, since the plugin owned the active route
|
|
52
|
-
info.shift();
|
|
53
|
-
|
|
54
|
-
restore.push({ route: savedRoute.route });
|
|
55
|
-
|
|
56
|
-
break;
|
|
57
|
-
} else {
|
|
58
|
-
// Need to update the previous item so that when it is removed, it restores the correct route
|
|
59
|
-
const previous = info[index - 1];
|
|
60
|
-
|
|
61
|
-
previous.route = savedRoute.route;
|
|
62
|
-
info.splice(index, 1);
|
|
63
|
-
|
|
64
|
-
break;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
// Remove routes from pluginRoutes, update matcher (to avoid dupes when re-adding plugin routes)
|
|
71
|
-
this.pluginRoutes = this.pluginRoutes.filter((pR) => !plugin.routes.find((r: any) => pR === r.route));
|
|
72
|
-
this.updateMatcher([], [
|
|
73
|
-
...this.pluginRoutes,
|
|
74
|
-
...(this.router.options.routes || [])
|
|
75
|
-
]);
|
|
76
|
-
|
|
77
|
-
// Restore appropriate routes
|
|
78
|
-
if (restore.length > 0) {
|
|
79
|
-
this.addRoutes(null, restore);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
public addRoutes(plugin: any, routes: RouteInfo[]) {
|
|
25
|
+
public addRoutes(plugin: any, newRouteInfos: RouteInfo[]) {
|
|
84
26
|
const allRoutes = [
|
|
85
|
-
...this.pluginRoutes,
|
|
86
27
|
...(this.router.options.routes || [])
|
|
87
28
|
];
|
|
88
29
|
|
|
89
30
|
// Need to take into account if routes are being replaced
|
|
90
31
|
// Despite what the docs say, routes are not replaced, so we use a workaround
|
|
91
32
|
// Remove all routes that are being replaced
|
|
92
|
-
|
|
33
|
+
const newRoutes = newRouteInfos.map((ri) => ri.route);
|
|
34
|
+
|
|
35
|
+
this.forEachNestedRoutes(newRoutes, (r: RouteConfig) => {
|
|
93
36
|
// Patch colliding legacy routes that start /:product
|
|
94
|
-
if (r.
|
|
37
|
+
if (r.path?.startsWith('/:product')) {
|
|
95
38
|
// Legacy pattern used by extensions - routes may collide, so modify them not to
|
|
96
39
|
let productName;
|
|
97
40
|
|
|
98
41
|
// If the route has a name (which is always the case for the extensions we have written), use it to get the product name
|
|
99
|
-
if (r.
|
|
100
|
-
const nameParts = r.
|
|
42
|
+
if (r.name) {
|
|
43
|
+
const nameParts = r.name.split('-');
|
|
101
44
|
|
|
102
45
|
// First part of the route name is the product name
|
|
103
46
|
productName = nameParts[0];
|
|
@@ -107,74 +50,40 @@ export class PluginRoutes {
|
|
|
107
50
|
productName = productName || plugin.name;
|
|
108
51
|
|
|
109
52
|
// Replace the path - removing :product and using the actual product name instead - this avoids route collisions
|
|
110
|
-
r.
|
|
111
|
-
r.
|
|
112
|
-
|
|
113
|
-
r.route.meta.product = r.route.meta.product || productName;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// See if the route exists
|
|
117
|
-
let existing: any;
|
|
118
|
-
|
|
119
|
-
if (r.parent) {
|
|
120
|
-
const pExisting = allRoutes.findIndex((route: any) => route.name === r.parent) as any;
|
|
121
|
-
const path = `${ pExisting.path }${ r.route.path }`;
|
|
122
|
-
|
|
123
|
-
// TODO: Validate
|
|
124
|
-
existing = allRoutes.findIndex((route: any) => route.path === path);
|
|
125
|
-
} else {
|
|
126
|
-
// no parent route
|
|
127
|
-
existing = allRoutes.findIndex((route: any) => route.name === r.route.name);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (existing >= 0) {
|
|
131
|
-
const existingRoute = allRoutes[existing];
|
|
132
|
-
|
|
133
|
-
// Store the route so we can restore it on uninstall
|
|
134
|
-
if (plugin && existingRoute?.name) {
|
|
135
|
-
if (!this.replacedRoutes[existingRoute.name]) {
|
|
136
|
-
this.replacedRoutes[existingRoute.name] = [];
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
this.replacedRoutes[existingRoute.name].unshift({
|
|
140
|
-
plugin: plugin.id,
|
|
141
|
-
route: existingRoute
|
|
142
|
-
});
|
|
143
|
-
}
|
|
53
|
+
r.path = `/${ productName }${ r.path.substr(9) }`;
|
|
54
|
+
r.meta = r.meta || {};
|
|
144
55
|
|
|
145
|
-
|
|
56
|
+
r.meta.product = r.meta.product || productName;
|
|
146
57
|
}
|
|
147
58
|
});
|
|
148
59
|
|
|
149
|
-
this.updateMatcher(
|
|
60
|
+
this.updateMatcher(newRouteInfos, allRoutes);
|
|
150
61
|
}
|
|
151
62
|
|
|
152
63
|
private updateMatcher(newRoutes: RouteInfo[], allRoutes: RouteConfig[]) {
|
|
153
64
|
// Note - Always use a new router and replace the existing router's matching
|
|
154
|
-
// Using the existing router and adding routes to it will force nuxt middleware
|
|
65
|
+
// Using the existing router and adding routes to it will force nuxt middleware to
|
|
155
66
|
// execute many times (nuxt middleware boils down to router.beforeEach). This issue was seen refreshing in a harvester cluster with a
|
|
156
67
|
// dynamically loaded cluster
|
|
157
68
|
|
|
158
|
-
const pluginRoutesWithParents: any[] = [];
|
|
159
69
|
const orderedPluginRoutes: any[] = [];
|
|
160
70
|
|
|
161
|
-
// separate plugin routes that have parent and not
|
|
162
|
-
newRoutes.forEach((r: any) => {
|
|
71
|
+
// separate plugin routes that have parent and not, you want to push the new routes in REVERSE order to the front of the existing list so that the order of routes specified by the extension is preserved
|
|
72
|
+
newRoutes.reverse().forEach((r: any) => {
|
|
163
73
|
let foundParentRoute;
|
|
164
74
|
|
|
165
75
|
if (r.parent) {
|
|
166
|
-
foundParentRoute =
|
|
76
|
+
foundParentRoute = this.findInNestedRoutes(allRoutes, (route: RouteConfig) => route.name === r.parent);
|
|
167
77
|
|
|
168
78
|
if (foundParentRoute) {
|
|
169
|
-
|
|
79
|
+
foundParentRoute.children = foundParentRoute?.children || [];
|
|
80
|
+
foundParentRoute.children.unshift(r.route);
|
|
170
81
|
}
|
|
171
82
|
}
|
|
172
83
|
|
|
173
84
|
if (!foundParentRoute) {
|
|
174
|
-
orderedPluginRoutes.
|
|
85
|
+
orderedPluginRoutes.unshift(r.route);
|
|
175
86
|
}
|
|
176
|
-
|
|
177
|
-
this.pluginRoutes.push(r.route);
|
|
178
87
|
});
|
|
179
88
|
|
|
180
89
|
const newRouter: Router = new Router({
|
|
@@ -182,12 +91,45 @@ export class PluginRoutes {
|
|
|
182
91
|
routes: [...orderedPluginRoutes, ...allRoutes]
|
|
183
92
|
});
|
|
184
93
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
94
|
+
(this.router as any).matcher = (newRouter as any).matcher;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Traverse the entire tree of nested routes
|
|
99
|
+
*
|
|
100
|
+
* @param routes The routes we wish to traverse through
|
|
101
|
+
* @param fn -> Return true if you'd like to break the loop early (small)
|
|
102
|
+
* @returns {@boolean} -> Returns true if breaking early
|
|
103
|
+
*/
|
|
104
|
+
private forEachNestedRoutes(routes: RouteConfig[] = [], fn: (route: RouteConfig) => boolean | undefined | void) {
|
|
105
|
+
for (let i = 0; i < routes.length; ++i) {
|
|
106
|
+
const route = routes[i];
|
|
107
|
+
const result = fn(route);
|
|
108
|
+
|
|
109
|
+
if (result || this.forEachNestedRoutes(route.children, fn)) {
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Find a route that matches the criteria defined by fn.
|
|
117
|
+
*
|
|
118
|
+
* @param routes The routes we wish to search through
|
|
119
|
+
* @param fn -> Returns true if the passed in route matches the expected criteria
|
|
120
|
+
* @returns The found route or undefined
|
|
121
|
+
*/
|
|
122
|
+
private findInNestedRoutes(routes: RouteConfig[] = [], fn: (route: RouteConfig) => boolean): RouteConfig | undefined {
|
|
123
|
+
let found: any;
|
|
124
|
+
|
|
125
|
+
this.forEachNestedRoutes(routes, (route) => {
|
|
126
|
+
if (fn(route)) {
|
|
127
|
+
found = route;
|
|
128
|
+
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
188
131
|
});
|
|
189
132
|
|
|
190
|
-
|
|
191
|
-
(this.router as any).matcher = (newRouter as any).matcher;
|
|
133
|
+
return found;
|
|
192
134
|
}
|
|
193
135
|
}
|
package/core/plugin.ts
CHANGED
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
PluginRouteConfig, RegisterStore, UnregisterStore, CoreStoreSpecifics, CoreStoreConfig, OnNavToPackage, OnNavAwayFromPackage, OnLogOut
|
|
16
16
|
} from './types';
|
|
17
17
|
import coreStore, { coreStoreModule, coreStoreState } from '@shell/plugins/dashboard-store';
|
|
18
|
-
import { registerLayout } from '@shell/initialize/layouts';
|
|
19
18
|
|
|
20
19
|
export type ProductFunction = (plugin: IPlugin, store: any) => void;
|
|
21
20
|
|
|
@@ -120,12 +119,27 @@ export class Plugin implements IPlugin {
|
|
|
120
119
|
const parent: string | undefined = hasParent ? parentOrRoute as string : undefined;
|
|
121
120
|
const route: RouteConfig = hasParent ? optionalRoute as RouteConfig : parentOrRoute as RouteConfig;
|
|
122
121
|
|
|
122
|
+
let parentOverride;
|
|
123
|
+
|
|
124
|
+
if (!parent) {
|
|
125
|
+
// TODO: Inspecting the route object in the browser clearly indicates it's not a RouteConfig. The type needs to be changed or at least extended.
|
|
126
|
+
const typelessRoute: any = route;
|
|
127
|
+
|
|
128
|
+
if (typelessRoute.component?.layout) {
|
|
129
|
+
console.warn(`Layouts have been deprecated. We still have parent routes which use the same name and styling as the previous layouts. \n\nFound a component ${ typelessRoute.component.name } with the '${ typelessRoute.component.layout }' layout specified `); // eslint-disable-line no-console
|
|
130
|
+
parentOverride = typelessRoute.component.layout.toLowerCase();
|
|
131
|
+
} else {
|
|
132
|
+
console.warn(`Layouts have been deprecated. We still have parent routes which use the same name and styling as the previous layouts. You should specify a parent, we're currently setting the parent to 'default'`); // eslint-disable-line no-console
|
|
133
|
+
parentOverride = 'default';
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
123
137
|
route.meta = {
|
|
124
138
|
...route?.meta,
|
|
125
139
|
pkg: this.name,
|
|
126
140
|
};
|
|
127
141
|
|
|
128
|
-
this.routes.push({ parent, route });
|
|
142
|
+
this.routes.push({ parent: parentOverride || parent, route });
|
|
129
143
|
}
|
|
130
144
|
|
|
131
145
|
private _addUIConfig(type: string, where: string, when: LocationConfig | string, config: any) {
|
|
@@ -268,14 +282,6 @@ export class Plugin implements IPlugin {
|
|
|
268
282
|
}
|
|
269
283
|
|
|
270
284
|
this.l10n[name].push(fn);
|
|
271
|
-
} else if (type === 'layouts') {
|
|
272
|
-
fn().then((component: any) => {
|
|
273
|
-
if (component.default) {
|
|
274
|
-
registerLayout(name, component.default);
|
|
275
|
-
} else {
|
|
276
|
-
console.error(`Failed to load layout ${ name } because the file didn't export a default component.`); // eslint-disable-line no-console
|
|
277
|
-
}
|
|
278
|
-
});
|
|
279
285
|
} else {
|
|
280
286
|
if (!this.types[type]) {
|
|
281
287
|
this.types[type] = {};
|
package/core/plugins-loader.js
CHANGED
|
@@ -20,14 +20,12 @@ export default function({
|
|
|
20
20
|
dynamicLoader.default($plugin);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
window.Vue = Vue;
|
|
23
|
+
// The libraries we build have Vue externalised, so we need to expose Vue as a global for
|
|
24
|
+
// them to pick up - see: https://cli.vuejs.org/guide/build-targets.html#library
|
|
25
|
+
window.Vue = Vue;
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
27
|
+
// Global libraries - allows us to externalise these to reduce package bundle size
|
|
28
|
+
window.$ = $;
|
|
29
|
+
window.__jszip = JSZip;
|
|
30
|
+
window.__jsyaml = jsyaml;
|
|
33
31
|
}
|
package/core/plugins.js
CHANGED
|
@@ -222,9 +222,6 @@ export default function({
|
|
|
222
222
|
promises.push(...this.removeTypeFromStore(store, 'management', Object.keys(plugin.types.models)));
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
-
// Uninstall routes
|
|
226
|
-
pluginRoutes.uninstall(plugin);
|
|
227
|
-
|
|
228
225
|
// Call plugin uninstall hooks
|
|
229
226
|
plugin.uninstallHooks.forEach((fn) => fn(plugin, this.internal()));
|
|
230
227
|
|
|
@@ -11,4 +11,4 @@ variables:
|
|
|
11
11
|
IMAGE_NAMESPACE: $CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME
|
|
12
12
|
|
|
13
13
|
include:
|
|
14
|
-
- remote: 'https://raw.githubusercontent.com/rancher/dashboard/master/.gitlab/workflows/build-extension-catalog.gitlab-ci.yml'
|
|
14
|
+
- remote: 'https://raw.githubusercontent.com/rancher/dashboard/master/shell/scripts/.gitlab/workflows/build-extension-catalog.gitlab-ci.yml'
|
|
@@ -8,7 +8,7 @@ import { MANAGEMENT, FLEET } from '@shell/config/types';
|
|
|
8
8
|
import { FLEET as FLEET_LABELS } from '@shell/config/labels-annotations';
|
|
9
9
|
|
|
10
10
|
export default {
|
|
11
|
-
name: '
|
|
11
|
+
name: 'FleetDetailCluster',
|
|
12
12
|
|
|
13
13
|
components: {
|
|
14
14
|
Loading,
|
|
@@ -36,6 +36,8 @@ export default {
|
|
|
36
36
|
this.allRepos = await this.$store.dispatch('management/findAll', { type: FLEET.GIT_REPO });
|
|
37
37
|
|
|
38
38
|
await this.$store.dispatch('management/findAll', { type: FLEET.WORKSPACE });
|
|
39
|
+
|
|
40
|
+
await this.$store.dispatch('management/findAll', { type: FLEET.BUNDLE_DEPLOYMENT });
|
|
39
41
|
},
|
|
40
42
|
|
|
41
43
|
data() {
|
|
@@ -43,6 +45,13 @@ export default {
|
|
|
43
45
|
},
|
|
44
46
|
|
|
45
47
|
computed: {
|
|
48
|
+
allBundleDeployments() {
|
|
49
|
+
return this.value.bundleDeployments;
|
|
50
|
+
},
|
|
51
|
+
clusterId() {
|
|
52
|
+
return this.value?.metadata?.labels[FLEET_LABELS.CLUSTER_NAME];
|
|
53
|
+
},
|
|
54
|
+
|
|
46
55
|
repos() {
|
|
47
56
|
return this.allRepos.filter((x) => {
|
|
48
57
|
return x.targetClusters.includes(this.value);
|
|
@@ -76,6 +85,7 @@ export default {
|
|
|
76
85
|
:weight="19"
|
|
77
86
|
>
|
|
78
87
|
<FleetRepos
|
|
88
|
+
:clusterId="clusterId"
|
|
79
89
|
:rows="repos"
|
|
80
90
|
:schema="repoSchema"
|
|
81
91
|
:paging="true"
|
|
@@ -775,10 +775,10 @@ export default {
|
|
|
775
775
|
v-clean-html="t('resourceTable.groupLabel.notInANodePool')"
|
|
776
776
|
/>
|
|
777
777
|
<div
|
|
778
|
-
v-if="group.ref && group.ref.
|
|
778
|
+
v-if="group.ref && group.ref.providerSummary"
|
|
779
779
|
class="description text-muted text-small"
|
|
780
780
|
>
|
|
781
|
-
{{ group.ref.
|
|
781
|
+
{{ group.ref.providerSummary }}
|
|
782
782
|
</div>
|
|
783
783
|
</div>
|
|
784
784
|
<div
|
|
@@ -880,7 +880,7 @@ export default {
|
|
|
880
880
|
<template v-if="group.ref.hasLink('update')">
|
|
881
881
|
<button
|
|
882
882
|
v-clean-tooltip="t('node.list.scaleDown')"
|
|
883
|
-
:disabled="group.ref.
|
|
883
|
+
:disabled="!group.ref.canScaleDownPool()"
|
|
884
884
|
type="button"
|
|
885
885
|
class="btn btn-sm role-secondary"
|
|
886
886
|
@click="toggleScaleDownModal($event, group.ref)"
|
|
@@ -1006,6 +1006,7 @@ export default {
|
|
|
1006
1006
|
>
|
|
1007
1007
|
<SortableTable
|
|
1008
1008
|
class="snapshots"
|
|
1009
|
+
:data-testid="'cluster-snapshots-list'"
|
|
1009
1010
|
:headers="value.isRke1 ? rke1SnapshotHeaders : rke2SnapshotHeaders"
|
|
1010
1011
|
default-sort-by="age"
|
|
1011
1012
|
:table-actions="value.isRke1"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { CAPI as CAPI_LABELS } from '@shell/config/labels-annotations';
|
|
3
|
-
import { CAPI } from '@shell/config/types';
|
|
3
|
+
import { MANAGEMENT, CAPI } from '@shell/config/types';
|
|
4
4
|
import GenericPrompt from './GenericPrompt';
|
|
5
5
|
|
|
6
6
|
export default {
|
|
@@ -14,30 +14,38 @@ export default {
|
|
|
14
14
|
},
|
|
15
15
|
|
|
16
16
|
async fetch() {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
if (this.isRke2) {
|
|
18
|
+
await Promise.all([
|
|
19
|
+
this.$store.dispatch('management/findAll', { type: CAPI.MACHINE_DEPLOYMENT }),
|
|
20
|
+
this.$store.dispatch('management/findAll', { type: CAPI.MACHINE })
|
|
21
|
+
]);
|
|
22
|
+
} else {
|
|
23
|
+
await Promise.all([
|
|
24
|
+
this.$store.dispatch('management/findAll', { type: MANAGEMENT.NODE_POOL }),
|
|
25
|
+
this.$store.dispatch('management/findAll', { type: MANAGEMENT.NODE })
|
|
26
|
+
]);
|
|
27
|
+
}
|
|
21
28
|
},
|
|
22
29
|
|
|
23
30
|
data() {
|
|
24
|
-
const
|
|
25
|
-
const cluster =
|
|
31
|
+
const isRke2 = this.resources[0].cluster?.isRke2;
|
|
32
|
+
const cluster = isRke2 ? this.resources[0].cluster : this.resources[0].provisioningCluster;
|
|
26
33
|
|
|
27
34
|
// Not all machines can be deleted, there must always be at least one left for roles control plane and etcd
|
|
28
35
|
// First ensure that at least one control plane exists... and then check from the remaining machines that at least one etcd exists
|
|
29
36
|
// This isn't optimisied, there may be cases that retaining a single machine with both roles would be better than retaining two with single roles
|
|
30
|
-
const [ignoredControlPlane, safeControlePlaneMachinesToDelete] = this.deleteType('isControlPlane',
|
|
31
|
-
const [ignoredEtcd, safeMachinesToDelete] = this.deleteType('isEtcd', safeControlePlaneMachinesToDelete, cluster);
|
|
37
|
+
const [ignoredControlPlane, safeControlePlaneMachinesToDelete] = this.deleteType('isControlPlane', this.resources, cluster, isRke2);
|
|
38
|
+
const [ignoredEtcd, safeMachinesToDelete] = this.deleteType('isEtcd', safeControlePlaneMachinesToDelete, cluster, isRke2);
|
|
32
39
|
const ignored = [ignoredControlPlane, ignoredEtcd].filter((i) => !!i);
|
|
33
40
|
|
|
34
41
|
return {
|
|
35
42
|
cluster,
|
|
36
|
-
|
|
43
|
+
isRke2,
|
|
44
|
+
allToDelete: this.resources,
|
|
37
45
|
safeMachinesToDelete,
|
|
38
46
|
ignored,
|
|
39
|
-
type:
|
|
40
|
-
config:
|
|
47
|
+
type: this.$store.getters['type-map/labelFor'](this.resources[0].schema, this.resources.length),
|
|
48
|
+
config: {
|
|
41
49
|
title: this.t('promptRemove.title'),
|
|
42
50
|
applyMode: 'delete',
|
|
43
51
|
applyAction: this.remove,
|
|
@@ -46,7 +54,7 @@ export default {
|
|
|
46
54
|
},
|
|
47
55
|
|
|
48
56
|
methods: {
|
|
49
|
-
deleteType(type, allToDelete, cluster) {
|
|
57
|
+
deleteType(type, allToDelete, cluster, isRke2) {
|
|
50
58
|
const allToDeleteByType = allToDelete.reduce((res, m) => {
|
|
51
59
|
if (m[type]) {
|
|
52
60
|
res.typed.push(m);
|
|
@@ -57,7 +65,8 @@ export default {
|
|
|
57
65
|
return res;
|
|
58
66
|
}, { typed: [], others: [] });
|
|
59
67
|
|
|
60
|
-
const
|
|
68
|
+
const machines = isRke2 ? cluster.machines : cluster.nodes;
|
|
69
|
+
const totalTypes = machines.filter((m) => m[type]).length;
|
|
61
70
|
const typesToDelete = allToDeleteByType.typed.length;
|
|
62
71
|
// If we're attempting to remove all control plan machines.... ignore one
|
|
63
72
|
const ignoredType = totalTypes - typesToDelete === 0 ? allToDeleteByType.typed.pop() : undefined;
|
|
@@ -67,6 +76,14 @@ export default {
|
|
|
67
76
|
},
|
|
68
77
|
|
|
69
78
|
async remove() {
|
|
79
|
+
if (!this.isRke2) {
|
|
80
|
+
await Promise.all(this.safeMachinesToDelete.map((node) => {
|
|
81
|
+
return node.norman?.doAction('scaledown');
|
|
82
|
+
}));
|
|
83
|
+
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
70
87
|
// Group machines into pools
|
|
71
88
|
const poolInfo = this.safeMachinesToDelete.reduce((res, m) => {
|
|
72
89
|
res.set(m.pool, res.get(m.pool) || []);
|
|
@@ -103,7 +120,7 @@ export default {
|
|
|
103
120
|
<template slot="body">
|
|
104
121
|
<div class="pl-10 pr-10 mt-20 mb-20 body">
|
|
105
122
|
<div v-if="allToDelete.length === 1">
|
|
106
|
-
{{ t('promptRemove.attemptingToRemove', { type }) }} <b>{{ safeMachinesToDelete[0].
|
|
123
|
+
{{ t('promptRemove.attemptingToRemove', { type }) }} <b>{{ safeMachinesToDelete[0].nameDisplay }}</b>
|
|
107
124
|
</div>
|
|
108
125
|
<div v-else>
|
|
109
126
|
{{ t('promptScaleMachineDown.attemptingToRemove', { type, count: allToDelete.length }, true) }}
|
|
@@ -115,8 +132,8 @@ export default {
|
|
|
115
132
|
<span class="mb-20">{{ t('promptScaleMachineDown.retainedMachine1') }}</span>
|
|
116
133
|
<span
|
|
117
134
|
v-for="i in ignored"
|
|
118
|
-
:key="i.
|
|
119
|
-
v-clean-html="t('promptScaleMachineDown.retainedMachine2', { name: i.
|
|
135
|
+
:key="i.nameDisplay"
|
|
136
|
+
v-clean-html="t('promptScaleMachineDown.retainedMachine2', { name: i.nameDisplay }, true)"
|
|
120
137
|
/>
|
|
121
138
|
</div>
|
|
122
139
|
</div>
|