@rancher/shell 3.0.8-rc.8 → 3.0.8
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/apis/impl/apis.ts +61 -0
- package/apis/index.ts +40 -0
- package/apis/intf/modal.ts +90 -0
- package/apis/intf/shell.ts +36 -0
- package/apis/intf/slide-in.ts +98 -0
- package/apis/intf/system.ts +41 -0
- package/apis/shell/__tests__/modal.test.ts +80 -0
- package/apis/shell/__tests__/notifications.test.ts +71 -0
- package/apis/shell/__tests__/slide-in.test.ts +54 -0
- package/apis/shell/__tests__/system.test.ts +129 -0
- package/apis/shell/index.ts +38 -0
- package/apis/shell/modal.ts +41 -0
- package/apis/shell/notifications.ts +65 -0
- package/apis/shell/slide-in.ts +33 -0
- package/apis/shell/system.ts +65 -0
- package/apis/vue-shim.d.ts +11 -0
- package/assets/brand/suse/dark/rancher-logo.svg +1 -64
- package/assets/styles/global/_tooltip.scss +6 -1
- package/assets/translations/en-us.yaml +14 -1
- package/components/ActionMenuShell.vue +3 -1
- package/components/BackLink.vue +8 -0
- package/components/BannerGraphic.vue +1 -5
- package/components/BrandImage.vue +17 -6
- package/components/Cron/CronExpressionEditor.vue +1 -1
- package/components/Cron/CronExpressionEditorModal.vue +1 -1
- package/components/CruResource.vue +8 -1
- package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +1 -0
- package/components/Drawer/ResourceDetailDrawer/__tests__/composables.test.ts +50 -1
- package/components/Drawer/ResourceDetailDrawer/composables.ts +19 -0
- package/components/Drawer/ResourceDetailDrawer/index.vue +4 -1
- package/components/Drawer/ResourceDetailDrawer/types.ts +2 -1
- package/components/LocaleSelector.vue +2 -2
- package/components/ModalManager.vue +11 -1
- package/components/Questions/__tests__/Yaml.test.ts +1 -1
- package/components/Questions/__tests__/index.test.ts +159 -0
- package/components/RelatedResources.vue +5 -0
- package/components/Resource/Detail/Metadata/Annotations/index.vue +2 -2
- package/components/Resource/Detail/Metadata/Labels/index.vue +2 -2
- package/components/Resource/Detail/Metadata/index.vue +3 -3
- package/components/Resource/Detail/ResourcePopover/index.vue +5 -1
- package/components/Resource/Detail/composables.ts +2 -2
- package/components/ResourceDetail/Masthead/latest.vue +23 -21
- package/components/ResourceDetail/index.vue +3 -0
- package/components/ResourceTable.vue +54 -21
- package/components/SlideInPanelManager.vue +16 -11
- package/components/SortableTable/THead.vue +2 -1
- package/components/SortableTable/index.vue +20 -2
- package/components/Tabbed/__tests__/index.test.ts +86 -0
- package/components/Tabbed/index.vue +37 -2
- package/components/__tests__/NamespaceFilter.test.ts +49 -0
- package/components/auth/SelectPrincipal.vue +28 -6
- package/components/auth/__tests__/SelectPrincipal.test.ts +119 -0
- package/components/auth/login/ldap.vue +3 -3
- package/components/fleet/FleetSecretSelector.vue +1 -1
- package/components/form/KeyValue.vue +1 -1
- package/components/form/NameNsDescription.vue +1 -1
- package/components/form/NodeScheduling.vue +2 -2
- package/components/form/ResourceTabs/composable.ts +2 -2
- package/components/form/ResourceTabs/index.vue +0 -2
- package/components/form/__tests__/NameNsDescription.test.ts +42 -0
- package/components/formatter/InternalExternalIP.vue +4 -1
- package/components/formatter/LinkName.vue +5 -0
- package/components/formatter/__tests__/InternalExternalIP.test.ts +1 -1
- package/components/nav/Group.vue +25 -7
- package/components/nav/Header.vue +1 -1
- package/components/nav/NamespaceFilter.vue +1 -0
- package/components/nav/Type.vue +17 -6
- package/components/nav/WindowManager/panels/TabBodyContainer.vue +1 -1
- package/components/nav/__tests__/Type.test.ts +59 -0
- package/components/templates/standalone.vue +1 -1
- package/composables/cruResource.ts +27 -0
- package/composables/focusTrap.ts +3 -1
- package/composables/resourceDetail.ts +15 -0
- package/composables/useI18n.ts +10 -1
- package/composables/useLabeledFormElement.ts +3 -4
- package/config/__test__/uiplugins.test.ts +309 -0
- package/config/labels-annotations.js +1 -0
- package/config/product/explorer.js +3 -1
- package/config/product/fleet.js +1 -1
- package/config/router/navigation-guards/clusters.js +3 -3
- package/config/router/navigation-guards/products.js +1 -1
- package/config/router/routes.js +7 -7
- package/config/types.js +7 -0
- package/config/uiplugins.js +46 -2
- package/core/__tests__/extension-manager-impl.test.js +437 -0
- package/core/extension-manager-impl.js +21 -25
- package/core/plugin-helpers.ts +2 -2
- package/core/plugin.ts +9 -1
- package/core/plugins-loader.js +2 -2
- package/core/types-provisioning.ts +5 -1
- package/core/types.ts +35 -0
- package/detail/provisioning.cattle.io.cluster.vue +9 -6
- package/dialog/DeveloperLoadExtensionDialog.vue +13 -4
- package/dialog/MoveNamespaceDialog.vue +20 -4
- package/dialog/RollbackWorkloadDialog.vue +2 -5
- package/dialog/SearchDialog.vue +1 -0
- package/dialog/__tests__/MoveNamespaceDialog.test.ts +249 -0
- package/directives/__tests__/clean-tooltip.test.ts +298 -0
- package/directives/clean-tooltip.ts +234 -0
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +2 -2
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +100 -3
- package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -0
- package/edit/configmap.vue +1 -0
- package/edit/constraints.gatekeeper.sh.constraint/index.vue +1 -0
- package/edit/fleet.cattle.io.helmop.vue +11 -6
- package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
- package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +1 -0
- package/edit/logging-flow/index.vue +1 -0
- package/edit/logging.banzaicloud.io.output/index.vue +1 -0
- package/edit/management.cattle.io.fleetworkspace.vue +1 -1
- package/edit/management.cattle.io.project.vue +1 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +4 -1
- package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +2 -1
- package/edit/monitoring.coreos.com.prometheusrule/index.vue +1 -0
- package/edit/monitoring.coreos.com.receiver/index.vue +2 -1
- package/edit/monitoring.coreos.com.route.vue +1 -1
- package/edit/namespace.vue +1 -0
- package/edit/networking.istio.io.destinationrule/index.vue +1 -0
- package/edit/networking.k8s.io.ingress/index.vue +1 -0
- package/edit/networking.k8s.io.networkpolicy/PolicyRules.vue +1 -0
- package/edit/networking.k8s.io.networkpolicy/index.vue +1 -0
- package/edit/node.vue +1 -0
- package/edit/persistentvolume/index.vue +27 -22
- package/edit/persistentvolume/plugins/awsElasticBlockStore.vue +13 -14
- package/edit/persistentvolume/plugins/azureDisk.vue +49 -48
- package/edit/persistentvolume/plugins/azureFile.vue +15 -14
- package/edit/persistentvolume/plugins/cephfs.vue +15 -14
- package/edit/persistentvolume/plugins/cinder.vue +15 -14
- package/edit/persistentvolume/plugins/csi.vue +18 -16
- package/edit/persistentvolume/plugins/fc.vue +13 -14
- package/edit/persistentvolume/plugins/flexVolume.vue +15 -14
- package/edit/persistentvolume/plugins/flocker.vue +1 -3
- package/edit/persistentvolume/plugins/gcePersistentDisk.vue +13 -14
- package/edit/persistentvolume/plugins/glusterfs.vue +15 -14
- package/edit/persistentvolume/plugins/hostPath.vue +40 -39
- package/edit/persistentvolume/plugins/iscsi.vue +13 -14
- package/edit/persistentvolume/plugins/local.vue +1 -3
- package/edit/persistentvolume/plugins/longhorn.vue +23 -22
- package/edit/persistentvolume/plugins/nfs.vue +15 -14
- package/edit/persistentvolume/plugins/photonPersistentDisk.vue +1 -14
- package/edit/persistentvolume/plugins/portworxVolume.vue +15 -14
- package/edit/persistentvolume/plugins/quobyte.vue +15 -14
- package/edit/persistentvolume/plugins/rbd.vue +15 -14
- package/edit/persistentvolume/plugins/scaleIO.vue +15 -14
- package/edit/persistentvolume/plugins/storageos.vue +15 -14
- package/edit/persistentvolume/plugins/vsphereVolume.vue +1 -3
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +21 -21
- package/edit/provisioning.cattle.io.cluster/index.vue +5 -5
- package/edit/provisioning.cattle.io.cluster/rke2.vue +9 -8
- package/edit/resources.cattle.io.restore.vue +1 -1
- package/edit/secret/index.vue +1 -1
- package/edit/service.vue +1 -0
- package/edit/serviceaccount.vue +1 -0
- package/edit/storage.k8s.io.storageclass/index.vue +1 -0
- package/edit/workload/Job.vue +2 -2
- package/edit/workload/index.vue +2 -1
- package/edit/workload/mixins/workload.js +1 -1
- package/initialize/App.vue +4 -4
- package/initialize/install-plugins.js +19 -5
- package/machine-config/azure.vue +1 -1
- package/machine-config/components/GCEImage.vue +1 -1
- package/mixins/__tests__/brand.spec.ts +2 -2
- package/mixins/brand.js +1 -7
- package/mixins/create-edit-view/index.js +5 -0
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +128 -5
- package/models/chart.js +70 -74
- package/models/management.cattle.io.cluster.js +21 -3
- package/models/provisioning.cattle.io.cluster.js +31 -11
- package/package.json +11 -10
- package/pages/auth/login.vue +4 -6
- package/pages/auth/setup.vue +1 -1
- package/pages/auth/verify.vue +3 -3
- package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +135 -0
- package/pages/c/_cluster/apps/charts/chart.vue +33 -15
- package/pages/c/_cluster/apps/charts/index.vue +122 -24
- package/pages/c/_cluster/apps/charts/install.vue +33 -0
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +1 -1
- package/pages/c/_cluster/explorer/index.vue +8 -6
- package/pages/c/_cluster/fleet/index.vue +4 -7
- package/pages/c/_cluster/manager/hostedprovider/index.vue +12 -6
- package/pages/c/_cluster/settings/brand.vue +1 -1
- package/pages/c/_cluster/settings/index.vue +5 -0
- package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +7 -0
- package/pages/c/_cluster/uiplugins/catalogs.vue +147 -0
- package/pages/c/_cluster/uiplugins/index.vue +126 -184
- package/pkg/auto-import.js +3 -3
- package/pkg/dynamic-importer.lib.js +1 -1
- package/pkg/import.js +1 -1
- package/plugins/__tests__/mutations.tests.ts +179 -0
- package/plugins/dashboard-client-init.js +3 -0
- package/plugins/dashboard-store/getters.js +19 -2
- package/plugins/dashboard-store/model-loader.js +1 -1
- package/plugins/dashboard-store/mutations.js +23 -2
- package/plugins/dashboard-store/resource-class.js +11 -5
- package/plugins/i18n.js +8 -0
- package/plugins/plugin.js +2 -2
- package/plugins/steve/__tests__/steve-pagination-utils.test.ts +506 -0
- package/plugins/steve/steve-class.js +1 -1
- package/plugins/steve/steve-pagination-utils.ts +131 -47
- package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +1 -1
- package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +6 -42
- package/rancher-components/Pill/RcStatusBadge/index.ts +0 -1
- package/rancher-components/Pill/RcStatusBadge/types.ts +1 -1
- package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +5 -28
- package/rancher-components/Pill/RcStatusIndicator/types.ts +2 -1
- package/rancher-components/Pill/types.ts +0 -1
- package/rancher-components/RcDropdown/useDropdownContext.ts +2 -4
- package/rancher-components/RcIcon/RcIcon.test.ts +51 -0
- package/rancher-components/RcIcon/RcIcon.vue +46 -0
- package/rancher-components/RcIcon/index.ts +1 -0
- package/rancher-components/RcIcon/types.ts +160 -0
- package/rancher-components/RcItemCard/RcItemCard.vue +1 -1
- package/rancher-components/utils/status.test.ts +67 -0
- package/rancher-components/utils/status.ts +77 -0
- package/scripts/publish-shell.sh +25 -0
- package/scripts/typegen.sh +1 -0
- package/store/__tests__/catalog.test.ts +1 -1
- package/store/__tests__/type-map.test.ts +164 -2
- package/store/action-menu.js +8 -0
- package/store/auth.js +25 -13
- package/store/catalog.js +6 -0
- package/store/i18n.js +3 -3
- package/store/index.js +8 -6
- package/store/notifications.ts +2 -0
- package/store/prefs.js +6 -7
- package/store/type-map.js +17 -7
- package/store/wm.ts +4 -4
- package/types/internal-api/shell/modal.d.ts +6 -6
- package/types/notifications/index.ts +126 -15
- package/types/rancher/index.d.ts +9 -0
- package/types/shell/index.d.ts +54 -3
- package/types/store/__tests__/pagination.types.spec.ts +137 -0
- package/types/store/pagination.types.ts +157 -9
- package/types/vue-shim.d.ts +5 -4
- package/utils/__tests__/provider.test.ts +98 -0
- package/utils/__tests__/router.test.js +238 -0
- package/utils/__tests__/selector-typed.test.ts +263 -0
- package/utils/cluster.js +4 -1
- package/utils/color.js +1 -1
- package/utils/dynamic-content/__tests__/info.test.ts +6 -0
- package/utils/dynamic-content/info.ts +43 -0
- package/utils/favicon.js +4 -4
- package/utils/fleet.ts +8 -1
- package/utils/pagination-utils.ts +2 -2
- package/utils/pagination-wrapper.ts +1 -1
- package/utils/provider.ts +14 -0
- package/utils/router.js +50 -0
- package/utils/selector-typed.ts +6 -2
- package/utils/unit-tests/pagination-utils.spec.ts +8 -8
- package/vue.config.js +3 -3
- package/composables/useExtensionManager.ts +0 -17
- package/core/plugins.js +0 -38
- package/directives/clean-tooltip.js +0 -32
- package/plugins/internal-api/index.ts +0 -37
- package/plugins/internal-api/shared/base-api.ts +0 -13
- package/plugins/internal-api/shell/shell.api.ts +0 -108
- package/plugins/nuxt-client-init.js +0 -3
- package/types/internal-api/shell/growl.d.ts +0 -25
- package/types/internal-api/shell/slideIn.d.ts +0 -15
|
@@ -65,6 +65,19 @@ export default {
|
|
|
65
65
|
this.installedApps = await this.$store.dispatch('cluster/findAll', { type: CATALOG_TYPES.APP });
|
|
66
66
|
},
|
|
67
67
|
|
|
68
|
+
updated() {
|
|
69
|
+
if (!this.observerInitialized && this.filteredCharts.length > 0) {
|
|
70
|
+
this.initIntersectionObserver();
|
|
71
|
+
}
|
|
72
|
+
this.ensureOverflow();
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
beforeUnmount() {
|
|
76
|
+
if (this.observer) {
|
|
77
|
+
this.observer.disconnect();
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
|
|
68
81
|
data() {
|
|
69
82
|
return {
|
|
70
83
|
DOCS_BASE,
|
|
@@ -107,7 +120,6 @@ export default {
|
|
|
107
120
|
}
|
|
108
121
|
}
|
|
109
122
|
],
|
|
110
|
-
appCardsCache: {},
|
|
111
123
|
selectedSortOption: CATALOG_SORT_OPTIONS.RECOMMENDED,
|
|
112
124
|
sortOptions: [
|
|
113
125
|
{ kind: 'group', label: this.t('catalog.charts.sort.prefix') },
|
|
@@ -115,7 +127,10 @@ export default {
|
|
|
115
127
|
{ value: CATALOG_SORT_OPTIONS.LAST_UPDATED_DESC, label: this.t('catalog.charts.sort.lastUpdatedDesc') },
|
|
116
128
|
{ value: CATALOG_SORT_OPTIONS.ALPHABETICAL_ASC, label: this.t('catalog.charts.sort.alphaAscending') },
|
|
117
129
|
{ value: CATALOG_SORT_OPTIONS.ALPHABETICAL_DESC, label: this.t('catalog.charts.sort.alphaDescending') },
|
|
118
|
-
]
|
|
130
|
+
],
|
|
131
|
+
initialVisibleChartsCount: 30,
|
|
132
|
+
visibleChartsCount: 20,
|
|
133
|
+
hasOverflow: false
|
|
119
134
|
};
|
|
120
135
|
},
|
|
121
136
|
|
|
@@ -262,26 +277,21 @@ export default {
|
|
|
262
277
|
},
|
|
263
278
|
|
|
264
279
|
appChartCards() {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
return this.appCardsCache[chart.id];
|
|
284
|
-
});
|
|
280
|
+
const charts = this.filteredCharts.slice(0, this.visibleChartsCount);
|
|
281
|
+
|
|
282
|
+
return charts.map((chart) => ({
|
|
283
|
+
id: chart.id,
|
|
284
|
+
pill: chart.featured ? { label: { key: 'generic.shortFeatured' }, tooltip: { key: 'generic.featured' } } : undefined,
|
|
285
|
+
header: {
|
|
286
|
+
title: { text: chart.chartNameDisplay },
|
|
287
|
+
statuses: chart.cardContent.statuses
|
|
288
|
+
},
|
|
289
|
+
subHeaderItems: chart.cardContent.subHeaderItems,
|
|
290
|
+
image: { src: chart.latestCompatibleVersion.icon, alt: { text: this.t('catalog.charts.iconAlt', { app: get(chart, 'chartNameDisplay') }) } },
|
|
291
|
+
content: { text: chart.chartDescription },
|
|
292
|
+
footerItems: chart.cardContent.footerItems,
|
|
293
|
+
rawChart: chart
|
|
294
|
+
}));
|
|
285
295
|
},
|
|
286
296
|
|
|
287
297
|
clusterId() {
|
|
@@ -293,7 +303,7 @@ export default {
|
|
|
293
303
|
},
|
|
294
304
|
|
|
295
305
|
totalMessage() {
|
|
296
|
-
const count = !this.isFilterUpdating ? this.
|
|
306
|
+
const count = !this.isFilterUpdating ? this.filteredCharts.length : '. . .';
|
|
297
307
|
|
|
298
308
|
if (this.noFiltersApplied) {
|
|
299
309
|
return this.t('catalog.charts.totalChartsMessage', { count });
|
|
@@ -304,6 +314,10 @@ export default {
|
|
|
304
314
|
},
|
|
305
315
|
|
|
306
316
|
watch: {
|
|
317
|
+
debouncedSearchQuery() {
|
|
318
|
+
this.resetLazyLoadState();
|
|
319
|
+
},
|
|
320
|
+
|
|
307
321
|
searchQuery: {
|
|
308
322
|
handler: debounce(function(q) {
|
|
309
323
|
this.debouncedSearchQuery = q;
|
|
@@ -315,6 +329,8 @@ export default {
|
|
|
315
329
|
filters: {
|
|
316
330
|
deep: true,
|
|
317
331
|
handler(newFilters) {
|
|
332
|
+
this.resetLazyLoadState();
|
|
333
|
+
|
|
318
334
|
const query = {
|
|
319
335
|
[REPO]: normalizeFilterQuery(newFilters.repos),
|
|
320
336
|
[CATEGORY]: normalizeFilterQuery(newFilters.categories),
|
|
@@ -425,11 +441,80 @@ export default {
|
|
|
425
441
|
});
|
|
426
442
|
},
|
|
427
443
|
|
|
444
|
+
resetLazyLoadState() {
|
|
445
|
+
this.visibleChartsCount = this.initialVisibleChartsCount;
|
|
446
|
+
this.observerInitialized = false;
|
|
447
|
+
this.hasOverflow = false;
|
|
448
|
+
},
|
|
449
|
+
|
|
450
|
+
// The lazy loading implementation has two parts
|
|
451
|
+
// 1. Initial Load (ensureOverflow): Having a simple calculation of how many items to load
|
|
452
|
+
// can fail in edge cases like browser zoom, where element sizing and viewport
|
|
453
|
+
// height can lead to miscalculations. If not enough content is loaded, the page
|
|
454
|
+
// won't be scrollable, breaking the IntersectionObserver. This method, called
|
|
455
|
+
// iteratively by the `updated` lifecycle hook, adds batches of charts and
|
|
456
|
+
// re-measures until the content height factually overflows the container,
|
|
457
|
+
// guaranteeing a scrollbar. It then sets `hasOverflow = true` to stop itself.
|
|
458
|
+
// 2. Scroll-based Load (IntersectionObserver): Once the page is scrollable, a standard
|
|
459
|
+
// IntersectionObserver (`initIntersectionObserver` and `loadMore`) takes care of
|
|
460
|
+
// loading new batches of charts as the user scrolls to the bottom.
|
|
461
|
+
ensureOverflow() {
|
|
462
|
+
this.$nextTick(() => {
|
|
463
|
+
if (this.hasOverflow || !this.$refs.chartsContainer) {
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
const mainLayout = document.querySelector('.main-layout');
|
|
468
|
+
|
|
469
|
+
if (!mainLayout) {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const contentHeight = this.$refs.chartsContainer.offsetHeight;
|
|
474
|
+
const containerHeight = mainLayout.offsetHeight;
|
|
475
|
+
|
|
476
|
+
if (contentHeight > containerHeight) {
|
|
477
|
+
this.hasOverflow = true;
|
|
478
|
+
} else if (this.visibleChartsCount < this.filteredCharts.length) {
|
|
479
|
+
// Load another batch
|
|
480
|
+
this.visibleChartsCount += this.initialVisibleChartsCount;
|
|
481
|
+
} else {
|
|
482
|
+
// All charts are visible
|
|
483
|
+
this.hasOverflow = true;
|
|
484
|
+
}
|
|
485
|
+
});
|
|
486
|
+
},
|
|
487
|
+
|
|
428
488
|
resetAllFilters() {
|
|
429
489
|
this.internalFilters = createInitialFilters();
|
|
430
490
|
this.filters = createInitialFilters();
|
|
431
491
|
this.searchQuery = '';
|
|
432
492
|
},
|
|
493
|
+
|
|
494
|
+
loadMore() {
|
|
495
|
+
if (this.visibleChartsCount >= this.filteredCharts.length) {
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
this.visibleChartsCount += this.initialVisibleChartsCount;
|
|
499
|
+
},
|
|
500
|
+
|
|
501
|
+
initIntersectionObserver() {
|
|
502
|
+
if (this.observer) {
|
|
503
|
+
this.observer.disconnect();
|
|
504
|
+
}
|
|
505
|
+
const mainLayout = document.querySelector('.main-layout');
|
|
506
|
+
const sentinel = this.$refs.sentinel;
|
|
507
|
+
|
|
508
|
+
if (sentinel && mainLayout) {
|
|
509
|
+
this.observer = new IntersectionObserver((entries) => {
|
|
510
|
+
if (entries[0].isIntersecting) {
|
|
511
|
+
this.loadMore();
|
|
512
|
+
}
|
|
513
|
+
}, { mainLayout });
|
|
514
|
+
this.observer.observe(sentinel);
|
|
515
|
+
this.observerInitialized = true;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
433
518
|
},
|
|
434
519
|
};
|
|
435
520
|
</script>
|
|
@@ -552,7 +637,10 @@ export default {
|
|
|
552
637
|
>
|
|
553
638
|
<div class="total-and-sort">
|
|
554
639
|
<div class="total">
|
|
555
|
-
<p
|
|
640
|
+
<p
|
|
641
|
+
class="total-message"
|
|
642
|
+
data-testid="charts-total-message"
|
|
643
|
+
>
|
|
556
644
|
{{ totalMessage }}
|
|
557
645
|
</p>
|
|
558
646
|
<a
|
|
@@ -594,6 +682,7 @@ export default {
|
|
|
594
682
|
</Select>
|
|
595
683
|
</div>
|
|
596
684
|
<div
|
|
685
|
+
ref="chartsContainer"
|
|
597
686
|
class="app-chart-cards"
|
|
598
687
|
data-testid="app-chart-cards-container"
|
|
599
688
|
>
|
|
@@ -629,6 +718,11 @@ export default {
|
|
|
629
718
|
</template>
|
|
630
719
|
</rc-item-card>
|
|
631
720
|
</div>
|
|
721
|
+
<div
|
|
722
|
+
ref="sentinel"
|
|
723
|
+
class="sentinel-charts"
|
|
724
|
+
data-testid="charts-lazy-load-sentinel"
|
|
725
|
+
/>
|
|
632
726
|
</div>
|
|
633
727
|
</div>
|
|
634
728
|
</div>
|
|
@@ -673,6 +767,10 @@ export default {
|
|
|
673
767
|
flex-direction: column;
|
|
674
768
|
gap: var(--gap-md);
|
|
675
769
|
flex: 1;
|
|
770
|
+
|
|
771
|
+
.sentinel-charts {
|
|
772
|
+
height: 1px;
|
|
773
|
+
}
|
|
676
774
|
}
|
|
677
775
|
|
|
678
776
|
.total-and-sort {
|
|
@@ -310,6 +310,7 @@ export default {
|
|
|
310
310
|
two different Helm chart versions is a "user value," or
|
|
311
311
|
a user-selected customization.
|
|
312
312
|
*/
|
|
313
|
+
this.preserveCustomRegistryValue();
|
|
313
314
|
userValues = diff(this.loadedVersionValues, this.chartValues);
|
|
314
315
|
} else if ( this.existing ) {
|
|
315
316
|
await this.existing.fetchValues(); // In theory this has already been called, but do again to be safe
|
|
@@ -824,6 +825,35 @@ export default {
|
|
|
824
825
|
},
|
|
825
826
|
|
|
826
827
|
methods: {
|
|
828
|
+
/**
|
|
829
|
+
* The custom registry UI fields (checkbox and input) are not directly bound to chartValues.
|
|
830
|
+
* Before calculating the diff to carry over user customizations, we must
|
|
831
|
+
* first synchronize the state of these UI fields with chartValues. This
|
|
832
|
+
* ensures any user changes to the custom registry settings are
|
|
833
|
+
* included in the diff and preserved when changing versions.
|
|
834
|
+
*/
|
|
835
|
+
preserveCustomRegistryValue() {
|
|
836
|
+
if (!this.showCustomRegistry) {
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
if (this.showCustomRegistryInput) {
|
|
841
|
+
set(this.chartValues, 'global.systemDefaultRegistry', this.customRegistrySetting);
|
|
842
|
+
set(this.chartValues, 'global.cattle.systemDefaultRegistry', this.customRegistrySetting);
|
|
843
|
+
} else {
|
|
844
|
+
// Note: Using `delete` here is safe because this is not a reactive property update
|
|
845
|
+
// that the UI needs to track. This is a one-time mutation before a diff.
|
|
846
|
+
if (get(this.chartValues, 'global.systemDefaultRegistry')) {
|
|
847
|
+
delete this.chartValues.global.systemDefaultRegistry;
|
|
848
|
+
}
|
|
849
|
+
if (get(this.chartValues, 'global.cattle.systemDefaultRegistry')) {
|
|
850
|
+
// It's possible `this.chartValues.global.cattle` doesn't exist,
|
|
851
|
+
// but `get` ensures we only proceed if the full path exists.
|
|
852
|
+
delete this.chartValues.global.cattle.systemDefaultRegistry;
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
},
|
|
856
|
+
|
|
827
857
|
async getClusterRegistry() {
|
|
828
858
|
const hasPermissionToSeeProvCluster = this.$store.getters[`management/schemaFor`](CAPI.RANCHER_CLUSTER);
|
|
829
859
|
|
|
@@ -1367,6 +1397,7 @@ export default {
|
|
|
1367
1397
|
<!-- We have a chart for the app, let the user select a new version -->
|
|
1368
1398
|
<LabeledSelect
|
|
1369
1399
|
v-if="chart"
|
|
1400
|
+
data-testid="chart-version-selector"
|
|
1370
1401
|
:label="t('catalog.install.version')"
|
|
1371
1402
|
:value="query.versionName"
|
|
1372
1403
|
:options="filteredVersions"
|
|
@@ -1435,6 +1466,7 @@ export default {
|
|
|
1435
1466
|
v-if="showCustomRegistry"
|
|
1436
1467
|
v-model:value="showCustomRegistryInput"
|
|
1437
1468
|
class="mb-20"
|
|
1469
|
+
data-testid="custom-registry-checkbox"
|
|
1438
1470
|
:label="t('catalog.chart.registry.custom.checkBoxLabel')"
|
|
1439
1471
|
:tooltip="t('catalog.chart.registry.tooltip')"
|
|
1440
1472
|
/>
|
|
@@ -1443,6 +1475,7 @@ export default {
|
|
|
1443
1475
|
<LabeledInput
|
|
1444
1476
|
v-if="showCustomRegistryInput"
|
|
1445
1477
|
v-model:value="customRegistrySetting"
|
|
1478
|
+
data-testid="custom-registry-input"
|
|
1446
1479
|
label-key="catalog.chart.registry.custom.inputLabel"
|
|
1447
1480
|
placeholder-key="catalog.chart.registry.custom.placeholder"
|
|
1448
1481
|
:min-height="30"
|
|
@@ -211,7 +211,7 @@ describe('page: cluster dashboard', () => {
|
|
|
211
211
|
|
|
212
212
|
expect(box.element).toBeDefined();
|
|
213
213
|
expect(box.element.classList).toContain(status);
|
|
214
|
-
expect(!!(box.element as any)
|
|
214
|
+
expect(!!(box.element as any).__tooltipOptions__?.content).toBe(clickable);
|
|
215
215
|
expect(icon.element.classList).toContain(iconClass);
|
|
216
216
|
|
|
217
217
|
await box.trigger('click');
|
|
@@ -222,7 +222,7 @@ export default {
|
|
|
222
222
|
displayProvider() {
|
|
223
223
|
const other = 'other';
|
|
224
224
|
|
|
225
|
-
let provider = this.currentCluster?.status?.provider || other;
|
|
225
|
+
let provider = this.currentCluster?.status?.provider || this.currentCluster?.status?.driver.toLowerCase() || other;
|
|
226
226
|
|
|
227
227
|
if (provider === 'rke.windows') {
|
|
228
228
|
provider = 'rkeWindows';
|
|
@@ -484,6 +484,12 @@ export default {
|
|
|
484
484
|
hasNodes() {
|
|
485
485
|
return this.nodes?.length > 0;
|
|
486
486
|
},
|
|
487
|
+
kubernetesVersion() {
|
|
488
|
+
const base = this.currentCluster?.kubernetesVersionBase || '';
|
|
489
|
+
const extension = this.currentCluster?.kubernetesVersionExtension || '';
|
|
490
|
+
|
|
491
|
+
return `${ base }${ extension }`;
|
|
492
|
+
}
|
|
487
493
|
},
|
|
488
494
|
|
|
489
495
|
methods: {
|
|
@@ -661,11 +667,7 @@ export default {
|
|
|
661
667
|
</div>
|
|
662
668
|
<div data-testid="kubernetesVersion__label">
|
|
663
669
|
<label>{{ t('glance.version') }}: </label>
|
|
664
|
-
<span>{{
|
|
665
|
-
<span
|
|
666
|
-
v-if="currentCluster.kubernetesVersionExtension"
|
|
667
|
-
style="font-size: 0.75em"
|
|
668
|
-
>{{ currentCluster.kubernetesVersionExtension }}</span>
|
|
670
|
+
<span>{{ kubernetesVersion }}</span>
|
|
669
671
|
</div>
|
|
670
672
|
<div
|
|
671
673
|
v-if="hasNodes"
|
|
@@ -321,16 +321,13 @@ export default {
|
|
|
321
321
|
|
|
322
322
|
this.selectedCard = selected;
|
|
323
323
|
|
|
324
|
-
this.$shell.
|
|
325
|
-
component: ResourceDetails,
|
|
324
|
+
this.$shell.slideIn.open(ResourceDetails, {
|
|
326
325
|
componentProps: {
|
|
326
|
+
showHeader: false,
|
|
327
|
+
width: window.innerWidth / 3 > 530 ? `${ window.innerWidth / 3 }px` : '530px',
|
|
327
328
|
value,
|
|
328
329
|
statePanel,
|
|
329
|
-
workspace
|
|
330
|
-
showHeader: false,
|
|
331
|
-
width: window.innerWidth / 3 > 530 ? `${ window.innerWidth / 3 }px` : '530px',
|
|
332
|
-
triggerFocusTrap: true,
|
|
333
|
-
returnFocusSelector: `[data-testid="resource-card-${ value.id }"]`
|
|
330
|
+
workspace
|
|
334
331
|
}
|
|
335
332
|
});
|
|
336
333
|
},
|
|
@@ -9,6 +9,7 @@ import RcStatusBadge from '@components/Pill/RcStatusBadge/RcStatusBadge.vue';
|
|
|
9
9
|
import { exceptionToErrorsArray } from '@shell/utils/error';
|
|
10
10
|
import { isRancherPrime } from '@shell/config/version';
|
|
11
11
|
import { stateDisplay, STATES_ENUM } from '@shell/plugins/dashboard-store/resource-class';
|
|
12
|
+
import { getHostedProviders } from '@shell/utils/provider';
|
|
12
13
|
|
|
13
14
|
export default {
|
|
14
15
|
name: 'HostedProviders',
|
|
@@ -67,12 +68,9 @@ export default {
|
|
|
67
68
|
axios: this.$store.$axios,
|
|
68
69
|
$extension: this.$store.app.$extension,
|
|
69
70
|
t: (...args) => this.t.apply(this, args),
|
|
70
|
-
isCreate: this.isCreate,
|
|
71
|
-
isEdit: this.isEdit,
|
|
72
|
-
isView: this.isView,
|
|
73
71
|
};
|
|
74
72
|
|
|
75
|
-
return
|
|
73
|
+
return getHostedProviders(context);
|
|
76
74
|
},
|
|
77
75
|
getSettings() {
|
|
78
76
|
this.settingResource = this.$store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.KEV2_OPERATORS );
|
|
@@ -107,7 +105,7 @@ export default {
|
|
|
107
105
|
}
|
|
108
106
|
},
|
|
109
107
|
async generateRows() {
|
|
110
|
-
this.rows = this.allProviders.
|
|
108
|
+
this.rows = this.allProviders.map((p) => {
|
|
111
109
|
const active = p.id in this.settings ? this.settings[p.id] : true;
|
|
112
110
|
const canNotPrime = p.prime && !this.prime;
|
|
113
111
|
const canNotChangeSettings = !this.settingResource?.canUpdate;
|
|
@@ -196,7 +194,8 @@ export default {
|
|
|
196
194
|
<span class="mr-10">{{ row.name }}</span>
|
|
197
195
|
<RcStatusBadge
|
|
198
196
|
v-if="row.prime"
|
|
199
|
-
|
|
197
|
+
class="prime-badge"
|
|
198
|
+
status="success"
|
|
200
199
|
>
|
|
201
200
|
{{ t('providers.hosted.prime') }}
|
|
202
201
|
</RcStatusBadge>
|
|
@@ -212,3 +211,10 @@ export default {
|
|
|
212
211
|
</ResourceTable>
|
|
213
212
|
</div>
|
|
214
213
|
</template>
|
|
214
|
+
|
|
215
|
+
<style lang="scss" scoped>
|
|
216
|
+
.prime-badge {
|
|
217
|
+
font-size: 10px;
|
|
218
|
+
line-height: 15px;
|
|
219
|
+
}
|
|
220
|
+
</style>
|
|
@@ -18,7 +18,7 @@ import { _EDIT, _VIEW } from '@shell/config/query-params';
|
|
|
18
18
|
import { setFavIcon } from '@shell/utils/favicon';
|
|
19
19
|
import TabTitle from '@shell/components/TabTitle';
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
import Color from 'color';
|
|
22
22
|
|
|
23
23
|
export default {
|
|
24
24
|
components: {
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
<script>
|
|
2
|
+
import { h } from 'vue';
|
|
2
3
|
import { NAME as SETTINGS } from '@shell/config/product/settings';
|
|
3
4
|
import { MANAGEMENT } from '@shell/config/types';
|
|
4
5
|
|
|
5
6
|
export default {
|
|
7
|
+
render() {
|
|
8
|
+
// Suppress warning: Component is missing template or render function
|
|
9
|
+
return h('div');
|
|
10
|
+
},
|
|
6
11
|
beforeCreate() {
|
|
7
12
|
const hasSettings = !!this.$store.getters[`management/schemaFor`](MANAGEMENT.SETTING);
|
|
8
13
|
|
|
@@ -164,6 +164,13 @@ describe('page: UI plugins/Extensions', () => {
|
|
|
164
164
|
});
|
|
165
165
|
|
|
166
166
|
describe('getFooterItems', () => {
|
|
167
|
+
it('should return "developer" label for isDeveloper plugins', () => {
|
|
168
|
+
const plugin = { isDeveloper: true };
|
|
169
|
+
const items = wrapper.vm.getFooterItems(plugin);
|
|
170
|
+
|
|
171
|
+
expect(items[0].labels).toContain('plugins.labels.isDeveloper');
|
|
172
|
+
});
|
|
173
|
+
|
|
167
174
|
it('should return "builtin" label for builtin plugins', () => {
|
|
168
175
|
const plugin = { builtin: true };
|
|
169
176
|
const items = wrapper.vm.getFooterItems(plugin);
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
|
|
2
|
+
<script>
|
|
3
|
+
import CatalogList from './CatalogList/index.vue';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
name: 'ExtensionsAirgappedView',
|
|
7
|
+
components: { CatalogList },
|
|
8
|
+
data() {
|
|
9
|
+
return {
|
|
10
|
+
extensionsPageLink: {
|
|
11
|
+
name: 'c-cluster-uiplugins',
|
|
12
|
+
params: { cluster: this.$route.params.cluster }
|
|
13
|
+
},
|
|
14
|
+
reloadRequired: false
|
|
15
|
+
};
|
|
16
|
+
},
|
|
17
|
+
methods: {
|
|
18
|
+
returnToExtensionsPage() {
|
|
19
|
+
this.$router.push(this.extensionsPageLink);
|
|
20
|
+
},
|
|
21
|
+
reload() {
|
|
22
|
+
this.$router.go();
|
|
23
|
+
},
|
|
24
|
+
showCatalogLoadDialog() {
|
|
25
|
+
this.$store.dispatch('management/promptModal', {
|
|
26
|
+
component: 'ExtensionCatalogInstallDialog',
|
|
27
|
+
returnFocusSelector: '[data-testid="extensions-catalog-load-dialog"]',
|
|
28
|
+
componentProps: {
|
|
29
|
+
refresh: () => {
|
|
30
|
+
this.reloadRequired = true;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
showCatalogUninstallDialog(ev) {
|
|
36
|
+
this.$store.dispatch('management/promptModal', {
|
|
37
|
+
component: 'ExtensionCatalogUninstallDialog',
|
|
38
|
+
returnFocusSelector: '[data-testid="extensions-catalog-load-dialog"]',
|
|
39
|
+
componentProps: {
|
|
40
|
+
catalog: ev,
|
|
41
|
+
refresh: () => {
|
|
42
|
+
this.reloadRequired = true;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<template>
|
|
52
|
+
<div id="extensions-airgapped-main-page">
|
|
53
|
+
<div class="plugin-header">
|
|
54
|
+
<!-- catalog/airgapped header -->
|
|
55
|
+
<div class="catalog-title">
|
|
56
|
+
<h2
|
|
57
|
+
class="mb-0 mr-10"
|
|
58
|
+
data-testid="extensions-catalog-title"
|
|
59
|
+
>
|
|
60
|
+
<a
|
|
61
|
+
class="link"
|
|
62
|
+
role="link"
|
|
63
|
+
tabindex="0"
|
|
64
|
+
:aria-label="t('plugins.manageCatalog.title')"
|
|
65
|
+
@click="returnToExtensionsPage()"
|
|
66
|
+
>
|
|
67
|
+
{{ t('plugins.manageCatalog.title') }}:
|
|
68
|
+
</a>
|
|
69
|
+
<t k="plugins.manageCatalog.subtitle" />
|
|
70
|
+
</h2>
|
|
71
|
+
</div>
|
|
72
|
+
<div class="actions-container">
|
|
73
|
+
<!-- extensions reload toast/notification -->
|
|
74
|
+
<div
|
|
75
|
+
v-if="reloadRequired"
|
|
76
|
+
class="plugin-reload-banner mmr-6"
|
|
77
|
+
data-testid="extension-reload-banner"
|
|
78
|
+
>
|
|
79
|
+
<i class="icon icon-checkmark mr-10" />
|
|
80
|
+
<span>
|
|
81
|
+
{{ t('plugins.reload') }}
|
|
82
|
+
</span>
|
|
83
|
+
<button
|
|
84
|
+
class="ml-10 btn btn-sm role-primary"
|
|
85
|
+
data-testid="extension-reload-banner-reload-btn"
|
|
86
|
+
role="button"
|
|
87
|
+
:aria-label="t('plugins.labels.reloadRancher')"
|
|
88
|
+
@click="reload()"
|
|
89
|
+
>
|
|
90
|
+
{{ t('generic.reload') }}
|
|
91
|
+
</button>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
<div>
|
|
96
|
+
<!-- Catalog list view -->
|
|
97
|
+
<CatalogList
|
|
98
|
+
@showCatalogLoadDialog="showCatalogLoadDialog"
|
|
99
|
+
@showCatalogUninstallDialog="showCatalogUninstallDialog($event)"
|
|
100
|
+
/>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
</template>
|
|
104
|
+
|
|
105
|
+
<style lang="scss" scoped>
|
|
106
|
+
.plugin-header {
|
|
107
|
+
display: flex;
|
|
108
|
+
align-items: center;
|
|
109
|
+
justify-content: space-between;
|
|
110
|
+
margin-bottom: 10px;
|
|
111
|
+
|
|
112
|
+
.catalog-title {
|
|
113
|
+
display: flex;
|
|
114
|
+
flex-direction: row;
|
|
115
|
+
align-items: center;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
> h2 {
|
|
119
|
+
flex: 1;
|
|
120
|
+
margin-bottom: 0;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.link {
|
|
124
|
+
cursor: pointer;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.plugin-reload-banner {
|
|
129
|
+
align-items: center;
|
|
130
|
+
background-color: var(--success-banner-bg);
|
|
131
|
+
display: flex;
|
|
132
|
+
padding: 4px 4px 4px 12px;
|
|
133
|
+
border-radius: 5px;
|
|
134
|
+
min-height: 36px;
|
|
135
|
+
|
|
136
|
+
> i {
|
|
137
|
+
color: var(--success);
|
|
138
|
+
font-size: 14px;
|
|
139
|
+
font-weight: bold;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
> button {
|
|
143
|
+
line-height: 30px;
|
|
144
|
+
min-height: 30px;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
</style>
|