@rancher/shell 3.0.0-rc.9 → 3.0.1-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/brand/harvester/favicon.png +0 -0
- package/assets/brand/harvester/metadata.json +3 -0
- package/assets/images/pl/harvester.svg +1 -0
- package/assets/translations/en-us.yaml +37 -15
- package/assets/translations/zh-hans.yaml +2 -5
- package/components/BrandImage.vue +5 -1
- package/components/CopyToClipboardText.vue +2 -0
- package/components/CruResourceFooter.vue +1 -0
- package/components/DetailTop.vue +1 -1
- package/components/EmberPage.vue +0 -8
- package/components/ExplorerMembers.vue +5 -1
- package/components/ExplorerProjectsNamespaces.vue +39 -15
- package/components/HardwareResourceGauge.vue +12 -2
- package/components/InputOrDisplay.vue +6 -2
- package/components/LandingPagePreference.vue +2 -2
- package/components/MessageLink.vue +1 -1
- package/components/ResourceDetail/Masthead.vue +22 -1
- package/components/ResourceDetail/index.vue +2 -8
- package/components/ResourceTable.vue +40 -7
- package/components/ResourceYaml.vue +1 -1
- package/components/SideNav.vue +1 -1
- package/components/SortableTable/actions.js +1 -1
- package/components/SortableTable/index.vue +17 -1
- package/components/SortableTable/selection.js +1 -1
- package/components/SortableTable/sorting.js +11 -3
- package/components/TableDataUserIcon.vue +1 -1
- package/components/fleet/FleetClusters.vue +0 -3
- package/components/fleet/FleetRepos.vue +0 -7
- package/components/form/ArrayList.vue +5 -1
- package/components/form/ArrayListSelect.vue +5 -1
- package/components/form/HookOption.vue +31 -29
- package/components/form/KeyValue.vue +1 -1
- package/components/form/LabeledSelect.vue +26 -7
- package/components/form/LifecycleHooks.vue +2 -2
- package/components/form/Password.vue +7 -1
- package/components/form/UnitInput.vue +10 -1
- package/components/form/__tests__/UnitInput.test.ts +1 -0
- package/components/formatter/ClusterProvider.vue +3 -3
- package/components/formatter/ImagePercentageBar.vue +1 -1
- package/components/formatter/SecretData.vue +1 -1
- package/components/formatter/Si.vue +5 -1
- package/components/formatter/Translate.vue +1 -1
- package/components/nav/Header.vue +38 -17
- package/components/nav/NamespaceFilter.vue +5 -8
- package/components/nav/TopLevelMenu.vue +11 -51
- package/components/nav/WorkspaceSwitcher.vue +0 -1
- package/config/labels-annotations.js +2 -0
- package/config/private-label.js +2 -1
- package/config/router/routes.js +2 -26
- package/config/settings.ts +5 -0
- package/config/table-headers.js +15 -0
- package/config/types.js +3 -0
- package/config/version.js +2 -0
- package/detail/catalog.cattle.io.app.vue +17 -4
- package/detail/fleet.cattle.io.bundle.vue +5 -68
- package/detail/fleet.cattle.io.cluster.vue +11 -9
- package/detail/fleet.cattle.io.gitrepo.vue +3 -2
- package/directives/clean-tooltip.js +4 -4
- package/edit/cis.cattle.io.clusterscan.vue +4 -3
- package/edit/fleet.cattle.io.gitrepo.vue +11 -8
- package/edit/logging-flow/Match.vue +75 -42
- package/edit/logging-flow/index.vue +89 -10
- package/edit/logging.banzaicloud.io.output/index.vue +2 -2
- package/edit/management.cattle.io.project.vue +4 -3
- package/edit/monitoring.coreos.com.prometheusrule/AlertingRule.vue +5 -5
- package/edit/monitoring.coreos.com.prometheusrule/index.vue +1 -1
- package/edit/namespace.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/__tests__/Advanced.test.ts +26 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/DirectoryConfig.test.ts +63 -149
- package/edit/provisioning.cattle.io.cluster/index.vue +2 -1
- package/edit/provisioning.cattle.io.cluster/rke2.vue +4 -4
- package/edit/provisioning.cattle.io.cluster/tabs/Advanced.vue +7 -2
- package/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue +108 -35
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryMirrors.vue +1 -1
- package/edit/workload/mixins/workload.js +1 -1
- package/list/harvesterhci.io.management.cluster.vue +244 -0
- package/list/namespace.vue +16 -4
- package/mixins/browser-tab-visibility.js +1 -1
- package/mixins/chart.js +6 -2
- package/mixins/metric-poller.js +1 -1
- package/mixins/resource-fetch.js +1 -1
- package/models/__tests__/management.cattle.io.cluster.test.ts +45 -3
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +0 -86
- package/models/catalog.cattle.io.app.js +108 -21
- package/models/cloudcredential.js +4 -4
- package/models/fleet.cattle.io.bundle.js +3 -1
- package/models/fleet.cattle.io.gitrepo.js +51 -63
- package/models/k8s.cni.cncf.io.networkattachmentdefinition.js +88 -0
- package/models/management.cattle.io.cluster.js +39 -7
- package/models/management.cattle.io.project.js +4 -0
- package/models/management.cattle.io.setting.js +25 -0
- package/models/provisioning.cattle.io.cluster.js +6 -16
- package/models/storage.k8s.io.storageclass.js +15 -4
- package/models/workload.js +1 -1
- package/package.json +5 -5
- package/pages/auth/login.vue +3 -2
- package/pages/auth/logout.vue +7 -9
- package/pages/auth/setup.vue +4 -1
- package/pages/c/_cluster/apps/charts/install.vue +11 -3
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +1 -1
- package/pages/c/_cluster/explorer/index.vue +1 -2
- package/pages/c/_cluster/fleet/index.vue +13 -9
- package/pages/c/_cluster/settings/brand.vue +4 -1
- package/pages/c/_cluster/uiplugins/index.vue +4 -2
- package/pages/diagnostic.vue +1 -0
- package/pages/prefs.vue +22 -10
- package/plugins/dashboard-store/resource-class.js +11 -3
- package/plugins/steve/mutations.js +4 -1
- package/plugins/steve/steve-pagination-utils.ts +1 -1
- package/plugins/steve/subscribe.js +3 -4
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +7 -2
- package/store/features.js +1 -0
- package/store/i18n.js +5 -1
- package/store/prefs.js +8 -0
- package/types/resources/fleet.d.ts +40 -0
- package/types/shell/index.d.ts +442 -396
- package/utils/__tests__/object.test.ts +152 -1
- package/utils/auth.js +1 -1
- package/utils/create-yaml.js +1 -1
- package/utils/favicon.js +2 -0
- package/utils/fleet.ts +159 -0
- package/utils/gc/gc.ts +1 -1
- package/utils/object.js +37 -0
- package/utils/string.js +9 -0
- package/utils/v-sphere.ts +31 -0
- package/utils/validators/cron-schedule.js +1 -1
- package/utils/validators/formRules/index.ts +2 -2
- package/config/product/multi-cluster-apps.js +0 -61
|
@@ -1,14 +1,29 @@
|
|
|
1
1
|
|
|
2
2
|
<script>
|
|
3
|
-
import { Checkbox } from '@components/Form/Checkbox';
|
|
4
3
|
import { LabeledInput } from '@components/Form/LabeledInput';
|
|
5
4
|
import { _CREATE } from '@shell/config/query-params';
|
|
5
|
+
import RadioGroup from '@components/Form/Radio/RadioGroup.vue';
|
|
6
|
+
|
|
7
|
+
export const DATA_DIR_RADIO_OPTIONS = {
|
|
8
|
+
DEFAULT: 'defaultDataDir',
|
|
9
|
+
COMMON: 'commonBaseDataDir',
|
|
10
|
+
CUSTOM: 'customDataDir',
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const DEFAULT_COMMON_BASE_PATH = '/var/lib/rancher';
|
|
14
|
+
|
|
15
|
+
export const DEFAULT_SUBDIRS = {
|
|
16
|
+
AGENT: 'agent',
|
|
17
|
+
PROVISIONING: 'provisioning',
|
|
18
|
+
K8S_DISTRO_RKE2: 'rke2',
|
|
19
|
+
K8S_DISTRO_K3S: 'k3s',
|
|
20
|
+
};
|
|
6
21
|
|
|
7
22
|
export default {
|
|
8
23
|
name: 'DirectoryConfig',
|
|
9
24
|
components: {
|
|
10
|
-
Checkbox,
|
|
11
25
|
LabeledInput,
|
|
26
|
+
RadioGroup
|
|
12
27
|
},
|
|
13
28
|
props: {
|
|
14
29
|
mode: {
|
|
@@ -16,52 +31,114 @@ export default {
|
|
|
16
31
|
required: true,
|
|
17
32
|
},
|
|
18
33
|
|
|
34
|
+
k8sVersion: {
|
|
35
|
+
type: String,
|
|
36
|
+
required: true,
|
|
37
|
+
},
|
|
38
|
+
|
|
19
39
|
value: {
|
|
20
40
|
type: Object,
|
|
21
41
|
required: true,
|
|
22
42
|
},
|
|
23
43
|
},
|
|
24
44
|
data() {
|
|
25
|
-
let
|
|
26
|
-
let
|
|
27
|
-
|
|
28
|
-
if (this.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
45
|
+
let dataConfigRadioValue = DATA_DIR_RADIO_OPTIONS.DEFAULT;
|
|
46
|
+
let k8sDistroSubDir = DEFAULT_SUBDIRS.K8S_DISTRO_RKE2;
|
|
47
|
+
|
|
48
|
+
if (this.k8sVersion && this.k8sVersion.includes('k3s')) {
|
|
49
|
+
k8sDistroSubDir = DEFAULT_SUBDIRS.K8S_DISTRO_K3S;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (this.mode !== _CREATE) {
|
|
53
|
+
if (this.value?.systemAgent?.length || this.value?.provisioning?.length || this.value?.k8sDistro?.length) {
|
|
54
|
+
dataConfigRadioValue = DATA_DIR_RADIO_OPTIONS.CUSTOM;
|
|
33
55
|
}
|
|
34
56
|
}
|
|
35
57
|
|
|
36
58
|
return {
|
|
37
|
-
|
|
38
|
-
|
|
59
|
+
DATA_DIR_RADIO_OPTIONS,
|
|
60
|
+
dataConfigRadioValue,
|
|
61
|
+
k8sDistroSubDir,
|
|
62
|
+
commonConfig: '',
|
|
39
63
|
};
|
|
40
64
|
},
|
|
41
65
|
watch: {
|
|
42
66
|
commonConfig(neu) {
|
|
43
|
-
if (neu && neu.length && this.
|
|
44
|
-
this.value.systemAgent = neu
|
|
45
|
-
this.value.provisioning = neu
|
|
46
|
-
this.value.k8sDistro = neu
|
|
67
|
+
if (neu && neu.length && this.dataConfigRadioValue === DATA_DIR_RADIO_OPTIONS.COMMON) {
|
|
68
|
+
this.value.systemAgent = `${ neu }/${ DEFAULT_SUBDIRS.AGENT }`;
|
|
69
|
+
this.value.provisioning = `${ neu }/${ DEFAULT_SUBDIRS.PROVISIONING }`;
|
|
70
|
+
this.value.k8sDistro = `${ neu }/${ this.k8sDistroSubDir }`;
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
k8sVersion: {
|
|
74
|
+
handler(neu) {
|
|
75
|
+
if (neu && neu.includes('k3s')) {
|
|
76
|
+
this.k8sDistroSubDir = DEFAULT_SUBDIRS.K8S_DISTRO_K3S;
|
|
77
|
+
} else {
|
|
78
|
+
this.k8sDistroSubDir = DEFAULT_SUBDIRS.K8S_DISTRO_RKE2;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (this.value.k8sDistro) {
|
|
82
|
+
this.value.k8sDistro = `${ neu }/${ this.k8sDistroSubDir }`;
|
|
83
|
+
}
|
|
47
84
|
}
|
|
48
85
|
}
|
|
49
86
|
},
|
|
50
87
|
computed: {
|
|
51
|
-
|
|
52
|
-
|
|
88
|
+
dataConfigRadioOptions() {
|
|
89
|
+
const defaultDataDirOption = {
|
|
90
|
+
value: DATA_DIR_RADIO_OPTIONS.DEFAULT,
|
|
91
|
+
label: this.t('cluster.directoryConfig.radioInput.defaultLabel')
|
|
92
|
+
};
|
|
93
|
+
const customDataDirOption = {
|
|
94
|
+
value: DATA_DIR_RADIO_OPTIONS.CUSTOM,
|
|
95
|
+
label: this.t('cluster.directoryConfig.radioInput.customLabel')
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
if (this.mode === _CREATE) {
|
|
99
|
+
return [
|
|
100
|
+
defaultDataDirOption,
|
|
101
|
+
{ value: DATA_DIR_RADIO_OPTIONS.COMMON, label: this.t('cluster.directoryConfig.radioInput.commonLabel') },
|
|
102
|
+
customDataDirOption
|
|
103
|
+
];
|
|
104
|
+
} else {
|
|
105
|
+
return [
|
|
106
|
+
defaultDataDirOption,
|
|
107
|
+
customDataDirOption
|
|
108
|
+
];
|
|
109
|
+
}
|
|
53
110
|
}
|
|
54
111
|
},
|
|
55
112
|
methods: {
|
|
56
|
-
|
|
57
|
-
|
|
113
|
+
handleRadioInput(val) {
|
|
114
|
+
switch (val) {
|
|
115
|
+
case DATA_DIR_RADIO_OPTIONS.DEFAULT:
|
|
116
|
+
if (this.mode === _CREATE) {
|
|
117
|
+
this.commonConfig = '';
|
|
118
|
+
}
|
|
119
|
+
this.value.systemAgent = '';
|
|
120
|
+
this.value.provisioning = '';
|
|
121
|
+
this.value.k8sDistro = '';
|
|
122
|
+
|
|
123
|
+
this.dataConfigRadioValue = DATA_DIR_RADIO_OPTIONS.DEFAULT;
|
|
124
|
+
break;
|
|
125
|
+
case DATA_DIR_RADIO_OPTIONS.COMMON:
|
|
126
|
+
this.commonConfig = DEFAULT_COMMON_BASE_PATH;
|
|
127
|
+
|
|
128
|
+
this.dataConfigRadioValue = DATA_DIR_RADIO_OPTIONS.COMMON;
|
|
129
|
+
break;
|
|
130
|
+
// default is custom config
|
|
131
|
+
default:
|
|
132
|
+
if (this.mode === _CREATE) {
|
|
133
|
+
this.commonConfig = '';
|
|
134
|
+
}
|
|
58
135
|
|
|
59
|
-
if (val) {
|
|
60
136
|
this.value.systemAgent = '';
|
|
61
137
|
this.value.provisioning = '';
|
|
62
138
|
this.value.k8sDistro = '';
|
|
63
|
-
|
|
64
|
-
this.
|
|
139
|
+
|
|
140
|
+
this.dataConfigRadioValue = DATA_DIR_RADIO_OPTIONS.CUSTOM;
|
|
141
|
+
break;
|
|
65
142
|
}
|
|
66
143
|
}
|
|
67
144
|
},
|
|
@@ -74,33 +151,31 @@ export default {
|
|
|
74
151
|
<h3 class="mb-20">
|
|
75
152
|
{{ t('cluster.directoryConfig.title') }}
|
|
76
153
|
</h3>
|
|
77
|
-
<
|
|
154
|
+
<RadioGroup
|
|
155
|
+
:value="dataConfigRadioValue"
|
|
78
156
|
class="mb-10"
|
|
79
|
-
:value="isSettingCommonConfig"
|
|
80
157
|
:mode="mode"
|
|
81
|
-
:
|
|
82
|
-
|
|
83
|
-
data-testid="rke2-directory-config-
|
|
84
|
-
@update:value="
|
|
158
|
+
:options="dataConfigRadioOptions"
|
|
159
|
+
name="directory-config-radio"
|
|
160
|
+
data-testid="rke2-directory-config-radio-input"
|
|
161
|
+
@update:value="handleRadioInput"
|
|
85
162
|
/>
|
|
86
163
|
<LabeledInput
|
|
87
|
-
v-if="
|
|
164
|
+
v-if="dataConfigRadioValue === DATA_DIR_RADIO_OPTIONS.COMMON"
|
|
88
165
|
v-model:value="commonConfig"
|
|
89
166
|
class="mb-20"
|
|
90
167
|
:mode="mode"
|
|
91
168
|
:label="t('cluster.directoryConfig.common.label')"
|
|
92
169
|
:tooltip="t('cluster.directoryConfig.common.tooltip')"
|
|
93
|
-
:disabled="disableEditInput"
|
|
94
170
|
data-testid="rke2-directory-config-common-data-dir"
|
|
95
171
|
/>
|
|
96
|
-
<div v-if="
|
|
172
|
+
<div v-if="dataConfigRadioValue === DATA_DIR_RADIO_OPTIONS.CUSTOM">
|
|
97
173
|
<LabeledInput
|
|
98
174
|
v-model:value="value.systemAgent"
|
|
99
175
|
class="mb-20"
|
|
100
176
|
:mode="mode"
|
|
101
177
|
:label="t('cluster.directoryConfig.systemAgent.label')"
|
|
102
178
|
:tooltip="t('cluster.directoryConfig.systemAgent.tooltip')"
|
|
103
|
-
:disabled="disableEditInput"
|
|
104
179
|
data-testid="rke2-directory-config-systemAgent-data-dir"
|
|
105
180
|
/>
|
|
106
181
|
<LabeledInput
|
|
@@ -109,7 +184,6 @@ export default {
|
|
|
109
184
|
:mode="mode"
|
|
110
185
|
:label="t('cluster.directoryConfig.provisioning.label')"
|
|
111
186
|
:tooltip="t('cluster.directoryConfig.provisioning.tooltip')"
|
|
112
|
-
:disabled="disableEditInput"
|
|
113
187
|
data-testid="rke2-directory-config-provisioning-data-dir"
|
|
114
188
|
/>
|
|
115
189
|
<LabeledInput
|
|
@@ -118,7 +192,6 @@ export default {
|
|
|
118
192
|
:mode="mode"
|
|
119
193
|
:label="t('cluster.directoryConfig.k8sDistro.label')"
|
|
120
194
|
:tooltip="t('cluster.directoryConfig.k8sDistro.tooltip')"
|
|
121
|
-
:disabled="disableEditInput"
|
|
122
195
|
data-testid="rke2-directory-config-k8sDistro-data-dir"
|
|
123
196
|
/>
|
|
124
197
|
</div>
|
|
@@ -154,7 +154,6 @@ export default {
|
|
|
154
154
|
:mode="mode"
|
|
155
155
|
:data-testid="`registry-auth-host-input-${i}`"
|
|
156
156
|
/>
|
|
157
|
-
|
|
158
157
|
<SelectOrCreateAuthSecret
|
|
159
158
|
v-model:value="row.value.authConfigSecretName"
|
|
160
159
|
:register-before-hook="wrapRegisterBeforeHook"
|
|
@@ -168,6 +167,7 @@ export default {
|
|
|
168
167
|
generate-name="registryconfig-auth-"
|
|
169
168
|
:data-testid="`registry-auth-select-or-create-${i}`"
|
|
170
169
|
:cache-secrets="true"
|
|
170
|
+
@update:value="update"
|
|
171
171
|
/>
|
|
172
172
|
</div>
|
|
173
173
|
<div class="col span-6">
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import BrandImage from '@shell/components/BrandImage';
|
|
3
|
+
import TypeDescription from '@shell/components/TypeDescription';
|
|
4
|
+
import ResourceTable from '@shell/components/ResourceTable';
|
|
5
|
+
import Masthead from '@shell/components/ResourceList/Masthead';
|
|
6
|
+
import Loading from '@shell/components/Loading';
|
|
7
|
+
import { HARVESTER_NAME as VIRTUAL } from '@shell/config/features';
|
|
8
|
+
import { CAPI, HCI, MANAGEMENT } from '@shell/config/types';
|
|
9
|
+
import { isHarvesterCluster } from '@shell/utils/cluster';
|
|
10
|
+
import { allHash } from '@shell/utils/promise';
|
|
11
|
+
|
|
12
|
+
export default {
|
|
13
|
+
components: {
|
|
14
|
+
BrandImage,
|
|
15
|
+
ResourceTable,
|
|
16
|
+
Masthead,
|
|
17
|
+
TypeDescription,
|
|
18
|
+
Loading
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
props: {
|
|
22
|
+
schema: {
|
|
23
|
+
type: Object,
|
|
24
|
+
required: true,
|
|
25
|
+
},
|
|
26
|
+
useQueryParamsForSimpleFiltering: {
|
|
27
|
+
type: Boolean,
|
|
28
|
+
default: false
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
async fetch() {
|
|
33
|
+
const inStore = this.$store.getters['currentProduct'].inStore;
|
|
34
|
+
|
|
35
|
+
const hash = await allHash({
|
|
36
|
+
hciClusters: this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.CLUSTER }),
|
|
37
|
+
mgmtClusters: this.$store.dispatch(`${ inStore }/findAll`, { type: MANAGEMENT.CLUSTER })
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
this.hciClusters = hash.hciClusters;
|
|
41
|
+
this.mgmtClusters = hash.mgmtClusters;
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
data() {
|
|
45
|
+
const resource = CAPI.RANCHER_CLUSTER;
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
navigating: false,
|
|
49
|
+
VIRTUAL,
|
|
50
|
+
hciDashboard: HCI.DASHBOARD,
|
|
51
|
+
resource,
|
|
52
|
+
hResource: HCI.CLUSTER,
|
|
53
|
+
hciClusters: [],
|
|
54
|
+
mgmtClusters: []
|
|
55
|
+
};
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
computed: {
|
|
59
|
+
realSchema() {
|
|
60
|
+
return this.$store.getters['management/schemaFor'](CAPI.RANCHER_CLUSTER);
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
importLocation() {
|
|
64
|
+
return {
|
|
65
|
+
name: 'c-cluster-product-resource-create',
|
|
66
|
+
params: {
|
|
67
|
+
product: this.$store.getters['currentProduct'].name,
|
|
68
|
+
resource: this.schema.id,
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
canCreateCluster() {
|
|
74
|
+
const schema = this.$store.getters['management/schemaFor'](CAPI.RANCHER_CLUSTER);
|
|
75
|
+
|
|
76
|
+
return !!schema?.collectionMethods.find((x) => x.toLowerCase() === 'post');
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
rows() {
|
|
80
|
+
return this.hciClusters.filter((c) => {
|
|
81
|
+
const cluster = this.mgmtClusters.find((cluster) => cluster?.metadata?.name === c?.status?.clusterName);
|
|
82
|
+
|
|
83
|
+
return isHarvesterCluster(cluster);
|
|
84
|
+
});
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
typeDisplay() {
|
|
88
|
+
return this.t(`typeLabel."${ HCI.CLUSTER }"`, { count: this.row?.length || 0 });
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
methods: {
|
|
93
|
+
async goToCluster(row) {
|
|
94
|
+
const timeout = setTimeout(() => {
|
|
95
|
+
// Don't show loading indicator for quickly fetched plugins
|
|
96
|
+
this.navigating = row.id;
|
|
97
|
+
}, 1000);
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
await row.goToCluster();
|
|
101
|
+
|
|
102
|
+
clearTimeout(timeout);
|
|
103
|
+
this.navigating = false;
|
|
104
|
+
} catch {
|
|
105
|
+
// The error handling is carried out within goToCluster, but just in case something happens before the promise chain can catch it...
|
|
106
|
+
clearTimeout(timeout);
|
|
107
|
+
this.navigating = false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
</script>
|
|
113
|
+
|
|
114
|
+
<template>
|
|
115
|
+
<Loading v-if="$fetchState.pending" />
|
|
116
|
+
<div v-else>
|
|
117
|
+
<Masthead
|
|
118
|
+
:schema="realSchema"
|
|
119
|
+
:resource="resource"
|
|
120
|
+
:is-creatable="false"
|
|
121
|
+
:type-display="typeDisplay"
|
|
122
|
+
>
|
|
123
|
+
<template #typeDescription>
|
|
124
|
+
<TypeDescription :resource="hResource" />
|
|
125
|
+
</template>
|
|
126
|
+
|
|
127
|
+
<template
|
|
128
|
+
v-if="canCreateCluster"
|
|
129
|
+
slot="extraActions"
|
|
130
|
+
>
|
|
131
|
+
<n-link
|
|
132
|
+
:to="importLocation"
|
|
133
|
+
class="btn role-primary"
|
|
134
|
+
>
|
|
135
|
+
{{ t('cluster.importAction') }}
|
|
136
|
+
</n-link>
|
|
137
|
+
</template>
|
|
138
|
+
</Masthead>
|
|
139
|
+
|
|
140
|
+
<ResourceTable
|
|
141
|
+
v-if="rows && rows.length"
|
|
142
|
+
:schema="schema"
|
|
143
|
+
:rows="rows"
|
|
144
|
+
:is-creatable="true"
|
|
145
|
+
:namespaced="false"
|
|
146
|
+
:use-query-params-for-simple-filtering="useQueryParamsForSimpleFiltering"
|
|
147
|
+
>
|
|
148
|
+
<template #col:name="{row}">
|
|
149
|
+
<td>
|
|
150
|
+
<span class="cluster-link">
|
|
151
|
+
<a
|
|
152
|
+
v-if="row.isReady"
|
|
153
|
+
class="link"
|
|
154
|
+
:disabled="navigating"
|
|
155
|
+
@click="goToCluster(row)"
|
|
156
|
+
>{{ row.nameDisplay }}</a>
|
|
157
|
+
<span v-else>
|
|
158
|
+
{{ row.nameDisplay }}
|
|
159
|
+
</span>
|
|
160
|
+
<i
|
|
161
|
+
class="icon icon-spinner icon-spin ml-5"
|
|
162
|
+
:class="{'navigating': navigating === row.id}"
|
|
163
|
+
/>
|
|
164
|
+
</span>
|
|
165
|
+
</td>
|
|
166
|
+
</template>
|
|
167
|
+
|
|
168
|
+
<template #cell:harvester="{row}">
|
|
169
|
+
<n-link
|
|
170
|
+
class="btn btn-sm role-primary"
|
|
171
|
+
:to="row.detailLocation"
|
|
172
|
+
>
|
|
173
|
+
{{ t('harvesterManager.manage') }}
|
|
174
|
+
</n-link>
|
|
175
|
+
</template>
|
|
176
|
+
</ResourceTable>
|
|
177
|
+
<div v-else>
|
|
178
|
+
<div class="no-clusters">
|
|
179
|
+
{{ t('harvesterManager.cluster.none') }}
|
|
180
|
+
</div>
|
|
181
|
+
<hr class="info-section">
|
|
182
|
+
<div class="logo">
|
|
183
|
+
<BrandImage
|
|
184
|
+
file-name="harvester.png"
|
|
185
|
+
height="64"
|
|
186
|
+
/>
|
|
187
|
+
</div>
|
|
188
|
+
<div class="tagline">
|
|
189
|
+
<div>{{ t('harvesterManager.cluster.description') }}</div>
|
|
190
|
+
</div>
|
|
191
|
+
<div class="tagline sub-tagline">
|
|
192
|
+
<div v-clean-html="t('harvesterManager.cluster.learnMore', {}, true)" />
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
</div>
|
|
196
|
+
</template>
|
|
197
|
+
|
|
198
|
+
<style lang="scss" scoped>
|
|
199
|
+
.cluster-link {
|
|
200
|
+
display: flex;
|
|
201
|
+
align-items: center;
|
|
202
|
+
|
|
203
|
+
.icon {
|
|
204
|
+
// Use visibility to avoid the columns re-adjusting when the icon is shown
|
|
205
|
+
visibility: hidden;
|
|
206
|
+
|
|
207
|
+
&.navigating {
|
|
208
|
+
visibility: visible;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
}
|
|
213
|
+
.no-clusters {
|
|
214
|
+
text-align: center;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.info-section {
|
|
218
|
+
margin-top: 60px;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.logo {
|
|
222
|
+
display: flex;
|
|
223
|
+
justify-content: center;
|
|
224
|
+
margin: 60px 0 40px 0;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.tagline {
|
|
228
|
+
display: flex;
|
|
229
|
+
justify-content: center;
|
|
230
|
+
margin-top: 30px;
|
|
231
|
+
|
|
232
|
+
> div {
|
|
233
|
+
font-size: 16px;
|
|
234
|
+
line-height: 22px;
|
|
235
|
+
max-width: 80%;
|
|
236
|
+
text-align: center;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.link {
|
|
241
|
+
cursor: pointer;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
</style>
|
package/list/namespace.vue
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { mapGetters } from 'vuex';
|
|
3
|
+
import { NS_SNAPSHOT_QUOTA } from '../config/table-headers';
|
|
3
4
|
import ResourceTable from '@shell/components/ResourceTable';
|
|
4
|
-
|
|
5
|
+
import { HCI } from '@shell/config/types';
|
|
5
6
|
export default {
|
|
6
7
|
name: 'ListNamespace',
|
|
7
8
|
components: { ResourceTable },
|
|
@@ -27,13 +28,23 @@ export default {
|
|
|
27
28
|
default: false
|
|
28
29
|
}
|
|
29
30
|
},
|
|
30
|
-
data() {
|
|
31
|
-
return { asddsa: true };
|
|
32
|
-
},
|
|
33
31
|
|
|
34
32
|
computed: {
|
|
35
33
|
...mapGetters(['currentProduct']),
|
|
34
|
+
hasHarvesterResourceQuotaSchema() {
|
|
35
|
+
const inStore = this.$store.getters['currentProduct'].inStore;
|
|
36
|
+
|
|
37
|
+
return !!this.$store.getters[`${ inStore }/schemaFor`](HCI.RESOURCE_QUOTA);
|
|
38
|
+
},
|
|
39
|
+
headers() {
|
|
40
|
+
const headersFromSchema = this.$store.getters['type-map/headersFor'](this.schema);
|
|
36
41
|
|
|
42
|
+
if (this.hasHarvesterResourceQuotaSchema) {
|
|
43
|
+
headersFromSchema.splice(2, 0, NS_SNAPSHOT_QUOTA);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return headersFromSchema;
|
|
47
|
+
},
|
|
37
48
|
filterRow() {
|
|
38
49
|
if (this.currentProduct.hideSystemResources) {
|
|
39
50
|
return this.rows.filter( (N) => {
|
|
@@ -56,6 +67,7 @@ export default {
|
|
|
56
67
|
v-bind="$attrs"
|
|
57
68
|
:rows="filterRow"
|
|
58
69
|
:groupable="false"
|
|
70
|
+
:headers="headers"
|
|
59
71
|
:schema="schema"
|
|
60
72
|
key-field="_key"
|
|
61
73
|
:loading="loading"
|
package/mixins/chart.js
CHANGED
|
@@ -291,6 +291,8 @@ export default {
|
|
|
291
291
|
id: `${ this.query.appNamespace }/${ this.query.appName }`,
|
|
292
292
|
});
|
|
293
293
|
|
|
294
|
+
await this.existing?.fetchValues(true);
|
|
295
|
+
|
|
294
296
|
this.mode = _EDIT;
|
|
295
297
|
} catch (e) {
|
|
296
298
|
this.mode = _CREATE;
|
|
@@ -450,10 +452,12 @@ export default {
|
|
|
450
452
|
}
|
|
451
453
|
}
|
|
452
454
|
if (existingCRDApp) {
|
|
455
|
+
await existingCRDApp.fetchValues(true);
|
|
456
|
+
|
|
453
457
|
// spec.values are any non-default values the user configured
|
|
454
458
|
// the installation form should show these, as well as any default values from the chart
|
|
455
|
-
const existingValues = clone(existingCRDApp.
|
|
456
|
-
const defaultValues = clone(existingCRDApp.
|
|
459
|
+
const existingValues = clone(existingCRDApp.values || {});
|
|
460
|
+
const defaultValues = clone(existingCRDApp.chartValues || {});
|
|
457
461
|
|
|
458
462
|
crdVersionInfo.existingValues = existingValues;
|
|
459
463
|
crdVersionInfo.allValues = merge(defaultValues, existingValues);
|
package/mixins/metric-poller.js
CHANGED
package/mixins/resource-fetch.js
CHANGED
|
@@ -48,7 +48,7 @@ export default {
|
|
|
48
48
|
};
|
|
49
49
|
},
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
beforeUnmount() {
|
|
52
52
|
// make sure this only runs once, for the initialized instance
|
|
53
53
|
if (this.init) {
|
|
54
54
|
// clear up the store to make sure we aren't storing anything that might interfere with the next rendered list view
|
|
@@ -4,12 +4,34 @@ jest.mock('@shell/utils/clipboard', () => {
|
|
|
4
4
|
return { copyTextToClipboard: jest.fn(() => Promise.resolve({})) };
|
|
5
5
|
});
|
|
6
6
|
|
|
7
|
+
const importedRKE2ClusterInfo = { status: { driver: 'rke2', provider: 'rke2' } };
|
|
8
|
+
|
|
9
|
+
const provisionedRKE2ClusterInfo = { status: { driver: 'rke2', provider: 'imported' } };
|
|
10
|
+
|
|
11
|
+
const importedK3sClusterInfo = { status: { driver: 'k3s', provider: 'k3s' } };
|
|
12
|
+
|
|
13
|
+
const provisionedK3sClusterInfo = { status: { driver: 'k3s', provider: 'imported' } };
|
|
14
|
+
|
|
15
|
+
const importedAksClusterInfo = { spec: { aksConfig: { imported: true } }, status: { provider: 'aks', driver: 'AKS' } };
|
|
16
|
+
|
|
17
|
+
const provisionedAksClusterInfo = { spec: { aksConfig: { imported: false } }, status: { provider: 'aks', driver: 'AKS' } };
|
|
18
|
+
|
|
19
|
+
const importedRKE1ClusterInfo = { status: { provider: 'rke', driver: 'imported' } };
|
|
20
|
+
|
|
21
|
+
const provisionedRKE1ClusterInfo = { status: { provider: 'rke', driver: 'rancherKubernetesEngine' } };
|
|
22
|
+
|
|
23
|
+
const localRKE1ClusterInfo = { status: { provider: 'rke', driver: 'imported' } };
|
|
24
|
+
|
|
25
|
+
const localRKE2ClusterInfo = { status: { provider: 'rke2', driver: 'rke2' } };
|
|
26
|
+
|
|
27
|
+
const localEKSClusterInfo = { status: { provider: 'eks', driver: 'imported' } };
|
|
28
|
+
|
|
7
29
|
describe('class MgmtCluster', () => {
|
|
8
30
|
describe('provisioner', () => {
|
|
9
31
|
const testCases = [
|
|
10
|
-
[{ provider: 'rke', driver: 'imported' }, '
|
|
11
|
-
[{ provider: 'k3s', driver: 'K3S' }, '
|
|
12
|
-
[{ provider: 'aks', driver: 'AKS' }, '
|
|
32
|
+
[{ provider: 'rke', driver: 'imported' }, 'imported'],
|
|
33
|
+
[{ provider: 'k3s', driver: 'K3S' }, 'K3S'],
|
|
34
|
+
[{ provider: 'aks', driver: 'AKS' }, 'AKS'],
|
|
13
35
|
[{}, 'imported'],
|
|
14
36
|
];
|
|
15
37
|
|
|
@@ -20,4 +42,24 @@ describe('class MgmtCluster', () => {
|
|
|
20
42
|
}
|
|
21
43
|
);
|
|
22
44
|
});
|
|
45
|
+
|
|
46
|
+
describe('isImported', () => {
|
|
47
|
+
it.each([
|
|
48
|
+
[importedRKE2ClusterInfo, true],
|
|
49
|
+
[provisionedRKE2ClusterInfo, false],
|
|
50
|
+
[importedK3sClusterInfo, true],
|
|
51
|
+
[provisionedK3sClusterInfo, false],
|
|
52
|
+
[importedAksClusterInfo, true],
|
|
53
|
+
[provisionedAksClusterInfo, false],
|
|
54
|
+
[importedRKE1ClusterInfo, true],
|
|
55
|
+
[provisionedRKE1ClusterInfo, false],
|
|
56
|
+
[localRKE1ClusterInfo, true],
|
|
57
|
+
[localRKE2ClusterInfo, true],
|
|
58
|
+
[localEKSClusterInfo, true]
|
|
59
|
+
])('should return isImported based on props data', (clusterData, expected) => {
|
|
60
|
+
const cluster = new MgmtCluster(clusterData);
|
|
61
|
+
|
|
62
|
+
expect(cluster.isImported).toBe(expected);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
23
65
|
});
|