Skip to content

Commit 0f5a1f6

Browse files
authored
Merge pull request #140 from headlamp-k8s/prometheus-update-styles
prometheus: Update look and add interval selector
2 parents 8016526 + f3e6d20 commit 0f5a1f6

File tree

7 files changed

+198
-147
lines changed

7 files changed

+198
-147
lines changed

prometheus/src/components/Chart/CPUChart/CPUChart.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { useTheme } from '@mui/material';
1+
import { alpha, useTheme } from '@mui/material';
2+
import { blue } from '@mui/material/colors';
23
import { fetchMetrics } from '../../../request';
34
import { createTickTimestampFormatter, dataProcessor } from '../../../util';
45
import Chart from '../Chart/Chart';
@@ -45,7 +46,7 @@ export function CPUChart(props: CPUChartProps) {
4546

4647
const YTickProps = {
4748
domain: ['dataMin', 'auto'],
48-
width: 80,
49+
width: 60,
4950
};
5051

5152
return (
@@ -54,8 +55,8 @@ export function CPUChart(props: CPUChartProps) {
5455
{
5556
query: props.query,
5657
name: 'cpu (cores)',
57-
strokeColor: '#CDC300',
58-
fillColor: '#FFF178',
58+
strokeColor: alpha(blue[400], 0.8),
59+
fillColor: alpha(blue[400], 0.1),
5960
dataProcessor: dataProcessor,
6061
},
6162
]}

prometheus/src/components/Chart/Chart/Chart.tsx

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
import { EmptyContent, Loader } from '@kinvolk/headlamp-plugin/lib/CommonComponents';
22
import { Box, useTheme } from '@mui/material';
33
import { useEffect, useState } from 'react';
4-
import { Area, AreaChart, Legend, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts';
4+
import {
5+
Area,
6+
AreaChart,
7+
CartesianGrid,
8+
Legend,
9+
ResponsiveContainer,
10+
Tooltip,
11+
XAxis,
12+
YAxis,
13+
} from 'recharts';
514
import { getTimeRange } from '../../../util';
615

716
/**
@@ -50,10 +59,11 @@ export default function Chart(props: ChartProps) {
5059
SUCCESS,
5160
}
5261
const { fetchMetrics, xAxisProps, yAxisProps } = props;
53-
const [metrics, setMetrics] = useState<object>({});
62+
const [metrics, setMetrics] = useState<Array<any>>([]);
5463
const [state, setState] = useState<ChartState | null>(null);
5564
const [error, setError] = useState<string | null>(null);
5665
const theme = useTheme();
66+
const timeRange = getTimeRange(props.interval);
5767

5868
const fetchMetricsData = async (
5969
plots: Array<{ query: string; name: string; dataProcessor: (data: any) => any }>,
@@ -142,29 +152,38 @@ export default function Chart(props: ChartProps) {
142152
clearInterval(refreshInterval);
143153
};
144154
}
145-
}, [props.autoRefresh, props.plots]);
155+
}, [props.autoRefresh, props.plots, props.interval]);
146156

147157
let chartContent;
148158

149159
if (state === ChartState.SUCCESS) {
150160
chartContent = (
151-
<AreaChart data={metrics}>
152-
<XAxis stroke={theme.palette.chartStyles.labelColor} {...xAxisProps} />
153-
<YAxis stroke={theme.palette.chartStyles.labelColor} {...yAxisProps} />
161+
<AreaChart data={metrics} style={{ fontSize: 14 }}>
162+
<XAxis
163+
stroke={theme.palette.chartStyles.labelColor}
164+
fontSize={12}
165+
{...xAxisProps}
166+
type="number"
167+
domain={[timeRange.from, timeRange.to]}
168+
allowDataOverflow
169+
/>
170+
<YAxis fontSize={14} stroke={theme.palette.chartStyles.labelColor} {...yAxisProps} />
154171
{props.CustomTooltip === undefined ? (
155172
<Tooltip />
156173
) : (
157174
<Tooltip content={props.CustomTooltip} />
158175
)}
159176
<Legend />
177+
<CartesianGrid strokeDasharray="2 4" stroke={theme.palette.divider} vertical={false} />
160178
{props.plots.map(plot => (
161179
<Area
162180
stackId="1"
163-
type="monotone"
181+
type="step"
164182
dataKey={plot.name}
165183
stroke={plot.strokeColor}
184+
strokeWidth={2}
166185
fill={plot.fillColor}
167-
activeDot={{ r: 8 }}
186+
activeDot={{ r: 2 }}
168187
animationDuration={props.autoRefresh ? 0 : 400} // Disable animation when refreshing
169188
/>
170189
))}

prometheus/src/components/Chart/FilesystemChart/FilesystemChart.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { useTheme } from '@mui/material';
1+
import { alpha, useTheme } from '@mui/material';
2+
import { orange, purple } from '@mui/material/colors';
23
import { fetchMetrics } from '../../../request';
34
import { createTickTimestampFormatter, dataProcessor } from '../../../util';
45
import { formatBytes } from '../../../util';
@@ -32,15 +33,15 @@ export function FilesystemChart(props: FilesystemChartProps) {
3233
{
3334
query: props.readQuery,
3435
name: 'read',
35-
strokeColor: '#CDC300',
36-
fillColor: '#FFF178',
36+
strokeColor: alpha(orange[400], 0.8),
37+
fillColor: alpha(orange[400], 0.1),
3738
dataProcessor: dataProcessor,
3839
},
3940
{
4041
query: props.writeQuery,
4142
name: 'write',
42-
strokeColor: '#006B58',
43-
fillColor: '#98F6DC',
43+
strokeColor: alpha(purple[400], 0.8),
44+
fillColor: alpha(purple[400], 0.1),
4445
dataProcessor: dataProcessor,
4546
},
4647
]}

prometheus/src/components/Chart/GenericMetricsChart/GenericMetricsChart.tsx

Lines changed: 137 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,15 @@ import { Icon } from '@iconify/react';
22
import { Loader } from '@kinvolk/headlamp-plugin/lib/CommonComponents';
33
import { SectionBox } from '@kinvolk/headlamp-plugin/lib/CommonComponents';
44
import { useCluster } from '@kinvolk/headlamp-plugin/lib/k8s';
5-
import { Box, IconButton, ToggleButton, ToggleButtonGroup, Tooltip } from '@mui/material';
5+
import {
6+
Box,
7+
Button,
8+
MenuItem,
9+
Paper,
10+
Select,
11+
ToggleButton,
12+
ToggleButtonGroup,
13+
} from '@mui/material';
614
import Alert from '@mui/material/Alert';
715
import { useEffect, useState } from 'react';
816
import { getConfigStore, getPrometheusInterval, getPrometheusPrefix } from '../../../util';
@@ -82,114 +90,142 @@ export function GenericMetricsChart(props: GenericMetricsChartProps) {
8290
setChartVariant(event.currentTarget.value);
8391
};
8492

93+
const interval = getPrometheusInterval(cluster);
94+
95+
const [timespan, setTimespan] = useState(interval ?? '1h');
96+
8597
if (!isVisible) {
8698
return null;
8799
}
88100

89-
const interval = getPrometheusInterval(cluster);
90-
91101
return (
92102
<SectionBox>
93-
<Box
94-
display="flex"
95-
justifyContent="space-around"
96-
alignItems="center"
97-
style={{ marginBottom: '1rem', margin: '0 auto', width: '0' }}
98-
>
99-
{state === prometheusState.INSTALLED
100-
? [
101-
<ToggleButtonGroup
102-
onChange={handleChartVariantChange}
103+
<Paper variant="outlined" sx={{ p: 1 }}>
104+
{state === prometheusState.INSTALLED && (
105+
<Box display="flex" gap={1} justifyContent="flex-end" mb={2}>
106+
<Button
107+
variant="outlined"
108+
size="small"
109+
onClick={() => {
110+
setRefresh(refresh => !refresh);
111+
}}
112+
startIcon={<Icon icon={refresh ? 'mdi:pause' : 'mdi:play'} />}
113+
sx={{ filter: 'grayscale(1.0)' }}
114+
>
115+
{refresh ? 'Pause' : 'Resume'}
116+
</Button>
117+
<ToggleButtonGroup
118+
onChange={handleChartVariantChange}
119+
size="small"
120+
aria-label="metric chooser"
121+
value={chartVariant}
122+
exclusive
123+
>
124+
<CustomToggleButton label="CPU" value="cpu" icon="mdi:chip" />
125+
<CustomToggleButton label="Memory" value="memory" icon="mdi:memory" />
126+
<CustomToggleButton
127+
label="Network"
128+
value="network"
129+
icon="mdi:folder-network-outline"
130+
/>
131+
<CustomToggleButton label="Filesystem" value="filesystem" icon="mdi:database" />
132+
</ToggleButtonGroup>
133+
<Box>
134+
<Select
135+
variant="outlined"
103136
size="small"
104-
aria-label="metric chooser"
105-
value={chartVariant}
106-
exclusive
137+
name="Time"
138+
value={timespan}
139+
onChange={e => setTimespan(e.target.value)}
107140
>
108-
<ToggleButton value="cpu">CPU</ToggleButton>
109-
<ToggleButton value="memory">Memory</ToggleButton>
110-
<ToggleButton value="network">Network</ToggleButton>
111-
<ToggleButton value="filesystem">Filesystem</ToggleButton>
112-
</ToggleButtonGroup>,
113-
<Box pl={2}>
114-
<IconButton
115-
onClick={() => {
116-
setRefresh(refresh => !refresh);
117-
}}
118-
size="large"
119-
>
120-
{refresh ? (
121-
<Tooltip title="Pause metrics">
122-
{' '}
123-
<Icon icon="mdi:pause" />{' '}
124-
</Tooltip>
125-
) : (
126-
<Tooltip title="Resume metrics">
127-
{' '}
128-
<Icon icon="mdi:play" />{' '}
129-
</Tooltip>
130-
)}
131-
</IconButton>
132-
</Box>,
133-
]
134-
: []}
135-
</Box>
136-
137-
{state === prometheusState.INSTALLED ? (
138-
<Box
139-
style={{
140-
justifyContent: 'center',
141-
display: 'flex',
142-
height: '40vh',
143-
width: '80%',
144-
margin: '0 auto',
145-
}}
146-
>
147-
{chartVariant === 'cpu' && (
148-
<CPUChart
149-
query={props.cpuQuery}
150-
autoRefresh={refresh}
151-
prometheusPrefix={prometheusPrefix}
152-
interval={interval}
153-
/>
154-
)}
155-
{chartVariant === 'memory' && (
156-
<MemoryChart
157-
query={props.memoryQuery}
158-
autoRefresh={refresh}
159-
prometheusPrefix={prometheusPrefix}
160-
interval={interval}
161-
/>
162-
)}
163-
{chartVariant === 'network' && (
164-
<NetworkChart
165-
rxQuery={props.networkRxQuery}
166-
txQuery={props.networkTxQuery}
167-
autoRefresh={refresh}
168-
interval={interval}
169-
prometheusPrefix={prometheusPrefix}
170-
/>
171-
)}
172-
{chartVariant === 'filesystem' && (
173-
<FilesystemChart
174-
readQuery={props.filesystemReadQuery}
175-
writeQuery={props.filesystemWriteQuery}
176-
autoRefresh={refresh}
177-
interval={interval}
178-
prometheusPrefix={prometheusPrefix}
179-
/>
180-
)}
181-
</Box>
182-
) : state === prometheusState.LOADING ? (
183-
<Box m={2}>
184-
<Loader title="Loading Prometheus Info" />
185-
</Box>
186-
) : state === prometheusState.ERROR ? (
187-
<Box m={2}>
188-
<Alert severity="warning">Error fetching prometheus Info</Alert>
189-
</Box>
190-
) : (
191-
<PrometheusNotFoundBanner />
192-
)}
141+
<MenuItem value={'10m'}>10 minutes</MenuItem>
142+
<MenuItem value={'30m'}>30 minutes</MenuItem>
143+
<MenuItem value={'1h'}>1 hour</MenuItem>
144+
<MenuItem value={'3h'}>3 hours</MenuItem>
145+
<MenuItem value={'6h'}>6 hours</MenuItem>
146+
<MenuItem value={'12h'}>12 hours</MenuItem>
147+
<MenuItem value={'24h'}>24 hours</MenuItem>
148+
<MenuItem value={'48h'}>48 hours</MenuItem>
149+
<MenuItem value={'today'}>Today</MenuItem>
150+
<MenuItem value={'yesterday'}>Yesterday</MenuItem>
151+
<MenuItem value={'week'}>Week</MenuItem>
152+
<MenuItem value={'lastweek'}>Last week</MenuItem>
153+
<MenuItem value={'7d'}>7 days</MenuItem>
154+
<MenuItem value={'14d'}>14 days</MenuItem>
155+
</Select>
156+
</Box>
157+
</Box>
158+
)}
159+
{state === prometheusState.INSTALLED ? (
160+
<Box
161+
style={{
162+
height: '400px',
163+
}}
164+
>
165+
{chartVariant === 'cpu' && (
166+
<CPUChart
167+
query={props.cpuQuery}
168+
autoRefresh={refresh}
169+
prometheusPrefix={prometheusPrefix}
170+
interval={timespan}
171+
/>
172+
)}
173+
{chartVariant === 'memory' && (
174+
<MemoryChart
175+
query={props.memoryQuery}
176+
autoRefresh={refresh}
177+
prometheusPrefix={prometheusPrefix}
178+
interval={timespan}
179+
/>
180+
)}
181+
{chartVariant === 'network' && (
182+
<NetworkChart
183+
rxQuery={props.networkRxQuery}
184+
txQuery={props.networkTxQuery}
185+
autoRefresh={refresh}
186+
interval={timespan}
187+
prometheusPrefix={prometheusPrefix}
188+
/>
189+
)}
190+
{chartVariant === 'filesystem' && (
191+
<FilesystemChart
192+
readQuery={props.filesystemReadQuery}
193+
writeQuery={props.filesystemWriteQuery}
194+
autoRefresh={refresh}
195+
interval={timespan}
196+
prometheusPrefix={prometheusPrefix}
197+
/>
198+
)}
199+
</Box>
200+
) : state === prometheusState.LOADING ? (
201+
<Box m={2}>
202+
<Loader title="Loading Prometheus Info" />
203+
</Box>
204+
) : state === prometheusState.ERROR ? (
205+
<Box m={2}>
206+
<Alert severity="warning">Error fetching prometheus Info</Alert>
207+
</Box>
208+
) : (
209+
<PrometheusNotFoundBanner />
210+
)}
211+
</Paper>
193212
</SectionBox>
194213
);
195214
}
215+
216+
function CustomToggleButton({
217+
label,
218+
icon,
219+
value,
220+
}: {
221+
label: string;
222+
icon: string;
223+
value: string;
224+
}) {
225+
return (
226+
<ToggleButton size="small" value={value} sx={{ textTransform: 'none', gap: 0.5, fontSize: 14 }}>
227+
<Icon icon={icon} width="18px" />
228+
{label}
229+
</ToggleButton>
230+
);
231+
}

0 commit comments

Comments
 (0)