diff --git a/cypress/e2e/tests/pages/global-settings/settings-p2.spec.ts b/cypress/e2e/tests/pages/global-settings/settings-p2.spec.ts
index dca4e8caf2a..9676fad8e60 100644
--- a/cypress/e2e/tests/pages/global-settings/settings-p2.spec.ts
+++ b/cypress/e2e/tests/pages/global-settings/settings-p2.spec.ts
@@ -9,7 +9,7 @@ import {
} from '@/cypress/e2e/blueprints/global_settings/settings-data';
// If there's more than one cluster the currentCluster used in links can be different to `local`
-const settingsClusterId = 'local';
+const settingsClusterId = '_';
const settingsPage = new SettingsPagePo(settingsClusterId);
const homePage = new HomePagePo();
const accountPage = new AccountPagePo();
diff --git a/cypress/e2e/tests/pages/global-settings/settings.spec.ts b/cypress/e2e/tests/pages/global-settings/settings.spec.ts
index a882c223ef9..9f6f899dc83 100644
--- a/cypress/e2e/tests/pages/global-settings/settings.spec.ts
+++ b/cypress/e2e/tests/pages/global-settings/settings.spec.ts
@@ -9,7 +9,7 @@ import { settings } from '@/cypress/e2e/blueprints/global_settings/settings-data
import UserMenuPo from '@/cypress/e2e/po/side-bars/user-menu.po';
// If there's more than one cluster the currentCluster used in links can be different to `local`
-const settingsClusterId = 'local';
+const settingsClusterId = '_';
const settingsPage = new SettingsPagePo(settingsClusterId);
const accountPage = new AccountPagePo();
const createKeyPage = new CreateKeyPagePo();
diff --git a/cypress/e2e/tests/pages/users-and-auth/azuread.spec.ts b/cypress/e2e/tests/pages/users-and-auth/azuread.spec.ts
index 9b457ec009c..b473ac77a4f 100644
--- a/cypress/e2e/tests/pages/users-and-auth/azuread.spec.ts
+++ b/cypress/e2e/tests/pages/users-and-auth/azuread.spec.ts
@@ -2,8 +2,9 @@ import HomePagePo from '@/cypress/e2e/po/pages/home.po';
import AzureadPo from '@/cypress/e2e/po/edit/auth/azuread.po';
import { AuthProvider, AuthProviderPo } from '@/cypress/e2e/po/pages/users-and-auth/authProvider.po';
-const authProviderPo = new AuthProviderPo('local');
-const azureadPo = new AzureadPo('local');
+const authClusterId = '_';
+const authProviderPo = new AuthProviderPo(authClusterId);
+const azureadPo = new AzureadPo(authClusterId);
const tenantId = '564b6f53-ebf4-43c3-8077-44c56a44990a';
const applicationId = '18cca356-170e-4bd9-a4a4-2e349855f96b';
diff --git a/cypress/e2e/tests/pages/users-and-auth/cognito.spec.ts b/cypress/e2e/tests/pages/users-and-auth/cognito.spec.ts
index e61d83d37ea..fbc858b2ab5 100644
--- a/cypress/e2e/tests/pages/users-and-auth/cognito.spec.ts
+++ b/cypress/e2e/tests/pages/users-and-auth/cognito.spec.ts
@@ -2,8 +2,9 @@ import HomePagePo from '@/cypress/e2e/po/pages/home.po';
import AmazonCognitoPo from '@/cypress/e2e/po/edit/auth/cognito.po';
import { AuthProvider, AuthProviderPo } from '@/cypress/e2e/po/pages/users-and-auth/authProvider.po';
-const authProviderPo = new AuthProviderPo('local');
-const cognitoPo = new AmazonCognitoPo('local');
+const authClusterId = '_';
+const authProviderPo = new AuthProviderPo(authClusterId);
+const cognitoPo = new AmazonCognitoPo(authClusterId);
const clientId = 'test-client-id';
const clientSecret = 'test-client-secret';
diff --git a/cypress/e2e/tests/pages/users-and-auth/githubapp.spec.ts b/cypress/e2e/tests/pages/users-and-auth/githubapp.spec.ts
index f48f930a79a..06160d97f1d 100644
--- a/cypress/e2e/tests/pages/users-and-auth/githubapp.spec.ts
+++ b/cypress/e2e/tests/pages/users-and-auth/githubapp.spec.ts
@@ -2,8 +2,9 @@ import HomePagePo from '@/cypress/e2e/po/pages/home.po';
import GithubAppPo from '@/cypress/e2e/po/edit/auth/githubapp.po';
import { AuthProvider, AuthProviderPo } from '@/cypress/e2e/po/pages/users-and-auth/authProvider.po';
-const authProviderPo = new AuthProviderPo('local');
-const githubAppPo = new GithubAppPo('local');
+const authClusterId = '_';
+const authProviderPo = new AuthProviderPo(authClusterId);
+const githubAppPo = new GithubAppPo(authClusterId);
const clientId = 'test-client-id';
const clientSecret = 'test-client-secret';
diff --git a/cypress/e2e/tests/priority/no-vai-setup.spec.ts b/cypress/e2e/tests/priority/no-vai-setup.spec.ts
index d3c8284f7e9..8d5991c7245 100644
--- a/cypress/e2e/tests/priority/no-vai-setup.spec.ts
+++ b/cypress/e2e/tests/priority/no-vai-setup.spec.ts
@@ -4,7 +4,7 @@ import { FeatureFlagsPagePo } from '@/cypress/e2e/po/pages/global-settings/featu
// Vai ('ui-sql-cache') is now on by default. This sets up the `noVai` test suite by disabling it
-const featureFlagsPage = new FeatureFlagsPagePo('local');
+const featureFlagsPage = new FeatureFlagsPagePo('_');
describe('Disable Vai', { testIsolation: 'off', tags: ['@noVai', '@adminUser'] }, () => {
before(() => {
diff --git a/shell/assets/styles/base/_typography.scss b/shell/assets/styles/base/_typography.scss
index 58e02326f31..2cd5b4c3f63 100644
--- a/shell/assets/styles/base/_typography.scss
+++ b/shell/assets/styles/base/_typography.scss
@@ -15,7 +15,7 @@ H1 {
}
H2 {
- font-size: 21px;
+ font-size: $font-size-h2;
}
H3 {
diff --git a/shell/assets/translations/en-us.yaml b/shell/assets/translations/en-us.yaml
index 9ac6d8366f9..a533953d276 100644
--- a/shell/assets/translations/en-us.yaml
+++ b/shell/assets/translations/en-us.yaml
@@ -3824,6 +3824,11 @@ landing:
homepage: Homepage
clusters:
title: Clusters
+ tooMany:
+ showAll: Show all clusters (may increase load time)
+ showSome: Show some clusters (may improve load time)
+ showingAll: Showing {total} clusters.
+ showingSome: Showing {rows} of {total} recently created clusters.
provider: Provider
distro: Distro
kubernetesVersion: Kubernetes Version
diff --git a/shell/components/SortableTable/index.vue b/shell/components/SortableTable/index.vue
index 916d896bb7f..5c262fddfc7 100644
--- a/shell/components/SortableTable/index.vue
+++ b/shell/components/SortableTable/index.vue
@@ -1090,7 +1090,7 @@ export default {
+
({ rootGetters: this.$store.getters }, 'homePageCluster'),
+
+ presetVersion: getVersionData()?.Version,
};
},
+ mounted() {
+ this.preset('altClusterListDisabled', 'boolean');
+ },
+
computed: {
...mapState(['managementReady']),
...mapGetters(['currentCluster', 'defaultClusterId']),
mcm: mapFeature(MULTI_CLUSTER),
+ vaiOnSettingsHeaders() {
+ return [
+ ...this.headers, // include age as we're sorting by it
+ AGE
+ ];
+ },
+
canCreateCluster() {
return !!this.provClusterSchema?.collectionMethods.find((x: string) => x.toLowerCase() === 'post');
},
@@ -216,6 +247,21 @@ export default defineComponent({
afterLoginRoute: mapPref(AFTER_LOGIN_ROUTE),
homePageCards: mapPref(HIDE_HOME_PAGE_CARDS),
+ /**
+ * Show the alt table
+ */
+ altClusterList() {
+ return this.tooManyClusters && !this.altClusterListDisabled;
+ }
+
+ },
+
+ watch: {
+ async altClusterList(neu) {
+ if (neu) {
+ await this.initAltClusters();
+ }
+ },
},
async created() {
@@ -227,6 +273,12 @@ export default defineComponent({
// If we do not, then if they set the landing page, that won't work unless the release notes are marked read
// otherwise we always take them to the home page to see the release notes
markSeenReleaseNotes(this.$store);
+
+ this.tooManyClusters = this.isTooManyClusters();
+
+ if (this.altClusterList) {
+ await this.initAltClusters();
+ }
},
// Forget the types when we leave the page
@@ -458,7 +510,83 @@ export default defineComponent({
}
return pagination;
- }
+ },
+
+ async toggleAltClusterListDisabled(disabled: boolean) {
+ // Clear the cache so the table doesn't show the previous mode's results
+ await this.$store.dispatch('management/forgetType', CAPI.RANCHER_CLUSTER);
+
+ this.altClusterListDisabled = disabled;
+ },
+
+ /**
+ * Determine if we should use an alternative cluster list which contains most recently created clusters
+ *
+ * Checks
+ * - can view clusters
+ * - if vai is on
+ * - if alt list feature is on
+ * - if cluster count exceeds threshold
+ */
+ isTooManyClusters(): boolean {
+ if (!this.provClusterSchema || !this.canViewMgmtClusters) {
+ return false;
+ }
+
+ const featureConfig = this.altClusterListFeature;
+
+ if (!featureConfig || !featureConfig.enabled) { // vai is off, or feature is explicitly disabled
+ return false;
+ }
+
+ const threshold = featureConfig.configuration?.threshold;
+
+ if (threshold === undefined) { // invalid config
+ return false;
+ }
+
+ const counts = this.$store.getters[`management/all`](COUNT)?.[0]?.counts || {};
+
+ this.clusterCount = counts[CAPI.RANCHER_CLUSTER]?.summary.count;
+
+ return this.clusterCount > threshold;
+ },
+
+ /**
+ * Fetch clusters used to populate alt table
+ */
+ async initAltClusters() {
+ const featureConfig = this.altClusterListFeature;
+ const results = featureConfig?.configuration?.results || 50;
+
+ // Fetch a limited number of provisioning clusters
+ const opt1: ActionFindPageArgs = {
+ pagination: {
+ projectsOrNamespaces: [],
+ filters: paginationFilterClusters(this.$store, false),
+ page: 1,
+ pageSize: results, // We're fetching the total results... then paging locally
+ sort: [{ field: 'metadata.creationTimestamp', asc: false }]
+ },
+ watch: false,
+ };
+ const provClusters = await this.$store.dispatch('management/findPage', { type: CAPI.RANCHER_CLUSTER, opt: opt1 });
+
+ // Also fetch the management clusters associated with the provisioning clusters
+ const opt2: ActionFindPageArgs = {
+ pagination: new FilterArgs({
+ filters: PaginationParamFilter.createMultipleFields(provClusters.map((r: any) => new PaginationFilterField({
+ field: 'id',
+ value: r.mgmtClusterId
+ }))),
+ }),
+ watch: false,
+ };
+
+ await this.$store.dispatch(`management/findPage`, { type: MANAGEMENT.CLUSTER, opt: opt2 });
+
+ this.altClusterListRows = provClusters;
+ },
}
});
@@ -485,9 +613,164 @@ export default defineComponent({
-
+
+
+
+
+
+
+ {{ t('landing.clusters.title') }}
+
+
+
+
+
+ {{ t('landing.clusters.tooMany.showingSome', { rows: altClusterListRows?.length || '...', total: clusterCount}) }}
+ {{ t('landing.clusters.tooMany.showAll') }}
+
+
+
+
+
+
+ {{ t('cluster.manageAction') }}
+
+
+ {{ t('cluster.importAction') }}
+
+
+ {{ t('generic.create') }}
+
+
+
+
+
+
+
+
+ {{ row.nameDisplay }}
+
+ {{ row.nameDisplay }}
+
+
+
+
+ {{ row.description }}
+
+
+ |
+
+
+
+
+ {{ row.kubernetesVersion }}
+
+
+ {{ row.architecture.label }}
+
+ |
+
+
+
+ {{ `${cpuAllocatable(row.mgmt)} ${t('landing.clusters.cores', {count:cpuAllocatable(row.mgmt) })}` }}
+ |
+
+ —
+ |
+
+
+
+ {{ memoryAllocatable(row.mgmt) }}
+ |
+
+ —
+ |
+
+
+
+
-
+
{{ t('landing.clusters.title') }}
-
+
+
+
+ {{ t('landing.clusters.tooMany.showingAll', { rows: altClusterListRows?.length || '...', total: clusterCount}) }}
+ {{ t('landing.clusters.tooMany.showSome') }}
+
+
INPUT {
background-color: transparent;
diff --git a/shell/plugins/steve/steve-pagination-utils.ts b/shell/plugins/steve/steve-pagination-utils.ts
index 3517cca4962..086ad35b1f3 100644
--- a/shell/plugins/steve/steve-pagination-utils.ts
+++ b/shell/plugins/steve/steve-pagination-utils.ts
@@ -676,8 +676,8 @@ export const PAGINATION_SETTINGS_STORE_DEFAULTS: PaginationSettingsStores = {
enableAll: false,
enableSome: {
enabled: [
- // { resource: CAPI.RANCHER_CLUSTER, context: ['home', 'side-bar'] },
- // { resource: MANAGEMENT.CLUSTER, context: ['side-bar'] },
+ { resource: CAPI.RANCHER_CLUSTER, context: ['side-bar'] },
+ { resource: MANAGEMENT.CLUSTER, context: ['side-bar'] },
{ resource: CATALOG.APP, context: ['branding'] },
SECRET
],
diff --git a/shell/types/resources/settings.d.ts b/shell/types/resources/settings.d.ts
index a2aee6ea38f..ee2be6c738a 100644
--- a/shell/types/resources/settings.d.ts
+++ b/shell/types/resources/settings.d.ts
@@ -20,14 +20,39 @@ export interface PaginationSettingsStore {
}
}
-/**
+/*
* Determine which resources can utilise server-side pagination
*/
export interface PaginationSettingsStores {
[store: string]: PaginationSettingsStore
}
-export type PaginationFeature = 'listAutoRefreshToggle' | 'listManualRefresh'
+/**
+ * Names of pagination features used in pagination settings (not featureflags)
+ */
+export type PaginationFeatureName = 'listAutoRefreshToggle' | 'listManualRefresh' | 'homePageCluster'
+
+export type PaginationFeatureHomePageClusterConfig = {
+ threshold: number,
+ results: number,
+ pagesPerRow: number
+}
+
+/**
+ * Details of a specific pagination feature
+ */
+export type PaginationFeature = {
+ version: number,
+ enabled: boolean,
+ configuration?: Config,
+}
+
+/**
+ * List of specific features that can be enabled / disabled
+ */
+export type PaginationSettingsFeatures = {
+ [key in PaginationFeatureName]?: PaginationFeature
+}
/**
* Settings to handle server side pagination
@@ -45,11 +70,7 @@ export interface PaginationSettings {
/**
* List of specific features that can be enabled / disabled
*/
- features?: {
- [key in PaginationFeature]: {
- enabled: boolean,
- }
- },
+ features?: PaginationSettingsFeatures,
/**
* Debounce the amount of time between a resource changing and the backend sending a resource.changes message
@@ -82,6 +103,7 @@ type ManagedFields = {
time: string;
};
+// Note - this should now be @RancherKubeMetadata
type Metadata = {
creationTimestamp: string;
fields: string[];
diff --git a/shell/utils/pagination-utils.ts b/shell/utils/pagination-utils.ts
index 962ae91c8b0..03f684e9698 100644
--- a/shell/utils/pagination-utils.ts
+++ b/shell/utils/pagination-utils.ts
@@ -1,4 +1,6 @@
-import { PaginationFeature, PaginationSettings, PaginationSettingsStore, PaginationSettingsStores } from '@shell/types/resources/settings';
+import {
+ PaginationFeature, PaginationFeatureHomePageClusterConfig, PaginationFeatureName, PaginationSettings, PaginationSettingsFeatures, PaginationSettingsStore, PaginationSettingsStores
+} from '@shell/types/resources/settings';
import {
NAMESPACE_FILTER_ALL_USER as ALL_USER,
NAMESPACE_FILTER_ALL as ALL,
@@ -22,6 +24,15 @@ import { EXT_IDS } from '@shell/core/plugin';
import { ExtensionManager } from '@shell/types/extension-manager';
import { DEFAULT_PERF_SETTING } from '@shell/config/settings';
+const homePageClusterFeature: PaginationFeature = {
+ version: 1,
+ enabled: true,
+ configuration: {
+ threshold: 500, results: 250, pagesPerRow: 25
+ }
+};
+const PAGINATION_SETTINGS_FEATURE_DEFAULTS: PaginationSettingsFeatures = { homePageCluster: homePageClusterFeature };
+
/**
* Helper functions for server side pagination
*/
@@ -222,15 +233,19 @@ class PaginationUtils {
return this.isFeatureEnabled({ rootGetters }, 'listManualRefresh');
}
- private isFeatureEnabled({ rootGetters }: any, featureName: PaginationFeature): boolean {
+ getFeature({ rootGetters }: any, featureName: PaginationFeatureName): PaginationFeature | undefined {
// Cache must be enabled to support pagination api
if (!this.isSteveCacheEnabled({ rootGetters })) {
- return false;
+ return undefined;
}
const settings = this.getSettings({ rootGetters });
- return !!settings.features?.[featureName]?.enabled;
+ return settings.features?.[featureName] || PAGINATION_SETTINGS_FEATURE_DEFAULTS[featureName];
+ }
+
+ private isFeatureEnabled({ rootGetters }: any, featureName: PaginationFeatureName): boolean {
+ return !!this.getFeature({ rootGetters }, featureName)?.enabled;
}
resourceChangesDebounceMs({ rootGetters }: any): number | undefined {