@rancher/shell 3.0.11 → 3.0.12-rc.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/entraid-black.svg +4 -0
- package/assets/images/providers/entraid.svg +9 -0
- package/assets/images/vendor/entraid.svg +9 -0
- package/assets/styles/app.scss +0 -1
- package/assets/styles/base/_mixins.scss +31 -0
- package/assets/styles/base/_variables.scss +2 -0
- package/assets/styles/themes/_modern.scss +6 -5
- package/assets/translations/en-us.yaml +24 -21
- package/assets/translations/zh-hans.yaml +4 -11
- package/chart/__tests__/S3.test.ts +10 -3
- package/components/CountBox.vue +20 -0
- package/components/CreateDriver.vue +0 -12
- package/components/DetailText.vue +12 -3
- package/components/EmptyProductPage.vue +76 -0
- package/components/Resource/Detail/CopyToClipboard.vue +1 -2
- package/components/Resource/Detail/Metadata/KeyValueRow.vue +9 -3
- package/components/Resource/Detail/TitleBar/__tests__/__snapshots__/index.test.ts.snap +31 -0
- package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +45 -1
- package/components/Resource/Detail/TitleBar/index.vue +1 -1
- package/components/Resource/Detail/ViewOptions/__tests__/__snapshots__/index.test.ts.snap +9 -0
- package/components/Resource/Detail/ViewOptions/__tests__/index.test.ts +62 -0
- package/components/Resource/Detail/ViewOptions/index.vue +2 -1
- package/components/ResourceList/Masthead.vue +25 -2
- package/components/SelectIconGrid.vue +5 -0
- package/components/SideNav.vue +13 -0
- package/components/__tests__/CountBox.test.ts +72 -0
- package/components/__tests__/DetailText.test.ts +113 -0
- package/components/__tests__/PromptModal.test.ts +2 -0
- package/components/fleet/FleetClusterTargets/index.vue +18 -1
- package/components/fleet/FleetClusters.vue +1 -0
- package/components/fleet/__tests__/FleetClusters.test.ts +71 -0
- package/components/form/InputWithSelect.vue +18 -10
- package/components/form/KeyValue.vue +17 -1
- package/components/form/LabeledSelect.vue +82 -24
- package/components/form/NodeScheduling.vue +17 -3
- package/components/form/PrivateRegistry.vue +69 -0
- package/components/form/Select.vue +73 -56
- package/components/form/ServiceNameSelect.vue +13 -11
- package/components/form/__tests__/KeyValue.test.ts +66 -0
- package/components/form/__tests__/NodeScheduling.test.ts +9 -0
- package/components/form/__tests__/PrivateRegistry.test.ts +133 -0
- package/components/form/labeled-select-utils/useLabeledSelectPagination.ts +138 -0
- package/components/formatter/WorkloadHealthScale.vue +3 -1
- package/components/nav/Group.vue +33 -9
- package/components/nav/Header.vue +56 -10
- package/components/nav/NotificationCenter/Notification.vue +4 -1
- package/components/nav/NotificationCenter/NotificationHeader.vue +20 -8
- package/components/nav/NotificationCenter/__tests__/NotificationHeader.test.ts +80 -0
- package/components/nav/TopLevelMenu.vue +15 -1
- package/components/nav/Type.vue +8 -7
- package/components/nav/WindowManager/index.vue +2 -1
- package/components/nav/WorkspaceSwitcher.vue +13 -0
- package/components/nav/__tests__/Group.test.ts +67 -0
- package/components/nav/__tests__/Header.test.ts +235 -0
- package/components/nav/__tests__/Type.test.ts +20 -3
- package/components/templates/default.vue +34 -4
- package/components/templates/home.vue +12 -25
- package/components/templates/plain.vue +13 -26
- package/composables/useLabeledFormElement.ts +10 -2
- package/composables/useLabeledSelect.ts +60 -0
- package/composables/useUserRetentionValidation.ts +1 -49
- package/config/cookies.js +0 -1
- package/config/labels-annotations.js +1 -0
- package/config/pagination-table-headers.js +8 -1
- package/config/product/apps.js +2 -1
- package/config/product/auth.js +1 -0
- package/config/product/backup.js +1 -0
- package/config/product/compliance.js +1 -1
- package/config/product/explorer.js +25 -6
- package/config/product/fleet.js +1 -0
- package/config/product/gatekeeper.js +1 -0
- package/config/product/istio.js +1 -0
- package/config/product/logging.js +1 -0
- package/config/product/longhorn.js +2 -1
- package/config/product/manager.js +1 -0
- package/config/product/monitoring.js +1 -0
- package/config/product/navlinks.js +1 -0
- package/config/product/neuvector.js +2 -1
- package/config/product/settings.js +1 -0
- package/config/product/uiplugins.js +1 -0
- package/config/query-params.js +1 -0
- package/config/router/routes.js +0 -8
- package/core/__tests__/plugin-products-helpers.test.ts +454 -0
- package/core/__tests__/plugin-products.test.ts +3810 -0
- package/core/extension-manager-impl.js +30 -1
- package/core/plugin-products-base.ts +392 -0
- package/core/plugin-products-extending.ts +44 -0
- package/core/plugin-products-helpers.ts +263 -0
- package/core/plugin-products-top-level.ts +66 -0
- package/core/plugin-products-type-guards.ts +33 -0
- package/core/plugin-products.ts +50 -0
- package/core/plugin-types.ts +237 -0
- package/core/plugin.ts +45 -10
- package/core/productDebugger.js +48 -0
- package/core/types.ts +97 -11
- package/detail/__tests__/__snapshots__/fleet.cattle.io.bundle.test.ts.snap +52 -0
- package/detail/__tests__/fleet.cattle.io.bundle.test.ts +171 -0
- package/detail/__tests__/management.cattle.io.fleetworkspace.test.ts +128 -0
- package/detail/fleet.cattle.io.bundle.vue +21 -34
- package/detail/management.cattle.io.fleetworkspace.vue +49 -0
- package/dialog/ExtensionCatalogInstallDialog.vue +1 -1
- package/dialog/InstallExtensionDialog.vue +6 -27
- package/dialog/UninstallExistingExtensionDialog.vue +141 -0
- package/dialog/UninstallExtensionDialog.vue +4 -26
- package/dialog/__tests__/UninstallExistingExtensionDialog.test.ts +114 -0
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +1 -0
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +9 -0
- package/edit/__tests__/kontainerDriver.test.ts +0 -13
- package/edit/__tests__/nodeDriver.test.ts +5 -11
- package/edit/__tests__/resources.cattle.io.restore.test.ts +9 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +6 -0
- package/edit/auth/__tests__/oidc.test.ts +54 -0
- package/edit/auth/azuread.vue +1 -1
- package/edit/auth/oidc.vue +8 -0
- package/edit/kontainerDriver.vue +1 -2
- package/edit/nodeDriver.vue +0 -2
- package/edit/provisioning.cattle.io.cluster/AgentEnv.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/AgentEnv.test.ts +25 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/Ingress.test.ts +176 -0
- package/edit/provisioning.cattle.io.cluster/index.vue +70 -99
- package/edit/provisioning.cattle.io.cluster/rke2.vue +4 -1
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +6 -0
- package/edit/provisioning.cattle.io.cluster/tabs/Ingress.vue +7 -2
- package/initialize/App.vue +29 -2
- package/initialize/install-plugins.js +0 -2
- package/list/__tests__/management.cattle.io.feature.test.ts +105 -0
- package/list/catalog.cattle.io.app.vue +25 -5
- package/list/management.cattle.io.feature.vue +1 -1
- package/list/management.cattle.io.fleetworkspace.vue +8 -0
- package/list/provisioning.cattle.io.cluster.vue +0 -1
- package/list/workload.vue +11 -4
- package/machine-config/amazonec2.vue +1 -0
- package/mixins/chart.js +40 -9
- package/mixins/resource-fetch.js +12 -3
- package/models/__tests__/catalog.cattle.io.app.test.ts +15 -1
- package/models/__tests__/catalog.cattle.io.clusterrepo.test.ts +84 -0
- package/models/__tests__/chart.test.ts +99 -6
- package/models/__tests__/management.cattle.io.feature.test.ts +131 -0
- package/models/__tests__/monitoring.coreos.com.alertmanagerconfig.test.ts +98 -0
- package/models/catalog.cattle.io.app.js +21 -17
- package/models/catalog.cattle.io.clusterrepo.js +39 -11
- package/models/chart.js +33 -19
- package/models/fleet-application.js +1 -1
- package/models/fleet.cattle.io.bundle.js +1 -1
- package/models/kontainerdriver.js +11 -0
- package/models/management.cattle.io.authconfig.js +5 -1
- package/models/management.cattle.io.cluster.js +0 -53
- package/models/management.cattle.io.feature.js +3 -3
- package/models/management.cattle.io.kontainerdriver.js +1 -26
- package/models/monitoring.coreos.com.alertmanagerconfig.js +31 -17
- package/models/nodedriver.js +7 -0
- package/models/pod.js +18 -0
- package/models/workload.js +20 -2
- package/package.json +13 -13
- package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +0 -1
- package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +189 -0
- package/pages/c/_cluster/apps/charts/__tests__/index.test.ts +55 -0
- package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +53 -0
- package/pages/c/_cluster/apps/charts/chart.vue +217 -33
- package/pages/c/_cluster/apps/charts/index.vue +2 -2
- package/pages/c/_cluster/apps/charts/install.vue +8 -3
- package/pages/c/_cluster/auth/user.retention/index.vue +55 -22
- package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +5 -7
- package/pages/c/_cluster/settings/brand.vue +4 -4
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +39 -2
- package/pages/c/_cluster/uiplugins/__tests__/PluginInfoPanel.test.ts +61 -0
- package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +246 -23
- package/pages/c/_cluster/uiplugins/index.vue +166 -62
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +1 -0
- package/plugins/dashboard-store/actions.js +3 -2
- package/plugins/dashboard-store/resource-class.js +62 -6
- package/plugins/plugin.js +16 -0
- package/plugins/steve/steve-pagination-utils.ts +7 -0
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +205 -1
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +82 -4
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +1 -1
- package/scripts/test-plugins-build.sh +5 -2
- package/scripts/typegen.sh +13 -1
- package/server/server-middleware.js +2 -2
- package/static/humans.txt +1 -0
- package/static/robots.txt +34 -0
- package/static/welcome-cow.svg +18 -0
- package/store/__tests__/catalog.test.ts +161 -11
- package/store/__tests__/type-map.test.ts +84 -24
- package/store/auth.js +0 -3
- package/store/catalog.js +60 -8
- package/store/type-map.js +42 -3
- package/tsconfig.paths.json +1 -0
- package/types/resources/pod.ts +18 -0
- package/types/shell/index.d.ts +8539 -2938
- package/types/store/dashboard-store.types.ts +5 -0
- package/types/store/pagination.types.ts +6 -0
- package/utils/__tests__/git.test.ts +270 -0
- package/utils/__tests__/inactivity.test.ts +316 -0
- package/utils/__tests__/object.test.ts +77 -0
- package/utils/__tests__/time.test.ts +14 -1
- package/utils/__tests__/url.test.ts +246 -0
- package/utils/axios.js +1 -4
- package/utils/dynamic-importer.js +3 -2
- package/utils/object.js +33 -2
- package/utils/pagination-utils.ts +1 -1
- package/utils/time.ts +5 -0
- package/utils/uiplugins.ts +12 -16
- package/utils/validators/__tests__/private-registry.test.ts +76 -0
- package/utils/validators/private-registry.ts +28 -0
- package/vue.config.js +0 -9
- package/assets/images/providers/azuread-black.svg +0 -22
- package/assets/images/providers/azuread.svg +0 -25
- package/assets/images/vendor/azuread.svg +0 -18
- package/assets/styles/fonts/_dots.scss +0 -18
- package/components/EmberPage.vue +0 -622
- package/components/EmberPageView.vue +0 -39
- package/components/form/labeled-select-utils/labeled-select-pagination.ts +0 -116
- package/mixins/labeled-form-element.ts +0 -225
- package/pages/c/_cluster/explorer/tools/pages/_page.vue +0 -28
- package/pages/c/_cluster/manager/pages/_page.vue +0 -22
- package/pages/c/_cluster/mcapps/pages/_page.vue +0 -22
- package/plugins/ember-cookie.js +0 -17
- package/utils/ember-page.js +0 -30
|
@@ -4,7 +4,6 @@ import Loading from '@shell/components/Loading';
|
|
|
4
4
|
import { Banner } from '@components/Banner';
|
|
5
5
|
import CruResource from '@shell/components/CruResource';
|
|
6
6
|
import SelectIconGrid from '@shell/components/SelectIconGrid';
|
|
7
|
-
import EmberPage from '@shell/components/EmberPage';
|
|
8
7
|
import {
|
|
9
8
|
CHART, FROM_CLUSTER, SUB_TYPE, RKE_TYPE, _EDIT, _IMPORT, _CONFIG, _VIEW
|
|
10
9
|
} from '@shell/config/query-params';
|
|
@@ -18,8 +17,8 @@ import { mapFeature, RKE2 as RKE2_FEATURE } from '@shell/store/features';
|
|
|
18
17
|
import { allHash } from '@shell/utils/promise';
|
|
19
18
|
import { BLANK_CLUSTER } from '@shell/store/store-types.js';
|
|
20
19
|
import { ELEMENTAL_PRODUCT_NAME, ELEMENTAL_CLUSTER_PROVIDER } from '../../config/elemental-types';
|
|
20
|
+
import { KONTAINER_TO_DRIVER } from '@shell/models/management.cattle.io.kontainerdriver';
|
|
21
21
|
import Rke2Config from './rke2';
|
|
22
|
-
import { DRIVER_TO_IMPORT } from '@shell/models/management.cattle.io.kontainerdriver';
|
|
23
22
|
import { requireAsset } from '@shell/utils/require-asset';
|
|
24
23
|
|
|
25
24
|
const SORT_GROUPS = {
|
|
@@ -44,7 +43,6 @@ export default {
|
|
|
44
43
|
|
|
45
44
|
components: {
|
|
46
45
|
CruResource,
|
|
47
|
-
EmberPage,
|
|
48
46
|
Loading,
|
|
49
47
|
Rke2Config,
|
|
50
48
|
SelectIconGrid,
|
|
@@ -103,19 +101,6 @@ export default {
|
|
|
103
101
|
hash.kontainerDrivers = this.$store.dispatch('management/findAll', { type: MANAGEMENT.KONTAINER_DRIVER });
|
|
104
102
|
}
|
|
105
103
|
|
|
106
|
-
// Not sure if needed for legacy hosted cluster?
|
|
107
|
-
if ( this.value.id && !this.value.isRke2 ) {
|
|
108
|
-
// These are needed to resolve references in the mgmt cluster -> node pool -> node template to figure out what provider the cluster is using
|
|
109
|
-
// so that the edit iframe for ember pages can go to the right place.
|
|
110
|
-
if (this.$store.getters[`management/canList`](MANAGEMENT.NODE_POOL)) {
|
|
111
|
-
hash.rke1NodePools = this.$store.dispatch('management/findAll', { type: MANAGEMENT.NODE_POOL });
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (this.$store.getters[`management/canList`](MANAGEMENT.NODE_TEMPLATE)) {
|
|
115
|
-
hash.rke1NodeTemplates = this.$store.dispatch('management/findAll', { type: MANAGEMENT.NODE_TEMPLATE });
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
104
|
const res = await allHash(hash);
|
|
120
105
|
|
|
121
106
|
this.nodeDrivers = res.nodeDrivers || [];
|
|
@@ -172,11 +157,50 @@ export default {
|
|
|
172
157
|
if ( this.$route.query[SUB_TYPE]) {
|
|
173
158
|
subType = this.$route.query[SUB_TYPE];
|
|
174
159
|
} else if (this.value.isImported) {
|
|
160
|
+
// Default imported clusters to the generic imported subType.
|
|
161
|
+
// Imported hosted clusters (e.g. AKS, EKS, GKE) that have an extension-provided
|
|
162
|
+
// component will be overridden below to load the correct custom form.
|
|
175
163
|
subType = IMPORTED;
|
|
176
164
|
} else if (this.value.isLocal) {
|
|
177
165
|
subType = LOCAL;
|
|
178
166
|
}
|
|
179
167
|
|
|
168
|
+
// For imported hosted clusters, check if the provisioner has a matching extension
|
|
169
|
+
// component and override the subType so the correct custom form loads instead of
|
|
170
|
+
// the generic imported configuration page.
|
|
171
|
+
if (subType === IMPORTED && this.value?.id && this.value.provisioner) {
|
|
172
|
+
const provisionerLower = this.value.provisioner.toLowerCase();
|
|
173
|
+
const hasExtension = this.extensions.some((ext) => ext.id === provisionerLower);
|
|
174
|
+
|
|
175
|
+
if (hasExtension) {
|
|
176
|
+
subType = provisionerLower;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Auto-detect subType for existing clusters being edited
|
|
181
|
+
if ( !subType && this.value?.id ) {
|
|
182
|
+
// Check for extension annotation first
|
|
183
|
+
const fromAnnotation = this.value.annotations?.[CAPI_ANNOTATIONS.UI_CUSTOM_PROVIDER];
|
|
184
|
+
|
|
185
|
+
if (fromAnnotation) {
|
|
186
|
+
subType = fromAnnotation;
|
|
187
|
+
} else if ( this.value.isRke2 ) {
|
|
188
|
+
// For custom RKE2 clusters
|
|
189
|
+
if ( this.value.isCustom && (this.realMode === _EDIT || (this.as === _CONFIG && this.realMode === _VIEW)) ) {
|
|
190
|
+
subType = 'custom';
|
|
191
|
+
} else if ( this.value.machineProvider ) {
|
|
192
|
+
// For RKE2/K3s clusters provisioned in Rancher, use the machine pool provisioner
|
|
193
|
+
subType = this.value.machineProvider;
|
|
194
|
+
}
|
|
195
|
+
} else if ( this.value.provisioner ) {
|
|
196
|
+
// For non-RKE2 clusters, try to match against extension-provided subtypes
|
|
197
|
+
const provisionerLower = this.value.provisioner.toLowerCase();
|
|
198
|
+
|
|
199
|
+
// This will be checked against available subtypes after they're computed
|
|
200
|
+
subType = provisionerLower;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
180
204
|
this.subType = subType;
|
|
181
205
|
},
|
|
182
206
|
|
|
@@ -217,74 +241,6 @@ export default {
|
|
|
217
241
|
},
|
|
218
242
|
_RKE2: () => _RKE2,
|
|
219
243
|
|
|
220
|
-
emberLink() {
|
|
221
|
-
if (this.value) {
|
|
222
|
-
// set subtype if editing EKS/GKE/AKS cluster -- this ensures that the component provided by extension is loaded instead of iframing old ember ui
|
|
223
|
-
if (this.value.provisioner) {
|
|
224
|
-
const matchingSubtype = this.subTypes.find((st) => {
|
|
225
|
-
const typeLower = st.id.toLowerCase();
|
|
226
|
-
const provisionerLower = this.value.provisioner.toLowerCase();
|
|
227
|
-
|
|
228
|
-
// This allows extensions to provide type for edit without breaking edit for Ember kontainer providers
|
|
229
|
-
return (!!st.component && (typeLower === provisionerLower)) || (DRIVER_TO_IMPORT[typeLower] === provisionerLower);
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
if (matchingSubtype) {
|
|
233
|
-
this.selectType(matchingSubtype.id, false);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// subType set by the ui during cluster creation
|
|
238
|
-
// this is likely from a ui extension trying to load custom ui to edit the cluster
|
|
239
|
-
const fromAnnotation = this.value.annotations?.[CAPI_ANNOTATIONS.UI_CUSTOM_PROVIDER];
|
|
240
|
-
|
|
241
|
-
if (fromAnnotation) {
|
|
242
|
-
this.selectType(fromAnnotation, false);
|
|
243
|
-
|
|
244
|
-
return '';
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// For custom RKE2 clusters, don't load an Ember page.
|
|
248
|
-
// It should be the dashboard.
|
|
249
|
-
if ( this.value.isRke2 && ((this.value.isCustom && this.mode === _EDIT) || (this.value.isCustom && this.as === _CONFIG && this.mode === _VIEW) || (this.subType || '').toLowerCase() === 'custom')) {
|
|
250
|
-
// For admins, this.value.isCustom is used to check if it is a custom cluster.
|
|
251
|
-
// For cluster owners, this.subtype is used.
|
|
252
|
-
this.selectType('custom', false);
|
|
253
|
-
|
|
254
|
-
return '';
|
|
255
|
-
}
|
|
256
|
-
// For existing RKE2/K3s clusters provisioned in Rancher,
|
|
257
|
-
// set the subtype using the machine pool provisioner
|
|
258
|
-
// do not use an iFramed Ember page.
|
|
259
|
-
if ( this.value.isRke2 && this.value.machineProvider ) {
|
|
260
|
-
this.selectType(this.value.machineProvider, false);
|
|
261
|
-
|
|
262
|
-
return '';
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
if ( this.subType ) {
|
|
266
|
-
// if driver type has a custom form component, don't load an ember page
|
|
267
|
-
if (this.selectedSubType?.component) {
|
|
268
|
-
return '';
|
|
269
|
-
}
|
|
270
|
-
// For RKE1 and hosted Kubernetes Clusters, set the ember link
|
|
271
|
-
// so that we load the page rather than using RKE2 create
|
|
272
|
-
if (this.selectedSubType?.emberLink) {
|
|
273
|
-
return this.selectedSubType.emberLink;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
return '';
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
if ( this.value.mgmt?.emberEditPath ) {
|
|
280
|
-
// Iframe an old page
|
|
281
|
-
return this.value.mgmt.emberEditPath;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
return '';
|
|
286
|
-
},
|
|
287
|
-
|
|
288
244
|
rke2Enabled: mapFeature(RKE2_FEATURE),
|
|
289
245
|
|
|
290
246
|
// todo nb is this info stored anywhere else..?
|
|
@@ -310,6 +266,24 @@ export default {
|
|
|
310
266
|
return this.value.isRke2;
|
|
311
267
|
},
|
|
312
268
|
|
|
269
|
+
isEmberKontainerDriver() {
|
|
270
|
+
// RKE2/K3s clusters are never legacy Ember kontainer drivers
|
|
271
|
+
if (!this.value?.id || !this.value?.provisioner || this.value.isRke2) {
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const provisioner = this.value.provisioner.toLowerCase();
|
|
276
|
+
// Resolve the provisioner to a driver name using the KONTAINER_TO_DRIVER map
|
|
277
|
+
const resolvedName = KONTAINER_TO_DRIVER[provisioner] || provisioner;
|
|
278
|
+
|
|
279
|
+
const driver = this.kontainerDrivers.find((d) => {
|
|
280
|
+
return d.driverName === resolvedName || d.driverName === provisioner || d.id === provisioner;
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
// If the driver exists and is not built-in, it's a legacy ember driver
|
|
284
|
+
return !!driver && !driver.spec?.builtIn;
|
|
285
|
+
},
|
|
286
|
+
|
|
313
287
|
templateOptions() {
|
|
314
288
|
if ( !this.rke2Enabled ) {
|
|
315
289
|
return [];
|
|
@@ -327,16 +301,14 @@ export default {
|
|
|
327
301
|
let out = [];
|
|
328
302
|
|
|
329
303
|
const templates = this.templateOptions;
|
|
330
|
-
const vueKontainerTypes = getters['plugins/clusterDrivers'];
|
|
331
304
|
const machineTypes = this.nodeDrivers.filter((x) => x.spec.active && x.state === 'active');
|
|
332
305
|
|
|
333
|
-
//
|
|
306
|
+
// Kontainer drivers that don't have an extension-provided component are legacy Ember-based
|
|
307
|
+
// and no longer functional. Show them as disabled with an informational tooltip.
|
|
308
|
+
const emberRemovalTooltip = getters['i18n/t']('drivers.kontainer.emberRemovalTooltip');
|
|
309
|
+
|
|
334
310
|
this.kontainerDrivers.filter((x) => (isImport ? x.showImport : x.showCreate)).forEach((obj) => {
|
|
335
|
-
|
|
336
|
-
addType(this.$extension, obj.driverName, 'hosted', false);
|
|
337
|
-
} else {
|
|
338
|
-
addType(this.$extension, obj.driverName, 'hosted', false, (isImport ? obj.emberImportPath : obj.emberCreatePath));
|
|
339
|
-
}
|
|
311
|
+
addType(this.$extension, obj.driverName, 'hosted', true, undefined, undefined, emberRemovalTooltip);
|
|
340
312
|
});
|
|
341
313
|
if (!isImport) {
|
|
342
314
|
templates.forEach((chart) => {
|
|
@@ -360,7 +332,7 @@ export default {
|
|
|
360
332
|
machineTypes.forEach((type) => {
|
|
361
333
|
const id = type.spec.displayName || type.id;
|
|
362
334
|
|
|
363
|
-
addType(this.$extension, id, _RKE2, false,
|
|
335
|
+
addType(this.$extension, id, _RKE2, false, undefined, type);
|
|
364
336
|
});
|
|
365
337
|
|
|
366
338
|
addType(this.$extension, 'custom', 'custom2', false);
|
|
@@ -409,7 +381,7 @@ export default {
|
|
|
409
381
|
out.push(subtype);
|
|
410
382
|
}
|
|
411
383
|
|
|
412
|
-
function addType(plugin, id, group, disabled = false,
|
|
384
|
+
function addType(plugin, id, group, disabled = false, iconClass = undefined, providerConfig = undefined, tooltip = undefined) {
|
|
413
385
|
const label = getters['i18n/withFallback'](`cluster.provider."${ id }"`, null, id);
|
|
414
386
|
const description = getters['i18n/withFallback'](`cluster.providerDescription."${ id }"`, null, '');
|
|
415
387
|
const tag = '';
|
|
@@ -439,8 +411,8 @@ export default {
|
|
|
439
411
|
iconClass,
|
|
440
412
|
group,
|
|
441
413
|
disabled,
|
|
442
|
-
emberLink,
|
|
443
414
|
tag,
|
|
415
|
+
tooltip,
|
|
444
416
|
providerConfig
|
|
445
417
|
};
|
|
446
418
|
|
|
@@ -594,12 +566,11 @@ export default {
|
|
|
594
566
|
/>
|
|
595
567
|
</div>
|
|
596
568
|
<div
|
|
597
|
-
v-else-if="
|
|
598
|
-
class="embed"
|
|
569
|
+
v-else-if="isEmberKontainerDriver"
|
|
599
570
|
>
|
|
600
|
-
<
|
|
601
|
-
|
|
602
|
-
|
|
571
|
+
<Banner
|
|
572
|
+
color="warning"
|
|
573
|
+
label-key="drivers.kontainer.emberRemovalMessage"
|
|
603
574
|
/>
|
|
604
575
|
</div>
|
|
605
576
|
<CruResource
|
|
@@ -297,7 +297,8 @@ export default {
|
|
|
297
297
|
originalKubeVersion: null,
|
|
298
298
|
isEmpty,
|
|
299
299
|
AGENT_CONFIGURATION_TYPES,
|
|
300
|
-
basicsValid: true
|
|
300
|
+
basicsValid: true,
|
|
301
|
+
originalIngressController: this.value.spec.rkeConfig.machineGlobalConfig?.[INGRESS_CONTROLLER] || INGRESS_NONE,
|
|
301
302
|
};
|
|
302
303
|
},
|
|
303
304
|
|
|
@@ -2522,6 +2523,7 @@ export default {
|
|
|
2522
2523
|
<Tab
|
|
2523
2524
|
v-if="!obj.remove"
|
|
2524
2525
|
:key="obj.id"
|
|
2526
|
+
:weight="-1 * idx"
|
|
2525
2527
|
:name="obj.id"
|
|
2526
2528
|
:label="obj.pool.name || '(Not Named)'"
|
|
2527
2529
|
:show-header="false"
|
|
@@ -2592,6 +2594,7 @@ export default {
|
|
|
2592
2594
|
:is-azure-provider-unsupported="isAzureProviderUnsupported"
|
|
2593
2595
|
:can-azure-migrate-on-edit="canAzureMigrateOnEdit"
|
|
2594
2596
|
:has-some-ipv6-pools="hasOnlyIpv6Pools"
|
|
2597
|
+
:original-ingress-controller="originalIngressController"
|
|
2595
2598
|
@update:value="$emit('input', $event)"
|
|
2596
2599
|
@cilium-values-changed="handleCiliumValuesChanged"
|
|
2597
2600
|
@enabled-system-services-changed="handleEnabledSystemServicesChanged"
|
|
@@ -120,6 +120,11 @@ export default {
|
|
|
120
120
|
canAzureMigrateOnEdit: {
|
|
121
121
|
type: Boolean,
|
|
122
122
|
required: true
|
|
123
|
+
},
|
|
124
|
+
originalIngressController: {
|
|
125
|
+
type: [String, Array],
|
|
126
|
+
required: false,
|
|
127
|
+
default: INGRESS_NONE
|
|
123
128
|
}
|
|
124
129
|
},
|
|
125
130
|
|
|
@@ -699,6 +704,7 @@ export default {
|
|
|
699
704
|
:traefik-chart="traefikChart"
|
|
700
705
|
:user-chart-values="userChartValues"
|
|
701
706
|
:version-info="versionInfo"
|
|
707
|
+
:original-ingress-controller="originalIngressController"
|
|
702
708
|
@update-values="(name, val) => $emit('update-values', name, val)"
|
|
703
709
|
@error="$emit('error', $event)"
|
|
704
710
|
@yaml-validation-changed="e => $emit('yaml-validation-changed', e)"
|
|
@@ -24,6 +24,7 @@ interface Props {
|
|
|
24
24
|
traefikChart: string;
|
|
25
25
|
userChartValues: any;
|
|
26
26
|
versionInfo: any;
|
|
27
|
+
originalIngressController?: string | string[];
|
|
27
28
|
}
|
|
28
29
|
const {
|
|
29
30
|
mode = _CREATE,
|
|
@@ -33,7 +34,8 @@ const {
|
|
|
33
34
|
nginxSupported,
|
|
34
35
|
traefikSupported,
|
|
35
36
|
userChartValues,
|
|
36
|
-
versionInfo
|
|
37
|
+
versionInfo,
|
|
38
|
+
originalIngressController = INGRESS_NONE
|
|
37
39
|
} = defineProps<Props>();
|
|
38
40
|
|
|
39
41
|
const emit = defineEmits(['update:value', 'error', 'config-validation-changed', 'yaml-validation-changed', 'update-values']);
|
|
@@ -179,7 +181,10 @@ const compatibilityMode = computed({
|
|
|
179
181
|
|
|
180
182
|
function selectIngress(id: string) {
|
|
181
183
|
if ( id === INGRESS_DUAL) {
|
|
182
|
-
|
|
184
|
+
const newValue: string | string[] = !Array.isArray(originalIngressController) ? (originalIngressController === TRAEFIK ? [TRAEFIK, INGRESS_NGINX] : [INGRESS_NGINX, TRAEFIK]) : originalIngressController;
|
|
185
|
+
|
|
186
|
+
emit('update:value', newValue);
|
|
187
|
+
|
|
183
188
|
preconfigureTraefik();
|
|
184
189
|
} else {
|
|
185
190
|
emit('update:value', id);
|
package/initialize/App.vue
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import GlobalLoading from '@shell/components/nav/GlobalLoading.vue';
|
|
3
|
+
import WindowManager from '@shell/components/nav/WindowManager';
|
|
3
4
|
|
|
4
5
|
import '@shell/assets/styles/app.scss';
|
|
5
6
|
|
|
6
7
|
export default {
|
|
7
|
-
data
|
|
8
|
+
data() {
|
|
9
|
+
return {
|
|
10
|
+
isOnline: true,
|
|
11
|
+
currentLayout: null,
|
|
12
|
+
};
|
|
13
|
+
},
|
|
8
14
|
|
|
9
15
|
created() {
|
|
10
16
|
// add to window so we can listen when ready
|
|
@@ -36,6 +42,14 @@ export default {
|
|
|
36
42
|
this.$loading = this.$refs.loading;
|
|
37
43
|
},
|
|
38
44
|
|
|
45
|
+
provide() {
|
|
46
|
+
return {
|
|
47
|
+
notifyWmContainerReady: (layout) => {
|
|
48
|
+
this.currentLayout = layout;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
|
|
39
53
|
computed: {
|
|
40
54
|
isOffline() {
|
|
41
55
|
return !this.isOnline;
|
|
@@ -55,7 +69,10 @@ export default {
|
|
|
55
69
|
},
|
|
56
70
|
},
|
|
57
71
|
|
|
58
|
-
components: {
|
|
72
|
+
components: {
|
|
73
|
+
GlobalLoading,
|
|
74
|
+
WindowManager,
|
|
75
|
+
}
|
|
59
76
|
};
|
|
60
77
|
</script>
|
|
61
78
|
<template>
|
|
@@ -65,6 +82,16 @@ export default {
|
|
|
65
82
|
id="__layout"
|
|
66
83
|
>
|
|
67
84
|
<router-view />
|
|
85
|
+
<!--
|
|
86
|
+
WindowManager is teleported into each template's wm-container
|
|
87
|
+
This keeps a single instance that never re-mounts while appearing in each template
|
|
88
|
+
-->
|
|
89
|
+
<Teleport
|
|
90
|
+
v-if="currentLayout"
|
|
91
|
+
:to="`#wm-container-${currentLayout}`"
|
|
92
|
+
>
|
|
93
|
+
<WindowManager :layout="currentLayout" />
|
|
94
|
+
</Teleport>
|
|
68
95
|
</div>
|
|
69
96
|
</div>
|
|
70
97
|
</template>
|
|
@@ -21,7 +21,6 @@ import plugin from '@shell/plugins/plugin';
|
|
|
21
21
|
import pluginsLoader from '@shell/core/plugins-loader.js';
|
|
22
22
|
import replaceAll from '@shell/plugins/replaceall';
|
|
23
23
|
import steveCreateWorker from '@shell/plugins/steve-create-worker';
|
|
24
|
-
import emberCookie from '@shell/plugins/ember-cookie';
|
|
25
24
|
import ShortKey from '@shell/plugins/shortkey';
|
|
26
25
|
import { initUiApis } from '@shell/apis/impl/apis';
|
|
27
26
|
|
|
@@ -57,7 +56,6 @@ export async function installInjectedPlugins(app, vueApp) {
|
|
|
57
56
|
replaceAll,
|
|
58
57
|
plugin,
|
|
59
58
|
steveCreateWorker,
|
|
60
|
-
emberCookie,
|
|
61
59
|
dynamicContent,
|
|
62
60
|
];
|
|
63
61
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { shallowMount } from '@vue/test-utils';
|
|
2
|
+
|
|
3
|
+
jest.mock('@shell/mixins/resource-fetch', () => ({
|
|
4
|
+
__esModule: true,
|
|
5
|
+
default: {
|
|
6
|
+
data() {
|
|
7
|
+
return {
|
|
8
|
+
forceUpdateLiveAndDelayed: 0, loading: false, rows: []
|
|
9
|
+
};
|
|
10
|
+
},
|
|
11
|
+
async $fetchType() {}
|
|
12
|
+
}
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
// eslint-disable-next-line import/first
|
|
16
|
+
import ManagementFeature from '@shell/list/management.cattle.io.feature.vue';
|
|
17
|
+
|
|
18
|
+
const createMockStore = () => ({
|
|
19
|
+
getters: {
|
|
20
|
+
'i18n/t': (key: string) => key,
|
|
21
|
+
'management/schemaFor': () => ({ resourceMethods: ['PUT'] }),
|
|
22
|
+
},
|
|
23
|
+
dispatch: jest.fn(),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const createWrapper = (rows: any[]) => {
|
|
27
|
+
return shallowMount(ManagementFeature, {
|
|
28
|
+
props: {
|
|
29
|
+
resource: 'management.cattle.io.feature',
|
|
30
|
+
schema: { id: 'management.cattle.io.feature' } as any,
|
|
31
|
+
},
|
|
32
|
+
data: () => ({ rows }),
|
|
33
|
+
global: {
|
|
34
|
+
mocks: {
|
|
35
|
+
$store: createMockStore(),
|
|
36
|
+
$fetchState: { pending: false },
|
|
37
|
+
$fetchType: jest.fn(),
|
|
38
|
+
},
|
|
39
|
+
stubs: {
|
|
40
|
+
// Render the cell:name slot directly so we can assert on the lock icon
|
|
41
|
+
ResourceTable: {
|
|
42
|
+
props: ['rows'],
|
|
43
|
+
template: '<div><slot name="cell:name" :row="rows[0]" /></div>',
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
describe('list/management.cattle.io.feature', () => {
|
|
51
|
+
describe('locked icon rendering in cell:name slot', () => {
|
|
52
|
+
it('should render the lock icon when status.lockedValue is not null', () => {
|
|
53
|
+
const row = {
|
|
54
|
+
metadata: { name: 'feature-a' },
|
|
55
|
+
nameDisplay: 'feature-a',
|
|
56
|
+
status: { lockedValue: true },
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const wrapper = createWrapper([row]);
|
|
60
|
+
|
|
61
|
+
expect(wrapper.find('i.icon-lock').exists()).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should not render the lock icon when status.lockedValue is null', () => {
|
|
65
|
+
const row = {
|
|
66
|
+
metadata: { name: 'feature-a' },
|
|
67
|
+
nameDisplay: 'feature-a',
|
|
68
|
+
status: { lockedValue: null },
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const wrapper = createWrapper([row]);
|
|
72
|
+
|
|
73
|
+
expect(wrapper.find('i.icon-lock').exists()).toBe(false);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should not throw and should not render the lock icon when status is missing (malformed feature flag)', () => {
|
|
77
|
+
const row = {
|
|
78
|
+
metadata: { name: 'feature-a' },
|
|
79
|
+
nameDisplay: 'feature-a',
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
expect(() => createWrapper([row])).not.toThrow();
|
|
83
|
+
|
|
84
|
+
const wrapper = createWrapper([row]);
|
|
85
|
+
|
|
86
|
+
expect(wrapper.find('i.icon-lock').exists()).toBe(false);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe('filteredRows', () => {
|
|
91
|
+
it('should filter out hidden feature flags', () => {
|
|
92
|
+
const rows = [
|
|
93
|
+
{ metadata: { name: 'fleet' } },
|
|
94
|
+
{ metadata: { name: 'some-feature' } },
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
const wrapper = createWrapper(rows);
|
|
98
|
+
|
|
99
|
+
const filtered = (wrapper.vm as any).filteredRows;
|
|
100
|
+
|
|
101
|
+
expect(filtered).toHaveLength(1);
|
|
102
|
+
expect(filtered[0].metadata.name).toBe('some-feature');
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
});
|
|
@@ -40,14 +40,15 @@ export default {
|
|
|
40
40
|
data-testid="installed-app-catalog-list"
|
|
41
41
|
>
|
|
42
42
|
<template #cell:upgrade="{row}">
|
|
43
|
-
<
|
|
43
|
+
<div
|
|
44
44
|
v-if="row.upgradeAvailable === APP_UPGRADE_STATUS.SINGLE_UPGRADE"
|
|
45
|
-
|
|
45
|
+
v-clean-tooltip="row.upgradeAvailableVersion"
|
|
46
|
+
class="badge-state bg-warning hand app-upgrade-badge"
|
|
46
47
|
@click="row.goToUpgrade(row.upgradeAvailableVersion)"
|
|
47
48
|
>
|
|
48
|
-
{{ row.upgradeAvailableVersion }}
|
|
49
|
+
<div>{{ row.upgradeAvailableVersion }}</div>
|
|
49
50
|
<i class="icon icon-upload" />
|
|
50
|
-
</
|
|
51
|
+
</div>
|
|
51
52
|
<span
|
|
52
53
|
v-else-if="row.upgradeAvailable === APP_UPGRADE_STATUS.NOT_APPLICABLE"
|
|
53
54
|
v-t="'catalog.app.managed'"
|
|
@@ -69,8 +70,27 @@ export default {
|
|
|
69
70
|
</PaginatedResourceTable>
|
|
70
71
|
</template>
|
|
71
72
|
|
|
72
|
-
<style scoped>
|
|
73
|
+
<style scoped lang="scss">
|
|
73
74
|
.apps :deep() .state-description{
|
|
74
75
|
color: var(--error)
|
|
75
76
|
}
|
|
77
|
+
|
|
78
|
+
.badge-state.app-upgrade-badge {
|
|
79
|
+
display: inline-flex;
|
|
80
|
+
align-items: center;
|
|
81
|
+
border-radius: var(--border-radius);
|
|
82
|
+
padding: 2px 4px;
|
|
83
|
+
|
|
84
|
+
> div {
|
|
85
|
+
overflow: hidden;
|
|
86
|
+
text-overflow: ellipsis;
|
|
87
|
+
white-space: nowrap;
|
|
88
|
+
min-width: 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
> .icon {
|
|
92
|
+
flex-shrink: 0;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
76
96
|
</style>
|
|
@@ -21,6 +21,14 @@ export default {
|
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
|
|
24
|
+
created() {
|
|
25
|
+
this.$store.dispatch('showWorkspaceSwitcher', false);
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
beforeUnmount() {
|
|
29
|
+
this.$store.dispatch('showWorkspaceSwitcher', true);
|
|
30
|
+
},
|
|
31
|
+
|
|
24
32
|
async fetch() {
|
|
25
33
|
try {
|
|
26
34
|
await this.$fetchType(this.resource);
|
|
@@ -220,7 +220,6 @@ export default {
|
|
|
220
220
|
:use-query-params-for-simple-filtering="useQueryParamsForSimpleFiltering"
|
|
221
221
|
:data-testid="'cluster-list'"
|
|
222
222
|
:force-update-live-and-delayed="forceUpdateLiveAndDelayed"
|
|
223
|
-
:sub-rows="true"
|
|
224
223
|
>
|
|
225
224
|
<!-- Why are state column and subrow overwritten here? -->
|
|
226
225
|
<!-- for rke1 clusters, where they try to use the mgmt cluster stateObj instead of prov cluster stateObj, -->
|
package/list/workload.vue
CHANGED
|
@@ -99,13 +99,21 @@ export default {
|
|
|
99
99
|
const schema = type !== workloadSchema.id ? this.$store.getters['cluster/schemaFor'](type) : workloadSchema;
|
|
100
100
|
const paginationEnabled = !allTypes && this.$store.getters[`cluster/paginationEnabled`]?.({ id: type });
|
|
101
101
|
|
|
102
|
+
const workloadIncludeAssociatedData = paginationEnabled && [
|
|
103
|
+
WORKLOAD_TYPES.DEPLOYMENT,
|
|
104
|
+
WORKLOAD_TYPES.DAEMON_SET,
|
|
105
|
+
WORKLOAD_TYPES.STATEFUL_SET,
|
|
106
|
+
WORKLOAD_TYPES.JOB,
|
|
107
|
+
].includes(type);
|
|
108
|
+
|
|
102
109
|
return {
|
|
103
110
|
allTypes,
|
|
104
111
|
schema,
|
|
105
112
|
paginationEnabled,
|
|
106
113
|
resources: [],
|
|
107
114
|
loadResources,
|
|
108
|
-
loadIndeterminate
|
|
115
|
+
loadIndeterminate,
|
|
116
|
+
workloadIncludeAssociatedData
|
|
109
117
|
};
|
|
110
118
|
},
|
|
111
119
|
|
|
@@ -143,10 +151,8 @@ export default {
|
|
|
143
151
|
* Fetch resources required to populate POD_RESTARTS and WORKLOAD_HEALTH_SCALE columns
|
|
144
152
|
*/
|
|
145
153
|
loadHeathResources() {
|
|
146
|
-
// See https://github.com/rancher/dashboard/issues/10417, health comes from selectors applied locally to all pods (bad)
|
|
147
154
|
if (this.paginationEnabled) {
|
|
148
|
-
//
|
|
149
|
-
// See https://github.com/rancher/dashboard/issues/14211
|
|
155
|
+
// When SSP is enabled we efficiently fetch stats for health column imbedded in the original resource type by supplying `includeAssociatedData` param
|
|
150
156
|
return;
|
|
151
157
|
}
|
|
152
158
|
|
|
@@ -184,6 +190,7 @@ export default {
|
|
|
184
190
|
v-if="paginationEnabled"
|
|
185
191
|
:schema="schema"
|
|
186
192
|
:use-query-params-for-simple-filtering="useQueryParamsForSimpleFiltering"
|
|
193
|
+
:includeAssociatedData="workloadIncludeAssociatedData"
|
|
187
194
|
/>
|
|
188
195
|
<ResourceTable
|
|
189
196
|
v-else
|