Skip to content

Commit 755d829

Browse files
committed
feat: add TypeScript interfaces and utility functions for resource detail formatting
Signed-off-by: Amit Amrutiya <[email protected]>
1 parent 081d695 commit 755d829

File tree

2 files changed

+355
-0
lines changed

2 files changed

+355
-0
lines changed
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
2+
import { ComponentType, ReactNode } from 'react';
3+
4+
export interface PrimaryDetailsProps {
5+
title: string;
6+
value: string;
7+
hide?: boolean;
8+
}
9+
10+
export interface CopyToClipboardProps {
11+
data: string;
12+
}
13+
14+
export interface CollapsibleSectionProps {
15+
title: string;
16+
children: ReactNode;
17+
showAll?: boolean;
18+
numberText?: string | number;
19+
level?: number;
20+
}
21+
22+
export interface SectionHeadingProps {
23+
children: string;
24+
}
25+
26+
export interface LongDetailsProps {
27+
title: string;
28+
value: string;
29+
}
30+
31+
export interface NumberStateProps {
32+
title?: string;
33+
value: string | number;
34+
quantity: string;
35+
}
36+
37+
export interface EnvironmentVariablesProps {
38+
title: string;
39+
value?: string;
40+
hide?: boolean;
41+
}
42+
43+
export interface CategoryProps {
44+
title: string;
45+
hide?: boolean;
46+
}
47+
48+
export interface NumberStateData {
49+
title: string;
50+
value: string | number;
51+
quantity: string;
52+
}
53+
54+
export interface NumberStateFormatterProps {
55+
data: NumberStateData[];
56+
}
57+
58+
export interface ActionIconButtonProps {
59+
title: string;
60+
Icon: ComponentType<{ fill: string; height?: number; width?: number }>;
61+
onClick: () => void;
62+
}
63+
64+
export interface KeyValueProps {
65+
Key: string;
66+
Value: string | number | ReactNode;
67+
}
68+
69+
export interface EnvironmentFormatterProps {
70+
data?: {
71+
name: string;
72+
value?: string;
73+
valueFrom?: {
74+
[key: string]: {
75+
apiVersion: string;
76+
fieldPath: string;
77+
};
78+
};
79+
}[];
80+
}
81+
82+
export interface CodeFormatterProps {
83+
data: any;
84+
}
85+
86+
export interface PortsFormatterProps {
87+
data?: {
88+
name?: string;
89+
containerPort?: number;
90+
port?: number;
91+
protocol: string;
92+
}[];
93+
}
94+
95+
export interface ArrayFormatterProps {
96+
data: any[];
97+
}
98+
99+
export interface ListFormatterProps {
100+
data: string[];
101+
}
102+
103+
export interface OperatorDynamicFormatterProps {
104+
data: any;
105+
level?: number;
106+
}
107+
108+
export interface StatusFormatterProps {
109+
status: string;
110+
rightPosition?: string;
111+
}
112+
113+
export interface LabelFormatterProps {
114+
data: string[];
115+
onClick: (labels: string[]) => void;
116+
selectedLabels: string[];
117+
}
118+
119+
export interface MemoryUsageProps {
120+
allocatable?: {
121+
cpu: string;
122+
memory: string;
123+
'ephemeral-storage': string;
124+
};
125+
capacity?: {
126+
cpu: string;
127+
memory: string;
128+
'ephemeral-storage': string;
129+
};
130+
height?: number;
131+
width?: number;
132+
}
133+
134+
export interface TableDataFormatterProps {
135+
title?: string;
136+
data?: any;
137+
showAll?: boolean;
138+
mainTableData?: any[][];
139+
mainTableCols?: any[];
140+
}
141+
142+
export interface TextWithLinkFormatterProps {
143+
title: string;
144+
value: string;
145+
variant: 'row' | 'column';
146+
onClick: () => void;
147+
}
148+
149+
export interface JSONViewFormatterProps {
150+
data: any;
151+
}
152+
153+
export interface DetailSectionProps {
154+
title?: string;
155+
data: any;
156+
formatter: React.ComponentType<any>;
157+
}
158+
159+
export interface ContainerFormatterProps {
160+
containerSpec: {
161+
ports?: any[];
162+
imagePullPolicy?: string;
163+
image?: string;
164+
env?: any[];
165+
volumeMounts?: {
166+
name: string;
167+
mountPath: string;
168+
readOnly?: boolean;
169+
}[];
170+
command?: any[];
171+
livenessProbe?: any;
172+
readinessProbe?: any;
173+
startupProbe?: any;
174+
args?: any[];
175+
resources?: {
176+
requests?: any;
177+
limits?: any;
178+
};
179+
};
180+
containerStatus: {
181+
state: {
182+
[key: string]: {
183+
startedAt?: string;
184+
};
185+
};
186+
restartCount: number;
187+
containerID: string;
188+
};
189+
}
190+
191+
export interface SecretFormatterProps {
192+
data: string;
193+
}
194+
195+
export interface NumberState {
196+
title: string;
197+
value: number | string;
198+
quantity: string;
199+
}
200+
201+
export interface Resource {
202+
status?: {
203+
attribute?: string;
204+
containerStatuses?: Array<{ restartCount?: number }>;
205+
nodeInfo?: { kubeletVersion?: string };
206+
podIP?: string;
207+
hostIP?: string;
208+
qosClass?: string;
209+
replicas?: number;
210+
availableReplicas?: number;
211+
readyReplicas?: number;
212+
loadBalancer?: { ingress?: Array<{ ip?: string }> };
213+
allocatable?: Record<string, string>;
214+
capacity?: Record<string, string>;
215+
conditions?: Array<{ type?: string }>;
216+
};
217+
spec?: {
218+
attribute?: string;
219+
containers?: Array<{ image?: string }>;
220+
initContainers?: Array<{ name?: string }>;
221+
nodeSelector?: Record<string, string>;
222+
template?: {
223+
spec?: {
224+
containers?: Array<{ image?: string }>;
225+
nodeSelector?: Record<string, string>;
226+
};
227+
};
228+
resources?: { requests?: { storage?: string } };
229+
claimRef?: { name?: string; namespace?: string };
230+
storageClassName?: string;
231+
type?: string;
232+
clusterIP?: string;
233+
updateStrategy?: { type?: string };
234+
externalIPs?: string[];
235+
finalizers?: string[];
236+
accessModes?: string[];
237+
selector?: { matchLabels?: Record<string, string> };
238+
serviceAccountName?: string;
239+
tolerations?: unknown;
240+
volumes?: unknown;
241+
rules?: Array<{ host?: string }>;
242+
};
243+
metadata?: {
244+
creationTimestamp?: string;
245+
namespace?: string;
246+
labels?: Array<{ key?: string; value?: string }>;
247+
annotations?: Array<{ key?: string; value?: string }>;
248+
};
249+
kind?: string;
250+
apiVersion?: string;
251+
configuration?: {
252+
spec?: { strategy?: { type?: string } };
253+
data?: unknown;
254+
};
255+
type?: string;
256+
data?: string;
257+
}
258+
259+
export interface GetResourceCleanDataProps {
260+
resource: Resource;
261+
dispatchMsgToEditor?: (msg: any) => void;
262+
activeLabels?: string[];
263+
showStatus?: boolean;
264+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
2+
import _ from 'lodash';
3+
4+
interface TableData {
5+
name: string;
6+
[key: string]: string | number | undefined;
7+
}
8+
9+
interface TableColumn {
10+
name: string;
11+
label: string;
12+
options: {
13+
sort: boolean;
14+
};
15+
}
16+
17+
interface TableStructure {
18+
key: string;
19+
columns: TableColumn[];
20+
rows: TableData[];
21+
}
22+
23+
export const splitCamelCaseString = (str: string): string => {
24+
const pluralPatternRegex = /(?<=\w)[A-Z]+s$/;
25+
const pluralMatches = str.match(pluralPatternRegex);
26+
27+
if (!pluralMatches) {
28+
return _.startCase(str);
29+
}
30+
const reconstructedInput = str.replace(pluralPatternRegex, '');
31+
32+
return _.startCase(reconstructedInput) + ' ' + pluralMatches[0];
33+
};
34+
35+
export const extractPodVolumnTables = (data: TableData[] | null): TableStructure[] => {
36+
if (!data) {
37+
return [];
38+
}
39+
const uniqueKeys = _.uniq(
40+
_.flatMap(data, (item) => Object.keys(item).filter((key) => key !== 'name'))
41+
);
42+
43+
return uniqueKeys.map((key) => {
44+
const rows = data
45+
.filter((item) => _.has(item, key))
46+
.map((item) => {
47+
const baseData: TableData = { name: item.name };
48+
const nestedData = _.get(item, key);
49+
50+
if (_.isObject(nestedData)) {
51+
Object.entries(nestedData).forEach(([nestedKey, value]) => {
52+
baseData[nestedKey] =
53+
nestedKey === 'defaultMode'
54+
? value?.toString()
55+
: nestedKey === 'sources' && _.isArray(value)
56+
? value?.length
57+
: JSON.stringify(value);
58+
});
59+
} else {
60+
baseData[key] = JSON.stringify(nestedData);
61+
}
62+
63+
return baseData;
64+
});
65+
66+
const columns: TableColumn[] = rows.length
67+
? Object.keys(rows[0]).map((columnKey) => ({
68+
name: columnKey,
69+
label: _.startCase(columnKey),
70+
options: {
71+
sort: false
72+
}
73+
}))
74+
: [];
75+
76+
return { key, columns, rows };
77+
});
78+
};
79+
80+
export function isEmptyAtAllDepths(input: any): boolean {
81+
if (_.isArray(input)) {
82+
// If the input is an array, check if all items are empty at all depths
83+
return input.every(isEmptyAtAllDepths);
84+
} else if (_.isObject(input)) {
85+
// If the input is an object, check if all properties are empty at all depths
86+
return _.every(input, isEmptyAtAllDepths);
87+
} else {
88+
// If the input is not an array or object, check if it's empty
89+
return _.isEmpty(input);
90+
}
91+
}

0 commit comments

Comments
 (0)