Skip to content

Commit 44c6e97

Browse files
authored
Merge pull request #872 from amitamrutiya/custom-formatters
Create custom formatters and the resource data extract hooks for the resource detail view
2 parents e8f61e1 + 693950c commit 44c6e97

File tree

15 files changed

+2486
-3
lines changed

15 files changed

+2486
-3
lines changed

package-lock.json

Lines changed: 549 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,10 @@
116116
"access": "public"
117117
},
118118
"dependencies": {
119+
"billboard.js": "^3.14.3",
119120
"js-yaml": "^4.1.0",
120121
"lodash": "^4.17.21",
122+
"moment": "^2.30.1",
121123
"react-share": "^5.1.0"
122124
}
123125
}

src/custom/BBChart/BBChart.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { ChartOptions, bb } from 'billboard.js';
2+
import { memo, useEffect, useRef } from 'react';
3+
4+
interface BBChartProps {
5+
options: ChartOptions;
6+
}
7+
8+
const BBChart = ({ options }: BBChartProps) => {
9+
const _chartRef = useRef<HTMLDivElement | null>(null);
10+
11+
useEffect(() => {
12+
if (!_chartRef.current) return;
13+
14+
const chart = bb.generate({
15+
bindto: _chartRef.current,
16+
...options
17+
});
18+
19+
return () => {
20+
chart.destroy();
21+
};
22+
}, [options]);
23+
24+
return <div ref={_chartRef} onClickCapture={(e) => e.stopPropagation()} />;
25+
};
26+
27+
export default memo(BBChart);

