From 427bf28730939455586a571c72d9ab185808079f Mon Sep 17 00:00:00 2001 From: Richard Date: Mon, 1 Jul 2024 11:36:35 +0100 Subject: [PATCH 1/2] Add conditional depagination by native api, apply to bindings --- shell/config/product/explorer.js | 15 ++++++-- shell/config/types.js | 2 +- shell/plugins/dashboard-store/actions.js | 5 ++- shell/store/type-map.utils.ts | 44 ++++++++++++++++++++++ shell/types/store/dashboard-store.types.ts | 24 ++++++++++++ shell/types/store/vuex.d.ts | 9 +++++ 6 files changed, 92 insertions(+), 7 deletions(-) create mode 100644 shell/store/type-map.utils.ts create mode 100644 shell/types/store/dashboard-store.types.ts create mode 100644 shell/types/store/vuex.d.ts diff --git a/shell/config/product/explorer.js b/shell/config/product/explorer.js index 750775b3407..dae58b0c139 100644 --- a/shell/config/product/explorer.js +++ b/shell/config/product/explorer.js @@ -22,6 +22,7 @@ import { } from '@shell/config/table-headers'; import { DSL } from '@shell/store/type-map'; +import { configureConditionalDepaginate } from '@shell/store/type-map.utils'; export const NAME = 'explorer'; @@ -49,7 +50,9 @@ export function init(store) { typeStoreMap: { [MANAGEMENT.PROJECT]: 'management', [MANAGEMENT.CLUSTER_ROLE_TEMPLATE_BINDING]: 'management', - [MANAGEMENT.PROJECT_ROLE_TEMPLATE_BINDING]: 'management' + [MANAGEMENT.PROJECT_ROLE_TEMPLATE_BINDING]: 'management', + [NORMAN.CLUSTER_ROLE_TEMPLATE_BINDING]: 'rancher', + [NORMAN.PROJECT_ROLE_TEMPLATE_BINDING]: 'rancher', } }); @@ -156,12 +159,16 @@ export function init(store) { mapGroup(/^(.*\.)?cluster\.x-k8s\.io$/, 'clusterProvisioning'); mapGroup(/^(aks|eks|gke|rke|rke-machine-config|rke-machine|provisioning)\.cattle\.io$/, 'clusterProvisioning'); + const dePaginateBindings = configureConditionalDepaginate({ maxResourceCount: 5000 }); + const dePaginateNormanBindings = configureConditionalDepaginate({ maxResourceCount: 5000, isNorman: true }) ; + configureType(NODE, { isCreatable: false, isEditable: true }); configureType(WORKLOAD_TYPES.JOB, { isEditable: false, match: WORKLOAD_TYPES.JOB }); - configureType(MANAGEMENT.CLUSTER_ROLE_TEMPLATE_BINDING, { isEditable: false }); - configureType(MANAGEMENT.PROJECT_ROLE_TEMPLATE_BINDING, { isEditable: false, depaginate: true }); + configureType(MANAGEMENT.CLUSTER_ROLE_TEMPLATE_BINDING, { isEditable: false, depaginate: dePaginateBindings }); + configureType(MANAGEMENT.PROJECT_ROLE_TEMPLATE_BINDING, { isEditable: false, depaginate: dePaginateBindings }); configureType(MANAGEMENT.PROJECT, { displayName: store.getters['i18n/t']('namespace.project.label') }); - configureType(NORMAN.PROJECT_ROLE_TEMPLATE_BINDING, { depaginate: true }); + configureType(NORMAN.CLUSTER_ROLE_TEMPLATE_BINDING, { depaginate: dePaginateNormanBindings }); + configureType(NORMAN.PROJECT_ROLE_TEMPLATE_BINDING, { depaginate: dePaginateNormanBindings }); configureType(EVENT, { limit: 500 }); weightType(EVENT, -1, true); diff --git a/shell/config/types.js b/shell/config/types.js index c815a8a7f3c..291f27133db 100644 --- a/shell/config/types.js +++ b/shell/config/types.js @@ -14,7 +14,7 @@ export const NORMAN = { ETCD_BACKUP: 'etcdbackup', CLUSTER: 'cluster', CLUSTER_TOKEN: 'clusterregistrationtoken', - CLUSTER_ROLE_TEMPLATE_BINDING: 'clusterRoleTemplateBinding', + CLUSTER_ROLE_TEMPLATE_BINDING: 'clusterroletemplatebinding', CLOUD_CREDENTIAL: 'cloudcredential', FLEET_WORKSPACES: 'fleetworkspace', GLOBAL_ROLE: 'globalRole', diff --git a/shell/plugins/dashboard-store/actions.js b/shell/plugins/dashboard-store/actions.js index 44a357a1681..a072cc82426 100644 --- a/shell/plugins/dashboard-store/actions.js +++ b/shell/plugins/dashboard-store/actions.js @@ -8,6 +8,7 @@ import { normalizeType } from './normalize'; import garbageCollect from '@shell/utils/gc/gc'; import { addSchemaIndexFields } from '@shell/plugins/steve/schema.utils'; import { addParam } from '@shell/utils/url'; +import { conditionalDepaginate } from '@shell/store/type-map.utils'; export const _ALL = 'all'; export const _MERGE = 'merge'; @@ -188,7 +189,7 @@ export default { opt = opt || {}; opt.url = getters.urlFor(type, null, opt); opt.stream = opt.stream !== false && load !== _NONE; - opt.depaginate = typeOptions?.depaginate; + opt.depaginate = conditionalDepaginate(typeOptions?.depaginate, { ctx, args: { type, opt } }); let skipHaveAll = false; @@ -367,7 +368,7 @@ export default { opt = opt || {}; opt.labelSelector = selector; opt.url = getters.urlFor(type, null, opt); - opt.depaginate = typeOptions?.depaginate; + opt.depaginate = conditionalDepaginate(typeOptions?.depaginate, { ctx, args: { type, opt } }); const res = await dispatch('request', { opt, type }); diff --git a/shell/store/type-map.utils.ts b/shell/store/type-map.utils.ts new file mode 100644 index 00000000000..b00e0e1ca32 --- /dev/null +++ b/shell/store/type-map.utils.ts @@ -0,0 +1,44 @@ +import { VuexStoreGetters } from '@shell/types/store/vuex'; +import { COUNT } from '@shell/config/types'; +import { ActionFindAllArgs } from '@shell/types/store/dashboard-store.types'; + +type conditionalDepaginateArgs ={ + ctx: { rootGetters: VuexStoreGetters}, + args: { type: string, opt: ActionFindAllArgs}, +}; +type conditionalDepaginateFn = (args: conditionalDepaginateArgs) => boolean + +/** + * Conditionally determine if a resource should use naive kube pagination api to fetch all results + * (not just first page) + */ +export const conditionalDepaginate = ( + depaginate?: conditionalDepaginateFn | boolean, + depaginateArgs?: conditionalDepaginateArgs +): boolean => { + if (typeof depaginate === 'function') { + return !!depaginateArgs ? depaginate(depaginateArgs) : false; + } + + return depaginate as boolean; +}; + +/** + * Setup a function that will determine if a resource should use native kube pagination api to fetch all resources + * (not just the first page) + */ +export const configureConditionalDepaginate = ( + { maxResourceCount, isNorman = false }: { maxResourceCount: number, isNorman: boolean }, +): conditionalDepaginateFn => { + return (fnArgs: conditionalDepaginateArgs ): boolean => { + const { rootGetters } = fnArgs.ctx; + const { type } = fnArgs.args; + const safeType = isNorman ? `management.cattle.io.${ type }` : type; + + const inStore = rootGetters['currentStore'](safeType); + const resourceCounts = rootGetters[`${ inStore }/all`](COUNT)[0]?.counts[safeType]; + const resourceCount = resourceCounts?.summary?.count; + + return resourceCount !== undefined ? resourceCount < maxResourceCount : false; + }; +}; diff --git a/shell/types/store/dashboard-store.types.ts b/shell/types/store/dashboard-store.types.ts new file mode 100644 index 00000000000..2a114df2878 --- /dev/null +++ b/shell/types/store/dashboard-store.types.ts @@ -0,0 +1,24 @@ +/** + * Properties on all findX actions + */ +export type ActionCoreFindArgs = { + force?: boolean, +} + +/** + * Args used for findAll action + */ +export interface ActionFindAllArgs extends ActionCoreFindArgs { + watch?: boolean, + namespaced?: string[], + incremental?: boolean, + hasManualRefresh?: boolean, + limit?: number, + /** + * Iterate over all pages and return all resources. + * + * This is done via the native kube pagination api, not steve + */ + depaginate?: boolean, +} + diff --git a/shell/types/store/vuex.d.ts b/shell/types/store/vuex.d.ts new file mode 100644 index 00000000000..aa051ca9ba9 --- /dev/null +++ b/shell/types/store/vuex.d.ts @@ -0,0 +1,9 @@ +// Unfortunately there's no current way to type the vuex store, however we have ts files that references it +// Until we bring that in, this file can contain the interfaces and types used by ts files in place of `any` + +/** + * Generic interface for Vuex getters + */ +export interface VuexStoreGetters { + [name: string]: Function; +} From 1bf35fba4ec6205fa927f0a32e5ae9df376affc3 Mon Sep 17 00:00:00 2001 From: Richard Date: Mon, 1 Jul 2024 12:41:59 +0100 Subject: [PATCH 2/2] Fix linting --- shell/types/store/dashboard-store.types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/shell/types/store/dashboard-store.types.ts b/shell/types/store/dashboard-store.types.ts index 2a114df2878..4990282ff38 100644 --- a/shell/types/store/dashboard-store.types.ts +++ b/shell/types/store/dashboard-store.types.ts @@ -21,4 +21,3 @@ export interface ActionFindAllArgs extends ActionCoreFindArgs { */ depaginate?: boolean, } -