From df2a4db2160b75c418b339bf904aa17d4fc60ccd Mon Sep 17 00:00:00 2001 From: Richard Cox Date: Mon, 3 Feb 2025 14:02:29 +0000 Subject: [PATCH] sdfdsf --- shell/components/form/ResourceSelector.vue | 10 +- shell/detail/workload/index.vue | 1 - .../PolicyRuleTarget.vue | 16 +-- .../networking.k8s.io.networkpolicy/index.vue | 12 +- shell/edit/service.vue | 2 +- shell/models/service.js | 45 ++++---- shell/models/workload.js | 2 +- shell/pages/c/_cluster/longhorn/index.vue | 10 +- .../CatalogList/CatalogUninstallDialog.vue | 45 ++++++-- shell/plugins/dashboard-store/actions.js | 39 +++++++ .../plugins/dashboard-store/resource-class.js | 17 ++- shell/plugins/steve/steve-class.js | 4 + shell/plugins/steve/steve-pagination-utils.ts | 105 +++++++++--------- shell/types/kube/kube-api.ts | 4 +- shell/types/store/pagination.types.ts | 10 +- shell/utils/selector-typed.ts | 63 +++++++++++ 16 files changed, 270 insertions(+), 115 deletions(-) create mode 100644 shell/utils/selector-typed.ts diff --git a/shell/components/form/ResourceSelector.vue b/shell/components/form/ResourceSelector.vue index 7b00275e16e..6a86545378b 100644 --- a/shell/components/form/ResourceSelector.vue +++ b/shell/components/form/ResourceSelector.vue @@ -2,12 +2,11 @@ import { Banner } from '@components/Banner'; import MatchExpressions from '@shell/components/form/MatchExpressions'; import ResourceTable from '@shell/components/ResourceTable'; -import { allHash } from '@shell/utils/promise'; import { _EDIT } from '@shell/config/query-params'; -import { convert, findMatchingResources, matching, simplify } from '@shell/utils/selector'; +import { convert, simplify } from '@shell/utils/selector'; import throttle from 'lodash/throttle'; -import { FilterArgs } from '@shell/types/store/pagination.types'; import { COUNT } from '@shell/config/types'; +import { findMatchingResources } from '@shell/utils/selector-typed'; export default { name: 'ResourceSelector', @@ -38,11 +37,6 @@ export default { }, async fetch() { - // Used in conjunction with `matches/match/label selectors`. Requires https://github.com/rancher/dashboard/issues/10417 to fix - // const hash = await allHash({ allResources: this.$store.dispatch('cluster/findAll', { type: this.type }) }); - - // this.allResources = hash.allResources; - this.updateMatchingResources(); }, diff --git a/shell/detail/workload/index.vue b/shell/detail/workload/index.vue index e5b05bb47ee..9ed5c465ca7 100644 --- a/shell/detail/workload/index.vue +++ b/shell/detail/workload/index.vue @@ -58,7 +58,6 @@ export default { allNodes: hasNodes ? this.$store.dispatch('cluster/findAll', { type: NODE }) : [] }; - debugger; if (this.podSchema) { hash.matchingPods = this.value.fetchPods(); } diff --git a/shell/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue b/shell/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue index 0e8da4217f0..a898c677a51 100644 --- a/shell/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +++ b/shell/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue @@ -10,6 +10,7 @@ import ArrayList from '@shell/components/form/ArrayList'; import { Banner } from '@components/Banner'; import throttle from 'lodash/throttle'; import { isValidCIDR } from '@shell/utils/validators/cidr'; +import { findMatchingResources } from '@shell/utils/selector-typed'; const TARGET_OPTIONS = { IP_BLOCK: 'ipBlock', @@ -198,14 +199,14 @@ export default { } }, async getMatchingPods() { - //TODO: RC TEST + // TODO: RC TEST return await findMatchingResources({ labelSelector: { matchExpressions: this.podSelectorExpressions }, type: POD, $store: this.$store, - inStore: 'cluster', - namespace: this.targetType === TARGET_OPTIONS.NAMESPACE_AND_POD_SELECTOR ? this.matchingNamespaces.matches.map(ns => ns.id) : this.namespace, // TODO: RC multiple? - transient: true, + inStore: 'cluster', + namespace: this.targetType === TARGET_OPTIONS.NAMESPACE_AND_POD_SELECTOR ? this.matchingNamespaces.matches.map((ns) => ns.id) : this.namespace, // TODO: RC multiple? + transient: true, }); // const namespaces = this.targetType === TARGET_OPTIONS.NAMESPACE_AND_POD_SELECTOR ? this.matchingNamespaces.matches : [{ id: this.namespace }]; @@ -223,16 +224,15 @@ export default { // }; }, async getMatchingNamespaces() { - //TODO: RC TEST + // TODO: RC TEST return await findMatchingResources({ labelSelector: { matchExpressions: this.namespaceSelectorExpressions }, type: NAMESPACE, $store: this.$store, - inStore: 'cluster', - transient: true, + inStore: 'cluster', + transient: true, }); - // const allNamespaces = this.allNamespaces; // const match = matching(allNamespaces, this.namespaceSelectorExpressions); // const matched = match.length || 0; diff --git a/shell/edit/networking.k8s.io.networkpolicy/index.vue b/shell/edit/networking.k8s.io.networkpolicy/index.vue index 8fa958d2145..f8d337530d2 100644 --- a/shell/edit/networking.k8s.io.networkpolicy/index.vue +++ b/shell/edit/networking.k8s.io.networkpolicy/index.vue @@ -8,7 +8,9 @@ import CruResource from '@shell/components/CruResource'; import { Banner } from '@components/Banner'; import Labels from '@shell/components/form/Labels'; import { NAMESPACE, POD } from '@shell/config/types'; -import { convert, findMatchingResources, matching, simplify } from '@shell/utils/selector'; +import { convert, simplify } from '@shell/utils/selector'; +import { findMatchingResources } from '@shell/utils/selector-typed'; + import { Checkbox } from '@components/Form/Checkbox'; import { addObject, removeObject } from '@shell/utils/array'; import MatchExpressions from '@shell/components/form/MatchExpressions'; @@ -150,12 +152,12 @@ export default { methods: { updateMatchingPods: throttle(async function() { - //TODO: RC TEST + // TODO: RC TEST this.matchingPods = await findMatchingResources({ labelSelector: { matchExpressions: this.selectorExpressions }, type: POD, $store: this.$store, - inStore: 'cluster', + inStore: 'cluster', namespace: this.value.metadata.namespace, }); // const allInNamespace = this.allPods.filter((pod) => pod.metadata.namespace === this.value.metadata.namespace); @@ -221,7 +223,7 @@ export default { :value="value" type="ingress" :mode="mode" - + @update:value="$emit('input', $event)" /> @@ -248,7 +250,7 @@ export default { :value="value" type="egress" :mode="mode" - + @update:value="$emit('input', $event)" /> diff --git a/shell/edit/service.vue b/shell/edit/service.vue index 43fa18115d9..38b5ebfa87c 100644 --- a/shell/edit/service.vue +++ b/shell/edit/service.vue @@ -23,7 +23,7 @@ import { clone } from '@shell/utils/object'; import { POD, CAPI, HCI, COUNT, NAMESPACE, SERVICE } from '@shell/config/types'; -import { findMatchingResources, matching } from '@shell/utils/selector'; +import { findMatchingResources } from '@shell/utils/selector-typed'; import { HARVESTER_NAME as HARVESTER } from '@shell/config/features'; import { allHash } from '@shell/utils/promise'; import { isHarvesterSatisfiesVersion } from '@shell/utils/cluster'; diff --git a/shell/models/service.js b/shell/models/service.js index 1e9c585b8b8..2f3e845b603 100644 --- a/shell/models/service.js +++ b/shell/models/service.js @@ -153,37 +153,42 @@ export default class Service extends SteveModel { // } if (isEmpty(selector)) { - return; + return undefined; } return { matchLabels: selector // TODO: RC confirm this is alll is ever is??? can it be string | exp[] | ?? }; } - async fetchPods(podSelector = this.podSelector) { - if (podSelector) { - const findPageArgs = { // Of type ActionFindPageArgs - namespaced: this.metadata.namespace, - pagination: new FilterArgs({ labelSelector: podSelector }), - }; + // TODO: RC confirm with pagination off.... no findPage usage + // TODO: RC ARG??? podSelector vs this.podRelationship.selector - return this.$dispatch('findPage', { type: POD, opt: findPageArgs }); - } + async fetchPods() { + // TODO: RC TEST + // if (!podSelector) { + // return; + // } - return Promise.resolve(undefined); + return await this.$dispatch('findMatchingOrPage', { + type: POD, + matching: { + namespace: this.metadata.namespace, + labelSelector: { matchLabels: this.podRelationship.selector } // TODO: RC is this string or map + } + // findPageOpts: { // Of type ActionFindPageArgs + // namespaced: this.metadata.namespace, + // pagination: new FilterArgs({ labelSelector: { matchLabels: this.podRelationship.selector} }), + // }, + // findMatchingOpts: { + // type: POD, + // selector: this.podRelationship.selector, + // namespace: this.namespace + // } + }); } - // async fetchPods() { - // if (this.podSelector) { - // await this.$dispatch('cluster/findMatching', { // TODO: RC LEGACY? No-op - // type: POD, - // selector: this.podRelationship.selector, - // namespace: this.namespace - // }, { root: true }); - // } - // } - get pods() { + // TODO: RC What uses this?? console.warn('Anything using this must be updated to ????!!!'); return []; diff --git a/shell/models/workload.js b/shell/models/workload.js index c33324bb4d6..e079c617a88 100644 --- a/shell/models/workload.js +++ b/shell/models/workload.js @@ -3,7 +3,7 @@ import { TIMESTAMP, CATTLE_PUBLIC_ENDPOINTS } from '@shell/config/labels-annotat import { WORKLOAD_TYPES, SERVICE, POD } from '@shell/config/types'; import { get, set } from '@shell/utils/object'; import day from 'dayjs'; -import { convertSelectorObj, findMatchingResources, matching, parse } from '@shell/utils/selector'; +import { convertSelectorObj, findMatchingResources, parse } from '@shell/utils/selector'; import { SEPARATOR } from '@shell/config/workload'; import WorkloadService from '@shell/models/workload.service'; import { FilterArgs } from '@shell/types/store/pagination.types'; diff --git a/shell/pages/c/_cluster/longhorn/index.vue b/shell/pages/c/_cluster/longhorn/index.vue index 988d33cd509..e3abd47a26b 100644 --- a/shell/pages/c/_cluster/longhorn/index.vue +++ b/shell/pages/c/_cluster/longhorn/index.vue @@ -12,9 +12,15 @@ export default { async fetch() { if ( this.$store.getters['cluster/schemaFor'](SERVICE) ) { - this.uiServices = await this.$store.dispatch('cluster/findMatching', { // TODO: RC LEGACY? No-op + // TODO: RC TEST + this.uiServices = await this.$store.dispatch('cluster/findMatchingOrPage', { type: SERVICE, - selector: 'app=longhorn-ui' + matching: { labelSelector: { matchLabels: { app: 'longhorn-ui' } } } + + // type: SERVICE, + // context: this.$store, + // findPageOpts: { pagination: new FilterArgs({ labelSelector: { matchLabels: { app: 'longhorn-ui' } } }) }, + // findMatchingOpts: { type: SERVICE, selector: 'app=longhorn-ui' } }); } }, diff --git a/shell/pages/c/_cluster/uiplugins/CatalogList/CatalogUninstallDialog.vue b/shell/pages/c/_cluster/uiplugins/CatalogList/CatalogUninstallDialog.vue index 362a69cbcda..8be25ecf0eb 100644 --- a/shell/pages/c/_cluster/uiplugins/CatalogList/CatalogUninstallDialog.vue +++ b/shell/pages/c/_cluster/uiplugins/CatalogList/CatalogUninstallDialog.vue @@ -7,6 +7,7 @@ import { allHash } from '@shell/utils/promise'; import AsyncButton from '@shell/components/AsyncButton'; import AppModal from '@shell/components/AppModal.vue'; +import { FilterArgs } from '@shell/types/store/pagination.types'; export default { emits: ['closed', 'refresh', 'update'], @@ -90,18 +91,48 @@ export default { }, async removeCatalogResources(catalog) { - const selector = `${ UI_PLUGIN_LABELS.CATALOG_IMAGE }=${ catalog.name }`; + // const selector = `${ UI_PLUGIN_LABELS.CATALOG_IMAGE }=${ catalog.name }`; + const pageSelector = { [UI_PLUGIN_LABELS.CATALOG_IMAGE]: catalog.name }; const namespace = UI_PLUGIN_NAMESPACE; - if ( selector ) { + // const findPageOpts = { + // namespaced: namespace, + // pagination: new FilterArgs({ labelSelector: { matchLabels: pageSelector } }), + // }; + + if ( catalog.name ) { const hash = await allHash({ - deployment: this.$store.dispatch('management/findMatching', { // TODO: RC LEGACY? No-op - type: WORKLOAD_TYPES.DEPLOYMENT, selector, namespace + deployment: this.$store.dispatch('management/findMatchingOrPage', { + type: WORKLOAD_TYPES.DEPLOYMENT, + matching: { namespace, labelSelector: { matchLabels: pageSelector } } + // type: WORKLOAD_TYPES.DEPLOYMENT, // context: this.$store, + // findPageOpts, + // findMatchingOpts: { + // type: WORKLOAD_TYPES.DEPLOYMENT, selector, namespace + // } }), - service: this.$store.dispatch('management/findMatching', { // TODO: RC LEGACY? No-op - type: SERVICE, selector, namespace + service: this.$store.dispatch('management/findMatchingOrPage', { + type: SERVICE, + matching: { namespace, labelSelector: { matchLabels: pageSelector } } + // type: SERVICE, + // context: this.$store, + // findPageOpts, + // findMatchingOpts: { // TODO: RC LEGACY? No-op + // type: SERVICE, selector, namespace + // } }), - repo: this.$store.dispatch('management/findMatching', { type: CATALOG.CLUSTER_REPO, selector }) // TODO: RC LEGACY? No-op + repo: this.$store.dispatch('management/findMatchingOrPage', { + type: CATALOG.CLUSTER_REPO, + matching: { labelSelector: { matchLabels: pageSelector } } + + // type: CATALOG.CLUSTER_REPO, + // context: this.$store, + // findPageOpts: { + // ...findPageOpts, + // namespace: undefined, + // }, + // findMatchingOpts: { type: CATALOG.CLUSTER_REPO, selector } + }) }); for ( const resource of Object.keys(hash) ) { diff --git a/shell/plugins/dashboard-store/actions.js b/shell/plugins/dashboard-store/actions.js index f174d092e7a..123b3c94eb4 100644 --- a/shell/plugins/dashboard-store/actions.js +++ b/shell/plugins/dashboard-store/actions.js @@ -9,6 +9,7 @@ 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'; +import { FilterArgs } from '@shell/types/store/pagination.types'; export const _ALL = 'all'; export const _MERGE = 'merge'; @@ -446,6 +447,44 @@ export default { } : findAllGetter(getters, type, opt); }, + /** + * + * labelSelector is of type KubeLabelSelector + */ + async findMatchingOrPage(ctx, { + type, + matching: { + namespace, + labelSelector + }, + opts + }) { + const { getters, dispatch } = ctx; + + const args = { + id: type, + context, + }; + + if (getters[`paginationEnabled`]?.(args)) { + return dispatch('findPage', { + type, + opts: { + ...(opts || {}), + namespaced: namespace, + pagination: new FilterArgs({ labelSelector }), + } + }); + } + + return dispatch('findMatching', { + type, + selector: labelSelector.matchLabels, + opts, + namespace, + }); + }, + async findMatching(ctx, { type, selector, diff --git a/shell/plugins/dashboard-store/resource-class.js b/shell/plugins/dashboard-store/resource-class.js index 63a8349779c..010d580cd8f 100644 --- a/shell/plugins/dashboard-store/resource-class.js +++ b/shell/plugins/dashboard-store/resource-class.js @@ -1838,9 +1838,22 @@ export default class Resource { const out = []; for ( const sel of selectors ) { - const matching = await this.$dispatch('findMatching', sel); // TODO: RC LEGACY? No-op + const { + type, + selector, + namespace, + opt, + } = sel; + const matching = await this.$dispatch('findMatchingOrPage', { + type, + matching: { + namespace, + labelSelector: { matchLabels: selector } // TODO: RC selector is string or map + }, + opts: opt + }); - addObjects(out, matching.data); + addObjects(out, matching.data); // TODO: RC not data...?? } for ( const obj of ids ) { diff --git a/shell/plugins/steve/steve-class.js b/shell/plugins/steve/steve-class.js index 882407f0fce..58b23497cf2 100644 --- a/shell/plugins/steve/steve-class.js +++ b/shell/plugins/steve/steve-class.js @@ -58,4 +58,8 @@ export default class SteveModel extends HybridModel { return val; } + + paginationEnabled() { + return this.$getters['paginationEnabled'](this.type); + } } diff --git a/shell/plugins/steve/steve-pagination-utils.ts b/shell/plugins/steve/steve-pagination-utils.ts index ef3808cb119..b66f2d1f163 100644 --- a/shell/plugins/steve/steve-pagination-utils.ts +++ b/shell/plugins/steve/steve-pagination-utils.ts @@ -474,91 +474,90 @@ class StevePaginationUtils extends NamespaceProjectFilters { private convertLabelSelectorPaginationParams(schema: Schema, labelSelector: KubeLabelSelector): string { // Get a list of matchExpressions - const expressions: KubeLabelSelectorExpression[] = labelSelector.matchExpressions ? [...labelSelector.matchExpressions] : [] + const expressions: KubeLabelSelectorExpression[] = labelSelector.matchExpressions ? [...labelSelector.matchExpressions] : []; // matchLabels are just shortcuts on matchExpressions, for ease convert them if (labelSelector.matchLabels) { Object.entries(labelSelector.matchLabels).forEach(([key, value]) => { const expression: KubeLabelSelectorExpression = { key, - values: [value], + values: [value], operator: 'In' - } + }; expressions.push(expression); - }) + }); } // TODO: RC gt | lt only applicable to NodeSelector. can check on node schema?? // concert all matchExpressions into string params const filters: string[] = expressions.reduce((res, exp) => { - const labelKey = `metadata.labels[${exp.key}]`; + const labelKey = `metadata.labels[${ exp.key }]`; // TODO: RC console for all below - switch(exp.operator) { - case 'In': - if (!exp.values?.length) { - // The operator 'IN' must have `values` specified - return res; - } + switch (exp.operator) { + case 'In': + if (!exp.values?.length) { + // The operator 'IN' must have `values` specified + return res; + } - res.push(`filter=${labelKey} IN (${exp.values.join(',')})`); - break; - case 'NotIn': - if (!exp.values?.length) { - // The operator 'NotIn' must have `values` specified - return res; - } + res.push(`filter=${ labelKey } IN (${ exp.values.join(',') })`); + break; + case 'NotIn': + if (!exp.values?.length) { + // The operator 'NotIn' must have `values` specified + return res; + } - res.push(`filter=${labelKey} NOTIN (${exp.values.join(',')})`); - break; - case 'Exists': - if (exp.values?.length) { - // The operator 'Exist' must not have `values` specified - return res; - } + res.push(`filter=${ labelKey } NOTIN (${ exp.values.join(',') })`); + break; + case 'Exists': + if (exp.values?.length) { + // The operator 'Exist' must not have `values` specified + return res; + } - res.push(`filter=${labelKey}`); - break; - case 'DoesNotExist': - if (exp.values?.length) { - // The operator 'DoesNotExist' must not have `values` specified - return res; - } + res.push(`filter=${ labelKey }`); + break; + case 'DoesNotExist': + if (exp.values?.length) { + // The operator 'DoesNotExist' must not have `values` specified + return res; + } - res.push(`filter=!${labelKey}`); - break; - case 'Gt': // TODO: RC test - if (typeof exp.values !== 'string') { - // The operator 'Gt' must not have `values` that is a string - return res; - } - res.push(`filter=${labelKey} > (${exp.values})`); - break; - case 'Lt': // TODO: RC test - if (typeof exp.values !== 'string') { - // The operator 'Lt' must not have `values` that is a string - return res; - } - res.push(`filter=${labelKey} < (${exp.values})`); - break; + res.push(`filter=!${ labelKey }`); + break; + case 'Gt': // TODO: RC test + if (typeof exp.values !== 'string') { + // The operator 'Gt' must not have `values` that is a string + return res; + } + res.push(`filter=${ labelKey } > (${ exp.values })`); + break; + case 'Lt': // TODO: RC test + if (typeof exp.values !== 'string') { + // The operator 'Lt' must not have `values` that is a string + return res; + } + res.push(`filter=${ labelKey } < (${ exp.values })`); + break; } - return res + return res; }, [] as string[]); - return filters.join(',') + return filters.join(','); // foo IN [bar] => ?filter=foo+IN+(bar) - // foo IN [bar, baz2] => ?filter=foo+IN+(bar,baz2) - // aaa NotIn [bar, baz2]=> ?filter=foo+NOTIN+(bar,baz2) + // foo IN [bar, baz2] => ?filter=foo+IN+(bar,baz2) + // aaa NotIn [bar, baz2]=> ?filter=foo+NOTIN+(bar,baz2) // bbb Exists=> ?filter=bbb // ccc DoesNotExist ?filter=!bbb. # or %21bbb // ddd Gt 1=> ?filter=ddd+<+1 // eee Lt 2=> ?filter=eee+>+2 - } } diff --git a/shell/types/kube/kube-api.ts b/shell/types/kube/kube-api.ts index 09da7a2cb6b..8d8383e2e6e 100644 --- a/shell/types/kube/kube-api.ts +++ b/shell/types/kube/kube-api.ts @@ -4,7 +4,7 @@ export interface KubeLabelSelectorExpression { * Gt and Lt are only applicable to node selectors */ operator: 'In' | 'NotIn' | 'Exists' | 'DoesNotExist' | 'Gt' | 'Lt', - /** + /** * An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. */ values?: string[], @@ -16,4 +16,4 @@ export interface KubeLabelSelector { * matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. */ matchLabels?: { [key: string]: string } -} \ No newline at end of file +} diff --git a/shell/types/store/pagination.types.ts b/shell/types/store/pagination.types.ts index 88018e752e4..acf1165ad6c 100644 --- a/shell/types/store/pagination.types.ts +++ b/shell/types/store/pagination.types.ts @@ -320,7 +320,7 @@ export class PaginationArgs { /** * TODO: RC */ - labelSelector: KubeLabelSelector | null; + labelSelector?: KubeLabelSelector; /** * Creates an instance of PaginationArgs. @@ -333,7 +333,7 @@ export class PaginationArgs { sort = [], filters = [], projectsOrNamespaces = [], - labelSelector = null, + labelSelector = undefined, }: // This would be neater as just Partial but we lose all jsdoc { @@ -364,7 +364,7 @@ export class PaginationArgs { /** * TODO: RC */ - labelSelector: KubeLabelSelector | null, + labelSelector?: KubeLabelSelector, }) { this.page = page; this.pageSize = pageSize; @@ -398,7 +398,7 @@ export class FilterArgs extends PaginationArgs { sort = [], filters = [], projectsOrNamespaces = [], - labelSelector = null, + labelSelector = undefined, }: // This would be neater as just Partial but we lose all jsdoc { @@ -421,7 +421,7 @@ export class FilterArgs extends PaginationArgs { /** * TODO: RC */ - labelSelector: KubeLabelSelector | null + labelSelector?: KubeLabelSelector }) { super({ page: null, pageSize: null, sort, filters, projectsOrNamespaces, labelSelector diff --git a/shell/utils/selector-typed.ts b/shell/utils/selector-typed.ts new file mode 100644 index 00000000000..9559d3eebfd --- /dev/null +++ b/shell/utils/selector-typed.ts @@ -0,0 +1,63 @@ +import { COUNT } from '@shell/config/types'; +import { KubeLabelSelector } from '@shell/types/kube/kube-api'; +import { FilterArgs } from '@shell/types/store/pagination.types'; +import { isEmpty } from '@shell/utils/object'; + +/** + * Conditionally make a http request to fetch the results of a labelSelector + * + * In order to determine resources that are in scope either supply `inScopeCount`, OR `$store` and `inStore` (this would be nicer in TS) + * + * Returns a specific object fit for ??? TODO: RC + */ + +// TODO: RC use this version everywhere + +export async function findMatchingResources({ + labelSelector, + type, + inStore, + $store, + inScopeCount = undefined, + namespace = undefined, + transient = false, +}: { + labelSelector: KubeLabelSelector, + type: string, + inStore: string, + $store: any, + inScopeCount?: number + namespace?: string, + transient?: boolean, +}) { + let match = []; + + if (labelSelector?.matchExpressions?.length || !isEmpty(labelSelector?.matchLabels)) { + if (typeof inScopeCount === 'undefined') { + const counts = $store.getters[`${ inStore }/all`](COUNT)?.[0]?.counts || {}; + + inScopeCount = namespace ? counts?.[type]?.namespaces[namespace]?.count || 0 : counts?.[type]?.summary?.count || 0; + } + + if (inScopeCount) { + const findPageArgs = { // Of type ActionFindPageArgs + namespaced: namespace, + pagination: new FilterArgs({ labelSelector }), + transient, + }; + + match = await $store.dispatch(`${ inStore }/findPage`, { type, opt: findPageArgs }); + } + } + + const matched = match.length || 0; + const sample = match[0]?.nameDisplay; + + return { + matched, + matches: match, + none: matched === 0, + sample, + total: inScopeCount, + }; +}