src/custom/BBChart/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import BBChart from './BBChart';
2+
3+
export { BBChart };
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
import React from 'react';
2+
import { Grid, IconButton, Typography } from '../../base';
3+
import { iconSmall } from '../../constants/iconsSizes';
4+
import { CopyIcon } from '../../icons';
5+
import { useTheme } from '../../theme';
6+
import { CustomTooltip } from './../CustomTooltip';
7+
import { NumberState } from './Formatter';
8+
import {
9+
Details,
10+
ElementDataWrap,
11+
Heading,
12+
KeyValueGrid,
13+
KeyValueGridCell,
14+
KeyValueGridTitle,
15+
LongWrap,
16+
StyledNumberBox,
17+
Title,
18+
VariableSubfield,
19+
Wrap
20+
} from './styles';
21+
import {
22+
ActionIconButtonProps,
23+
CategoryProps,
24+
CopyToClipboardProps,
25+
EnvironmentVariablesProps,
26+
KeyValueProps,
27+
LongDetailsProps,
28+
NumberStateFormatterProps,
29+
PrimaryDetailsProps,
30+
SectionHeadingProps
31+
} from './types';
32+
import { splitCamelCaseString } from './utils.js';
33+
34+
export const PrimaryDetails: React.FC<PrimaryDetailsProps> = ({ title, value, hide = false }) => {
35+
const titleFormatted = splitCamelCaseString(title);
36+
const show = hide === false ? hide : true;
37+
38+
if (!value || value === ` `) {
39+
return null;
40+
}
41+
42+
if (show) {
43+
return (
44+
<Details noPadding={true}>
45+
<Wrap>
46+
<Typography variant="body1">{titleFormatted}: </Typography>
47+
<ElementDataWrap>{value}</ElementDataWrap>
48+
</Wrap>
49+
</Details>
50+
);
51+
}
52+
return null;
53+
};
54+
55+
export const CopyToClipboard: React.FC<CopyToClipboardProps> = ({ data }) => {
56+
const theme = useTheme();
57+
const copyToClipboard = () => {
58+
navigator.clipboard.writeText(data);
59+
};
60+
61+
return (
62+
<span
63+
style={{
64+
display: 'flex',
65+
alignItems: 'center',
66+
cursor: 'pointer'
67+
}}
68+
>
69+
<IconButton onClickCapture={copyToClipboard} style={{ paddingBlock: '4px' }}>
70+
<CopyIcon height={20} width={20} fill={theme.palette.icon.secondary} />
71+
</IconButton>
72+
</span>
73+
);
74+
};
75+
76+
export const SectionHeading: React.FC<SectionHeadingProps> = ({ children }) => {
77+
return <Typography variant="body1">{children + ':'}</Typography>;
78+
};
79+
80+
export const LongDetails: React.FC<LongDetailsProps> = ({ title, value }) => {
81+
const titleFormatted = splitCamelCaseString(title);
82+
83+
if (!value || value === ` `) {
84+
return null;
85+
}
86+
87+
return (
88+
<Details noPadding={true}>
89+
<LongWrap>
90+
<SectionHeading>{titleFormatted}</SectionHeading>
91+
{/* <CodeFormatter data={value} /> */}
92+
</LongWrap>
93+
</Details>
94+
);
95+
};
96+
97+
export const EnvironmentVariables: React.FC<EnvironmentVariablesProps> = ({ title, value }) => {
98+
return (
99+
<Details noPadding>
100+
<LongWrap>
101+
<VariableSubfield>
102+
{title}:{value}
103+
</VariableSubfield>
104+
</LongWrap>
105+
</Details>
106+
);
107+
};
108+
109+
export const Category: React.FC<CategoryProps> = ({ title, hide = false }) => {
110+
const show = hide === false ? hide : true;
111+
112+
if (show) {
113+
return (
114+
<Heading>
115+
<Title>{title}</Title>
116+
</Heading>
117+
);
118+
}
119+
return null;
120+
};
121+
122+
export const NumberStateFormatter: React.FC<NumberStateFormatterProps> = ({ data }) => {
123+
if (!data) {
124+
return null;
125+
}
126+
127+
return (
128+
<StyledNumberBox>
129+
{data.map((item) => (
130+
<NumberState
131+
key={item.title}
132+
title={item.title}
133+
value={item.value}
134+
quantity={item.quantity}
135+
/>
136+
))}
137+
</StyledNumberBox>
138+
);
139+
};
140+
141+
export const ActionIconButton: React.FC<ActionIconButtonProps> = ({ title, Icon, onClick }) => {
142+
const theme = useTheme();
143+
return (
144+
<CustomTooltip title={title}>
145+
<div>
146+
<IconButton size="small" onClickCapture={onClick}>
147+
<Icon {...iconSmall} fill={theme.palette.icon.default} />
148+
</IconButton>
149+
</div>
150+
</CustomTooltip>
151+
);
152+
};
153+
154+
export const KeyValueInRow: React.FC<KeyValueProps> = ({ Key, Value }) => {
155+
if (!Value || !Key) return null;
156+
return (
157+
<KeyValueGrid container>
158+
<React.Fragment key={Key}>
159+
<KeyValueGridCell item xs={3}>
160+
<KeyValueGridTitle>{Key}</KeyValueGridTitle>
161+
</KeyValueGridCell>
162+
<Grid item xs={9}>
163+
<div>{React.isValidElement(Value) ? Value : String(Value)}</div>
164+
</Grid>
165+
</React.Fragment>
166+
</KeyValueGrid>
167+
);
168+
};
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
2+
import { OperatorDataContainer } from './styles';
3+
import { isEmptyAtAllDepths } from './utils';
4+
5+
interface OperatorDataFormatterProps {
6+
data: any;
7+
FormatStructuredData: any;
8+
propertyFormatter: any;
9+
}
10+
11+
export const OperatorDataFormatter = ({
12+
data,
13+
FormatStructuredData,
14+
propertyFormatter
15+
}: OperatorDataFormatterProps) => {
16+
if (!data || isEmptyAtAllDepths(data)) {
17+
return null;
18+
}
19+
20+
return (
21+
<OperatorDataContainer>
22+
<FormatStructuredData data={data} propertyFormatters={propertyFormatter} isLevel={false} />
23+
</OperatorDataContainer>
24+
);
25+
};
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
2+
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
3+
import { iconMedium } from '../../constants/iconsSizes';
4+
import { useTheme } from '../../theme';
5+
6+
interface ExpandArrowProps {
7+
expanded: boolean;
8+
}
9+
10+
const ExpandArrow: React.FC<ExpandArrowProps> = ({ expanded }) => {
11+
const theme = useTheme();
12+
return expanded ? (
13+
<ExpandLessIcon fill={theme.palette.icon.default} {...iconMedium} />
14+
) : (
15+
<ExpandMoreIcon fill={theme.palette.icon.default} {...iconMedium} />
16+
);
17+
};
18+
19+
export default ExpandArrow;

0 commit comments

Comments
 (0)