@rancher/shell 3.0.2-rc.5 → 3.0.2
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/nutanix.svg +12 -1
- package/assets/styles/base/_basic.scss +2 -1
- package/assets/styles/base/_helpers.scss +4 -0
- package/assets/styles/base/_variables.scss +2 -0
- package/assets/styles/global/_labeled-input.scss +5 -13
- package/assets/styles/global/_layout.scss +4 -1
- package/assets/styles/global/_select.scss +5 -0
- package/assets/styles/themes/_dark.scss +1 -3
- package/assets/styles/themes/_light.scss +5 -1
- package/assets/translations/en-us.yaml +130 -23
- package/assets/translations/zh-hans.yaml +0 -3
- package/cloud-credential/azure.vue +1 -1
- package/components/ActionMenuShell.vue +105 -0
- package/components/AppModal.vue +2 -2
- package/components/AsyncButton.vue +2 -0
- package/components/ButtonGroup.vue +9 -2
- package/components/ClusterBadge.vue +1 -0
- package/components/ClusterIconMenu.vue +3 -0
- package/components/ClusterProviderIcon.vue +14 -1
- package/components/CodeMirror.vue +96 -5
- package/components/Collapse.vue +16 -3
- package/components/CruResource.vue +9 -0
- package/components/CruResourceFooter.vue +1 -1
- package/components/ExplorerMembers.vue +2 -1
- package/components/FixedBanner.vue +19 -12
- package/components/Import.vue +14 -1
- package/components/LandingPagePreference.vue +4 -2
- package/components/PodSecurityAdmission.vue +8 -6
- package/components/PromptChangePassword.vue +1 -0
- package/components/PromptRemove.vue +23 -21
- package/components/ResourceDetail/Masthead.vue +30 -11
- package/components/ResourceDetail/__tests__/Masthead.test.ts +61 -0
- package/components/ResourceDetail/index.vue +6 -0
- package/components/ResourceTable.vue +6 -1
- package/components/ResourceYaml.vue +1 -0
- package/components/Setting.vue +115 -0
- package/components/SortableTable/THead.vue +2 -0
- package/components/SortableTable/index.vue +7 -12
- package/components/StatusBadge.vue +71 -0
- package/components/Tabbed/index.vue +16 -15
- package/components/Wizard.vue +108 -104
- package/components/YamlEditor.vue +12 -2
- package/components/__tests__/Collapse.test.ts +2 -2
- package/components/__tests__/FixedBanner.test.ts +3 -3
- package/components/auth/Principal.vue +29 -17
- package/components/auth/__tests__/Principal.test.ts +40 -0
- package/components/auth/login/ldap.vue +7 -0
- package/components/fleet/FleetBundles.vue +1 -1
- package/components/fleet/FleetRepos.vue +1 -1
- package/components/fleet/FleetResources.vue +0 -2
- package/components/fleet/FleetSummary.vue +60 -65
- package/components/fleet/ForceDirectedTreeChart/index.vue +5 -1
- package/components/fleet/__tests__/FleetSummary.test.ts +49 -9
- package/components/form/ArrayList.vue +6 -2
- package/components/form/ColorInput.vue +1 -0
- package/components/form/KeyValue.vue +11 -12
- package/components/form/LabeledSelect.vue +15 -3
- package/components/form/Labels.vue +8 -1
- package/components/form/Members/MembershipEditor.vue +230 -222
- package/components/form/Members/__tests__/MembershipEditor.test.ts +62 -0
- package/components/form/Password.vue +3 -0
- package/components/form/ProjectMemberEditor.vue +6 -3
- package/components/form/ResourceTabs/index.vue +15 -13
- package/components/form/SSHKnownHosts/KnownHostsEditDialog.vue +5 -4
- package/components/form/SchedulingCustomization.vue +85 -0
- package/components/form/Select.vue +3 -2
- package/components/form/SelectOrCreateAuthSecret.vue +2 -1
- package/components/form/UnitInput.vue +3 -4
- package/components/form/__tests__/ArrayList.test.ts +9 -6
- package/components/form/__tests__/LabeledSelect.test.ts +37 -0
- package/components/form/__tests__/SelectOrCreateAuthSecret.test.ts +34 -0
- package/components/form/__tests__/UnitInput.test.ts +4 -5
- package/components/formatter/LiveDate.vue +3 -1
- package/components/formatter/ServiceType.vue +12 -4
- package/components/formatter/WorkloadHealthScale.vue +2 -1
- package/components/nav/Header.vue +35 -2
- package/components/nav/HeaderPageActionMenu.vue +11 -40
- package/components/nav/Jump.vue +8 -2
- package/components/nav/NamespaceFilter.vue +5 -4
- package/components/nav/Pinned.vue +1 -1
- package/components/nav/TopLevelMenu.helper.ts +5 -5
- package/components/nav/TopLevelMenu.vue +1 -12
- package/components/nav/WindowManager/ContainerLogs.vue +96 -58
- package/components/nav/WindowManager/ContainerShell.vue +99 -18
- package/components/nav/WindowManager/index.vue +74 -6
- package/components/nav/__tests__/TopLevelMenu.test.ts +0 -40
- package/components/templates/default.vue +2 -47
- package/config/features.js +1 -0
- package/config/labels-annotations.js +11 -1
- package/config/router/navigation-guards/index.js +2 -1
- package/config/router/navigation-guards/record-last-route.js +24 -0
- package/config/settings.ts +66 -98
- package/config/version.js +1 -1
- package/core/types-provisioning.ts +7 -0
- package/detail/fleet.cattle.io.bundle.vue +7 -0
- package/detail/fleet.cattle.io.cluster.vue +0 -3
- package/detail/fleet.cattle.io.gitrepo.vue +8 -15
- package/detail/provisioning.cattle.io.cluster.vue +8 -2
- package/dialog/DeactivateDriverDialog.vue +5 -5
- package/dialog/GitRepoForceUpdateDialog.vue +132 -0
- package/directives/strip-html-aria-label.js +19 -0
- package/edit/__tests__/cis.cattle.io.clusterscan.test.ts +87 -0
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +217 -37
- package/edit/auth/__tests__/oidc.test.ts +60 -12
- package/edit/auth/ldap/__tests__/config.test.ts +40 -0
- package/edit/auth/ldap/config.vue +67 -89
- package/edit/auth/oidc.vue +16 -2
- package/edit/catalog.cattle.io.clusterrepo.vue +12 -8
- package/edit/cis.cattle.io.clusterscan.vue +13 -1
- package/edit/fleet.cattle.io.gitrepo.vue +198 -72
- package/edit/logging-flow/Match.vue +0 -21
- package/edit/management.cattle.io.project.vue +1 -1
- package/edit/monitoring.coreos.com.prometheusrule/AlertingRule.vue +10 -3
- package/edit/monitoring.coreos.com.prometheusrule/RecordingRule.vue +5 -1
- package/edit/monitoring.coreos.com.prometheusrule/index.vue +5 -2
- package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +8 -1
- package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +2 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/Advanced.test.ts +0 -2
- package/edit/provisioning.cattle.io.cluster/__tests__/CustomCommand.test.ts +55 -15
- package/edit/provisioning.cattle.io.cluster/index.vue +28 -30
- package/edit/provisioning.cattle.io.cluster/rke2.vue +64 -13
- package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +37 -2
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +3 -2
- package/edit/resources.cattle.io.backup.vue +150 -15
- package/edit/secret/__tests__/ssh.test.ts +79 -0
- package/edit/secret/ssh.vue +7 -1
- package/edit/service.vue +0 -3
- package/edit/workload/Job.vue +8 -8
- package/edit/workload/__tests__/Job.test.ts +0 -1
- package/edit/workload/index.vue +3 -1
- package/initialize/install-directives.js +2 -0
- package/initialize/install-plugins.js +6 -1
- package/list/catalog.cattle.io.app.vue +21 -4
- package/list/fleet.cattle.io.bundle.vue +1 -1
- package/list/management.cattle.io.setting.vue +34 -132
- package/list/provisioning.cattle.io.cluster.vue +11 -3
- package/machine-config/vmwarevsphere.vue +15 -8
- package/mixins/__tests__/auth-config.test.ts +74 -0
- package/mixins/__tests__/chart.test.ts +5 -4
- package/mixins/__tests__/create-edit-view.test.ts +38 -0
- package/mixins/auth-config.js +8 -0
- package/mixins/chart.js +2 -2
- package/mixins/create-edit-view/impl.js +4 -1
- package/mixins/vue-select-overrides.js +10 -0
- package/models/__tests__/catalog.cattle.io.app.test.ts +148 -0
- package/models/__tests__/fleet.cattle.io.gitrepo.test.ts +157 -0
- package/models/__tests__/secret.test.ts +56 -13
- package/models/catalog.cattle.io.app.js +112 -37
- package/models/cluster.js +11 -0
- package/models/fleet.cattle.io.bundle.js +40 -2
- package/models/fleet.cattle.io.gitrepo.js +169 -109
- package/models/management.cattle.io.fleetworkspace.js +4 -0
- package/models/management.cattle.io.kontainerdriver.js +7 -0
- package/models/nodedriver.js +4 -1
- package/models/provisioning.cattle.io.cluster.js +24 -0
- package/models/secret.js +1 -1
- package/package.json +5 -5
- package/pages/auth/login.vue +5 -11
- package/pages/auth/verify.vue +11 -1
- package/pages/c/_cluster/apps/charts/index.vue +6 -4
- package/pages/c/_cluster/apps/charts/install.vue +1 -1
- package/pages/c/_cluster/explorer/ConfigBadge.vue +3 -5
- package/pages/c/_cluster/explorer/EventsTable.vue +3 -2
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +9 -9
- package/pages/c/_cluster/explorer/index.vue +33 -35
- package/pages/c/_cluster/explorer/tools/index.vue +3 -3
- package/pages/c/_cluster/fleet/index.vue +0 -5
- package/pages/c/_cluster/legacy/project/index.vue +1 -1
- package/pages/c/_cluster/settings/performance.vue +52 -53
- package/pages/c/_cluster/uiplugins/index.vue +19 -22
- package/pages/home.vue +17 -12
- package/pages/prefs.vue +5 -1
- package/plugins/shortkey.js +10 -1
- package/plugins/steve/steve-pagination-utils.ts +58 -8
- package/promptRemove/management.cattle.io.fleetworkspace.vue +98 -0
- package/promptRemove/management.cattle.io.globalrole.vue +1 -1
- package/promptRemove/management.cattle.io.project.vue +2 -8
- package/promptRemove/management.cattle.io.roletemplate.vue +1 -1
- package/promptRemove/mixin/roleDeletionCheck.js +1 -7
- package/promptRemove/pod.vue +7 -28
- package/rancher-components/Card/Card.vue +9 -1
- package/rancher-components/Form/Checkbox/Checkbox.vue +42 -6
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +30 -3
- package/rancher-components/Form/Radio/RadioButton.vue +18 -3
- package/rancher-components/Form/Radio/RadioGroup.vue +39 -5
- package/rancher-components/LabeledTooltip/LabeledTooltip.vue +13 -1
- package/rancher-components/RcButton/RcButton.test.ts +97 -0
- package/rancher-components/RcButton/RcButton.vue +14 -9
- package/rancher-components/RcDropdown/RcDropdown.vue +3 -1
- package/rancher-components/RcDropdown/RcDropdownItem.vue +8 -2
- package/rancher-components/RcDropdown/RcDropdownMenu.vue +66 -0
- package/rancher-components/RcDropdown/index.ts +1 -0
- package/rancher-components/RcDropdown/types.ts +27 -0
- package/rancher-components/RcDropdown/useDropdownContext.ts +5 -2
- package/scripts/extension/helm/charts/ui-plugin-server/templates/_helpers.tpl +2 -2
- package/scripts/typegen.sh +1 -0
- package/store/__tests__/auth.test.ts +120 -0
- package/store/action-menu.js +13 -3
- package/store/auth.js +14 -9
- package/store/aws.js +9 -2
- package/store/catalog.js +14 -7
- package/store/features.js +1 -0
- package/store/prefs.js +9 -28
- package/store/type-map.utils.ts +4 -0
- package/types/resources/settings.d.ts +27 -20
- package/types/shell/index.d.ts +18 -12
- package/utils/__tests__/array.test.ts +13 -1
- package/utils/__tests__/string.test.ts +80 -1
- package/utils/array.ts +13 -0
- package/utils/auth.js +4 -0
- package/utils/banners.js +0 -45
- package/utils/cluster.js +1 -1
- package/{edit/monitoring.coreos.com.prometheusrule → utils}/duration.js +5 -3
- package/utils/object.js +0 -3
- package/utils/pagination-utils.ts +15 -2
- package/utils/string.js +31 -7
- package/utils/validators/formRules/__tests__/index.test.ts +27 -0
- package/utils/validators/formRules/index.ts +16 -0
- package/edit/provisioning.cattle.io.cluster/import.vue +0 -198
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import GitRepo from '@shell/models/fleet.cattle.io.gitrepo.js';
|
|
2
|
+
|
|
3
|
+
const status = {
|
|
4
|
+
commit: 'foo',
|
|
5
|
+
conditions: [
|
|
6
|
+
{
|
|
7
|
+
error: true,
|
|
8
|
+
lastUpdateTime: '2025-02-28T15:39:52Z',
|
|
9
|
+
message: 'Modified(1) [Cluster fleet-local/local]; configmap.v1 lots-a/test-config-one missing',
|
|
10
|
+
status: 'False',
|
|
11
|
+
transitioning: true,
|
|
12
|
+
type: 'Ready'
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
error: false,
|
|
16
|
+
lastUpdateTime: '2025-02-28T15:36:25Z',
|
|
17
|
+
status: 'True',
|
|
18
|
+
transitioning: false,
|
|
19
|
+
type: 'GitPolling'
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
error: false,
|
|
23
|
+
lastUpdateTime: '2025-02-28T15:36:25Z',
|
|
24
|
+
status: 'False',
|
|
25
|
+
transitioning: false,
|
|
26
|
+
type: 'Reconciling'
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
error: false,
|
|
30
|
+
lastUpdateTime: '2025-02-28T15:36:25Z',
|
|
31
|
+
status: 'False',
|
|
32
|
+
transitioning: false,
|
|
33
|
+
type: 'Stalled'
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
error: false,
|
|
37
|
+
lastUpdateTime: '2025-02-28T15:36:25Z',
|
|
38
|
+
status: 'True',
|
|
39
|
+
transitioning: false,
|
|
40
|
+
type: 'Accepted'
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
desiredReadyClusters: 1,
|
|
44
|
+
display: {
|
|
45
|
+
readyBundleDeployments: '1/2',
|
|
46
|
+
state: 'Modified'
|
|
47
|
+
},
|
|
48
|
+
gitJobStatus: 'Current',
|
|
49
|
+
lastPollingTriggered: '2025-02-28T16:08:39Z',
|
|
50
|
+
observedGeneration: 1,
|
|
51
|
+
perClusterResourceCounts: {
|
|
52
|
+
'fleet-local/local': {
|
|
53
|
+
desiredReady: 2,
|
|
54
|
+
missing: 1,
|
|
55
|
+
modified: 0,
|
|
56
|
+
notReady: 0,
|
|
57
|
+
orphaned: 0,
|
|
58
|
+
ready: 2,
|
|
59
|
+
unknown: 0,
|
|
60
|
+
waitApplied: 0
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
readyClusters: 0,
|
|
64
|
+
resourceCounts: {
|
|
65
|
+
desiredReady: 2,
|
|
66
|
+
missing: 1,
|
|
67
|
+
modified: 0,
|
|
68
|
+
notReady: 0,
|
|
69
|
+
orphaned: 0,
|
|
70
|
+
ready: 2,
|
|
71
|
+
unknown: 0,
|
|
72
|
+
waitApplied: 0
|
|
73
|
+
},
|
|
74
|
+
resources: [
|
|
75
|
+
{
|
|
76
|
+
apiVersion: 'v1',
|
|
77
|
+
id: 'lots-a/test-config-one',
|
|
78
|
+
kind: 'ConfigMap',
|
|
79
|
+
name: 'test-config-one',
|
|
80
|
+
namespace: 'lots-a',
|
|
81
|
+
perClusterState: {
|
|
82
|
+
missing: [
|
|
83
|
+
'fleet-local/local'
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
state: 'Missing',
|
|
87
|
+
type: 'configmap'
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
apiVersion: 'v1',
|
|
91
|
+
id: 'lots-a/test-config-two',
|
|
92
|
+
kind: 'ConfigMap',
|
|
93
|
+
name: 'test-config-two',
|
|
94
|
+
namespace: 'lots-a',
|
|
95
|
+
perClusterState: {
|
|
96
|
+
ready: [
|
|
97
|
+
'fleet-local/local'
|
|
98
|
+
]
|
|
99
|
+
},
|
|
100
|
+
state: 'Ready',
|
|
101
|
+
type: 'configmap'
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
summary: {
|
|
105
|
+
desiredReady: 2,
|
|
106
|
+
modified: 1,
|
|
107
|
+
nonReadyResources: [
|
|
108
|
+
{
|
|
109
|
+
bundleState: 'Modified',
|
|
110
|
+
modifiedStatus: [
|
|
111
|
+
{
|
|
112
|
+
apiVersion: 'v1',
|
|
113
|
+
kind: 'ConfigMap',
|
|
114
|
+
missing: true,
|
|
115
|
+
name: 'test-config-one',
|
|
116
|
+
namespace: 'lots-a'
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
name: 'lots-a-scale-lotsofbundles-one'
|
|
120
|
+
}
|
|
121
|
+
],
|
|
122
|
+
ready: 1
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
describe('class GitRepo', () => {
|
|
127
|
+
describe('resourcesStatuses', () => {
|
|
128
|
+
it.each([
|
|
129
|
+
[]
|
|
130
|
+
])('foobat', () => {
|
|
131
|
+
jest.spyOn(GitRepo.prototype, '$getters', 'get').mockReturnValue({ byId: jest.fn() });
|
|
132
|
+
|
|
133
|
+
jest.spyOn(GitRepo.prototype, 'targetClusters', 'get').mockReturnValue([{
|
|
134
|
+
id: 'fleet-local/local',
|
|
135
|
+
metadata: { labels: {} }
|
|
136
|
+
}]);
|
|
137
|
+
|
|
138
|
+
const gitRepo = new GitRepo({
|
|
139
|
+
metadata: { namespace: 'fleet-local' },
|
|
140
|
+
spec: {},
|
|
141
|
+
status
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const resourcesStatuses = gitRepo.resourcesStatuses;
|
|
145
|
+
|
|
146
|
+
const resource1 = resourcesStatuses.find((el: any) => el.id === 'lots-a/test-config-one');
|
|
147
|
+
|
|
148
|
+
expect(resource1.state).toStrictEqual('missing');
|
|
149
|
+
expect(resource1.detailLocation).toBeUndefined();
|
|
150
|
+
|
|
151
|
+
const resource2 = resourcesStatuses.find((el: any) => el.id === 'lots-a/test-config-two');
|
|
152
|
+
|
|
153
|
+
expect(resource2.state).toStrictEqual('ready');
|
|
154
|
+
expect(resource2.detailLocation).toBeDefined();
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
});
|
|
@@ -1,37 +1,80 @@
|
|
|
1
1
|
import Secret from '@shell/models/secret';
|
|
2
|
+
import { SECRET_TYPES as TYPES } from '@shell/config/secret';
|
|
2
3
|
|
|
3
4
|
describe('class Secret', () => {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
describe('cleanForDownload', () => {
|
|
6
|
+
it('should contains the type attribute if cleanForDownload', async() => {
|
|
7
|
+
const secret = new Secret({});
|
|
8
|
+
const yaml = `apiVersion: v1
|
|
7
9
|
kind: Secret
|
|
8
10
|
metadata:
|
|
9
11
|
name: my-secret
|
|
10
12
|
type: Opaque
|
|
11
13
|
`;
|
|
12
|
-
|
|
14
|
+
const cleanYaml = await secret.cleanForDownload(yaml);
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
expect(cleanYaml).toBe(yaml);
|
|
17
|
+
});
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
it('should remove id, links and actions keys if cleanForDownload', async() => {
|
|
20
|
+
const secret = new Secret({});
|
|
21
|
+
const expectedYamlStr = `apiVersion: v1
|
|
20
22
|
kind: Secret
|
|
21
23
|
metadata:
|
|
22
24
|
name: my-secret
|
|
23
25
|
namespace: default
|
|
24
26
|
type: Opaque
|
|
25
27
|
`;
|
|
26
|
-
|
|
28
|
+
const part = `id: test_id
|
|
27
29
|
links:
|
|
28
30
|
view: https://example.com
|
|
29
31
|
actions:
|
|
30
32
|
remove: https://example.com`;
|
|
31
|
-
|
|
33
|
+
const yaml = `${ expectedYamlStr }
|
|
32
34
|
${ part }`;
|
|
33
|
-
|
|
35
|
+
const cleanYaml = await secret.cleanForDownload(yaml);
|
|
36
|
+
|
|
37
|
+
expect(cleanYaml).toBe(expectedYamlStr);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe('supportsSshKnownHosts', () => {
|
|
42
|
+
it.each([
|
|
43
|
+
[
|
|
44
|
+
false,
|
|
45
|
+
'type is not SSH',
|
|
46
|
+
'generic',
|
|
47
|
+
{ known_hosts: 'S05PV05fSE9TVFM=' },
|
|
48
|
+
],
|
|
49
|
+
[
|
|
50
|
+
false,
|
|
51
|
+
'missing known_hosts',
|
|
52
|
+
TYPES.SSH,
|
|
53
|
+
{},
|
|
54
|
+
],
|
|
55
|
+
[
|
|
56
|
+
false,
|
|
57
|
+
'data is null',
|
|
58
|
+
TYPES.SSH,
|
|
59
|
+
null,
|
|
60
|
+
],
|
|
61
|
+
[
|
|
62
|
+
true,
|
|
63
|
+
'type is SSH key and known_hosts exists',
|
|
64
|
+
TYPES.SSH,
|
|
65
|
+
{ known_hosts: 'S05PV05fSE9TVFM=' },
|
|
66
|
+
],
|
|
67
|
+
])('is %p if %p', (
|
|
68
|
+
supported,
|
|
69
|
+
descr,
|
|
70
|
+
_type,
|
|
71
|
+
data
|
|
72
|
+
) => {
|
|
73
|
+
const secret = new Secret({ _type, data });
|
|
74
|
+
|
|
75
|
+
const result = secret.supportsSshKnownHosts;
|
|
34
76
|
|
|
35
|
-
|
|
77
|
+
expect(result).toBe(supported);
|
|
78
|
+
});
|
|
36
79
|
});
|
|
37
80
|
});
|
|
@@ -9,7 +9,7 @@ import { SHOW_PRE_RELEASE } from '@shell/store/prefs';
|
|
|
9
9
|
import { set } from '@shell/utils/object';
|
|
10
10
|
|
|
11
11
|
import SteveModel from '@shell/plugins/steve/steve-class';
|
|
12
|
-
import { compatibleVersionsFor } from '@shell/store/catalog';
|
|
12
|
+
import { compatibleVersionsFor, APP_UPGRADE_STATUS } from '@shell/store/catalog';
|
|
13
13
|
|
|
14
14
|
export default class CatalogApp extends SteveModel {
|
|
15
15
|
showMasthead(mode) {
|
|
@@ -22,6 +22,7 @@ export default class CatalogApp extends SteveModel {
|
|
|
22
22
|
set(this, 'skipCRDs', false);
|
|
23
23
|
set(this, 'timeout', 300);
|
|
24
24
|
set(this, 'wait', true);
|
|
25
|
+
set(this, 'upgradeAvailableVersion', '');
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
get _availableActions() {
|
|
@@ -40,7 +41,7 @@ export default class CatalogApp extends SteveModel {
|
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
get warnDeletionMessage() {
|
|
43
|
-
if (this.upgradeAvailable ===
|
|
44
|
+
if (this.upgradeAvailable === APP_UPGRADE_STATUS.NOT_APPLICABLE) {
|
|
44
45
|
const manager = this.spec?.chart?.metadata?.annotations?.[CATALOG_ANNOTATIONS.MANAGED] || 'Rancher';
|
|
45
46
|
|
|
46
47
|
return this.t('catalog.delete.warning.managed', { manager: manager === 'true' ? 'Rancher' : manager, name: this.name });
|
|
@@ -49,25 +50,56 @@ export default class CatalogApp extends SteveModel {
|
|
|
49
50
|
return null;
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Finds matching charts based on the current chart's name, repository, and other attributes.
|
|
55
|
+
* The function filters out charts that do not meet specific criteria, including version and home value matches.
|
|
56
|
+
*
|
|
57
|
+
* @param includeHidden - Whether to include hidden charts in the search.
|
|
58
|
+
* @returns An array of matching chart objects that meet the specified criteria.
|
|
59
|
+
*/
|
|
60
|
+
matchingCharts(includeHidden) {
|
|
53
61
|
const chart = this.spec?.chart;
|
|
54
62
|
|
|
55
63
|
if ( !chart ) {
|
|
56
|
-
return;
|
|
64
|
+
return [];
|
|
57
65
|
}
|
|
58
66
|
|
|
59
67
|
const chartName = chart.metadata?.name;
|
|
60
68
|
const repoName = chart.metadata?.annotations?.[CATALOG_ANNOTATIONS.SOURCE_REPO_NAME] || this.metadata?.labels?.[CATALOG_ANNOTATIONS.CLUSTER_REPO_NAME];
|
|
61
|
-
const preferRepoType = chart.metadata?.annotations?.[CATALOG_ANNOTATIONS.SOURCE_REPO_TYPE] || 'cluster';
|
|
62
69
|
|
|
63
|
-
const
|
|
70
|
+
const matchingCharts = this.$rootGetters['catalog/chart']({
|
|
64
71
|
chartName,
|
|
65
72
|
repoName,
|
|
66
|
-
|
|
67
|
-
|
|
73
|
+
includeHidden,
|
|
74
|
+
multiple: true
|
|
75
|
+
}) || [];
|
|
76
|
+
|
|
77
|
+
if (matchingCharts.length === 0) {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Filtering matches by verifying if the current version is in the matched chart's available versions, and that the home value matches as well
|
|
82
|
+
const thisHome = chart?.metadata?.home;
|
|
83
|
+
const bestMatches = matchingCharts.filter(({ versions }) => {
|
|
84
|
+
// First checking if the latest version has the same home value
|
|
85
|
+
if (thisHome === versions[0]?.home) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
for (let i = 1; i < versions.length; i++) {
|
|
90
|
+
const { version, home } = versions[i];
|
|
91
|
+
|
|
92
|
+
// Finding the exact version, if the version is not there, then most likely it's not a match
|
|
93
|
+
// if the exact version is found, then we can compare the home value
|
|
94
|
+
if (version === this.currentVersion && (home === thisHome)) {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return false;
|
|
68
100
|
});
|
|
69
101
|
|
|
70
|
-
return
|
|
102
|
+
return bestMatches;
|
|
71
103
|
}
|
|
72
104
|
|
|
73
105
|
get currentVersion() {
|
|
@@ -75,28 +107,42 @@ export default class CatalogApp extends SteveModel {
|
|
|
75
107
|
}
|
|
76
108
|
|
|
77
109
|
get upgradeAvailable() {
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
110
|
+
// one of the following statuses gets returned:
|
|
111
|
+
// NOT_APPLICABLE - managed by fleet
|
|
112
|
+
// NO_UPGRADE - no upgrade found
|
|
113
|
+
// SINGLE_UPGRADE - a version available to upgrade to
|
|
114
|
+
// MULTIPLE_UPGRADES - more than one match found
|
|
81
115
|
|
|
82
116
|
if (
|
|
83
117
|
this.spec?.chart?.metadata?.annotations?.[CATALOG_ANNOTATIONS.MANAGED] ||
|
|
84
118
|
this.spec?.chart?.metadata?.annotations?.[FLEET.BUNDLE_ID]
|
|
85
119
|
) {
|
|
86
120
|
// Things managed by fleet shouldn't show upgrade available even if there might be.
|
|
87
|
-
return
|
|
121
|
+
return APP_UPGRADE_STATUS.NOT_APPLICABLE;
|
|
88
122
|
}
|
|
89
|
-
const chart = this.matchingChart(false);
|
|
90
123
|
|
|
91
|
-
|
|
92
|
-
|
|
124
|
+
const charts = this.matchingCharts(false);
|
|
125
|
+
|
|
126
|
+
if (charts.length === 0) {
|
|
127
|
+
return APP_UPGRADE_STATUS.NO_UPGRADE;
|
|
93
128
|
}
|
|
94
129
|
|
|
95
|
-
|
|
130
|
+
// Handle single chart logic
|
|
131
|
+
if (charts.length === 1) {
|
|
132
|
+
return this.evaluateUpgradeForChart(charts[0]);
|
|
133
|
+
}
|
|
96
134
|
|
|
135
|
+
// Handle multiple upgrade matches
|
|
136
|
+
return this.handleMultipleUpgradeMatches(charts);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Evaluates upgrade status for a single chart.
|
|
141
|
+
*/
|
|
142
|
+
evaluateUpgradeForChart(chart) {
|
|
143
|
+
const workerOSs = this.$rootGetters['currentCluster'].workerOSs;
|
|
97
144
|
const showPreRelease = this.$rootGetters['prefs/get'](SHOW_PRE_RELEASE);
|
|
98
145
|
|
|
99
|
-
const thisVersion = this.spec?.chart?.metadata?.version;
|
|
100
146
|
let versions = chart.versions;
|
|
101
147
|
|
|
102
148
|
if (!showPreRelease) {
|
|
@@ -108,45 +154,75 @@ export default class CatalogApp extends SteveModel {
|
|
|
108
154
|
const newestChart = versions?.[0];
|
|
109
155
|
const newestVersion = newestChart?.version;
|
|
110
156
|
|
|
111
|
-
if (
|
|
112
|
-
return
|
|
157
|
+
if (!this.currentVersion || !newestVersion) {
|
|
158
|
+
return APP_UPGRADE_STATUS.NO_UPGRADE;
|
|
113
159
|
}
|
|
114
160
|
|
|
115
|
-
if (
|
|
116
|
-
|
|
161
|
+
if (compare(this.currentVersion, newestVersion) < 0) {
|
|
162
|
+
// Set the available upgrade version to be used in other places
|
|
163
|
+
this.upgradeAvailableVersion = cleanupVersion(newestVersion);
|
|
164
|
+
|
|
165
|
+
return APP_UPGRADE_STATUS.SINGLE_UPGRADE;
|
|
117
166
|
}
|
|
118
167
|
|
|
119
|
-
return
|
|
168
|
+
return APP_UPGRADE_STATUS.NO_UPGRADE;
|
|
120
169
|
}
|
|
121
170
|
|
|
122
|
-
|
|
123
|
-
|
|
171
|
+
/**
|
|
172
|
+
* Handles the case where multiple upgrade matches are found.
|
|
173
|
+
* @param charts - Array of matching charts
|
|
174
|
+
*/
|
|
175
|
+
handleMultipleUpgradeMatches(charts) {
|
|
176
|
+
const qualifiedCharts = [];
|
|
177
|
+
|
|
178
|
+
for (const chart of charts) {
|
|
179
|
+
const status = this.evaluateUpgradeForChart(chart);
|
|
124
180
|
|
|
125
|
-
|
|
126
|
-
|
|
181
|
+
if (status === APP_UPGRADE_STATUS.SINGLE_UPGRADE) {
|
|
182
|
+
qualifiedCharts.push(chart);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (qualifiedCharts.length > 1) {
|
|
187
|
+
return APP_UPGRADE_STATUS.MULTIPLE_UPGRADES;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (qualifiedCharts.length === 1) {
|
|
191
|
+
const newestVersion = qualifiedCharts[0]?.versions?.[0]?.version;
|
|
192
|
+
|
|
193
|
+
this.upgradeAvailableVersion = cleanupVersion(newestVersion);
|
|
194
|
+
|
|
195
|
+
return APP_UPGRADE_STATUS.SINGLE_UPGRADE;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return APP_UPGRADE_STATUS.NO_UPGRADE;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
get upgradeAvailableSort() {
|
|
202
|
+
if (this.upgradeAvailable === APP_UPGRADE_STATUS.SINGLE_UPGRADE) {
|
|
203
|
+
return sortable(this.upgradeAvailableVersion);
|
|
127
204
|
}
|
|
128
205
|
|
|
129
|
-
return
|
|
206
|
+
return '~'; // Tilde sorts after all numbers and letters
|
|
130
207
|
}
|
|
131
208
|
|
|
132
209
|
get currentVersionCompatible() {
|
|
133
210
|
const workerOSs = this.$rootGetters['currentCluster'].workerOSs;
|
|
134
211
|
|
|
135
|
-
const chart = this.
|
|
136
|
-
const thisVersion = this.spec?.chart?.metadata?.version;
|
|
212
|
+
const chart = this.matchingCharts(false)[0];
|
|
137
213
|
|
|
138
214
|
if (!chart) {
|
|
139
215
|
return true;
|
|
140
216
|
}
|
|
141
217
|
|
|
142
|
-
const versionInChart = chart.versions.find((version) => version.version ===
|
|
218
|
+
const versionInChart = chart.versions.find((version) => version.version === this.currentVersion);
|
|
143
219
|
|
|
144
220
|
if (!versionInChart) {
|
|
145
221
|
return true;
|
|
146
222
|
}
|
|
147
223
|
const compatibleVersions = compatibleVersionsFor(chart, workerOSs, true) || [];
|
|
148
224
|
|
|
149
|
-
const thisVersionCompatible = !!compatibleVersions.find((version) => version.version ===
|
|
225
|
+
const thisVersionCompatible = !!compatibleVersions.find((version) => version.version === this.currentVersion);
|
|
150
226
|
|
|
151
227
|
return thisVersionCompatible;
|
|
152
228
|
}
|
|
@@ -155,7 +231,7 @@ export default class CatalogApp extends SteveModel {
|
|
|
155
231
|
if (this.currentVersionCompatible) {
|
|
156
232
|
return null;
|
|
157
233
|
}
|
|
158
|
-
if (this.
|
|
234
|
+
if (this.upgradeAvailableVersion) {
|
|
159
235
|
return this.t('catalog.os.versionIncompatible');
|
|
160
236
|
}
|
|
161
237
|
|
|
@@ -163,12 +239,11 @@ export default class CatalogApp extends SteveModel {
|
|
|
163
239
|
}
|
|
164
240
|
|
|
165
241
|
goToUpgrade(forceVersion, fromTools) {
|
|
166
|
-
const match = this.
|
|
167
|
-
const versionName = this.spec?.chart?.metadata?.version;
|
|
242
|
+
const match = this.matchingCharts(true)[0];
|
|
168
243
|
const query = {
|
|
169
244
|
[NAMESPACE]: this.metadata.namespace,
|
|
170
245
|
[NAME]: this.metadata.name,
|
|
171
|
-
[VERSION]: forceVersion ||
|
|
246
|
+
[VERSION]: forceVersion || this.currentVersion,
|
|
172
247
|
};
|
|
173
248
|
|
|
174
249
|
if ( match ) {
|
|
@@ -223,7 +298,7 @@ export default class CatalogApp extends SteveModel {
|
|
|
223
298
|
}
|
|
224
299
|
|
|
225
300
|
get versionDisplay() {
|
|
226
|
-
return cleanupVersion(this.
|
|
301
|
+
return cleanupVersion(this.currentVersion);
|
|
227
302
|
}
|
|
228
303
|
|
|
229
304
|
get versionSort() {
|
package/models/cluster.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import NormanModel from '@shell/plugins/steve/norman-class';
|
|
2
|
+
import { CAPI } from '@shell/config/types';
|
|
2
3
|
|
|
3
4
|
export const LABEL_CONTAINS_PROTECTED = [
|
|
4
5
|
'io.cattle.lifecycle',
|
|
@@ -13,6 +14,7 @@ export const ANNOTATIONS_CONTAINS_PROTECTED = [
|
|
|
13
14
|
'k3s.io',
|
|
14
15
|
'kubernetes.io',
|
|
15
16
|
'k3s.io',
|
|
17
|
+
'rancher.io'
|
|
16
18
|
];
|
|
17
19
|
export default class NormanCluster extends NormanModel {
|
|
18
20
|
get systemLabels() {
|
|
@@ -30,4 +32,13 @@ export default class NormanCluster extends NormanModel {
|
|
|
30
32
|
get hasSystemAnnotations() {
|
|
31
33
|
return !!(this.systemAnnotations || []).length;
|
|
32
34
|
}
|
|
35
|
+
|
|
36
|
+
waitForProvisioning(timeout = 60000, interval) {
|
|
37
|
+
return this.waitForTestFn(() => {
|
|
38
|
+
const ns = this.annotations['objectset.rio.cattle.io/owner-namespace'] || 'fleet-default';
|
|
39
|
+
const id = `${ ns }/${ this.id }`;
|
|
40
|
+
|
|
41
|
+
return id && !!this.$rootGetters['management/byId'](CAPI.RANCHER_CLUSTER, id);
|
|
42
|
+
}, this.$rootGetters['i18n/t']('cluster.managementTimeout'), timeout, interval);
|
|
43
|
+
}
|
|
33
44
|
}
|
|
@@ -2,7 +2,8 @@ import { escapeHtml, ucFirst } from '@shell/utils/string';
|
|
|
2
2
|
import SteveModel from '@shell/plugins/steve/steve-class';
|
|
3
3
|
import typeHelper from '@shell/utils/type-helpers';
|
|
4
4
|
import { addObject, addObjects, findBy } from '@shell/utils/array';
|
|
5
|
-
import { FLEET } from '@shell/config/types';
|
|
5
|
+
import { FLEET, MANAGEMENT } from '@shell/config/types';
|
|
6
|
+
import { FLEET as FLEET_ANNOTATIONS } from '@shell/config/labels-annotations';
|
|
6
7
|
import { convertSelectorObj, matching } from '@shell/utils/selector';
|
|
7
8
|
|
|
8
9
|
export default class FleetBundle extends SteveModel {
|
|
@@ -21,7 +22,7 @@ export default class FleetBundle extends SteveModel {
|
|
|
21
22
|
get repoName() {
|
|
22
23
|
const labels = this.metadata?.labels || {};
|
|
23
24
|
|
|
24
|
-
return labels[
|
|
25
|
+
return labels[FLEET_ANNOTATIONS.REPO_NAME];
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
get targetClusters() {
|
|
@@ -127,4 +128,41 @@ export default class FleetBundle extends SteveModel {
|
|
|
127
128
|
);
|
|
128
129
|
}
|
|
129
130
|
}
|
|
131
|
+
|
|
132
|
+
get authorId() {
|
|
133
|
+
return this.metadata?.labels?.[FLEET_ANNOTATIONS.CREATED_BY_USER_ID];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
get author() {
|
|
137
|
+
if (this.authorId) {
|
|
138
|
+
return this.$rootGetters['management/byId'](MANAGEMENT.USER, this.authorId);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
get createdBy() {
|
|
145
|
+
const displayName = this.metadata?.labels?.[FLEET_ANNOTATIONS.CREATED_BY_USER_NAME];
|
|
146
|
+
|
|
147
|
+
if (!displayName) {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
displayName,
|
|
153
|
+
location: !this.author ? null : {
|
|
154
|
+
name: 'c-cluster-product-resource-id',
|
|
155
|
+
params: {
|
|
156
|
+
cluster: '_',
|
|
157
|
+
product: 'auth',
|
|
158
|
+
resource: MANAGEMENT.USER,
|
|
159
|
+
id: this.author.id,
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
get showCreatedBy() {
|
|
166
|
+
return !!this.createdBy;
|
|
167
|
+
}
|
|
130
168
|
}
|