Skip to content

Commit d5226ec

Browse files
authored
Adds optional label selector to k8sResourcePrefix x-descriptor (#12525)
Enables resource filtering within the k8sResourcePrefix x-descriptor by combining label selector and uri query syntax.
1 parent 8e1b8d5 commit d5226ec

File tree

6 files changed

+47
-6
lines changed

6 files changed

+47
-6
lines changed

frontend/packages/console-shared/src/components/dynamic-form/widgets.tsx

+6-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { WidgetProps } from '@rjsf/core';
44
import { getSchemaType } from '@rjsf/core/dist/cjs/utils';
55
import * as _ from 'lodash';
66
import { useTranslation } from 'react-i18next';
7+
import { Selector } from '@console/dynamic-plugin-sdk/src/api/common-types';
78
import { RadioGroup } from '@console/internal/components/radio';
89
import { NumberSpinner, ListDropdown, Dropdown } from '@console/internal/components/utils';
910
import { K8sKind, GroupVersionKind, ImagePullPolicy } from '@console/internal/module/k8s';
@@ -119,7 +120,7 @@ export const K8sResourceWidget: React.FC<K8sResourceWidgetProps> = ({
119120
onChange,
120121
}) => {
121122
const { t } = useTranslation();
122-
const { model, groupVersionKind } = options;
123+
const { model, groupVersionKind, selector } = options;
123124
const { namespace } = formContext;
124125
const selectedKey = value ? `${value}-${groupVersionKind}` : null;
125126

@@ -129,7 +130,9 @@ export const K8sResourceWidget: React.FC<K8sResourceWidgetProps> = ({
129130
<ListDropdown
130131
key={id}
131132
id={id}
132-
resources={[{ kind: groupVersionKind, namespace: model.namespaced ? namespace : null }]}
133+
resources={[
134+
{ kind: groupVersionKind, selector, namespace: model.namespaced ? namespace : null },
135+
]}
133136
desc={label}
134137
placeholder={t('console-shared~Select {{label}}', { label: model.label })}
135138
onChange={(next) => onChange(next)}
@@ -196,6 +199,7 @@ type K8sResourceWidgetProps = WidgetProps & {
196199
options: {
197200
model: K8sKind;
198201
groupVersionKind: GroupVersionKind;
202+
selector: Selector;
199203
};
200204
};
201205

frontend/packages/operator-lifecycle-manager/src/components/descriptors/const.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export const REGEXP_FIELD_DEPENDENCY_CAPABILITY = _.escapeRegExp(SpecCapability.
66
export const REGEXP_SELECT_CAPABILITY = _.escapeRegExp(SpecCapability.select);
77

88
export const REGEXP_K8S_RESOURCE_SUFFIX = new RegExp(
9-
`^${REGEXP_K8S_RESOURCE_CAPABILITY}(?:core[:~]v1[:~])?(.*)$`,
9+
`^${REGEXP_K8S_RESOURCE_CAPABILITY}(?:core[:~]v1[:~])?([^?]*)[?]?(.*)$`,
1010
);
1111
export const REGEXP_SELECT_OPTION = new RegExp(`${REGEXP_SELECT_CAPABILITY}(.*)$`);
1212
export const REGEXP_FIELD_DEPENDENCY_PATH_VALUE = new RegExp(

frontend/packages/operator-lifecycle-manager/src/components/descriptors/reference/reference.md

+9
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,15 @@ x-descriptors:
141141
142142
```
143143

144+
With optional label selector being specified:
145+
146+
```yaml
147+
148+
x-descriptors:
149+
- urn:alm:descriptor:io.kubernetes:Deployment?tier!=frontend,environment in (production, qa)'
150+
151+
```
152+
144153
**UI**
145154
<table style="width:100%">
146155
<tr valign="top">

frontend/packages/operator-lifecycle-manager/src/components/operand/utils.spec.ts

+23
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ServiceAccountModel } from '@console/internal/models';
2+
import { selectorFromString } from '@console/internal/module/k8s/selector';
23
import { getJSONSchemaOrder } from '@console/shared/src/components/dynamic-form/utils';
34
import { SpecCapability } from '../descriptors/types';
45
import { capabilitiesToUISchema } from './utils';
@@ -99,6 +100,28 @@ describe('capabilitiesToUISchema', () => {
99100
expect(uiSchema['ui:options'].model).toEqual(ServiceAccountModel);
100101
expect(uiSchema['ui:options'].groupVersionKind).toEqual('ServiceAccount');
101102
});
103+
it('Handles SpecCapability.k8sResourcePrefix with equality-based label queries', () => {
104+
const uiSchema = capabilitiesToUISchema([
105+
`${SpecCapability.k8sResourcePrefix}ServiceAccount?label!=test,level=production` as SpecCapability,
106+
]);
107+
expect(uiSchema['ui:widget']).toEqual('K8sResourceWidget');
108+
expect(uiSchema['ui:options'].model).toEqual(ServiceAccountModel);
109+
expect(uiSchema['ui:options'].groupVersionKind).toEqual('ServiceAccount');
110+
expect(uiSchema['ui:options'].selector).toEqual(
111+
selectorFromString('label!=test,level=production'),
112+
);
113+
});
114+
it('Handles SpecCapability.k8sResourcePrefix with set-based label queries', () => {
115+
const uiSchema = capabilitiesToUISchema([
116+
`${SpecCapability.k8sResourcePrefix}ServiceAccount?level in (production,qa)` as SpecCapability,
117+
]);
118+
expect(uiSchema['ui:widget']).toEqual('K8sResourceWidget');
119+
expect(uiSchema['ui:options'].model).toEqual(ServiceAccountModel);
120+
expect(uiSchema['ui:options'].groupVersionKind).toEqual('ServiceAccount');
121+
expect(uiSchema['ui:options'].selector).toEqual(
122+
selectorFromString('level in (production, qa)'),
123+
);
124+
});
102125
it('Handles SpecCapablitiy.select', () => {
103126
const uiSchema = capabilitiesToUISchema([
104127
`${SpecCapability.select}DEBUG` as SpecCapability,

frontend/packages/operator-lifecycle-manager/src/components/operand/utils.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { JSONSchema7 } from 'json-schema';
44
import * as _ from 'lodash';
55
import i18n from '@console/internal/i18n';
66
import { modelFor } from '@console/internal/module/k8s';
7+
import { selectorFromString } from '@console/internal/module/k8s/selector';
78
import { getSchemaAtPath } from '@console/shared';
89
import {
910
getJSONSchemaOrder,
@@ -33,13 +34,16 @@ export const hideAllExistingProperties = (schema: JSONSchema7) => {
3334
};
3435

3536
const k8sResourceCapabilityToUISchema = (capability: SpecCapability): UiSchema => {
36-
const [, suffix] = capability.match(REGEXP_K8S_RESOURCE_SUFFIX) ?? [];
37-
const groupVersionKind = suffix?.replace(/:/g, '~');
37+
const [, groupVersionKindToken, selectorToken] =
38+
capability.match(REGEXP_K8S_RESOURCE_SUFFIX) ?? [];
39+
const groupVersionKind = groupVersionKindToken?.replace(/:/g, '~');
40+
const selector = selectorFromString(selectorToken);
41+
3842
const model = groupVersionKind && modelFor(groupVersionKind);
3943
if (model) {
4044
return {
4145
'ui:widget': 'K8sResourceWidget',
42-
'ui:options': { model, groupVersionKind },
46+
'ui:options': { model, groupVersionKind, selector },
4347
};
4448
}
4549
return {};

frontend/public/components/utils/list-dropdown.jsx

+1
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ ListDropdown.propTypes = {
196196
PropTypes.shape({
197197
kind: PropTypes.string.isRequired,
198198
namespace: PropTypes.string,
199+
selector: PropTypes.object,
199200
}),
200201
).isRequired,
201202
placeholder: PropTypes.string,

0 commit comments

Comments
 (0)