-
+
|
= ({ operands, loaded, csvName
{operand.kind}
|
- {operand.metadata.namespace ? (
+ {operand.metadata?.namespace ? (
) : (
@@ -644,10 +644,10 @@ const OperandErrorList: React.FC = ({ operandErrors, csvN
{_.map(operandErrors, (operandError) => (
-
- {' '}
+ {' '}
{operandError.operand.kind}
{' '}
{t('olm~Error: {{error}}', {
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/modals/update-strategy-modal.tsx b/frontend/packages/operator-lifecycle-manager/src/components/modals/update-strategy-modal.tsx
index 8ce1ea9e1d6..f21966f68db 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/modals/update-strategy-modal.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/modals/update-strategy-modal.tsx
@@ -77,7 +77,7 @@ export const UpdateStrategyModal: React.FC = ({
errorMessage={errorMessage}
inProgress={inProgress}
submitText={t('public~Save')}
- cancel={cancel}
+ cancel={cancel as any}
/>
);
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/operand/DEPRECATED_operand-form.tsx b/frontend/packages/operator-lifecycle-manager/src/components/operand/DEPRECATED_operand-form.tsx
index 9acaec1077b..d7a357ba98c 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/operand/DEPRECATED_operand-form.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/operand/DEPRECATED_operand-form.tsx
@@ -117,7 +117,11 @@ const idFromPath = (path) => `DEPRECATED_root_${path.split('.').join('_')}`;
* both prefix and suffix are provided, this will return true only if the field has a capability
* that matches the concatenation of prefix + suffix.
*/
-const hasDescriptor = (field: OperandField, prefix: string, suffix: string = null): boolean => {
+const hasDescriptor = (
+ field: OperandField,
+ prefix: string,
+ suffix: string | null = null,
+): boolean => {
return suffix
? _.includes(field.capabilities, `${prefix}${suffix}`)
: _.some(field.capabilities, (capability) => capability.startsWith(prefix));
@@ -137,7 +141,7 @@ const parseGroupDescriptor = (
descriptor.startsWith(SpecCapability.fieldGroup) ||
descriptor.startsWith(SpecCapability.arrayFieldGroup),
);
- const [regexMatch, groupType, groupName] = groupDescriptor.match(GROUP_PATTERN) || [];
+ const [regexMatch, groupType, groupName] = groupDescriptor?.match(GROUP_PATTERN) || [];
return { regexMatch, groupName, groupType };
};
@@ -435,8 +439,8 @@ const specDescriptorToFields = (
displayName,
description,
capabilities,
- type: null,
- required: null,
+ type: null as any,
+ required: null as any,
})),
);
}
@@ -445,8 +449,8 @@ const specDescriptorToFields = (
path: `spec.${path}`,
displayName,
description,
- type: null,
- required: null,
+ type: null as any,
+ required: null as any,
capabilities,
},
];
@@ -520,16 +524,16 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
// Immutable will not initialize a deep path as a List if it includes an integer, so we need to manually
// initialize non-existent array properties to a List instance before updating state at that path.
if (regexMatch && index === 0) {
- const existing = immutableFormData.getIn([...pathToArray(pathBeforeIndex), 0]);
- const item = Immutable.Map(existing || {}).setIn(pathToArray(pathAfterIndex), value);
+ const existing = immutableFormData.getIn([...pathToArray(pathBeforeIndex || ''), 0]);
+ const item = Immutable.Map(existing || {}).setIn(pathToArray(pathAfterIndex || ''), value);
const list = Immutable.List([item]);
- onChange(immutableFormData.setIn(pathToArray(pathBeforeIndex), list).toJS());
+ onChange?.(immutableFormData.setIn(pathToArray(pathBeforeIndex || ''), list).toJS());
}
- onChange(immutableFormData.setIn(pathToArray(path), value).toJS());
+ onChange?.(immutableFormData.setIn(pathToArray(path), value).toJS());
};
- const handleFormDataDelete = (path) => {
- onChange(immutableFormData.deleteIn(pathToArray(path)).toJS());
+ const handleFormDataDelete = (path: string) => {
+ onChange?.(immutableFormData.deleteIn(pathToArray(path)).toJS());
};
// Map providedAPI spec descriptors and openAPI spec properties to OperandField[] array
@@ -538,7 +542,7 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
const schemaFields = fieldsForOpenAPI(
schema?.properties?.spec as JSONSchema6,
providedAPI,
- formData,
+ formData as K8sResourceKind,
);
// Get fields from providedAPI that do not exist in the OpenAPI spec.
@@ -553,7 +557,7 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
// Add the field if it doesn't exist
return [
...providedAPIFieldsAccumulator,
- ...specDescriptorToFields(specDescriptor, formData),
+ ...specDescriptorToFields(specDescriptor, formData as K8sResourceKind),
];
},
[],
@@ -643,14 +647,17 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
groupName,
fieldLists: _.reduce(
fieldsInGroup,
- (fieldListsAccumulator, field) => {
+ (fieldListsAccumulator: OperandField[][], field) => {
const { index, regexMatch } = parseArrayPath(field.path);
if (regexMatch) {
- fieldListsAccumulator[index] = [...(fieldListsAccumulator[index] || []), field];
+ fieldListsAccumulator[index || 0] = [
+ ...(fieldListsAccumulator[index || 0] || []),
+ field,
+ ];
}
return fieldListsAccumulator;
},
- [],
+ [] as OperandField[][],
),
}));
}, [arrayFields]);
@@ -790,8 +797,10 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
);
}
if (capabilities.some((c) => c.startsWith(SpecCapability.k8sResourcePrefix))) {
- const groupVersionKind: GroupVersionKind = capabilities
- .find((c) => c.startsWith(SpecCapability.k8sResourcePrefix))
+ const capability = capabilities.find((c) => c.startsWith(SpecCapability.k8sResourcePrefix));
+ if (!capability) return null;
+
+ const groupVersionKind: GroupVersionKind = capability
.split(SpecCapability.k8sResourcePrefix)[1]
.replace('core~v1~', '');
const k8sModel = modelFor(groupVersionKind);
@@ -805,13 +814,13 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
resources={[
{
kind: groupVersionKind,
- namespace: k8sModel.namespaced ? params?.ns : null,
+ namespace: k8sModel.namespaced ? params?.ns : undefined,
},
]}
desc={displayName}
placeholder={t('olm~Select {{item}}', { item: kindForReference(groupVersionKind) })}
onChange={(value) => handleFormDataUpdate(path, value)}
- selectedKey={currentValue ? `${currentValue}-${k8sModel?.kind}` : null}
+ selectedKey={currentValue ? `${currentValue}-${k8sModel?.kind}` : undefined}
/>
) : null;
}
@@ -980,7 +989,7 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
const leftShiftedFields = _.reduce(
fieldsToLeftShift,
(fieldAccumulator, field) => {
- const path = modifyArrayFieldPathIndex(field.path, (index) => index - 1);
+ const path = modifyArrayFieldPathIndex(field.path, (index) => (index || 1) - 1);
return [...fieldAccumulator, { ...field, path }];
},
[],
@@ -1010,8 +1019,11 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
const groupDisplayName = _.startCase(groupName);
const singularGroupDisplayName = groupDisplayName.replace(/s$/, '');
const id = `root_spec_${groupName}`;
- const isExpanded = !_.some(fieldLists, (fieldList) =>
- _.some(fieldList, (f) => hasDescriptor(f, SpecCapability.advanced) && !f.required),
+ const isExpanded = !_.some(fieldLists, (fieldList: OperandField[]) =>
+ _.some(
+ fieldList,
+ (f) => hasDescriptor(f as OperandField, SpecCapability.advanced) && !f.required,
+ ),
);
return (
@@ -1033,7 +1045,11 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
)}
{_.map(fieldList, (field) => (
-
+
))}
))}
@@ -1049,7 +1065,7 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
);
- });
+ }).filter(Boolean);
const renderFieldGroups = () =>
_.map(_.sortBy(fieldGroups, 'groupName'), ({ fieldList, groupName }) => {
@@ -1064,16 +1080,16 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
return (
{_.map(fieldList, (field) => (
-
+
))}
);
- });
+ }).filter(Boolean);
const renderNormalFields = () =>
_.map(normalFields, (field) => (
-
- ));
+
+ )).filter(Boolean);
const renderAdvancedFields = () =>
advancedFields.length > 0 && (
@@ -1083,8 +1099,8 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
textCollapsed={t('olm~Advanced configuration')}
>
{_.map(advancedFields, (field) => (
-
- ))}
+
+ )).filter(Boolean)}
);
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/operand/create-operand.spec.tsx b/frontend/packages/operator-lifecycle-manager/src/components/operand/create-operand.spec.tsx
index 09a62e88da9..0e42605166a 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/operand/create-operand.spec.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/operand/create-operand.spec.tsx
@@ -63,7 +63,10 @@ xdescribe('[https://issues.redhat.com/browse/CONSOLE-2137] CreateOperand', () =>
it('passes correct YAML to YAML editor', () => {
const data = _.cloneDeep(testClusterServiceVersion);
const testResourceInstanceYAML = safeDump(testResourceInstance);
- data.metadata.annotations = { 'alm-examples': JSON.stringify([testResourceInstance]) };
+ data.metadata = {
+ ...data.metadata,
+ annotations: { 'alm-examples': JSON.stringify([testResourceInstance]) },
+ };
wrapper = wrapper.setProps({ csv: data, loaded: true, loadError: null });
expect(wrapper.find(OperandYAML).props().initialYAML).toEqual(testResourceInstanceYAML);
});
@@ -93,7 +96,7 @@ xdescribe('[https://issues.redhat.com/browse/CONSOLE-2136] CreateOperandForm', (
wrapper = shallow(
,
@@ -102,7 +105,9 @@ xdescribe('[https://issues.redhat.com/browse/CONSOLE-2136] CreateOperandForm', (
it('renders form', () => {
expect(
- referenceForProvidedAPI(testClusterServiceVersion.spec.customresourcedefinitions.owned[0]),
+ referenceForProvidedAPI(
+ testClusterServiceVersion.spec?.customresourcedefinitions?.owned?.[0] as any,
+ ),
).toEqual(k8s.referenceForModel(testModel));
expect(wrapper.find('form').exists()).toBe(true);
@@ -110,7 +115,7 @@ xdescribe('[https://issues.redhat.com/browse/CONSOLE-2136] CreateOperandForm', (
it('renders input component for each field', () => {
wrapper.find('.co-dynamic-form__form-group').forEach((formGroup) => {
- const descriptor = testClusterServiceVersion.spec.customresourcedefinitions.owned[0].specDescriptors.find(
+ const descriptor = testClusterServiceVersion.spec?.customresourcedefinitions?.owned?.[0]?.specDescriptors?.find(
(d) => d.displayName === formGroup.find('.form-label').text(),
);
@@ -131,8 +136,8 @@ xdescribe('[https://issues.redhat.com/browse/CONSOLE-2136] CreateOperandForm', (
expect(model).toEqual(testModel);
expect(obj.apiVersion).toEqual(k8s.apiVersionForModel(testModel));
expect(obj.kind).toEqual(testModel.kind);
- expect(obj.metadata.name).toEqual('example');
- expect(obj.metadata.namespace).toEqual('default');
+ expect(obj.metadata?.name).toEqual('example');
+ expect(obj.metadata?.namespace).toEqual('default');
done();
})
.catch((err) => fail(err));
@@ -157,7 +162,7 @@ xdescribe('[https://issues.redhat.com/browse/CONSOLE-2136] CreateOperandForm', (
});
});
-describe(OperandYAML.displayName, () => {
+describe(OperandYAML.displayName || '', () => {
let wrapper: ShallowWrapper;
beforeEach(() => {
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/operand/create-operand.tsx b/frontend/packages/operator-lifecycle-manager/src/components/operand/create-operand.tsx
index 440872da424..7ea9be06761 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/operand/create-operand.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/operand/create-operand.tsx
@@ -59,7 +59,7 @@ export const CreateOperand: React.FC = ({
isList: false,
name: nameForModel(model),
}
- : undefined,
+ : null,
);
const formHelpText = t(
@@ -128,7 +128,7 @@ export const CreateOperand: React.FC = ({
;
const CreateOperandPage: React.FC = () => {
const { t } = useTranslation();
const params = useParams();
- const createResourceExtension = useCreateResourceExtension(params.plural);
+ const createResourceExtension = useCreateResourceExtension(params.plural || '');
const { csvName, ns } = useParams();
- const [csv, loaded, loadError] = useClusterServiceVersion(csvName, ns);
+ const [csv, loaded, loadError] = useClusterServiceVersion(csvName || '', ns || '');
return (
<>
- {t('olm~Create {{item}}', { item: kindForReference(params.plural) })}
+ {t('olm~Create {{item}}', { item: kindForReference(params.plural || '') })}
-
+
{createResourceExtension ? (
({
const i18nNS = 'public';
-describe(OperandTableRow.displayName, () => {
+describe(OperandTableRow.displayName || '', () => {
let wrapper: ReactWrapper;
beforeEach(() => {
@@ -152,7 +152,7 @@ describe(OperandTableRow.displayName, () => {
const col = wrapper.childAt(2);
const link = col.find(ResourceLink);
- expect(link.props().name).toEqual(testResourceInstance.metadata.namespace);
+ expect(link.props().name).toEqual(testResourceInstance.metadata?.namespace);
});
it('renders column for resource status', () => {
const col = wrapper.childAt(3);
@@ -165,14 +165,14 @@ describe(OperandTableRow.displayName, () => {
const labelList = col.find(LabelList);
expect(labelList.props().kind).toEqual(testResourceInstance.kind);
- expect(labelList.props().labels).toEqual(testResourceInstance.metadata.labels);
+ expect(labelList.props().labels).toEqual(testResourceInstance.metadata?.labels);
});
it('renders column for last updated timestamp', () => {
const col = wrapper.childAt(5);
const timestamp = col.find(Timestamp);
- expect(timestamp.props().timestamp).toEqual(testResourceInstance.metadata.creationTimestamp);
+ expect(timestamp.props().timestamp).toEqual(testResourceInstance.metadata?.creationTimestamp);
});
it('renders a `LazyActionsMenu` for resource actions', () => {
@@ -181,7 +181,7 @@ describe(OperandTableRow.displayName, () => {
});
});
-describe(OperandList.displayName, () => {
+describe(OperandList.displayName || '', () => {
let wrapper: ReactWrapper;
let resources: K8sResourceKind[];
@@ -217,14 +217,14 @@ describe(OperandList.displayName, () => {
});
});
-describe(OperandDetails.displayName, () => {
+describe(OperandDetails.displayName || '', () => {
let wrapper: ShallowWrapper;
let resourceDefinition: any;
beforeEach(() => {
resourceDefinition = {
plural: testModel.plural,
- annotations: testCRD.metadata.annotations,
+ annotations: testCRD.metadata?.annotations,
apiVersion: testModel.apiVersion,
};
wrapper = shallow(
@@ -233,7 +233,7 @@ describe(OperandDetails.displayName, () => {
crd={testCRD}
obj={testResourceInstance}
kindObj={resourceDefinition}
- appName={testClusterServiceVersion.metadata.name}
+ appName={testClusterServiceVersion.metadata?.name || ''}
/>,
);
});
@@ -250,10 +250,10 @@ describe(OperandDetails.displayName, () => {
});
it('does not render filtered status fields', () => {
- const crd = testClusterServiceVersion.spec.customresourcedefinitions.owned.find(
+ const crd = testClusterServiceVersion.spec?.customresourcedefinitions?.owned?.find(
(c) => c.name === 'testresources.testapp.coreos.com',
);
- const filteredDescriptor = crd.statusDescriptors.find((sd) => sd.path === 'importantMetrics');
+ const filteredDescriptor = crd?.statusDescriptors?.find((sd) => sd.path === 'importantMetrics');
const statusView = wrapper
.find(DescriptorDetailsItem)
.filterWhere((node) => node.props().descriptor === filteredDescriptor);
@@ -263,7 +263,9 @@ describe(OperandDetails.displayName, () => {
it('does not render any spec descriptor fields if there are none defined on the `ClusterServiceVersion`', () => {
const csv = _.cloneDeep(testClusterServiceVersion);
- csv.spec.customresourcedefinitions.owned = [];
+ if (csv.spec?.customresourcedefinitions?.owned) {
+ csv.spec.customresourcedefinitions.owned = [];
+ }
wrapper = wrapper.setProps({ csv });
expect(wrapper.find(DescriptorDetailsItem).length).toEqual(0);
@@ -273,28 +275,31 @@ describe(OperandDetails.displayName, () => {
expect(
wrapper.find(DescriptorDetailsItemList).last().shallow().find(DescriptorDetailsItem).length,
).toEqual(
- testClusterServiceVersion.spec.customresourcedefinitions.owned[0].specDescriptors.length,
+ testClusterServiceVersion.spec?.customresourcedefinitions?.owned?.[0]?.specDescriptors
+ ?.length,
);
});
xit('[CONSOLE-2336] renders spec descriptor fields if the custom resource is `required`', () => {
const csv = _.cloneDeep(testClusterServiceVersion);
- csv.spec.customresourcedefinitions.required = _.cloneDeep(
- csv.spec.customresourcedefinitions.owned,
- );
- csv.spec.customresourcedefinitions.owned = [];
+ if (csv.spec?.customresourcedefinitions?.owned) {
+ csv.spec.customresourcedefinitions.required = _.cloneDeep(
+ csv.spec.customresourcedefinitions.owned,
+ );
+ csv.spec.customresourcedefinitions.owned = [];
+ }
wrapper = wrapper.setProps({ csv });
expect(
wrapper.find(DescriptorDetailsItemList).last().shallow().find(DescriptorDetailsItem).length,
- ).toEqual(csv.spec.customresourcedefinitions.required[0].specDescriptors.length);
+ ).toEqual(csv.spec?.customresourcedefinitions?.required?.[0]?.specDescriptors?.length);
});
it('renders a Condtions table', () => {
expect(wrapper.find('SectionHeading').at(1).prop('text')).toEqual('Conditions');
expect(wrapper.find('Conditions').prop('conditions')).toEqual(
- testResourceInstance.status.conditions,
+ testResourceInstance.status?.conditions,
);
});
@@ -332,7 +337,7 @@ describe('ResourcesList', () => {
);
const multiListPage = wrapper.find(MultiListPage);
expect(multiListPage.props().resources).toEqual(
- testClusterServiceVersion.spec.customresourcedefinitions.owned[0].resources.map(
+ testClusterServiceVersion.spec?.customresourcedefinitions?.owned?.[0]?.resources?.map(
(resource) => ({ kind: resource.kind, namespaced: true, prop: 'Pod' }),
),
);
@@ -377,12 +382,12 @@ describe(OperandDetailsPage.displayName, () => {
);
const detailsPage = wrapper.find(DetailsPage);
- expect(detailsPage.props().pages[0].nameKey).toEqual(`${i18nNS}~Details`);
- expect(detailsPage.props().pages[0].href).toEqual('');
- expect(detailsPage.props().pages[1].nameKey).toEqual(`${i18nNS}~YAML`);
- expect(detailsPage.props().pages[1].href).toEqual('yaml');
- expect(detailsPage.props().pages[2].nameKey).toEqual('olm~Resources');
- expect(detailsPage.props().pages[2].href).toEqual('resources');
+ expect(detailsPage.props().pages?.[0]?.nameKey).toEqual(`${i18nNS}~Details`);
+ expect(detailsPage.props().pages?.[0]?.href).toEqual('');
+ expect(detailsPage.props().pages?.[1]?.nameKey).toEqual(`${i18nNS}~YAML`);
+ expect(detailsPage.props().pages?.[1]?.href).toEqual('yaml');
+ expect(detailsPage.props().pages?.[2]?.nameKey).toEqual('olm~Resources');
+ expect(detailsPage.props().pages?.[2]?.href).toEqual('resources');
});
it('renders a `DetailsPage` which also watches the parent CSV', () => {
@@ -393,7 +398,7 @@ describe(OperandDetailsPage.displayName, () => {
,
);
- expect(wrapper.find(DetailsPage).prop('resources')[0]).toEqual({
+ expect(wrapper.find(DetailsPage).prop('resources')?.[0]).toEqual({
kind: 'CustomResourceDefinition',
name: 'testresources.testapp.coreos.com',
isList: false,
@@ -420,7 +425,12 @@ describe(OperandDetailsPage.displayName, () => {
,
);
- expect(wrapper.find(DetailsPage).props().breadcrumbsFor(null)).toEqual([
+ expect(
+ wrapper
+ .find(DetailsPage)
+ .props()
+ .breadcrumbsFor?.(null as any),
+ ).toEqual([
{
name: 'Installed Operators',
path: `/k8s/ns/default/${ClusterServiceVersionModel.plural}`,
@@ -456,7 +466,12 @@ describe(OperandDetailsPage.displayName, () => {
,
);
- expect(wrapper.find(DetailsPage).props().breadcrumbsFor(null)).toEqual([
+ expect(
+ wrapper
+ .find(DetailsPage)
+ .props()
+ .breadcrumbsFor?.(null as any),
+ ).toEqual([
{
name: 'Installed Operators',
path: `/k8s/ns/example/${ClusterServiceVersionModel.plural}`,
@@ -501,7 +516,7 @@ describe(OperandDetailsPage.displayName, () => {
uid: 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
ownerReferences: [
{
- uid: testResourceInstance.metadata.uid,
+ uid: testResourceInstance.metadata?.uid || '',
name: 'foo',
kind: 'fooKind',
apiVersion: 'fooVersion',
@@ -519,20 +534,20 @@ describe(OperandDetailsPage.displayName, () => {
Deployment: {
data: [deployment],
loaded: true,
- loadError: undefined,
+ loadError: undefined as any,
},
Secret: {
data: [secret],
loaded: true,
- loadError: undefined,
+ loadError: undefined as any,
},
Pod: {
data: [pod],
loaded: true,
- loadError: undefined,
+ loadError: undefined as any,
},
};
- const data = flatten(resources);
+ const data = flatten?.(resources);
expect(data.map((obj) => obj.metadata.uid)).not.toContain(secret.metadata.uid);
expect(data.map((obj) => obj.metadata.uid)).toContain(pod.metadata.uid);
@@ -580,7 +595,7 @@ describe(ProvidedAPIsPage.displayName, () => {
it('passes `items` props and render ListPageCreateDropdown create button if app has multiple owned CRDs', () => {
const obj = _.cloneDeep(testClusterServiceVersion);
- obj.spec.customresourcedefinitions.owned.push({
+ obj.spec?.customresourcedefinitions?.owned?.push({
name: 'foobars.testapp.coreos.com',
displayName: 'Foo Bars',
version: 'v1',
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/operand/index.tsx b/frontend/packages/operator-lifecycle-manager/src/components/operand/index.tsx
index d59e94c9534..10a81c76fb0 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/operand/index.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/operand/index.tsx
@@ -57,6 +57,7 @@ import {
CustomResourceDefinitionKind,
definitionFor,
K8sResourceCommon,
+ K8sResourceKindReference,
} from '@console/internal/module/k8s';
import {
Status,
@@ -97,7 +98,7 @@ const tableColumnClasses = [
Kebab.columnClass,
];
-const getOperandStatus = (obj: K8sResourceKind): OperandStatusType => {
+const getOperandStatus = (obj: K8sResourceKind): OperandStatusType | null => {
const { phase, status, state, conditions } = obj?.status || {};
if (phase && _.isString(phase)) {
@@ -146,7 +147,7 @@ const hasAllNamespaces = (csv: ClusterServiceVersionKind) => {
};
export const OperandStatus: React.FC = ({ operand }) => {
- const status: OperandStatusType = getOperandStatus(operand);
+ const status: OperandStatusType | null = getOperandStatus(operand);
if (!status) {
return <>->;
}
@@ -182,11 +183,11 @@ export const OperandTableRow: React.FC = ({ obj, showNames
{showNamespace && (
- {obj.metadata.namespace ? (
+ {obj.metadata?.namespace ? (
) : (
'-'
@@ -197,10 +198,13 @@ export const OperandTableRow: React.FC = ({ obj, showNames
-
+
-
+
@@ -280,10 +284,10 @@ export const OperandList: React.FC = (props) => {
if (obj.apiVersion && obj.kind) {
return obj;
}
- const reference = props.kinds[0];
+ const reference = props.kinds?.[0];
return {
- apiVersion: apiVersionForReference(reference),
- kind: kindForReference(reference),
+ apiVersion: apiVersionForReference(reference as any),
+ kind: kindForReference(reference as any),
...obj,
};
}) ?? [],
@@ -295,7 +299,7 @@ export const OperandList: React.FC = (props) => {
{...props}
customSorts={{
operandStatus: getOperandStatusText,
- getOperandNamespace,
+ getOperandNamespace: getOperandNamespace as (obj: any) => string,
}}
data={data}
EmptyMsg={() =>
@@ -366,7 +370,7 @@ export const ProvidedAPIsPage = (props: ProvidedAPIsPageProps) => {
const providedAPIs = providedAPIsForCSV(obj);
const owners = (ownerRefs: OwnerReference[], items: K8sResourceKind[]) =>
- ownerRefs.filter(({ uid }) => items.filter(({ metadata }) => metadata.uid === uid).length > 0);
+ ownerRefs.filter(({ uid }) => items.filter(({ metadata }) => metadata?.uid === uid).length > 0);
const flatten: Flatten<{
[key: string]: K8sResourceCommon[];
}> = React.useCallback(
@@ -374,7 +378,7 @@ export const ProvidedAPIsPage = (props: ProvidedAPIsPageProps) => {
_.flatMap(resources, (resource) => _.map(resource.data, (item) => item)).filter(
({ kind, metadata }, i, allResources) =>
providedAPIs.filter((item) => item.kind === kind).length > 0 ||
- owners(metadata.ownerReferences || [], allResources).length > 0,
+ owners(metadata?.ownerReferences || [], allResources).length > 0,
),
[providedAPIs],
);
@@ -391,7 +395,7 @@ export const ProvidedAPIsPage = (props: ProvidedAPIsPageProps) => {
const watchedResources = getK8sWatchResources(
models,
providedAPIs,
- listAllNamespaces ? null : namespace,
+ listAllNamespaces ? undefined : namespace,
);
const resources = useK8sWatchResources<{ [key: string]: K8sResourceKind[] }>(watchedResources);
@@ -448,7 +452,7 @@ export const ProvidedAPIsPage = (props: ProvidedAPIsPageProps) => {
return inFlight ? null : (
<>
}
>
@@ -467,7 +471,7 @@ export const ProvidedAPIsPage = (props: ProvidedAPIsPageProps) => {
hideColumnManagement={hideColumnManagement}
/>
= (props) =>
return (
<>
}
>
@@ -594,7 +598,7 @@ const PodStatuses: React.FC = ({ kindObj, obj, podStatusDescri
descriptor={statusDescriptor}
model={kindObj}
obj={obj}
- schema={schema}
+ schema={schema as JSONSchema7}
/>
);
@@ -605,7 +609,7 @@ const PodStatuses: React.FC = ({ kindObj, obj, podStatusDescri
export const OperandDetails = connectToModel(({ crd, csv, kindObj, obj }: OperandDetailsProps) => {
const { t } = useTranslation();
const { kind, status } = obj;
- const [errorMessage, setErrorMessage] = React.useState(null);
+ const [errorMessage, setErrorMessage] = React.useState(null);
const handleError = (err: Error) => setErrorMessage(err.message);
// Find the matching CRD spec for the kind of this resource in the CSV.
@@ -705,7 +709,7 @@ export const OperandDetails = connectToModel(({ crd, csv, kindObj, obj }: Operan
{
const context = {
[referenceForModel(resourceModel)]: resource,
@@ -755,8 +759,8 @@ const DefaultOperandDetailsPage = ({ k8sModel }: DefaultOperandDetailsPageProps)
return (
{
const { plural, ns, name } = useParams();
- const resourceDetailsPage = useResourceDetailsPage(plural);
+ const resourceDetailsPage = useResourceDetailsPage(plural as any);
const [k8sModel, inFlight] = useK8sModel(plural);
if (inFlight && !k8sModel) {
return null;
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/operand/operand-form.tsx b/frontend/packages/operator-lifecycle-manager/src/components/operand/operand-form.tsx
index 53b40d268be..c29ada4bbf5 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/operand/operand-form.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/operand/operand-form.tsx
@@ -54,8 +54,8 @@ export const OperandForm: React.FC = ({
history.replace(
resourcePathFromModel(
ClusterServiceVersionModel,
- csv.metadata.name,
- csv.metadata.namespace,
+ csv.metadata?.name || '',
+ csv.metadata?.namespace || '',
),
);
} else {
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/operand/operand-link.tsx b/frontend/packages/operator-lifecycle-manager/src/components/operand/operand-link.tsx
index 1e1426549e8..83477bbf415 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/operand/operand-link.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/operand/operand-link.tsx
@@ -15,7 +15,7 @@ export const csvNameFromWindow = () =>
);
export const OperandLink: React.FC = (props) => {
- const { namespace, name } = props.obj.metadata;
+ const { namespace, name } = props.obj.metadata || { namespace: '', name: '' };
const csvName = props.csvName || csvNameFromWindow();
const reference = referenceFor(props.obj);
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/operand/utils.spec.ts b/frontend/packages/operator-lifecycle-manager/src/components/operand/utils.spec.ts
index 1b34e5d1bff..b6a084bc789 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/operand/utils.spec.ts
+++ b/frontend/packages/operator-lifecycle-manager/src/components/operand/utils.spec.ts
@@ -96,26 +96,26 @@ describe('capabilitiesToUISchema', () => {
`${SpecCapability.k8sResourcePrefix}ServiceAccount` as SpecCapability,
]);
expect(uiSchema['ui:widget']).toEqual('K8sResourceWidget');
- expect(uiSchema['ui:options'].model).toEqual(ServiceAccountModel);
- expect(uiSchema['ui:options'].groupVersionKind).toEqual('ServiceAccount');
+ expect(uiSchema['ui:options']?.model).toEqual(ServiceAccountModel);
+ expect(uiSchema['ui:options']?.groupVersionKind).toEqual('ServiceAccount');
});
it('Handles SpecCapability.k8sResourcePrefix with equality-based label queries', () => {
const uiSchema = capabilitiesToUISchema([
`${SpecCapability.k8sResourcePrefix}ServiceAccount?label!=test,level=production` as SpecCapability,
]);
expect(uiSchema['ui:widget']).toEqual('K8sResourceWidget');
- expect(uiSchema['ui:options'].model).toEqual(ServiceAccountModel);
- expect(uiSchema['ui:options'].groupVersionKind).toEqual('ServiceAccount');
- expect(uiSchema['ui:options'].selector).toEqual('label!=test,level=production');
+ expect(uiSchema['ui:options']?.model).toEqual(ServiceAccountModel);
+ expect(uiSchema['ui:options']?.groupVersionKind).toEqual('ServiceAccount');
+ expect(uiSchema['ui:options']?.selector).toEqual('label!=test,level=production');
});
it('Handles SpecCapability.k8sResourcePrefix with set-based label queries', () => {
const uiSchema = capabilitiesToUISchema([
`${SpecCapability.k8sResourcePrefix}ServiceAccount?level in (production,qa)` as SpecCapability,
]);
expect(uiSchema['ui:widget']).toEqual('K8sResourceWidget');
- expect(uiSchema['ui:options'].model).toEqual(ServiceAccountModel);
- expect(uiSchema['ui:options'].groupVersionKind).toEqual('ServiceAccount');
- expect(uiSchema['ui:options'].selector).toEqual('level in (production,qa)');
+ expect(uiSchema['ui:options']?.model).toEqual(ServiceAccountModel);
+ expect(uiSchema['ui:options']?.groupVersionKind).toEqual('ServiceAccount');
+ expect(uiSchema['ui:options']?.selector).toEqual('level in (production,qa)');
});
it('Handles SpecCapablitiy.select', () => {
const uiSchema = capabilitiesToUISchema([
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-items.tsx b/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-items.tsx
index 9cf54715495..eac9cf7cea2 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-items.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-items.tsx
@@ -245,7 +245,7 @@ const determineAvailableFilters = (
const filters = _.cloneDeep(initialFilters);
_.each(filterGroups, (field) => {
- const values = [];
+ const values: { label: any; synonyms?: any; value: any; active: boolean }[] = [];
_.each(items, (item) => {
let value = item[field];
let synonyms;
@@ -571,14 +571,14 @@ const OperatorHubTile: React.FC = ({ item, onClick }) => {
export const OperatorHubTileView: React.FC = (props) => {
const { t } = useTranslation();
- const [detailsItem, setDetailsItem] = React.useState(null);
+ const [detailsItem, setDetailsItem] = React.useState(null);
const [showDetails, setShowDetails] = React.useState(false);
const [ignoreOperatorWarning, setIgnoreOperatorWarning, loaded] = useUserSettingsCompatibility<
boolean
>(userSettingsKey, storeKey, false);
const [updateChannel, setUpdateChannel] = React.useState('');
const [updateVersion, setUpdateVersion] = React.useState('');
- const [tokenizedAuth, setTokenizedAuth] = React.useState(null);
+ const [tokenizedAuth, setTokenizedAuth] = React.useState(null);
const installVersion = getQueryArgument('version');
const filteredItems = filterByArchAndOS(props.items);
@@ -709,7 +709,7 @@ export const OperatorHubTileView: React.FC = (props) =
const currentItem = _.find(filteredItems, {
uid: detailsItemID,
});
- setDetailsItem(currentItem);
+ setDetailsItem(currentItem as OperatorHubItem);
setShowDetails(!_.isNil(currentItem));
if (
currentItem &&
@@ -793,23 +793,30 @@ export const OperatorHubTileView: React.FC = (props) =
const installParamsURL =
detailsItem &&
detailsItem.obj &&
- new URLSearchParams({
- pkg: detailsItem.obj.metadata.name,
- catalog: detailsItem.catalogSource,
- catalogNamespace: detailsItem.catalogSourceNamespace,
- targetNamespace: props.namespace,
- channel: updateChannel,
- version: updateVersion,
- tokenizedAuth,
- }).toString();
+ new URLSearchParams(
+ Object.entries({
+ pkg: detailsItem.obj.metadata?.name,
+ catalog: detailsItem.catalogSource,
+ catalogNamespace: detailsItem.catalogSourceNamespace,
+ targetNamespace: props.namespace,
+ channel: updateChannel,
+ version: updateVersion,
+ tokenizedAuth,
+ }).reduce((acc, [key, value]) => {
+ if (value !== undefined && value !== '') {
+ acc[key] = value as string;
+ }
+ return acc;
+ }, {} as Record),
+ ).toString();
const installLink =
- detailsItem && detailsItem.obj && `/operatorhub/subscribe?${installParamsURL.toString()}`;
+ detailsItem && detailsItem.obj && `/operatorhub/subscribe?${installParamsURL}`;
const uninstallLink = () =>
detailsItem &&
detailsItem.subscription &&
- `/k8s/ns/${detailsItem.subscription.metadata.namespace}/${SubscriptionModel.plural}/${detailsItem.subscription.metadata.name}?showDelete=true`;
+ `/k8s/ns/${detailsItem.subscription.metadata?.namespace}/${SubscriptionModel.plural}/${detailsItem.subscription.metadata?.name}?showDelete=true`;
if (_.isEmpty(filteredItems)) {
return (
@@ -849,7 +856,7 @@ export const OperatorHubTileView: React.FC = (props) =
const titleAndDeprecatedPackage = () => (
<>
- {detailsItem.name}
+ {detailsItem?.name}
{detailsItem?.obj?.status?.deprecation && (
= (props) =
/* eslint-disable */
// CONSOLE TABLE FOR TESTING - Using memoized sorted data for performance
// Displays search results with 'Search Relevance Score' and 'Is Red Hat' provider priority values, used in determining display order of operators
-
+
const getActiveFiltersDescription = () => {
const activeFilters = [];
if (selectedCategory !== 'all') activeFilters.push(`Category: ${selectedCategory}`);
@@ -871,10 +878,10 @@ export const OperatorHubTileView: React.FC = (props) =
if (selectedCapabilityLevel !== 'all') activeFilters.push(`Capability Level: ${selectedCapabilityLevel}`);
if (selectedInfraFeatures !== 'all') activeFilters.push(`Infrastructure Features: ${selectedInfraFeatures}`);
if (selectedValidSubscriptionFilters !== 'all') activeFilters.push(`Valid Subscription: ${selectedValidSubscriptionFilters}`);
-
+
return activeFilters.length > 0 ? activeFilters.join(', ') : 'No filters applied';
};
-
+
// Debug logging for non-production environments
if (process.env.NODE_ENV !== 'production') {
if (searchTerm) {
@@ -890,7 +897,7 @@ export const OperatorHubTileView: React.FC = (props) =
} else {
console.log('š OperatorHub Items Array:', sortedItems.map(item => item.name || 'N/A'));
}
-
+
// Debug: Log component state to identify race conditions
console.log('š Debug Info:', {
searchTerm,
@@ -899,7 +906,7 @@ export const OperatorHubTileView: React.FC = (props) =
hasSearchTerm: !!searchTerm,
isInitialLoad: (!filteredItems || filteredItems.length === 0)
});
-
+
console.log(`š Current Active Filters: ${getActiveFiltersDescription()}`);
console.log(`š Search Term: "${searchTerm || 'none'}"`);
console.log(`š Sorted Items Count: ${sortedItems.length}`);
@@ -913,14 +920,14 @@ export const OperatorHubTileView: React.FC = (props) =
relevanceScore: calculateRelevanceScore(searchTerm, item),
}))
.filter((item) => item.relevanceScore > 0);
-
+
// Sort the filtered items the same way TileViewPage will sort them
const searchSortedItems = orderAndSortByRelevance(searchFilteredItems, searchTerm);
-
+
const tableData = searchSortedItems.map((item, index) => ({
Title: item.name || 'N/A',
'Search Relevance Score': item.relevanceScore || 0,
- 'Is Red Hat Provider (Priority)': getRedHatPriority(item) === REDHAT_PRIORITY.EXACT_MATCH ? `Exact Match (${REDHAT_PRIORITY.EXACT_MATCH})` :
+ 'Is Red Hat Provider (Priority)': getRedHatPriority(item) === REDHAT_PRIORITY.EXACT_MATCH ? `Exact Match (${REDHAT_PRIORITY.EXACT_MATCH})` :
getRedHatPriority(item) === REDHAT_PRIORITY.CONTAINS_REDHAT ? `Contains Red Hat (${REDHAT_PRIORITY.CONTAINS_REDHAT})` : `Non-Red Hat (${REDHAT_PRIORITY.NON_REDHAT})`,
// Source: item.source || 'N/A',
'Metadata Provider': _.get(item, 'obj.metadata.labels.provider', 'N/A'),
@@ -933,18 +940,18 @@ export const OperatorHubTileView: React.FC = (props) =
return itemCapability;
}
}
-
+
const specCapability = _.get(item, 'obj.spec.capabilityLevel', '');
if (specCapability) return specCapability;
-
+
const metadataCapability = _.get(item, 'obj.metadata.annotations["operators.operatorframework.io/capability-level"]', '');
if (metadataCapability) return metadataCapability;
-
+
return 'N/A';
})(),
'Infrastructure Features': Array.isArray(item.infraFeatures) ? item.infraFeatures.join(', ') : 'N/A',
}));
-
+
console.log(`\nš OperatorHub Search Results for "${searchTerm}" (${searchSortedItems.length} matches)`);
console.log(`š Active Filters: ${getActiveFiltersDescription()}`);
console.table(tableData);
@@ -952,7 +959,7 @@ export const OperatorHubTileView: React.FC = (props) =
// Console table for filtered results without search term (category/filter-based) - using memoized data
const tableData = sortedItems.map((item, index) => ({
Title: item.name || 'N/A',
- 'Is Red Hat Provider (Priority)': getRedHatPriority(item) === REDHAT_PRIORITY.EXACT_MATCH ? `Exact Match (${REDHAT_PRIORITY.EXACT_MATCH})` :
+ 'Is Red Hat Provider (Priority)': getRedHatPriority(item) === REDHAT_PRIORITY.EXACT_MATCH ? `Exact Match (${REDHAT_PRIORITY.EXACT_MATCH})` :
getRedHatPriority(item) === REDHAT_PRIORITY.CONTAINS_REDHAT ? `Contains Red Hat (${REDHAT_PRIORITY.CONTAINS_REDHAT})` : `Non-Red Hat (${REDHAT_PRIORITY.NON_REDHAT})`,
// Source: item.source || 'N/A',
'Metadata Provider': _.get(item, 'obj.metadata.labels.provider', 'N/A'),
@@ -965,18 +972,18 @@ export const OperatorHubTileView: React.FC = (props) =
return itemCapability;
}
}
-
+
const specCapability = _.get(item, 'obj.spec.capabilityLevel', '');
if (specCapability) return specCapability;
-
+
const metadataCapability = _.get(item, 'obj.metadata.annotations["operators.operatorframework.io/capability-level"]', '');
if (metadataCapability) return metadataCapability;
-
+
return 'N/A';
})(),
'Infrastructure Features': Array.isArray(item.infraFeatures) ? item.infraFeatures.join(', ') : 'N/A',
}));
-
+
console.log(`\nš OperatorHub Filtered Results (${tableData.length} items)`);
console.log(`š Active Filters: ${getActiveFiltersDescription()}`);
console.table(tableData);
@@ -1035,7 +1042,7 @@ export const OperatorHubTileView: React.FC = (props) =
'co-catalog-page__overlay-action',
)}
data-test-id="operator-install-btn"
- to={installLink}
+ to={installLink as any}
>
{t('olm~Install')}
@@ -1044,7 +1051,7 @@ export const OperatorHubTileView: React.FC = (props) =
className="co-catalog-page__overlay-action"
data-test-id="operator-uninstall-btn"
isDisabled={!detailsItem.installed}
- onClick={() => history.push(uninstallLink())}
+ onClick={() => history.push(uninstallLink() as any)}
variant="secondary"
>
{t('olm~Uninstall')}
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-page.tsx b/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-page.tsx
index b7b413d48a3..e4462edb5fc 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-page.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-page.tsx
@@ -53,19 +53,21 @@ const clusterServiceVersionFor = (
clusterServiceVersions: ClusterServiceVersionKind[],
csvName: string,
): ClusterServiceVersionKind =>
- clusterServiceVersions?.find((csv) => csv.metadata.name === csvName);
+ clusterServiceVersions?.find(
+ (csv) => csv.metadata?.name === csvName,
+ ) as ClusterServiceVersionKind;
const onInfrastructureFeaturesAnnotationError = (error: Error, pkg: PackageManifestKind) =>
// eslint-disable-next-line no-console
console.warn(
- `Error parsing infrastructure features from PackageManifest "${pkg.metadata.name}":`,
+ `Error parsing infrastructure features from PackageManifest "${pkg.metadata?.name}":`,
error,
);
const onValidSubscriptionAnnotationError = (error: Error, pkg: PackageManifestKind) =>
// eslint-disable-next-line no-console
console.warn(
- `Error parsing valid subscription from PackageManifest "${pkg.metadata.name}":`,
+ `Error parsing valid subscription from PackageManifest "${pkg.metadata?.name}":`,
error,
);
@@ -105,9 +107,21 @@ export const OperatorHubList: React.FC = ({
const packageManifests = props.packageManifests?.data ?? [];
const marketplacePackageManifests = props.marketplacePackageManifests?.data ?? [];
const allPackageManifests = [...marketplacePackageManifests, ...packageManifests];
- const clusterIsAWSSTS = isAWSSTSCluster(cloudCredentials, infrastructure, authentication);
- const clusterIsAzureWIF = isAzureWIFCluster(cloudCredentials, infrastructure, authentication);
- const clusterIsGCPWIF = isGCPWIFCluster(cloudCredentials, infrastructure, authentication);
+ const clusterIsAWSSTS = isAWSSTSCluster(
+ cloudCredentials as CloudCredentialKind,
+ infrastructure as InfrastructureKind,
+ authentication as AuthenticationKind,
+ );
+ const clusterIsAzureWIF = isAzureWIFCluster(
+ cloudCredentials as CloudCredentialKind,
+ infrastructure as InfrastructureKind,
+ authentication as AuthenticationKind,
+ );
+ const clusterIsGCPWIF = isGCPWIFCluster(
+ cloudCredentials as CloudCredentialKind,
+ infrastructure as InfrastructureKind,
+ authentication as AuthenticationKind,
+ );
return allPackageManifests
.filter((pkg) => {
const { channels, defaultChannel } = pkg.status ?? {};
@@ -115,12 +129,12 @@ export const OperatorHubList: React.FC = ({
if (!defaultChannel) {
// eslint-disable-next-line no-console
console.warn(
- `PackageManifest ${pkg.metadata.name} has no status.defaultChannel and has been excluded`,
+ `PackageManifest ${pkg.metadata?.name} has no status.defaultChannel and has been excluded`,
);
return false;
}
- const { currentCSVDesc } = channels.find((ch) => ch.name === defaultChannel);
+ const { currentCSVDesc } = channels.find((ch) => ch.name === defaultChannel) as any;
// if CSV contains annotation for a non-standalone operator, filter it out
return !(
currentCSVDesc.annotations?.[OLMAnnotation.OperatorType] ===
@@ -133,9 +147,14 @@ export const OperatorHubList: React.FC = ({
loaded && subscriptionFor(subscriptions)(operatorGroups)(pkg)(namespace);
const clusterServiceVersion =
loaded &&
- clusterServiceVersionFor(clusterServiceVersions, subscription?.status?.installedCSV);
+ clusterServiceVersionFor(
+ clusterServiceVersions,
+ subscription?.status?.installedCSV || '',
+ );
const { channels, defaultChannel } = pkg.status ?? {};
- const { currentCSVDesc } = (channels || []).find(({ name }) => name === defaultChannel);
+ const { currentCSVDesc } = (channels || []).find(
+ ({ name }) => name === defaultChannel,
+ ) as any;
const currentCSVAnnotations: CSVAnnotations = currentCSVDesc?.annotations ?? {};
const infraFeatures = getInfrastructureFeatures(currentCSVAnnotations, {
clusterIsAWSSTS,
@@ -165,7 +184,7 @@ export const OperatorHubList: React.FC = ({
const installed = loaded && clusterServiceVersion?.status?.phase === 'Succeeded';
return {
- authentication,
+ authentication: authentication as AuthenticationKind,
capabilityLevel,
catalogSource: pkg.status.catalogSource,
catalogSourceNamespace: pkg.status.catalogSourceNamespace,
@@ -173,14 +192,14 @@ export const OperatorHubList: React.FC = ({
.split(',')
.map((category) => category.trim()),
certifiedLevel,
- cloudCredentials,
+ cloudCredentials: cloudCredentials as CloudCredentialKind,
containerImage,
createdAt,
description: currentCSVAnnotations.description || currentCSVDesc.description,
healthIndex,
imgUrl: iconFor(pkg),
infraFeatures,
- infrastructure,
+ infrastructure: infrastructure as InfrastructureKind,
installed,
installState: installed ? InstalledState.Installed : InstalledState.NotInstalled,
isInstalling:
@@ -194,15 +213,15 @@ export const OperatorHubList: React.FC = ({
marketplaceActionText,
marketplaceRemoteWorkflow,
marketplaceSupportWorkflow,
- name: currentCSVDesc?.displayName ?? pkg.metadata.name,
+ name: currentCSVDesc?.displayName ?? pkg.metadata?.name,
obj: pkg,
- provider: pkg.status.provider?.name ?? pkg.metadata.labels?.provider,
+ provider: pkg.status.provider?.name ?? pkg.metadata?.labels?.provider,
repository,
source: getPackageSource(pkg),
subscription,
support,
tags: [],
- uid: `${pkg.metadata.name}-${pkg.status.catalogSource}-${pkg.status.catalogSourceNamespace}`,
+ uid: `${pkg.metadata?.name}-${pkg.status.catalogSource}-${pkg.status.catalogSourceNamespace}`,
validSubscription,
validSubscriptionFilters,
version: currentCSVDesc?.version,
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-utils.spec.ts b/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-utils.spec.ts
index cae3a5a0fde..ab280ca2e68 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-utils.spec.ts
+++ b/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-utils.spec.ts
@@ -23,7 +23,7 @@ import { InfrastructureFeature, OLMAnnotation, ValidSubscriptionValue } from '.'
describe('getPackageSource', () => {
it('should handle undefined argument', () => {
- const source = getPackageSource(undefined);
+ const source = getPackageSource(undefined as any);
expect(source).toBeUndefined();
});
it('should return correct default Red Hat operator sources', () => {
@@ -53,7 +53,7 @@ describe('getPackageSource', () => {
describe('isAWSSTSCluster', () => {
it('should handle undefined arguments', () => {
- const result = isAWSSTSCluster(undefined, undefined, undefined);
+ const result = isAWSSTSCluster(undefined as any, undefined as any, undefined as any);
expect(result).toEqual(false);
});
it('should return true', () => {
@@ -88,7 +88,7 @@ describe('isAWSSTSCluster', () => {
describe('isAzureWIFCluster', () => {
it('should handle undefined arguments', () => {
- const result = isAzureWIFCluster(undefined, undefined, undefined);
+ const result = isAzureWIFCluster(undefined as any, undefined as any, undefined as any);
expect(result).toEqual(false);
});
it('should return true', () => {
@@ -123,7 +123,7 @@ describe('isAzureWIFCluster', () => {
describe('isGCPWIFCluster', () => {
it('should handle undefined arguments', () => {
- const result = isGCPWIFCluster(undefined, undefined, undefined);
+ const result = isGCPWIFCluster(undefined as any, undefined as any, undefined as any);
expect(result).toEqual(false);
});
it('should return true', () => {
@@ -232,7 +232,7 @@ describe('getClusterServiceVersionPlugins', () => {
expect(result).toEqual([]);
});
it('returns an empty array when annotations are null', () => {
- const result = getClusterServiceVersionPlugins(null);
+ const result = getClusterServiceVersionPlugins(null as any);
expect(result).toEqual([]);
});
it('returns an empty array when annotations are undefined', () => {
@@ -271,7 +271,7 @@ describe('getInternalObjects', () => {
expect(result).toEqual([]);
});
it('returns an empty array when annotations are null', () => {
- const result = getInternalObjects(null);
+ const result = getInternalObjects(null as any);
expect(result).toEqual([]);
});
it('returns an empty array when annotations are undefined', () => {
@@ -310,7 +310,7 @@ describe('getSuggestedNamespaceTemplate', () => {
expect(result).toBeNull();
});
it('returns null when annotations are null', () => {
- const result = getSuggestedNamespaceTemplate(null);
+ const result = getSuggestedNamespaceTemplate(null as any);
expect(result).toBeNull();
});
it('returns null when annotations are undefined', () => {
@@ -349,7 +349,7 @@ describe('getInitializationResource', () => {
expect(result).toBeNull();
});
it('returns null when annotations are null', () => {
- const result = getInitializationResource(null);
+ const result = getInitializationResource(null as any);
expect(result).toBeNull();
});
it('returns null when annotations are undefined', () => {
@@ -440,7 +440,7 @@ describe('getValidSubscription', () => {
expect(filters).toEqual([]);
});
it('returns an empty when annotations are null', () => {
- const [subscriptions, filters] = getValidSubscription(null);
+ const [subscriptions, filters] = getValidSubscription(null as any);
expect(subscriptions).toEqual([]);
expect(filters).toEqual([]);
});
@@ -638,7 +638,7 @@ describe('getInfrastructureFeatures', () => {
expect(result).toEqual([]);
});
it('returns an empty array when annotations are null', () => {
- const result = getInfrastructureFeatures(null);
+ const result = getInfrastructureFeatures(null as any);
expect(result).toEqual([]);
});
it('returns an empty array when annotations are undefined', () => {
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub.spec.tsx b/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub.spec.tsx
index d830d33373d..6c20af3b6c3 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub.spec.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub.spec.tsx
@@ -28,6 +28,7 @@ import {
OperatorHubTileViewProps,
} from './operator-hub-items';
import { OperatorHubList, OperatorHubListProps } from './operator-hub-page';
+import { OperatorHubItem } from '.';
xdescribe('[https://issues.redhat.com/browse/CONSOLE-2136] OperatorHubList', () => {
let wrapper: ReactWrapper;
@@ -37,8 +38,10 @@ xdescribe('[https://issues.redhat.com/browse/CONSOLE-2136] OperatorHubList', ()
,
);
@@ -63,7 +66,7 @@ xdescribe('[https://issues.redhat.com/browse/CONSOLE-2136] OperatorHubList', ()
);
expect(amqTileProps.iconClass).toBe(null);
expect(amqTileProps.vendor).toEqual(
- `provided by ${amqPackageManifest.metadata.labels.provider}`,
+ `provided by ${amqPackageManifest.metadata?.labels?.provider}`,
);
expect(
amqTileProps.description.startsWith(
@@ -85,7 +88,7 @@ xdescribe('[https://issues.redhat.com/browse/CONSOLE-2136] OperatorHubList', ()
);
expect(prometheusTileProps.iconClass).toBe(null);
expect(prometheusTileProps.vendor).toEqual(
- `provided by ${prometheusPackageManifest.metadata.labels.provider}`,
+ `provided by ${prometheusPackageManifest.metadata?.labels?.provider}`,
);
expect(
prometheusTileProps.description.startsWith(
@@ -110,7 +113,7 @@ xdescribe('[https://issues.redhat.com/browse/CONSOLE-2136] OperatorHubList', ()
expect(modalItem.imgUrl).toEqual(
'/api/kubernetes/apis/packages.operators.coreos.com/v1/namespaces/openshift-operator-lifecycle-manager/packagemanifests/amq-streams/icon?resourceVersion=amq-streams.preview.amqstreams.v1.0.0.beta',
);
- expect(modalItem.provider).toEqual(amqPackageManifest.metadata.labels.provider);
+ expect(modalItem.provider).toEqual(amqPackageManifest.metadata?.labels?.provider);
expect(
modalItem.description.startsWith(
'**Red Hat AMQ Streams** is a massively scalable, distributed, and high performance data streaming platform based on the Apache Kafka project.',
@@ -142,7 +145,7 @@ xdescribe(`[https://issues.redhat.com/browse/CONSOLE-2136] ${OperatorHubTileView
});
it('updates filter counts on item changes', () => {
- wrapper.setProps(operatorHubTileViewPagePropsWithDummy);
+ wrapper.setProps(operatorHubTileViewPagePropsWithDummy as any);
wrapper.update();
const filterItemsChanged = wrapper.find(FilterSidePanelCategoryItem);
@@ -169,7 +172,7 @@ xdescribe(`[https://issues.redhat.com/browse/CONSOLE-2136] ${OperatorHubTileView
const { filter, resultLength } = filterTest;
const results = _.reduce(
operatorHubTileViewPageProps.items,
- (matches, item) => {
+ (matches: OperatorHubItem[], item) => {
if (keywordCompare(filter, item)) {
matches.push(item);
}
@@ -194,7 +197,7 @@ xdescribe(`[https://issues.redhat.com/browse/CONSOLE-2136] ${OperatorHubTileView
// TODO: Test category functionality
});
-describe(OperatorHubItemDetails.displayName, () => {
+describe(OperatorHubItemDetails.displayName || '', () => {
const wrapper: ReactWrapper = mount(
,
{
@@ -211,7 +214,7 @@ describe(OperatorHubItemDetails.displayName, () => {
expect(noMarkdown.exists()).toBe(false);
- wrapper.setProps({ item: itemWithLongDescription });
+ wrapper.setProps({ item: itemWithLongDescription as any });
wrapper.update();
const markdown = wrapper.find(MarkdownView);
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/package-manifest.spec.tsx b/frontend/packages/operator-lifecycle-manager/src/components/package-manifest.spec.tsx
index d7d7671f0fa..75ac1ce7897 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/package-manifest.spec.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/package-manifest.spec.tsx
@@ -80,7 +80,7 @@ describe('PackageManifestTableRow', () => {
wrapper = shallow(
,
);
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/subscription.spec.tsx b/frontend/packages/operator-lifecycle-manager/src/components/subscription.spec.tsx
index ac0aff906cd..8991f03f64d 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/subscription.spec.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/subscription.spec.tsx
@@ -115,7 +115,9 @@ describe('SubscriptionTableRow', () => {
};
wrapper = updateWrapper();
- expect(wrapper.childAt(2).find(SubscriptionStatus).shallow().text()).toContain('Upgrading');
+ expect(wrapper.childAt(2).find(SubscriptionStatus).shallow().text()).toContain(
+ 'Upgrade available',
+ );
});
it('renders column for subscription state when no updates available', () => {
From aecc829e1a08eefc9b0e906b12e15da24b1950dc Mon Sep 17 00:00:00 2001
From: Krish Agarwal
Date: Tue, 26 Aug 2025 14:22:28 -0400
Subject: [PATCH 3/5] Fixed build and test failures
---
.../spec/resource-requirements.spec.tsx | 21 +++++--------------
1 file changed, 5 insertions(+), 16 deletions(-)
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/descriptors/spec/resource-requirements.spec.tsx b/frontend/packages/operator-lifecycle-manager/src/components/descriptors/spec/resource-requirements.spec.tsx
index c55b4ed5f55..49717a444fb 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/descriptors/spec/resource-requirements.spec.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/descriptors/spec/resource-requirements.spec.tsx
@@ -78,19 +78,12 @@ describe(ResourceRequirementsModalLink.displayName || '', () => {
beforeEach(() => {
obj = _.cloneDeep(testResourceInstance);
- if (obj.spec) {
- obj.spec.resources = {
+ obj.spec = {
+ resources: {
limits: { memory: '50Mi', cpu: '500m', 'ephemeral-storage': '50Mi' },
requests: { memory: '50Mi', cpu: '500m', 'ephemeral-storage': '50Mi' },
- };
- } else {
- obj.spec = {
- resources: {
- limits: { memory: '50Mi', cpu: '500m', 'ephemeral-storage': '50Mi' },
- requests: { memory: '50Mi', cpu: '500m', 'ephemeral-storage': '50Mi' },
- },
- };
- }
+ },
+ };
wrapper = shallow(
{
});
it('renders default values if undefined', () => {
- if (obj.spec) {
- obj.spec.resources = {} as any;
- } else {
- obj.spec = { resources: {} as any };
- }
+ obj.spec = { resources: {} as any };
wrapper.setProps({ obj });
expect(wrapper.find(Button).render().text()).toEqual('CPU: None, Memory: None, Storage: None');
From 8bf23eeee987c08012ef42cdfbf9d1f7d6b3d7ca Mon Sep 17 00:00:00 2001
From: Krish Agarwal
Date: Wed, 3 Sep 2025 14:59:02 -0400
Subject: [PATCH 4/5] Addressed Jon's reviews
---
.../user-preferences/UserPreferenceForm.tsx | 2 +-
.../user-preferences/UserPreferencePage.tsx | 6 +-
.../volume-snapshot-content-details.tsx | 3 +-
.../volume-snapshot-content.tsx | 6 +-
.../volume-snapshot-details.tsx | 2 +-
.../volume-snapshot/volume-snapshot.tsx | 4 +-
.../hooks/useExtensionCatalogCategories.ts | 8 +-
.../components/clusterserviceversion.spec.tsx | 41 +++----
.../src/components/dashboard/csv-status.tsx | 6 +-
.../descriptors/spec/configure-size.tsx | 2 +-
.../spec/configure-update-strategy.tsx | 2 +-
.../src/components/descriptors/spec/index.tsx | 103 +++++++++---------
.../operand/DEPRECATED_operand-form.tsx | 6 +-
.../src/components/operand/index.tsx | 5 +-
.../src/components/operand/operand-link.tsx | 3 +-
.../operator-hub/operator-hub-items.tsx | 15 ++-
.../operator-hub/operator-hub.spec.tsx | 5 +-
.../TopologyOperatorBackedResources.tsx | 9 +-
.../topology/sidebar/resource-sections.tsx | 2 +-
.../src/utils/useClusterServiceVersions.tsx | 2 +-
20 files changed, 118 insertions(+), 114 deletions(-)
diff --git a/frontend/packages/console-app/src/components/user-preferences/UserPreferenceForm.tsx b/frontend/packages/console-app/src/components/user-preferences/UserPreferenceForm.tsx
index c6500b799b0..3e2d88c41fd 100644
--- a/frontend/packages/console-app/src/components/user-preferences/UserPreferenceForm.tsx
+++ b/frontend/packages/console-app/src/components/user-preferences/UserPreferenceForm.tsx
@@ -8,7 +8,7 @@ import './UserPreferenceForm.scss';
type UserPreferenceFormProps = { items: ResolvedUserPreferenceItem[] };
const UserPreferenceForm: React.FC = ({ items }) =>
- items?.length > 0 ? (
+ items && items.length > 0 ? (
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/modals/installplan-approval-modal.spec.tsx b/frontend/packages/operator-lifecycle-manager/src/components/modals/installplan-approval-modal.spec.tsx
index 5f87cff54d8..8b25b9675c1 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/modals/installplan-approval-modal.spec.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/modals/installplan-approval-modal.spec.tsx
@@ -70,7 +70,10 @@ describe(InstallPlanApprovalModal.name, () => {
.find(Radio)
.at(1)
.props()
- .onChange?.({ target: { value: InstallPlanApproval.Manual } } as any, true);
+ .onChange?.(
+ { target: { value: InstallPlanApproval.Manual } } as React.ChangeEvent,
+ true,
+ );
wrapper.find('form').simulate('submit', new Event('submit'));
});
@@ -87,7 +90,10 @@ describe(InstallPlanApprovalModal.name, () => {
.find(Radio)
.at(1)
.props()
- .onChange?.({ target: { value: InstallPlanApproval.Manual } } as any, true);
+ .onChange?.(
+ { target: { value: InstallPlanApproval.Manual } } as React.ChangeEvent,
+ true,
+ );
wrapper.find('form').simulate('submit', new Event('submit'));
});
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/modals/subscription-channel-modal.spec.tsx b/frontend/packages/operator-lifecycle-manager/src/components/modals/subscription-channel-modal.spec.tsx
index e47d183a1af..71352a214fe 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/modals/subscription-channel-modal.spec.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/modals/subscription-channel-modal.spec.tsx
@@ -91,7 +91,7 @@ describe('SubscriptionChannelModal', () => {
.find(Radio)
.at(1)
.props()
- .onChange?.({ target: { value: 'nightly' } } as any, true);
+ .onChange?.({ target: { value: 'nightly' } } as React.ChangeEvent, true);
wrapper.find('form').simulate('submit', new Event('submit'));
});
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/modals/subscription-channel-modal.tsx b/frontend/packages/operator-lifecycle-manager/src/components/modals/subscription-channel-modal.tsx
index 6390ead54d9..a93c9e3c817 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/modals/subscription-channel-modal.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/modals/subscription-channel-modal.tsx
@@ -87,7 +87,7 @@ export const SubscriptionChannelModal: React.FC =
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/modals/uninstall-operator-modal.tsx b/frontend/packages/operator-lifecycle-manager/src/components/modals/uninstall-operator-modal.tsx
index 0d8c2114815..11d74f0f906 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/modals/uninstall-operator-modal.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/modals/uninstall-operator-modal.tsx
@@ -177,8 +177,8 @@ export const UninstallOperatorModal: React.FC = ({
),
]
: []),
- ...(removePlugins
- ? [k8sPatch(ConsoleOperatorConfigModel, consoleOperatorConfig, [patch as any])]
+ ...(removePlugins && patch
+ ? [k8sPatch(ConsoleOperatorConfigModel, consoleOperatorConfig, [patch])]
: []),
];
@@ -343,7 +343,7 @@ export const UninstallOperatorModal: React.FC = ({
operands={operands}
loaded={operandsLoaded}
csvName={csvName || ''}
- cancel={cancel as any} // for breadcrumbs & cancel modal when clicking on operand links
+ cancel={cancel} // for breadcrumbs & cancel modal when clicking on operand links
/>
= ({
) : operandDeletionVerificationError ? (
= ({
= ({ operands, loaded, csvName
.map((operand) => (
-
+
|
= ({ operandErrors, csvN
key={operandError.operand.metadata?.uid || ''}
className="pf-v6-c-list pf-m-plain co-operator-uninstall-alert__list-item"
>
- {' '}
+ {' '}
{operandError.operand.kind}
{' '}
{t('olm~Error: {{error}}', {
@@ -684,13 +684,18 @@ type UninstallOperatorModalProviderProps = UninstallOperatorModalProps & ModalCo
export type UninstallOperatorModalProps = {
cancel?: () => void;
close?: () => void;
- k8sKill: (kind: K8sKind, resource: K8sResourceKind, options: any, json: any) => Promise;
+ k8sKill: (
+ kind: K8sKind,
+ resource: K8sResourceKind,
+ options: unknown,
+ json: unknown,
+ ) => Promise;
k8sGet: (kind: K8sKind, name: string, namespace: string) => Promise;
k8sPatch: (
kind: K8sKind,
resource: K8sResourceKind,
- data: { op: string; path: string; value: any }[],
- ) => Promise;
+ data: { op: string; path: string; value: unknown }[],
+ ) => Promise;
subscription: K8sResourceKind;
csv?: K8sResourceKind;
blocking?: boolean;
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/modals/update-strategy-modal.tsx b/frontend/packages/operator-lifecycle-manager/src/components/modals/update-strategy-modal.tsx
index f21966f68db..9595861d3e4 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/modals/update-strategy-modal.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/modals/update-strategy-modal.tsx
@@ -77,7 +77,7 @@ export const UpdateStrategyModal: React.FC = ({
errorMessage={errorMessage}
inProgress={inProgress}
submitText={t('public~Save')}
- cancel={cancel as any}
+ cancel={cancel}
/>
);
@@ -88,7 +88,7 @@ export const updateStrategyModal = createModalLauncher(UpdateStrategyModal);
UpdateStrategyModal.displayName = 'UpdateStrategyModal';
export type UpdateStrategyModalProps = {
- defaultValue: any;
+ defaultValue;
path: string;
resource: K8sResourceKind;
resourceKind: K8sKind;
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/operand/DEPRECATED_operand-form.tsx b/frontend/packages/operator-lifecycle-manager/src/components/operand/DEPRECATED_operand-form.tsx
index 5516cdc915b..595ca448990 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/operand/DEPRECATED_operand-form.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/operand/DEPRECATED_operand-form.tsx
@@ -162,12 +162,12 @@ const parseArrayPath = (
*/
const modifyArrayFieldPathIndex = (
path: string,
- operation: (index?: number) => string | number,
+ operation: (index: number) => string | number,
): string => {
const { regexMatch, index, pathBeforeIndex, pathAfterIndex } = parseArrayPath(path);
return !regexMatch
? path
- : `${pathBeforeIndex}[${operation(index)}]${pathAfterIndex && `.${pathAfterIndex}`}`;
+ : `${pathBeforeIndex}[${operation(index || 0)}]${pathAfterIndex && `.${pathAfterIndex}`}`;
};
// Accepts a SpecCapbability[] array and returns an appropriate default value for that field
@@ -268,7 +268,7 @@ const flattenNestedProperties = (
property: JSONSchema6,
name: string,
providedAPI: ProvidedAPI,
- obj: K8sResourceKind,
+ obj: K8sResourceKind | Record,
{
currentCapabilities = [],
currentPath = [],
@@ -392,7 +392,7 @@ const getPropertyDepth = (property: JSONSchema6, depth: number = 0): number => {
const fieldsForOpenAPI = (
schema: JSONSchema6,
providedAPI: ProvidedAPI,
- obj: K8sResourceKind,
+ obj: K8sResourceKind | Record,
depth: number = MAX_DEPTH,
): OperandField[] => {
return _.reduce(
@@ -418,7 +418,7 @@ const fieldsForOpenAPI = (
*/
const specDescriptorToFields = (
{ description, displayName, path, 'x-descriptors': capabilities = [] }: Descriptor,
- obj: K8sResourceKind,
+ obj: K8sResourceKind | Record,
): OperandField[] => {
// Use regex to check path for an array index, and parse out the parts of the path before
// and after the array index.
@@ -435,8 +435,8 @@ const specDescriptorToFields = (
displayName,
description,
capabilities,
- type: null as any,
- required: null as any,
+ type: 'string' as JSONSchema6TypeName,
+ required: false,
})),
);
}
@@ -445,8 +445,8 @@ const specDescriptorToFields = (
path: `spec.${path}`,
displayName,
description,
- type: null as any,
- required: null as any,
+ type: 'string' as JSONSchema6TypeName,
+ required: false,
capabilities,
},
];
@@ -514,7 +514,7 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
const { t } = useTranslation();
const params = useParams();
const immutableFormData = Immutable.fromJS(formData);
- const handleFormDataUpdate = (path: string, value: any): void => {
+ const handleFormDataUpdate = (path: string, value: unknown): void => {
const { regexMatch, index, pathBeforeIndex, pathAfterIndex } = parseArrayPath(path);
// Immutable will not initialize a deep path as a List if it includes an integer, so we need to manually
@@ -538,7 +538,7 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
const schemaFields = fieldsForOpenAPI(
schema?.properties?.spec as JSONSchema6,
providedAPI,
- formData as K8sResourceKind,
+ formData || {},
);
// Get fields from providedAPI that do not exist in the OpenAPI spec.
@@ -553,7 +553,7 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
// Add the field if it doesn't exist
return [
...providedAPIFieldsAccumulator,
- ...specDescriptorToFields(specDescriptor, formData as K8sResourceKind),
+ ...specDescriptorToFields(specDescriptor, formData || {}),
];
},
[],
@@ -641,9 +641,9 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
// of the appropriate fields, grouped by index.
return _.map(groupedByName, (fieldsInGroup, groupName: string) => ({
groupName,
- fieldLists: _.reduce(
+ fieldLists: _.reduce(
fieldsInGroup,
- (fieldListsAccumulator: OperandField[][], field) => {
+ (fieldListsAccumulator, field) => {
const { index, regexMatch } = parseArrayPath(field.path);
if (regexMatch) {
fieldListsAccumulator[index || 0] = [
@@ -653,7 +653,7 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
}
return fieldListsAccumulator;
},
- [] as OperandField[][],
+ [],
),
}));
}, [arrayFields]);
@@ -816,7 +816,7 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
desc={displayName}
placeholder={t('olm~Select {{item}}', { item: kindForReference(groupVersionKind) })}
onChange={(value) => handleFormDataUpdate(path, value)}
- selectedKey={currentValue ? `${currentValue}-${k8sModel?.kind}` : undefined}
+ selectedKey={currentValue ? `${currentValue}-${k8sModel?.kind}` : ''}
/>
) : null;
}
@@ -985,7 +985,7 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
const leftShiftedFields = _.reduce(
fieldsToLeftShift,
(fieldAccumulator, field) => {
- const path = modifyArrayFieldPathIndex(field.path, (index) => (index || 1) - 1);
+ const path = modifyArrayFieldPathIndex(field.path, (index) => Math.max(0, index - 1));
return [...fieldAccumulator, { ...field, path }];
},
[],
@@ -1018,7 +1018,7 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
const isExpanded = !_.some(fieldLists, (fieldList: OperandField[]) =>
_.some(
fieldList,
- (f) => hasDescriptor(f as OperandField, SpecCapability.advanced) && !f.required,
+ (f: OperandField) => hasDescriptor(f, SpecCapability.advanced) && !f.required,
),
);
@@ -1041,11 +1041,7 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
)}
{_.map(fieldList, (field) => (
-
+
))}
))}
@@ -1076,7 +1072,7 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
return (
{_.map(fieldList, (field) => (
-
+
))}
);
@@ -1084,7 +1080,7 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
const renderNormalFields = () =>
_.map(normalFields, (field) => (
-
+
)).filter(Boolean);
const renderAdvancedFields = () =>
@@ -1095,7 +1091,7 @@ export const DEPRECATED_CreateOperandForm: React.FC = ({
textCollapsed={t('olm~Advanced configuration')}
>
{_.map(advancedFields, (field) => (
-
+
)).filter(Boolean)}
@@ -1221,7 +1217,7 @@ type FlattenNestedPropertiesAccumulator = {
type OperandFormInputGroupProps = {
field: OperandField;
- input: JSX.Element;
+ input: JSX.Element | null;
};
type FieldGroupProps = {
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/operand/create-operand.tsx b/frontend/packages/operator-lifecycle-manager/src/components/operand/create-operand.tsx
index 7ea9be06761..116db6f0650 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/operand/create-operand.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/operand/create-operand.tsx
@@ -128,7 +128,7 @@ export const CreateOperand: React.FC = ({
{
};
export const OperandStatus: React.FC = ({ operand }) => {
- const { type, value }: OperandStatusType = getOperandStatus(operand);
- if (!type || !value) {
+ const status = getOperandStatus(operand);
+ if (!status) {
return <>->;
}
+ const { type, value } = status;
return (
@@ -284,9 +285,12 @@ export const OperandList: React.FC = (props) => {
return obj;
}
const reference = props.kinds?.[0];
+ if (!reference) {
+ return obj; // Return original object if no reference available
+ }
return {
- apiVersion: apiVersionForReference(reference as any),
- kind: kindForReference(reference as any),
+ apiVersion: apiVersionForReference(reference),
+ kind: kindForReference(reference),
...obj,
};
}) ?? [],
@@ -298,7 +302,7 @@ export const OperandList: React.FC = (props) => {
{...props}
customSorts={{
operandStatus: getOperandStatusText,
- getOperandNamespace: getOperandNamespace as (obj: any) => string,
+ getOperandNamespace: getOperandNamespace as (obj: K8sResourceKind) => string,
}}
data={data}
EmptyMsg={() =>
@@ -445,7 +449,7 @@ export const ProvidedAPIsPage = (props: ProvidedAPIsPageProps) => {
const [staticData, filteredData, onFilterChange] = useListPageFilter(data, rowFilters);
const loaded = Object.values(resources).every((r) => r.loaded);
// only pass the first loadError as StatusBox can only display one
- const loadError: Record = Object.values(resources).find((r) => r.loadError)
+ const loadError: Record = Object.values(resources).find((r) => r.loadError)
?.loadError;
return inFlight ? null : (
@@ -624,12 +628,7 @@ export const OperandDetails = connectToModel(({ crd, csv, kindObj, obj }: Operan
crd?.spec?.versions?.find((v) => v.name === version)?.schema?.openAPIV3Schema ??
(definitionFor(kindObj) as JSONSchema7);
- const {
- podStatuses,
- mainStatusDescriptor,
- conditionsStatusDescriptors,
- otherStatusDescriptors,
- } = (statusDescriptors ?? []).reduce((acc, descriptor) => {
+ const statusDescriptorGroups = (statusDescriptors ?? []).reduce((acc, descriptor) => {
if (isMainStatusDescriptor(descriptor)) {
return {
...acc,
@@ -660,6 +659,13 @@ export const OperandDetails = connectToModel(({ crd, csv, kindObj, obj }: Operan
};
}, {} as any);
+ const {
+ podStatuses = [],
+ mainStatusDescriptor,
+ conditionsStatusDescriptors = [],
+ otherStatusDescriptors = [],
+ } = statusDescriptorGroups;
+
return (
@@ -782,7 +788,9 @@ const DefaultOperandDetailsPage = ({ k8sModel }: DefaultOperandDetailsPageProps)
path: location.pathname.slice(0, location.pathname.lastIndexOf('/')),
},
{
- name: t('olm~{{item}} details', { item: kindForReference(params.plural as any) }), // Use url param in case model doesn't exist
+ name: t('olm~{{item}} details', {
+ item: params.plural ? kindForReference(params.plural) : '',
+ }), // Use url param in case model doesn't exist
path: `${location.pathname}`,
},
]}
@@ -803,8 +811,8 @@ const DefaultOperandDetailsPage = ({ k8sModel }: DefaultOperandDetailsPageProps)
export const OperandDetailsPage = (props) => {
const { plural, ns, name } = useParams();
- const resourceDetailsPage = useResourceDetailsPage(plural as any);
- const [k8sModel, inFlight] = useK8sModel(plural);
+ const resourceDetailsPage = useResourceDetailsPage(plural || '');
+ const [k8sModel, inFlight] = useK8sModel(plural || '');
if (inFlight && !k8sModel) {
return null;
}
@@ -840,9 +848,9 @@ export type OperandListProps = {
filters?: Filter[];
reduxID?: string;
reduxIDs?: string[];
- rowSplitter?: any;
- staticFilters?: any;
- loadError?: Record;
+ rowSplitter?: unknown;
+ staticFilters?: Filter[];
+ loadError?: Record;
noAPIsFound?: boolean;
showNamespace?: boolean;
};
@@ -894,7 +902,7 @@ export type OperandDetailsProps = {
crd: CustomResourceDefinitionKind;
};
-type DefaultOperandDetailsPageProps = { customData: any; k8sModel: K8sModel };
+type DefaultOperandDetailsPageProps = { customData: unknown; k8sModel: K8sModel };
export type OperandResourceDetailsProps = {
csv?: { data: ClusterServiceVersionKind };
@@ -907,7 +915,7 @@ type Header = {
title: string;
sortField?: string;
sortFunc?: string;
- transforms?: any;
+ transforms?: unknown;
props: { className: string };
};
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/operand/operand-form.tsx b/frontend/packages/operator-lifecycle-manager/src/components/operand/operand-form.tsx
index c29ada4bbf5..7e07171f850 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/operand/operand-form.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/operand/operand-form.tsx
@@ -89,7 +89,7 @@ export const OperandForm: React.FC = ({
formContext={{ namespace: params.ns }}
uiSchema={uiSchema}
formData={formData}
- onChange={onChange}
+ onChange={onChange as any}
onError={setErrors}
onSubmit={handleSubmit}
onCancel={handleCancel}
@@ -105,11 +105,11 @@ type ProvidedAPI = CRDDescription | APIServiceDefinition;
export type OperandFormProps = {
formData?: K8sResourceKind;
- onChange?: (formData?: any) => void;
+ onChange?: (formData?: K8sResourceKind) => void;
next?: string;
csv: ClusterServiceVersionKind;
model: K8sKind;
providedAPI: ProvidedAPI;
- prune?: (data: any) => any;
+ prune?: (data: K8sResourceKind) => K8sResourceKind;
schema: JSONSchema7;
};
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/index.ts b/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/index.ts
index d72b718390e..0cb3e483ae1 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/index.ts
+++ b/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/index.ts
@@ -46,23 +46,28 @@ export type OperatorHubItem = {
catalogSourceNamespace: string;
categories: string[];
cloudCredentials: CloudCredentialKind;
+ capabilityLevel?: string | string[];
createdAt?: string;
description: string;
infraFeatures: InfrastructureFeature[];
infrastructure: InfrastructureKind;
installed: boolean;
installState?: InstalledState;
+ isInstalling: boolean;
kind: string;
longDescription: string;
+ marketplaceSupportWorkflow?: string;
name: string;
obj: PackageManifestKind;
provider: string;
+ repository?: string;
source?: string;
subscription?: SubscriptionKind;
tags: string[];
uid: string;
validSubscription: string[];
- [key: string]: any;
+ version: string;
+ [key: string]: unknown;
};
export enum OLMAnnotation {
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-item-details.tsx b/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-item-details.tsx
index 831eca08078..940b35ac37b 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-item-details.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-item-details.tsx
@@ -406,7 +406,15 @@ export const OperatorHubItemDetails: React.FCC = ({
/>
: notAvailable}
+ value={
+ capability ? (
+
+ ) : (
+ notAvailable
+ )
+ }
/>
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-items.tsx b/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-items.tsx
index f7eb93896af..a86da157f9c 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-items.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-items.tsx
@@ -207,8 +207,15 @@ export const getProviderValue = (value: string): string => {
return value;
};
-const sortFilterValues = (values: any[], field: string): any[] => {
- let sorter: any = ['value'];
+interface FilterValue {
+ label: string;
+ synonyms?: string[];
+ value: string;
+ active: boolean;
+}
+
+const sortFilterValues = (values: FilterValue[], field: string): FilterValue[] => {
+ let sorter: ((value: FilterValue) => string | number) | string[] = ['value'];
if (field === 'provider') {
sorter = ({ value }) => providerSort(value);
@@ -237,23 +244,50 @@ const sortFilterValues = (values: any[], field: string): any[] => {
return _.sortBy(values, sorter);
};
+interface FilterState {
+ [key: string]: {
+ [value: string]: FilterValue;
+ };
+}
+
const determineAvailableFilters = (
- initialFilters: any,
+ initialFilters: FilterState,
items: OperatorHubItem[],
filterGroups: string[],
-): any => {
+): FilterState => {
const filters = _.cloneDeep(initialFilters);
_.each(filterGroups, (field) => {
- const values: { label: any; synonyms?: any; value: any; active: boolean }[] = [];
+ const values: FilterValue[] = [];
_.each(items, (item) => {
- let value = item[field];
- let synonyms;
+ let value: string | string[] = '';
+ let synonyms: string[] = [];
+
if (field === 'provider') {
- value = getProviderValue(value);
+ value = getProviderValue(item.provider);
synonyms = _.map(ignoredProviderTails, (tail) => `${value}${tail}`);
+ } else if (field === 'categories') {
+ value = item.categories?.map((cat) => cat.toLowerCase()) ?? [];
+ } else if (field === 'tags') {
+ value = item.tags?.map((tag) => tag.toLowerCase()) ?? [];
+ } else if (field === 'source') {
+ value = item.source ?? '';
+ } else if (field === 'installState') {
+ value = item.installState ?? '';
+ } else if (field === 'capabilityLevel') {
+ value = Array.isArray(item.capabilityLevel)
+ ? item.capabilityLevel
+ : item.capabilityLevel
+ ? [item.capabilityLevel]
+ : [];
+ } else if (field === 'infraFeatures') {
+ value = item.infraFeatures?.map((feature) => feature) ?? [];
+ } else if (field === 'validSubscriptionFilters') {
+ value = item.validSubscription?.map((sub) => sub) ?? [];
+ } else {
+ value = (item as any)[field] as string;
}
- if (value !== undefined && !Array.isArray(value)) {
+ if (value !== undefined && value !== '' && !Array.isArray(value)) {
if (!_.some(values, { value })) {
values.push({
label: value,
@@ -266,7 +300,7 @@ const determineAvailableFilters = (
if (Array.isArray(value)) {
_.each(value, (v) => {
- if (!_.some(values, { v })) {
+ if (!_.some(values, { value: v })) {
values.push({
label: v,
synonyms,
@@ -278,7 +312,7 @@ const determineAvailableFilters = (
}
});
- _.forEach(sortFilterValues(values, field), (nextValue: any) =>
+ _.forEach(sortFilterValues(values, field), (nextValue: FilterValue) =>
_.set(filters, [field, nextValue.value], nextValue),
);
});
@@ -312,11 +346,11 @@ export const keywordCompare = (filterString: string, item: OperatorHubItem): boo
if (!item) {
return false;
}
- const keywords = item.keywords?.map((k) => k.toLowerCase()) ?? [];
+ const keywords = (item.keywords as string[])?.map((k) => k.toLowerCase()) ?? [];
return (
item.name.toLowerCase().includes(filterString) ||
- _.get(item, 'obj.metadata.name', '').toLowerCase().includes(filterString) ||
+ (_.get(item, 'obj.metadata.name', '') as string).toLowerCase().includes(filterString) ||
(item.description && item.description.toLowerCase().includes(filterString)) ||
keywords.includes(filterString)
);
@@ -329,7 +363,7 @@ export const calculateRelevanceScore = (filterString: string, item: OperatorHubI
}
const searchTerm = filterString.toLowerCase();
- const keywords = item.keywords?.map((k) => k.toLowerCase()) ?? [];
+ const keywords = (item.keywords as string[])?.map((k) => k.toLowerCase()) ?? [];
let score = 0;
// Title/Name matches get highest weight
@@ -415,7 +449,7 @@ const getRedHatPriority = (item: OperatorHubItem): number => {
// Check metadata.labels.provider
const metadataProvider = _.get(item, 'obj.metadata.labels.provider', '');
if (metadataProvider) {
- const provider = metadataProvider.toLowerCase();
+ const provider = (metadataProvider as string).toLowerCase();
if (/^red hat(,?\s?inc\.?)?$/.test(provider)) {
return REDHAT_PRIORITY.EXACT_MATCH; // Highest priority for exact matches of 'red hat', 'red hat, inc.', 'red hat inc.', 'red hat inc'
}
@@ -513,7 +547,7 @@ export const orderAndSortByRelevance = (
...itemWithoutScoring,
// Preserve relevanceScore for console table debugging
// eslint-disable-next-line no-underscore-dangle
- relevanceScore: _scoringData.relevanceScore,
+ relevanceScore: (_scoringData as any).relevanceScore,
};
});
};
@@ -524,9 +558,9 @@ const OperatorHubTile: React.FC = ({ item, onClick }) => {
return null;
}
const { uid, name, imgUrl, provider, description, installed } = item;
- const vendor = provider ? t('olm~provided by {{provider}}', { provider }) : null;
+ const vendor = provider ? (t('olm~provided by {{provider}}', { provider }) as string) : null;
const badges = item?.source ? [] : [];
- const icon = ;
+ const icon = ;
const vendorAndDeprecated = () => (
<>
{vendor}
@@ -599,7 +633,7 @@ export const OperatorHubTileView: React.FC = (props) =
}, [filteredItems]);
const getAvailableFiltersFromAllItems = React.useCallback(
- (initialFilters: any, _items: OperatorHubItem[], filterGroups: string[]) => {
+ (initialFilters: FilterState, _items: OperatorHubItem[], filterGroups: string[]) => {
// Always use filteredItems (full list) instead of the passed items (which are already filtered)
return determineAvailableFilters(initialFilters, filteredItems, filterGroups);
},
@@ -641,7 +675,7 @@ export const OperatorHubTileView: React.FC = (props) =
if (selectedCapabilityLevel !== 'all') {
const capabilityLevelsToFilter = JSON.parse(selectedCapabilityLevel);
items = items.filter((item) => {
- const itemCapability = (item as any).capabilityLevel;
+ const itemCapability = item.capabilityLevel;
if (itemCapability) {
if (Array.isArray(itemCapability)) {
return itemCapability.some((level) => capabilityLevelsToFilter.includes(level));
@@ -878,9 +912,12 @@ export const OperatorHubTileView: React.FC = (props) =
if (selectedCategory !== 'all') activeFilters.push(`Category: ${selectedCategory}`);
if (selectedSource !== 'all') activeFilters.push(`Source: ${selectedSource}`);
if (selectedProvider !== 'all') activeFilters.push(`Provider: ${selectedProvider}`);
- if (selectedCapabilityLevel !== 'all') activeFilters.push(`Capability Level: ${selectedCapabilityLevel}`);
- if (selectedInfraFeatures !== 'all') activeFilters.push(`Infrastructure Features: ${selectedInfraFeatures}`);
- if (selectedValidSubscriptionFilters !== 'all') activeFilters.push(`Valid Subscription: ${selectedValidSubscriptionFilters}`);
+ if (selectedCapabilityLevel !== 'all')
+ activeFilters.push(`Capability Level: ${selectedCapabilityLevel}`);
+ if (selectedInfraFeatures !== 'all')
+ activeFilters.push(`Infrastructure Features: ${selectedInfraFeatures}`);
+ if (selectedValidSubscriptionFilters !== 'all')
+ activeFilters.push(`Valid Subscription: ${selectedValidSubscriptionFilters}`);
return activeFilters.length > 0 ? activeFilters.join(', ') : 'No filters applied';
};
@@ -896,9 +933,15 @@ export const OperatorHubTileView: React.FC = (props) =
}))
.filter((item) => item.relevanceScore > 0);
const searchSortedForDisplay = orderAndSortByRelevance(searchFilteredForDisplay, searchTerm);
- console.log('š OperatorHub Items Array (Search Filtered & Sorted):', searchSortedForDisplay.map(item => item.name || 'N/A'));
+ console.log(
+ 'š OperatorHub Items Array (Search Filtered & Sorted):',
+ searchSortedForDisplay.map((item) => item.name || 'N/A'),
+ );
} else {
- console.log('š OperatorHub Items Array:', sortedItems.map(item => item.name || 'N/A'));
+ console.log(
+ 'š OperatorHub Items Array:',
+ sortedItems.map((item) => item.name || 'N/A'),
+ );
}
// Debug: Log component state to identify race conditions
@@ -907,7 +950,7 @@ export const OperatorHubTileView: React.FC = (props) =
filteredItemsCount: filteredItems?.length || 0,
sortedItemsCount: sortedItems?.length || 0,
hasSearchTerm: !!searchTerm,
- isInitialLoad: (!filteredItems || filteredItems.length === 0)
+ isInitialLoad: !filteredItems || filteredItems.length === 0,
});
console.log(`š Current Active Filters: ${getActiveFiltersDescription()}`);
@@ -916,26 +959,30 @@ export const OperatorHubTileView: React.FC = (props) =
// Use memoized sortedItems instead of recalculating
if (searchTerm && sortedItems.length > 0) {
- // For console display, filter items by search term since TileViewPage will do this later
- const searchFilteredItems = sortedItems
- .map((item) => ({
- ...item,
- relevanceScore: calculateRelevanceScore(searchTerm, item),
- }))
- .filter((item) => item.relevanceScore > 0);
-
- // Sort the filtered items the same way TileViewPage will sort them
- const searchSortedItems = orderAndSortByRelevance(searchFilteredItems, searchTerm);
-
- const tableData = searchSortedItems.map((item, index) => ({
+ // For console display, filter items by search term since TileViewPage will do this later
+ const searchFilteredItems = sortedItems
+ .map((item) => ({
+ ...item,
+ relevanceScore: calculateRelevanceScore(searchTerm, item),
+ }))
+ .filter((item) => item.relevanceScore > 0);
+
+ // Sort the filtered items the same way TileViewPage will sort them
+ const searchSortedItems = orderAndSortByRelevance(searchFilteredItems, searchTerm);
+
+ const tableData = searchSortedItems.map((item, index) => ({
Title: item.name || 'N/A',
'Search Relevance Score': item.relevanceScore || 0,
- 'Is Red Hat Provider (Priority)': getRedHatPriority(item) === REDHAT_PRIORITY.EXACT_MATCH ? `Exact Match (${REDHAT_PRIORITY.EXACT_MATCH})` :
- getRedHatPriority(item) === REDHAT_PRIORITY.CONTAINS_REDHAT ? `Contains Red Hat (${REDHAT_PRIORITY.CONTAINS_REDHAT})` : `Non-Red Hat (${REDHAT_PRIORITY.NON_REDHAT})`,
+ 'Is Red Hat Provider (Priority)':
+ getRedHatPriority(item) === REDHAT_PRIORITY.EXACT_MATCH
+ ? `Exact Match (${REDHAT_PRIORITY.EXACT_MATCH})`
+ : getRedHatPriority(item) === REDHAT_PRIORITY.CONTAINS_REDHAT
+ ? `Contains Red Hat (${REDHAT_PRIORITY.CONTAINS_REDHAT})`
+ : `Non-Red Hat (${REDHAT_PRIORITY.NON_REDHAT})`,
// Source: item.source || 'N/A',
'Metadata Provider': _.get(item, 'obj.metadata.labels.provider', 'N/A'),
'Capability Level': (() => {
- const itemCapability = (item as any).capabilityLevel;
+ const itemCapability = item.capabilityLevel;
if (itemCapability) {
if (Array.isArray(itemCapability)) {
return itemCapability.join(', ');
@@ -947,27 +994,39 @@ export const OperatorHubTileView: React.FC = (props) =
const specCapability = _.get(item, 'obj.spec.capabilityLevel', '');
if (specCapability) return specCapability;
- const metadataCapability = _.get(item, 'obj.metadata.annotations["operators.operatorframework.io/capability-level"]', '');
+ const metadataCapability = _.get(
+ item,
+ 'obj.metadata.annotations["operators.operatorframework.io/capability-level"]',
+ '',
+ );
if (metadataCapability) return metadataCapability;
return 'N/A';
})(),
- 'Infrastructure Features': Array.isArray(item.infraFeatures) ? item.infraFeatures.join(', ') : 'N/A',
+ 'Infrastructure Features': Array.isArray(item.infraFeatures)
+ ? item.infraFeatures.join(', ')
+ : 'N/A',
}));
- console.log(`\nš OperatorHub Search Results for "${searchTerm}" (${searchSortedItems.length} matches)`);
+ console.log(
+ `\nš OperatorHub Search Results for "${searchTerm}" (${searchSortedItems.length} matches)`,
+ );
console.log(`š Active Filters: ${getActiveFiltersDescription()}`);
console.table(tableData);
} else if (sortedItems.length > 0) {
// Console table for filtered results without search term (category/filter-based) - using memoized data
const tableData = sortedItems.map((item, index) => ({
Title: item.name || 'N/A',
- 'Is Red Hat Provider (Priority)': getRedHatPriority(item) === REDHAT_PRIORITY.EXACT_MATCH ? `Exact Match (${REDHAT_PRIORITY.EXACT_MATCH})` :
- getRedHatPriority(item) === REDHAT_PRIORITY.CONTAINS_REDHAT ? `Contains Red Hat (${REDHAT_PRIORITY.CONTAINS_REDHAT})` : `Non-Red Hat (${REDHAT_PRIORITY.NON_REDHAT})`,
+ 'Is Red Hat Provider (Priority)':
+ getRedHatPriority(item) === REDHAT_PRIORITY.EXACT_MATCH
+ ? `Exact Match (${REDHAT_PRIORITY.EXACT_MATCH})`
+ : getRedHatPriority(item) === REDHAT_PRIORITY.CONTAINS_REDHAT
+ ? `Contains Red Hat (${REDHAT_PRIORITY.CONTAINS_REDHAT})`
+ : `Non-Red Hat (${REDHAT_PRIORITY.NON_REDHAT})`,
// Source: item.source || 'N/A',
'Metadata Provider': _.get(item, 'obj.metadata.labels.provider', 'N/A'),
'Capability Level': (() => {
- const itemCapability = (item as any).capabilityLevel;
+ const itemCapability = item.capabilityLevel;
if (itemCapability) {
if (Array.isArray(itemCapability)) {
return itemCapability.join(', ');
@@ -979,12 +1038,18 @@ export const OperatorHubTileView: React.FC = (props) =
const specCapability = _.get(item, 'obj.spec.capabilityLevel', '');
if (specCapability) return specCapability;
- const metadataCapability = _.get(item, 'obj.metadata.annotations["operators.operatorframework.io/capability-level"]', '');
+ const metadataCapability = _.get(
+ item,
+ 'obj.metadata.annotations["operators.operatorframework.io/capability-level"]',
+ '',
+ );
if (metadataCapability) return metadataCapability;
return 'N/A';
})(),
- 'Infrastructure Features': Array.isArray(item.infraFeatures) ? item.infraFeatures.join(', ') : 'N/A',
+ 'Infrastructure Features': Array.isArray(item.infraFeatures)
+ ? item.infraFeatures.join(', ')
+ : 'N/A',
}));
console.log(`\nš OperatorHub Filtered Results (${tableData.length} items)`);
@@ -1022,8 +1087,8 @@ export const OperatorHubTileView: React.FC = (props) =
<>
= (props) =
'co-catalog-page__overlay-action',
)}
data-test-id="operator-install-btn"
- to={installLink as any}
+ to={installLink}
>
{t('olm~Install')}
@@ -1054,7 +1119,7 @@ export const OperatorHubTileView: React.FC = (props) =
className="co-catalog-page__overlay-action"
data-test-id="operator-uninstall-btn"
isDisabled={!detailsItem.installed}
- onClick={() => history.push(uninstallLink() as any)}
+ onClick={() => history.push(uninstallLink())}
variant="secondary"
>
{t('olm~Uninstall')}
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-utils.spec.ts b/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-utils.spec.ts
index ab280ca2e68..0b317423515 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-utils.spec.ts
+++ b/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub-utils.spec.ts
@@ -23,7 +23,7 @@ import { InfrastructureFeature, OLMAnnotation, ValidSubscriptionValue } from '.'
describe('getPackageSource', () => {
it('should handle undefined argument', () => {
- const source = getPackageSource(undefined as any);
+ const source = getPackageSource(undefined);
expect(source).toBeUndefined();
});
it('should return correct default Red Hat operator sources', () => {
@@ -53,7 +53,7 @@ describe('getPackageSource', () => {
describe('isAWSSTSCluster', () => {
it('should handle undefined arguments', () => {
- const result = isAWSSTSCluster(undefined as any, undefined as any, undefined as any);
+ const result = isAWSSTSCluster(undefined, undefined, undefined);
expect(result).toEqual(false);
});
it('should return true', () => {
@@ -88,7 +88,7 @@ describe('isAWSSTSCluster', () => {
describe('isAzureWIFCluster', () => {
it('should handle undefined arguments', () => {
- const result = isAzureWIFCluster(undefined as any, undefined as any, undefined as any);
+ const result = isAzureWIFCluster(undefined, undefined, undefined);
expect(result).toEqual(false);
});
it('should return true', () => {
@@ -123,7 +123,7 @@ describe('isAzureWIFCluster', () => {
describe('isGCPWIFCluster', () => {
it('should handle undefined arguments', () => {
- const result = isGCPWIFCluster(undefined as any, undefined as any, undefined as any);
+ const result = isGCPWIFCluster(undefined, undefined, undefined);
expect(result).toEqual(false);
});
it('should return true', () => {
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub.spec.tsx b/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub.spec.tsx
index 7231bb47c32..8aed02938b1 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub.spec.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/operator-hub/operator-hub.spec.tsx
@@ -38,7 +38,7 @@ xdescribe('[https://issues.redhat.com/browse/CONSOLE-2136] OperatorHubList', ()
@@ -144,7 +144,13 @@ xdescribe(`[https://issues.redhat.com/browse/CONSOLE-2136] ${OperatorHubTileView
});
it('updates filter counts on item changes', () => {
- wrapper.setProps(operatorHubTileViewPagePropsWithDummy as any);
+ // Ensure the test data matches the expected OperatorHubItem[] type
+ // This prevents type errors due to missing required properties
+ wrapper.setProps({
+ ...operatorHubTileViewPageProps,
+ ...operatorHubTileViewPagePropsWithDummy,
+ items: operatorHubTileViewPagePropsWithDummy.items as OperatorHubItem[],
+ });
wrapper.update();
const filterItemsChanged = wrapper.find(FilterSidePanelCategoryItem);
@@ -213,7 +219,7 @@ describe(OperatorHubItemDetails.displayName || '', () => {
expect(noMarkdown.exists()).toBe(false);
- wrapper.setProps({ item: itemWithLongDescription as any });
+ wrapper.setProps({ item: itemWithLongDescription });
wrapper.update();
const markdown = wrapper.find(MarkdownView);
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/package-manifest.spec.tsx b/frontend/packages/operator-lifecycle-manager/src/components/package-manifest.spec.tsx
index 75ac1ce7897..b607b92e1af 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/package-manifest.spec.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/package-manifest.spec.tsx
@@ -41,7 +41,7 @@ describe('PackageManifestTableRow', () => {
beforeEach(() => {
jest.spyOn(UIActions, 'getActiveNamespace').mockReturnValue('default');
- const columns: any[] = [];
+ const columns: unknown[] = [];
wrapper = shallow(
{
// This is to verify cataloSource column gets rendered on the Search page for PackageManifest resource
it('renders column for catalog source for a package when no catalog source is defined', () => {
const catalogSourceName = testPackageManifest.status.catalogSource;
- const columns: any[] = [];
+ const columns: unknown[] = [];
wrapper = shallow(
,
);
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/subscription.spec.tsx b/frontend/packages/operator-lifecycle-manager/src/components/subscription.spec.tsx
index 8991f03f64d..b383eb8ce82 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/subscription.spec.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/subscription.spec.tsx
@@ -53,7 +53,8 @@ describe('SubscriptionTableRow', () => {
const updateWrapper = () => {
const rowArgs: RowFunctionArgs = {
obj: subscription,
- } as any;
+ columns: [],
+ };
wrapper = shallow();
return wrapper;
diff --git a/frontend/packages/operator-lifecycle-manager/src/types.ts b/frontend/packages/operator-lifecycle-manager/src/types.ts
index 64438568e1c..4231d565834 100644
--- a/frontend/packages/operator-lifecycle-manager/src/types.ts
+++ b/frontend/packages/operator-lifecycle-manager/src/types.ts
@@ -123,7 +123,7 @@ export type ClusterServiceVersionKind = {
serviceAccountName: string;
rules: { apiGroups: string[]; resources: string[]; verbs: string[] }[];
}[];
- deployments: { name: string; spec: any }[];
+ deployments: { name: string; spec: unknown }[];
};
};
customresourcedefinitions?: { owned?: CRDDescription[]; required?: CRDDescription[] };
diff --git a/frontend/public/components/factory/modal.tsx b/frontend/public/components/factory/modal.tsx
index c6537eb35da..946ae437790 100644
--- a/frontend/public/components/factory/modal.tsx
+++ b/frontend/public/components/factory/modal.tsx
@@ -20,7 +20,7 @@ export const createModal: CreateModal = (getModalElement) => {
if (e && e.stopPropagation) {
e.stopPropagation();
}
- ReactDOM.unmountComponentAtNode(containerElement);
+ containerElement && ReactDOM.unmountComponentAtNode(containerElement);
resolve();
};
Modal.setAppElement(document.getElementById('app-content'));
@@ -134,7 +134,7 @@ export const ModalFooter: React.FC = ({
infoMessage={message}
inProgress={inProgress}
>
- {children}
+ {children || null}
);
};
@@ -157,12 +157,12 @@ export const ModalSubmitFooter: React.FC = ({
const { t } = useTranslation();
const onCancelClick = (e) => {
e.stopPropagation();
- cancel(e);
+ cancel?.(e);
};
const onResetClick = (e) => {
e.stopPropagation();
- reset(e);
+ reset?.(e);
};
const cancelButton = (
@@ -268,7 +268,7 @@ export type ModalSubmitFooterProps = {
message?: string;
errorMessage?: string;
inProgress: boolean;
- cancel: (e: React.SyntheticEvent) => void;
+ cancel?: (e: React.SyntheticEvent) => void;
cancelText?: React.ReactNode;
className?: string;
resetText?: React.ReactNode;
| |