@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
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import { mapGetters } from 'vuex';
|
|
3
2
|
import { MANAGEMENT } from '@shell/config/types';
|
|
4
|
-
import { ALLOWED_SETTINGS } from '@shell/config/settings';
|
|
3
|
+
import { ALLOWED_SETTINGS, PROVISIONING_SETTINGS } from '@shell/config/settings';
|
|
5
4
|
import { Banner } from '@components/Banner';
|
|
6
5
|
import Loading from '@shell/components/Loading';
|
|
7
6
|
import { VIEW_IN_API } from '@shell/store/prefs';
|
|
7
|
+
import Setting from '@shell/components/Setting';
|
|
8
|
+
import { mapGetters } from 'vuex';
|
|
8
9
|
|
|
9
10
|
export default {
|
|
10
|
-
components: {
|
|
11
|
+
components: {
|
|
12
|
+
Banner, Loading, Setting
|
|
13
|
+
},
|
|
11
14
|
|
|
12
15
|
async fetch() {
|
|
13
16
|
const viewInApi = this.$store.getters['prefs/get'](VIEW_IN_API);
|
|
@@ -21,6 +24,7 @@ export default {
|
|
|
21
24
|
}, {});
|
|
22
25
|
|
|
23
26
|
const settings = [];
|
|
27
|
+
const provisioningSettings = [];
|
|
24
28
|
|
|
25
29
|
// Combine the allowed settings with the data from the API
|
|
26
30
|
for ( const id in ALLOWED_SETTINGS ) {
|
|
@@ -52,43 +56,22 @@ export default {
|
|
|
52
56
|
// There are only 2 actions that can be enabled - Edit Setting or View in API
|
|
53
57
|
// If neither is available for this setting then we hide the action menu button
|
|
54
58
|
s.hasActions = (!s.readOnly || viewInApi) && setting.availableActions?.length;
|
|
55
|
-
|
|
59
|
+
|
|
60
|
+
if (PROVISIONING_SETTINGS.includes(s.id) ) {
|
|
61
|
+
provisioningSettings.push(s);
|
|
62
|
+
} else {
|
|
63
|
+
settings.push(s);
|
|
64
|
+
}
|
|
56
65
|
}
|
|
57
66
|
|
|
58
67
|
this.settings = settings;
|
|
68
|
+
this.provisioningSettings = provisioningSettings;
|
|
59
69
|
},
|
|
60
70
|
|
|
61
71
|
data() {
|
|
62
|
-
return { settings: null };
|
|
63
|
-
},
|
|
64
|
-
|
|
65
|
-
computed: {
|
|
66
|
-
...mapGetters({ t: 'i18n/t' }),
|
|
67
|
-
...mapGetters({
|
|
68
|
-
// Use either these Vuex getters
|
|
69
|
-
// OR the props to set the action menu state,
|
|
70
|
-
// but don't use both.
|
|
71
|
-
targetElem: 'action-menu/elem',
|
|
72
|
-
shouldShow: 'action-menu/showing',
|
|
73
|
-
}),
|
|
72
|
+
return { settings: null, provisioningSettings: null };
|
|
74
73
|
},
|
|
75
|
-
|
|
76
|
-
methods: {
|
|
77
|
-
toggleActionMenu(e, setting) {
|
|
78
|
-
const actionElement = e.srcElement;
|
|
79
|
-
|
|
80
|
-
if (!this.targetElem && !this.shouldShow) {
|
|
81
|
-
this.$store.commit(`action-menu/show`, {
|
|
82
|
-
resources: setting.data,
|
|
83
|
-
elem: actionElement
|
|
84
|
-
});
|
|
85
|
-
} else if (this.targetElem === actionElement && this.shouldShow) {
|
|
86
|
-
// this condition is needed so that we can "toggle" the action menu with
|
|
87
|
-
// the keyboard for accessibility (row action menu)
|
|
88
|
-
this.$store.commit('action-menu/hide');
|
|
89
|
-
}
|
|
90
|
-
},
|
|
91
|
-
}
|
|
74
|
+
computed: { ...mapGetters({ t: 'i18n/t' }) }
|
|
92
75
|
};
|
|
93
76
|
</script>
|
|
94
77
|
|
|
@@ -98,77 +81,31 @@ export default {
|
|
|
98
81
|
<Banner
|
|
99
82
|
color="warning"
|
|
100
83
|
class="settings-banner"
|
|
84
|
+
data-testid="global-settings-banner"
|
|
101
85
|
>
|
|
102
86
|
<div>
|
|
103
87
|
{{ t('advancedSettings.subtext') }}
|
|
104
88
|
</div>
|
|
105
89
|
</Banner>
|
|
106
90
|
<div
|
|
107
|
-
v-for="(setting
|
|
108
|
-
:key="
|
|
109
|
-
class="advanced-setting mb-20"
|
|
110
|
-
:data-testid="`advanced-setting__option-${setting.id}`"
|
|
91
|
+
v-for="(setting) in settings"
|
|
92
|
+
:key="setting.id"
|
|
111
93
|
>
|
|
112
|
-
<
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
<div
|
|
128
|
-
v-if="setting.hasActions"
|
|
129
|
-
class="action"
|
|
130
|
-
>
|
|
131
|
-
<button
|
|
132
|
-
aria-haspopup="true"
|
|
133
|
-
aria-expanded="false"
|
|
134
|
-
type="button"
|
|
135
|
-
class="btn btn-sm role-multi-action actions"
|
|
136
|
-
role="button"
|
|
137
|
-
:aria-label="t('advancedSettings.edit.moreActions', { setting: setting.id })"
|
|
138
|
-
@click="toggleActionMenu($event, setting)"
|
|
139
|
-
>
|
|
140
|
-
<i
|
|
141
|
-
class="icon icon-actions"
|
|
142
|
-
:alt="t('advancedSettings.edit.moreActions', { setting: setting.id })"
|
|
143
|
-
/>
|
|
144
|
-
</button>
|
|
145
|
-
</div>
|
|
146
|
-
</div>
|
|
147
|
-
<div value>
|
|
148
|
-
<div v-if="setting.canHide">
|
|
149
|
-
<button
|
|
150
|
-
class="btn btn-sm role-primary"
|
|
151
|
-
role="button"
|
|
152
|
-
:aria-label="t('advancedSettings.hideShow')"
|
|
153
|
-
@click="setting.hide = !setting.hide"
|
|
154
|
-
>
|
|
155
|
-
{{ setting.hide ? t('advancedSettings.show') : t('advancedSettings.hide') }} {{ setting.id }}
|
|
156
|
-
</button>
|
|
157
|
-
</div>
|
|
158
|
-
<div
|
|
159
|
-
v-show="!setting.canHide || (setting.canHide && !setting.hide)"
|
|
160
|
-
class="settings-value"
|
|
161
|
-
>
|
|
162
|
-
<pre v-if="setting.kind === 'json'">{{ setting.json }}</pre>
|
|
163
|
-
<pre v-else-if="setting.kind === 'multiline'">{{ setting.data.value || setting.data.default }}</pre>
|
|
164
|
-
<pre v-else-if="setting.kind === 'enum'">{{ t(setting.enum) }}</pre>
|
|
165
|
-
<pre v-else-if="setting.data.value || setting.data.default">{{ setting.data.value || setting.data.default }}</pre>
|
|
166
|
-
<pre
|
|
167
|
-
v-else
|
|
168
|
-
class="text-muted"
|
|
169
|
-
><{{ t('advancedSettings.none') }}></pre>
|
|
170
|
-
</div>
|
|
171
|
-
</div>
|
|
94
|
+
<Setting
|
|
95
|
+
:value="setting"
|
|
96
|
+
/>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<h2>
|
|
100
|
+
{{ t('advancedSettings.provisioning.header') }}
|
|
101
|
+
</h2>
|
|
102
|
+
<div
|
|
103
|
+
v-for="(setting) in provisioningSettings"
|
|
104
|
+
:key="setting.id"
|
|
105
|
+
>
|
|
106
|
+
<Setting
|
|
107
|
+
:value="setting"
|
|
108
|
+
/>
|
|
172
109
|
</div>
|
|
173
110
|
</div>
|
|
174
111
|
</template>
|
|
@@ -177,39 +114,4 @@ export default {
|
|
|
177
114
|
.settings-banner {
|
|
178
115
|
margin-top: 0;
|
|
179
116
|
}
|
|
180
|
-
.advanced-setting {
|
|
181
|
-
border: 1px solid var(--border);
|
|
182
|
-
padding: 20px;
|
|
183
|
-
border-radius: var(--border-radius);
|
|
184
|
-
|
|
185
|
-
h1 {
|
|
186
|
-
font-size: 14px;
|
|
187
|
-
}
|
|
188
|
-
h2 {
|
|
189
|
-
font-size: 12px;
|
|
190
|
-
margin-bottom: 0;
|
|
191
|
-
opacity: 0.8;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
.settings-value pre {
|
|
196
|
-
margin: 0;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
.header {
|
|
200
|
-
display: flex;
|
|
201
|
-
margin-bottom: 20px;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
.title {
|
|
205
|
-
flex: 1;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
.modified {
|
|
209
|
-
margin-left: 10px;
|
|
210
|
-
border: 1px solid var(--primary);
|
|
211
|
-
border-radius: 5px;
|
|
212
|
-
padding: 2px 10px;
|
|
213
|
-
font-size: 12px;
|
|
214
|
-
}
|
|
215
117
|
</style>
|
|
@@ -77,13 +77,15 @@ export default {
|
|
|
77
77
|
const res = await allHash(hash);
|
|
78
78
|
|
|
79
79
|
this.mgmtClusters = res.mgmtClusters;
|
|
80
|
+
this.showRke1DeprecationWarning = this.rows.some((r) => r.isRke1);
|
|
80
81
|
},
|
|
81
82
|
|
|
82
83
|
data() {
|
|
83
84
|
return {
|
|
84
|
-
resource:
|
|
85
|
-
schema:
|
|
86
|
-
mgmtClusters:
|
|
85
|
+
resource: CAPI.RANCHER_CLUSTER,
|
|
86
|
+
schema: this.$store.getters['management/schemaFor'](CAPI.RANCHER_CLUSTER),
|
|
87
|
+
mgmtClusters: [],
|
|
88
|
+
showRke1DeprecationWarning: false
|
|
87
89
|
};
|
|
88
90
|
},
|
|
89
91
|
|
|
@@ -180,6 +182,12 @@ export default {
|
|
|
180
182
|
|
|
181
183
|
<template>
|
|
182
184
|
<div>
|
|
185
|
+
<Banner
|
|
186
|
+
v-if="showRke1DeprecationWarning"
|
|
187
|
+
color="warning"
|
|
188
|
+
label-key="cluster.banner.rke1DeprecationMessage"
|
|
189
|
+
/>
|
|
190
|
+
|
|
183
191
|
<Banner
|
|
184
192
|
v-if="hiddenHarvesterCount"
|
|
185
193
|
color="info"
|
|
@@ -149,7 +149,6 @@ export default {
|
|
|
149
149
|
const datacenterAlreadySet = !!this.value.datacenter;
|
|
150
150
|
|
|
151
151
|
await this.loadDataCenters();
|
|
152
|
-
|
|
153
152
|
if (datacenterAlreadySet) {
|
|
154
153
|
this.loadAllDatacenterResources();
|
|
155
154
|
}
|
|
@@ -382,12 +381,14 @@ export default {
|
|
|
382
381
|
|
|
383
382
|
set(this.value, 'boot2dockerUrl', boot2dockerUrl);
|
|
384
383
|
},
|
|
385
|
-
vappMode(value) {
|
|
384
|
+
vappMode(value, oldValue) {
|
|
386
385
|
if (value === VAPP_MODE.AUTO) {
|
|
387
386
|
const defaultVappOptions = getDefaultVappOptions(this.networkNames || []);
|
|
388
387
|
|
|
389
388
|
return this.updateVappOptions(defaultVappOptions);
|
|
390
|
-
} else {
|
|
389
|
+
} else if (value === VAPP_MODE.DISABLED) {
|
|
390
|
+
this.updateVappOptions(INITIAL_VAPP_OPTIONS);
|
|
391
|
+
} else if (value === VAPP_MODE.MANUAL && oldValue === VAPP_MODE.AUTO) {
|
|
391
392
|
this.updateVappOptions(INITIAL_VAPP_OPTIONS);
|
|
392
393
|
}
|
|
393
394
|
},
|
|
@@ -417,12 +418,18 @@ export default {
|
|
|
417
418
|
|
|
418
419
|
const url = `/meta/vsphere/${ resource }?${ queryParams }`;
|
|
419
420
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
421
|
+
try {
|
|
422
|
+
const result = await this.$store.dispatch('management/request', {
|
|
423
|
+
url,
|
|
424
|
+
redirectUnauthorized: false,
|
|
425
|
+
}, { root: true });
|
|
424
426
|
|
|
425
|
-
|
|
427
|
+
return result.data;
|
|
428
|
+
} catch (ex) {
|
|
429
|
+
console.warn(`There was a problem requesting the resource: "${ resource }"" for datacenter: "${ dataCenter }"" and library: "${ library }"`, ex); // eslint-disable-line no-console
|
|
430
|
+
|
|
431
|
+
return [];
|
|
432
|
+
}
|
|
426
433
|
},
|
|
427
434
|
|
|
428
435
|
async loadDataCenters() {
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import authConfigMixin from '@shell/mixins/auth-config';
|
|
3
|
+
|
|
4
|
+
describe('mixin: authConfigMixin', () => {
|
|
5
|
+
describe('method: save', () => {
|
|
6
|
+
const componentMock = (model: any) => ({
|
|
7
|
+
data: () => ({
|
|
8
|
+
value: { configType: 'oidc' },
|
|
9
|
+
model,
|
|
10
|
+
}),
|
|
11
|
+
computed: { principal: () => ({ me: {} }) },
|
|
12
|
+
global: {
|
|
13
|
+
mocks: {
|
|
14
|
+
$store: {
|
|
15
|
+
dispatch: () => model,
|
|
16
|
+
commit: () => ({ 'auth/loggedInAs': jest.fn() }),
|
|
17
|
+
},
|
|
18
|
+
$route: {
|
|
19
|
+
params: { id: '123' },
|
|
20
|
+
query: { mode: 'edit' },
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
const FakeComponent = {
|
|
26
|
+
render() {},
|
|
27
|
+
mixins: [authConfigMixin],
|
|
28
|
+
methods: { applyHooks: jest.fn() },
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
it('should return error', async() => {
|
|
32
|
+
const instance = mount(FakeComponent, componentMock({
|
|
33
|
+
doAction: jest.fn(),
|
|
34
|
+
save: 'make it fail'
|
|
35
|
+
})).vm as any;
|
|
36
|
+
const fakeCallback = jest.fn();
|
|
37
|
+
|
|
38
|
+
await instance.save(fakeCallback);
|
|
39
|
+
|
|
40
|
+
expect(fakeCallback).toHaveBeenCalledWith(false);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should not return error', async() => {
|
|
44
|
+
const model = {
|
|
45
|
+
authConfigName: 'whatever',
|
|
46
|
+
doAction: jest.fn(),
|
|
47
|
+
save: async() => {}
|
|
48
|
+
};
|
|
49
|
+
const instance = mount(FakeComponent, componentMock(model)).vm as any;
|
|
50
|
+
const fakeCallback = jest.fn();
|
|
51
|
+
|
|
52
|
+
await instance.save(fakeCallback);
|
|
53
|
+
|
|
54
|
+
expect(fakeCallback).toHaveBeenCalledWith(true);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it.each([
|
|
58
|
+
'oidc'
|
|
59
|
+
])('should keep custom scope on save', async(type) => {
|
|
60
|
+
const scope = 'openid profile email groups whatever';
|
|
61
|
+
const model = {
|
|
62
|
+
scope,
|
|
63
|
+
authConfigName: 'whatever',
|
|
64
|
+
doAction: jest.fn(),
|
|
65
|
+
save: async() => {}
|
|
66
|
+
};
|
|
67
|
+
const instance = mount(FakeComponent, componentMock(model)).vm as any;
|
|
68
|
+
|
|
69
|
+
await instance.save(jest.fn());
|
|
70
|
+
|
|
71
|
+
expect(instance.model.scope).toStrictEqual(scope);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import ChartMixin from '@shell/mixins/chart';
|
|
2
2
|
import { OPA_GATE_KEEPER_ID } from '@shell/pages/c/_cluster/gatekeeper/index.vue';
|
|
3
3
|
import { mount } from '@vue/test-utils';
|
|
4
|
+
import { APP_UPGRADE_STATUS } from '@shell/store/catalog';
|
|
4
5
|
|
|
5
6
|
describe('chartMixin', () => {
|
|
6
7
|
const testCases = {
|
|
@@ -10,10 +11,10 @@ describe('chartMixin', () => {
|
|
|
10
11
|
['any_other_id', 0]
|
|
11
12
|
],
|
|
12
13
|
managedApps: [
|
|
13
|
-
[false,
|
|
14
|
-
[true,
|
|
15
|
-
[true,
|
|
16
|
-
[true,
|
|
14
|
+
[false, APP_UPGRADE_STATUS.NOT_APPLICABLE, 0],
|
|
15
|
+
[true, APP_UPGRADE_STATUS.NO_UPGRADE, 0],
|
|
16
|
+
[true, 'some-version', 0],
|
|
17
|
+
[true, APP_UPGRADE_STATUS.NOT_APPLICABLE, 1],
|
|
17
18
|
],
|
|
18
19
|
};
|
|
19
20
|
|
|
@@ -15,4 +15,42 @@ describe('createEditView should', () => {
|
|
|
15
15
|
|
|
16
16
|
expect(instance.mode).toContain(_EDIT);
|
|
17
17
|
});
|
|
18
|
+
|
|
19
|
+
it.each([
|
|
20
|
+
['_status', { _status: 409 }],
|
|
21
|
+
['status', { status: 409 }],
|
|
22
|
+
])('catch conflict error by %p field and retry save()', async(_, error) => {
|
|
23
|
+
const Component = {
|
|
24
|
+
render() {},
|
|
25
|
+
mixins: [CreateEditView],
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const wrapper = mount(Component, {
|
|
29
|
+
props: { value: { id: '123', type: '' } },
|
|
30
|
+
global: {
|
|
31
|
+
mocks: {
|
|
32
|
+
$store: {
|
|
33
|
+
getters: {
|
|
34
|
+
currentStore: () => 'current_store',
|
|
35
|
+
'type-map/isSpoofed': jest.fn().mockImplementation(() => false),
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const instance = (wrapper as any).vm;
|
|
43
|
+
|
|
44
|
+
instance.actuallySave = async() => {
|
|
45
|
+
throw error;
|
|
46
|
+
};
|
|
47
|
+
instance.conflict = async() => '';
|
|
48
|
+
instance.done = async() => '';
|
|
49
|
+
|
|
50
|
+
const spyConflict = jest.spyOn(wrapper.vm, 'conflict');
|
|
51
|
+
|
|
52
|
+
await instance.save(() => '', 'url');
|
|
53
|
+
|
|
54
|
+
expect(spyConflict).toHaveBeenCalledTimes(1);
|
|
55
|
+
});
|
|
18
56
|
});
|
package/mixins/auth-config.js
CHANGED
|
@@ -137,6 +137,14 @@ export default {
|
|
|
137
137
|
}
|
|
138
138
|
},
|
|
139
139
|
|
|
140
|
+
/**
|
|
141
|
+
* On save several operations are executed to return a URL or open pop-up:
|
|
142
|
+
* - Retrieve data from the UI
|
|
143
|
+
* - "Test" the configuration through action and override the model
|
|
144
|
+
* - Retrieve scopes from redirect URL
|
|
145
|
+
* - Set default scopes and merge them with the ones from the redirect URL and from the "test" action
|
|
146
|
+
* @param {*} btnCb
|
|
147
|
+
*/
|
|
140
148
|
async save(btnCb) {
|
|
141
149
|
await this.applyHooks(BEFORE_SAVE_HOOKS);
|
|
142
150
|
|
package/mixins/chart.js
CHANGED
|
@@ -14,7 +14,7 @@ import { formatSi, parseSi } from '@shell/utils/units';
|
|
|
14
14
|
import { CAPI, CATALOG } from '@shell/config/types';
|
|
15
15
|
import { isPrerelease } from '@shell/utils/version';
|
|
16
16
|
import difference from 'lodash/difference';
|
|
17
|
-
import { LINUX } from '@shell/store/catalog';
|
|
17
|
+
import { LINUX, APP_UPGRADE_STATUS } from '@shell/store/catalog';
|
|
18
18
|
import { clone } from '@shell/utils/object';
|
|
19
19
|
import { merge } from 'lodash';
|
|
20
20
|
|
|
@@ -181,7 +181,7 @@ export default {
|
|
|
181
181
|
warnings.unshift(this.t('gatekeeperIndex.deprecated', {}, true));
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
if (this.existing && this.existing.upgradeAvailable ===
|
|
184
|
+
if (this.existing && this.existing.upgradeAvailable === APP_UPGRADE_STATUS.NOT_APPLICABLE) {
|
|
185
185
|
const manager = this.existing?.spec?.chart?.metadata?.annotations?.[CATALOG_ANNOTATIONS.MANAGED] || 'Rancher';
|
|
186
186
|
|
|
187
187
|
warnings.unshift(this.t('catalog.install.warning.managed', {
|
|
@@ -159,8 +159,11 @@ export default {
|
|
|
159
159
|
|
|
160
160
|
this.done();
|
|
161
161
|
} catch (err) {
|
|
162
|
+
// This exception handles errors from the `request` action when it receives a failed http request. The `err` object could be from the action's error handler (raw http response object containing `status`) or thrown later on given the response of the action (a massaged object containing `_status`). TBD why one 409 triggers the error handler and another does not.
|
|
163
|
+
const IS_ERR_409 = err.status === 409 || err._status === 409;
|
|
164
|
+
|
|
162
165
|
// Conflict, the resource being edited has changed since starting editing
|
|
163
|
-
if (
|
|
166
|
+
if (IS_ERR_409 && depth === 0 && this.isEdit) {
|
|
164
167
|
const errors = await this.conflict();
|
|
165
168
|
|
|
166
169
|
if ( errors === false ) {
|
|
@@ -20,6 +20,9 @@ export default {
|
|
|
20
20
|
|
|
21
21
|
// escape
|
|
22
22
|
(out[27] = (e) => {
|
|
23
|
+
e.preventDefault();
|
|
24
|
+
e.stopPropagation();
|
|
25
|
+
|
|
23
26
|
vm.open = false;
|
|
24
27
|
vm.search = '';
|
|
25
28
|
|
|
@@ -36,6 +39,13 @@ export default {
|
|
|
36
39
|
return;
|
|
37
40
|
}
|
|
38
41
|
|
|
42
|
+
// if the index of the option is -1
|
|
43
|
+
// it means are pressing enter on an invalid option
|
|
44
|
+
// we should exit
|
|
45
|
+
if (vm.typeAheadPointer === -1) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
39
49
|
let option = vm.filteredOptions[vm.typeAheadPointer];
|
|
40
50
|
|
|
41
51
|
vm.$emit('option:selecting', option);
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import CatalogApp from '@shell/models/catalog.cattle.io.app';
|
|
2
|
+
import { APP_UPGRADE_STATUS } from '@shell/store/catalog';
|
|
3
|
+
import { CATALOG as CATALOG_ANNOTATIONS } from '@shell/config/labels-annotations';
|
|
4
|
+
|
|
5
|
+
const latestVersion = '1.16.2';
|
|
6
|
+
const secondLatestVersion = '1.16.1';
|
|
7
|
+
const chartName = 'cert-manager';
|
|
8
|
+
|
|
9
|
+
const appCo = {
|
|
10
|
+
repoName: 'appCo',
|
|
11
|
+
home: 'https://apps.rancher.io/applications/cert-manager'
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const certManagerOfficial = {
|
|
15
|
+
repoName: 'certManagerOfficial',
|
|
16
|
+
home: 'https://cert-manager.io',
|
|
17
|
+
oldHome: 'https://github.com/jetstack/cert-manager' // older versions of cert-manager used to have this home url(e.g. 1.7.1)
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// cert-manager chart from application collection OCI repo
|
|
21
|
+
const appCoMatchingChart1 = {
|
|
22
|
+
name: chartName,
|
|
23
|
+
repoName: appCo.repoName,
|
|
24
|
+
versions: [{
|
|
25
|
+
version: latestVersion,
|
|
26
|
+
home: appCo.home,
|
|
27
|
+
repoName: appCo.repoName,
|
|
28
|
+
annotations: {}
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
version: secondLatestVersion,
|
|
32
|
+
home: appCo.home,
|
|
33
|
+
repoName: appCo.repoName,
|
|
34
|
+
annotations: {}
|
|
35
|
+
}]
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const appCoMatchingChart2 = {
|
|
39
|
+
name: chartName,
|
|
40
|
+
repoName: appCo.repoName,
|
|
41
|
+
versions: [{
|
|
42
|
+
version: latestVersion,
|
|
43
|
+
home: appCo.home,
|
|
44
|
+
repoName: appCo.repoName,
|
|
45
|
+
annotations: {}
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
version: secondLatestVersion,
|
|
49
|
+
home: appCo.home,
|
|
50
|
+
repoName: appCo.repoName,
|
|
51
|
+
annotations: {}
|
|
52
|
+
}]
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// cert-manager chart from its official helm repo 'https://cert-manager.io' added to Rancher UI repositories
|
|
56
|
+
const certManagerOfficialMatchingChart1 = {
|
|
57
|
+
name: chartName,
|
|
58
|
+
repoName: certManagerOfficial.repoName,
|
|
59
|
+
versions: [{
|
|
60
|
+
version: latestVersion,
|
|
61
|
+
home: certManagerOfficial.home,
|
|
62
|
+
repoName: certManagerOfficial.repoName,
|
|
63
|
+
annotations: {},
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
version: secondLatestVersion,
|
|
67
|
+
home: certManagerOfficial.oldHome,
|
|
68
|
+
repoName: certManagerOfficial.repoName,
|
|
69
|
+
annotations: {},
|
|
70
|
+
}]
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const certManagerOfficialMatchingChart2 = {
|
|
74
|
+
name: chartName,
|
|
75
|
+
repoName: certManagerOfficial.repoName,
|
|
76
|
+
versions: [{
|
|
77
|
+
version: latestVersion,
|
|
78
|
+
home: certManagerOfficial.home,
|
|
79
|
+
repoName: certManagerOfficial.repoName,
|
|
80
|
+
annotations: {},
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
version: secondLatestVersion,
|
|
84
|
+
home: certManagerOfficial.oldHome,
|
|
85
|
+
repoName: certManagerOfficial.repoName,
|
|
86
|
+
annotations: {},
|
|
87
|
+
}]
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const installedCertManagerAppCoFromRancherUI = {
|
|
91
|
+
metadata: {
|
|
92
|
+
annotations: { [CATALOG_ANNOTATIONS.SOURCE_REPO_NAME]: appCo.repoName },
|
|
93
|
+
name: chartName,
|
|
94
|
+
home: appCo.home,
|
|
95
|
+
version: secondLatestVersion
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const installedCertManagerOfficialFromCli = {
|
|
100
|
+
metadata: {
|
|
101
|
+
name: chartName,
|
|
102
|
+
home: certManagerOfficial.oldHome,
|
|
103
|
+
version: secondLatestVersion
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const installedCertManagerOfficialFromRancherUI = {
|
|
108
|
+
metadata: {
|
|
109
|
+
annotations: { [CATALOG_ANNOTATIONS.SOURCE_REPO_NAME]: certManagerOfficial.repoName },
|
|
110
|
+
name: chartName,
|
|
111
|
+
home: certManagerOfficial.oldHome,
|
|
112
|
+
version: secondLatestVersion
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
describe('class CatalogApp', () => {
|
|
117
|
+
describe('upgradeAvailable', () => {
|
|
118
|
+
const testCases = [
|
|
119
|
+
// when you follow Rancher Installation docs to install cert-manager through CLI
|
|
120
|
+
[installedCertManagerOfficialFromCli, [], APP_UPGRADE_STATUS.NO_UPGRADE],
|
|
121
|
+
[installedCertManagerOfficialFromCli, [appCoMatchingChart1], APP_UPGRADE_STATUS.NO_UPGRADE],
|
|
122
|
+
[installedCertManagerOfficialFromCli, [appCoMatchingChart1, appCoMatchingChart2], APP_UPGRADE_STATUS.NO_UPGRADE],
|
|
123
|
+
[installedCertManagerOfficialFromCli, [appCoMatchingChart1, appCoMatchingChart2, certManagerOfficialMatchingChart1], APP_UPGRADE_STATUS.SINGLE_UPGRADE],
|
|
124
|
+
// when you add application collection OCI repo through UI
|
|
125
|
+
[installedCertManagerAppCoFromRancherUI, [], APP_UPGRADE_STATUS.NO_UPGRADE],
|
|
126
|
+
[installedCertManagerAppCoFromRancherUI, [appCoMatchingChart1], APP_UPGRADE_STATUS.SINGLE_UPGRADE],
|
|
127
|
+
[installedCertManagerAppCoFromRancherUI, [appCoMatchingChart1, certManagerOfficialMatchingChart1], APP_UPGRADE_STATUS.SINGLE_UPGRADE],
|
|
128
|
+
[installedCertManagerAppCoFromRancherUI, [appCoMatchingChart1, appCoMatchingChart2], APP_UPGRADE_STATUS.MULTIPLE_UPGRADES],
|
|
129
|
+
// when you add cert-manager official helm repo through UI
|
|
130
|
+
[installedCertManagerOfficialFromRancherUI, [], APP_UPGRADE_STATUS.NO_UPGRADE],
|
|
131
|
+
[installedCertManagerOfficialFromRancherUI, [certManagerOfficialMatchingChart1], APP_UPGRADE_STATUS.SINGLE_UPGRADE],
|
|
132
|
+
[installedCertManagerOfficialFromRancherUI, [certManagerOfficialMatchingChart1, appCoMatchingChart1], APP_UPGRADE_STATUS.SINGLE_UPGRADE],
|
|
133
|
+
[installedCertManagerOfficialFromRancherUI, [certManagerOfficialMatchingChart1, certManagerOfficialMatchingChart2], APP_UPGRADE_STATUS.MULTIPLE_UPGRADES]
|
|
134
|
+
];
|
|
135
|
+
|
|
136
|
+
it.each(testCases)('should return the correct upgrade status', (installedChart: Object, matchingCharts: any, expected: any) => {
|
|
137
|
+
const catalogApp = new CatalogApp({ spec: { chart: installedChart } }, {
|
|
138
|
+
rootGetters: {
|
|
139
|
+
'catalog/chart': () => matchingCharts,
|
|
140
|
+
currentCluster: { workerOSs: ['linux'] },
|
|
141
|
+
'prefs/get': () => false
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
expect(catalogApp.upgradeAvailable).toBe(expected);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
});
|