Skip to content

Commit faf9893

Browse files
Refactored components
1 parent 6f7d69f commit faf9893

File tree

5 files changed

+128
-47
lines changed

5 files changed

+128
-47
lines changed

src/components/CustomResources/CustomResources.jsx renamed to src/components/CustomResources/CustomResources.tsx

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { FormEventHandler, RefObject } from 'react';
12
import jp from 'jsonpath';
23
import pluralize from 'pluralize';
34

@@ -8,6 +9,27 @@ import CRCreate from 'resources/CustomResourceDefinitions/CRCreate';
89
import { useUrl } from 'hooks/useUrl';
910
import { extractApiGroupVersion } from 'resources/Roles/helpers';
1011

12+
export type Version = {
13+
name: string;
14+
served?: boolean;
15+
additionalPrinterColumns?: { name: string; jsonPath: string }[];
16+
};
17+
18+
type CustomResourcesProps = {
19+
crd: {
20+
spec: { group: string; names: { plural: string; kind: string } };
21+
apiVersion: string;
22+
metadata: { name: string; namespace?: string };
23+
};
24+
version: Version;
25+
showTitle?: boolean;
26+
omitColumnsIds?: string[];
27+
hideCreateOption?: boolean;
28+
enableColumnLayout?: boolean;
29+
layoutCloseCreateUrl?: string;
30+
simpleEmptyListMessage?: boolean;
31+
};
32+
1133
export function CustomResources({
1234
crd,
1335
version,
@@ -17,7 +39,7 @@ export function CustomResources({
1739
enableColumnLayout,
1840
layoutCloseCreateUrl,
1941
simpleEmptyListMessage = false,
20-
}) {
42+
}: CustomResourcesProps) {
2143
const { group, names } = crd.spec;
2244
const name = names.plural;
2345
const customUrl = useCustomResourceUrl(crd);
@@ -32,7 +54,7 @@ export function CustomResources({
3254
? `/apis/${group}/${version.name}/namespaces/${namespace}/${name}`
3355
: `/apis/${group}/${version.name}/${name}`;
3456

35-
const getJsonPath = (resource, jsonPath) => {
57+
const getJsonPath = (resource: Record<string, any>, jsonPath: string) => {
3658
// try catch to parse annotations to take value from resource using jsonpath
3759
let value;
3860
try {
@@ -48,7 +70,7 @@ export function CustomResources({
4870
) || EMPTY_TEXT_PLACEHOLDER;
4971
} catch (e) {
5072
console.error(e);
51-
value = e.message;
73+
value = (e as Error)?.message;
5274
}
5375
if (typeof value === 'boolean') {
5476
return value.toString();
@@ -61,12 +83,16 @@ export function CustomResources({
6183

6284
const customColumns = version.additionalPrinterColumns?.map((column) => ({
6385
header: column.name,
64-
value: (resource) => getJsonPath(resource, column.jsonPath),
86+
value: (resource: Record<string, any>) =>
87+
getJsonPath(resource, column.jsonPath),
6588
}));
6689
// CRD can have infinite number of additionalPrinterColumns what would be impossible to fit into the table
67-
if (customColumns?.length > 5) customColumns.length = 5;
90+
if (customColumns?.length && customColumns?.length > 5)
91+
customColumns.length = 5;
6892

69-
const customColumnLayout = (resource) => {
93+
const customColumnLayout = (resource?: {
94+
metadata?: { name?: string; namespace?: string };
95+
}) => {
7096
const { group, version } = extractApiGroupVersion(crd?.apiVersion);
7197
return {
7298
resourceName: resource?.metadata?.name,
@@ -89,9 +115,13 @@ export function CustomResources({
89115
testid: 'crd-custom-resources',
90116
omitColumnsIds,
91117
hideCreateOption,
92-
createResourceForm: (props) => (
93-
<CRCreate {...props} crd={crd} layoutNumber="midColumn" />
94-
),
118+
createResourceForm: (props: {
119+
[x: string]: any;
120+
onChange: FormEventHandler<HTMLElement>;
121+
formElementRef: RefObject<HTMLFormElement>;
122+
layoutNumber: number;
123+
resource: any;
124+
}) => <CRCreate {...props} crd={crd} layoutNumber="midColumn" />,
95125
resourceUrlPrefix: `/apis/${group}/${version.name}`,
96126
searchSettings: {
97127
textSearchProperties: ['metadata.namespace'],
@@ -106,5 +136,6 @@ export function CustomResources({
106136
parentCrdName: crd.metadata.name,
107137
simpleEmptyListMessage,
108138
};
139+
/*@ts-expect-error Type mismatch between js and ts*/
109140
return <ResourcesList {...params} />;
110141
}

src/components/CustomResources/CustomResourcesByGroup.jsx renamed to src/components/CustomResources/CustomResourcesByGroup.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,18 @@ export default function CustomResourcesByGroup() {
1616
);
1717

1818
return (
19+
/*@ts-expect-error Type mismatch between js and ts*/
1920
<GroupingListPage
2021
title={t('custom-resources.title')}
2122
description={description}
22-
filter={(crd) =>
23-
crd.spec.scope === (namespace ? 'Namespaced' : 'Cluster')
23+
filter={(crd: { spec: { scope: string } }) =>
24+
crd?.spec?.scope === (namespace ? 'Namespaced' : 'Cluster')
2425
}
2526
resourceListProps={{
26-
customUrl: (crd) => scopedUrl(`customresources/${crd.metadata.name}`),
27-
nameSelector: (entry) => pluralize(entry?.spec.names.kind || ''),
27+
customUrl: (crd: { metadata: { name: string } }) =>
28+
scopedUrl(`customresources/${crd.metadata.name}`),
29+
nameSelector: (entry?: { spec: { names: { kind: string } } }) =>
30+
pluralize(entry?.spec?.names?.kind || ''),
2831
readOnly: true,
2932
}}
3033
enableColumnLayout={true}

src/components/CustomResources/CustomResourcesOfType.jsx renamed to src/components/CustomResources/CustomResourcesOfType.tsx

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,27 @@ import { useTranslation } from 'react-i18next';
33
import { useGet } from 'shared/hooks/BackendAPI/useGet';
44
import { DynamicPageComponent } from 'shared/components/DynamicPageComponent/DynamicPageComponent';
55
import { Spinner } from 'shared/components/Spinner/Spinner';
6-
import { CustomResources } from 'components/CustomResources/CustomResources';
6+
import {
7+
CustomResources,
8+
Version,
9+
} from 'components/CustomResources/CustomResources';
710
import { useUrl } from 'hooks/useUrl';
811
import YamlUploadDialog from 'resources/Namespaces/YamlUpload/YamlUploadDialog';
912
import { UI5Panel } from 'shared/components/UI5Panel/UI5Panel';
1013
import { Link } from 'shared/components/Link/Link';
1114
import { createPortal } from 'react-dom';
1215

16+
type CustomResourcesOfTypeProps = {
17+
crdName: string;
18+
enableColumnLayout?: boolean;
19+
layoutCloseCreateUrl?: string;
20+
};
21+
1322
export default function CustomResourcesOfType({
1423
crdName,
1524
enableColumnLayout,
1625
layoutCloseCreateUrl,
17-
}) {
26+
}: CustomResourcesOfTypeProps) {
1827
const { t } = useTranslation();
1928
const { clusterUrl } = useUrl();
2029
const {
@@ -26,7 +35,19 @@ export default function CustomResourcesOfType({
2635
{
2736
skip: !crdName,
2837
},
29-
);
38+
) as {
39+
data?: {
40+
spec: {
41+
group: string;
42+
names: { plural: string; kind: string };
43+
versions: Version[];
44+
};
45+
apiVersion: string;
46+
metadata: { name: string; namespace?: string };
47+
} | null;
48+
loading?: boolean;
49+
error?: Error | null;
50+
};
3051

3152
if (loading) return <Spinner />;
3253
if (error) {
@@ -43,27 +64,28 @@ export default function CustomResourcesOfType({
4364

4465
return (
4566
<>
67+
{/*@ts-expect-error Type mismatch between js and ts*/}
4668
<DynamicPageComponent
4769
layoutNumber="midColumn"
48-
title={pluralize(crd.spec.names.kind)}
70+
title={pluralize(crd?.spec?.names?.kind ?? '')}
4971
content={
5072
<CustomResources
5173
crd={crd}
52-
version={crd.spec.versions.find((v) => v.served)}
74+
version={crd?.spec?.versions?.find((v) => v.served) as Version}
5375
showTitle={false}
54-
showNamespace={false}
5576
enableColumnLayout={enableColumnLayout}
5677
layoutCloseCreateUrl={layoutCloseCreateUrl}
5778
/>
5879
}
5980
>
81+
{/*@ts-expect-error Type mismatch between js and ts*/}
6082
<DynamicPageComponent.Column
6183
title={t('custom-resource-definitions.name_singular')}
6284
>
6385
<Link
64-
url={clusterUrl(`customresourcedefinitions/${crd.metadata.name}`)}
86+
url={clusterUrl(`customresourcedefinitions/${crd?.metadata?.name}`)}
6587
>
66-
{crd.metadata.name}
88+
{crd?.metadata?.name}
6789
</Link>
6890
</DynamicPageComponent.Column>
6991
</DynamicPageComponent>

src/components/CustomResources/GroupingListPage.jsx renamed to src/components/CustomResources/GroupingListPage.tsx

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState } from 'react';
1+
import { ComponentProps, useState } from 'react';
22
import { useTranslation } from 'react-i18next';
33
import { groupBy } from 'lodash';
44
import { Tokens } from 'shared/components/Tokens';
@@ -14,21 +14,39 @@ import { UI5Panel } from 'shared/components/UI5Panel/UI5Panel';
1414
import { createPortal } from 'react-dom';
1515
import './GroupingListPage.scss';
1616

17+
type Crd = {
18+
metadata: { name: string };
19+
spec: { names: { categories?: string[] }; group: string; scope: string };
20+
};
21+
22+
type GroupingListPageProps = {
23+
title: string;
24+
description?: string;
25+
filter?: (entry: any) => boolean;
26+
resourceListProps?: Partial<ComponentProps<typeof ResourceListRenderer>>;
27+
showCrdScope?: boolean;
28+
enableColumnLayout?: boolean;
29+
};
30+
1731
export function GroupingListPage({
1832
title,
1933
description,
2034
filter,
2135
resourceListProps,
2236
showCrdScope,
2337
enableColumnLayout,
24-
}) {
38+
}: GroupingListPageProps) {
2539
const [searchQuery, setSearchQuery] = useState('');
2640
const { t } = useTranslation();
2741
useWindowTitle(title);
2842

2943
const resourceUrl = `/apis/apiextensions.k8s.io/v1/customresourcedefinitions`;
30-
const { data, loading, error } = useGetList(filter)(resourceUrl);
31-
const crdsByGroup = groupBy(data, (e) => e.spec.group);
44+
const { data, loading, error } = useGetList(filter)(resourceUrl) as {
45+
data: Crd[] | null;
46+
loading?: boolean;
47+
error?: Error | null;
48+
};
49+
const crdsByGroup = groupBy(data, (e) => e?.spec?.group);
3250

3351
if (loading) {
3452
return <Spinner />;
@@ -47,15 +65,18 @@ export function GroupingListPage({
4765
if (searchQuery) {
4866
const query = searchQuery.toLowerCase();
4967

50-
const removeEmpty = ([, crds]) => crds.length;
68+
const removeEmpty = ([_, crds]: [any, Crd[]]) => crds?.length;
5169

52-
const filterBySearchQuery = (crd) =>
70+
const filterBySearchQuery = (crd: Crd) =>
5371
crd.metadata.name.includes(query) ||
5472
crd.spec.names.categories?.includes(query);
5573

5674
entries = entries
57-
.map(([group, crds]) => [group, crds.filter(filterBySearchQuery)])
58-
.filter(removeEmpty);
75+
.map(([group, crds]): [string, Crd[]] => [
76+
group,
77+
crds.filter(filterBySearchQuery),
78+
])
79+
.filter(([group, crds]) => removeEmpty([group, crds]));
5980
}
6081

6182
const lists = (
@@ -64,6 +85,7 @@ export function GroupingListPage({
6485
.sort(([groupA], [groupB]) => groupA.localeCompare(groupB))
6586
.map(([group, crds]) => (
6687
<li key={group} className="cr-group-list-item">
88+
{/*@ts-expect-error Type mismatch between js and ts*/}
6789
<ResourceListRenderer
6890
resourceUrl={resourceUrl}
6991
resourceType="CustomResourceDefinition"
@@ -74,22 +96,24 @@ export function GroupingListPage({
7496
title={group}
7597
resources={crds}
7698
isCompact={true}
77-
customColumns={[
78-
{
79-
header: t('custom-resource-definitions.headers.categories'),
80-
value: (entry) => (
81-
<Tokens tokens={entry.spec.names.categories} />
82-
),
83-
},
84-
...(showCrdScope
85-
? [
86-
{
87-
header: t('scope'),
88-
value: (entry) => entry.spec.scope,
89-
},
90-
]
91-
: []),
92-
]}
99+
customColumns={
100+
[
101+
{
102+
header: t('custom-resource-definitions.headers.categories'),
103+
value: (entry: Crd) => (
104+
<Tokens tokens={entry.spec.names.categories} />
105+
),
106+
},
107+
...(showCrdScope
108+
? [
109+
{
110+
header: t('scope'),
111+
value: (entry: Crd) => entry.spec.scope,
112+
},
113+
]
114+
: []),
115+
] as any
116+
}
93117
searchSettings={{
94118
showSearchField: false,
95119
}}
@@ -102,13 +126,14 @@ export function GroupingListPage({
102126

103127
return (
104128
<>
129+
{/*@ts-expect-error Type mismatch between js and ts*/}
105130
<DynamicPageComponent
106131
title={title}
107132
description={description}
108133
actions={
109134
<SearchInput
110135
entriesKind={title}
111-
value={searchQuery}
136+
searchQuery={searchQuery}
112137
handleQueryChange={setSearchQuery}
113138
allowSlashShortcut
114139
/>

src/shared/components/UI5Panel/UI5Panel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ type UI5PanelProps = {
1515
modeActions?: ReactNode;
1616
keyComponent?: string;
1717
className?: string;
18-
children: ReactNode;
18+
children?: ReactNode;
1919
description?: string;
2020
stickyHeader?: boolean;
2121
headerTop?: string;

0 commit comments

Comments
 (0)