Refactor HistoryDisplay component to streamline imports and enhance layout structure. Consolidate loading state handling and improve chart rendering logic for better performance and user experience.

This commit is contained in:
Tom Butcher 2026-07-18 18:59:51 +01:00
parent 7ca78280b3
commit cd30be7677

View File

@ -1,13 +1,5 @@
import { useEffect, useState, useContext, useMemo } from 'react' import { useEffect, useState, useContext, useMemo } from 'react'
import { import { Card, Segmented, Flex, Popover, DatePicker, Button, Space } from 'antd'
Card,
Segmented,
Flex,
Popover,
DatePicker,
Button,
Space
} from 'antd'
import { import {
ResponsiveContainer, ResponsiveContainer,
BarChart, BarChart,
@ -25,9 +17,9 @@ import { ApiServerContext } from '../context/ApiServerContext'
import { AuthContext } from '../context/AuthContext' import { AuthContext } from '../context/AuthContext'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { useThemeContext } from '../context/ThemeContext' import { useThemeContext } from '../context/ThemeContext'
import LoadingPlaceholder from './LoadingPlaceholder'
import MissingPlaceholder from './MissingPlaceholder' import MissingPlaceholder from './MissingPlaceholder'
import CheckIcon from '../../Icons/CheckIcon' import CheckIcon from '../../Icons/CheckIcon'
import { LoadingOutlined } from '@ant-design/icons'
const HistoryDisplay = ({ const HistoryDisplay = ({
objectType, objectType,
@ -291,15 +283,17 @@ const HistoryDisplay = ({
}) })
const chartRows = Array.from( const chartRows = Array.from(
chartData.reduce((acc, item) => { chartData
const existing = acc.get(item.date) || { .reduce((acc, item) => {
date: item.date, const existing = acc.get(item.date) || {
dateFormatted: item.dateFormatted date: item.date,
} dateFormatted: item.dateFormatted
existing[item.category] = item.value }
acc.set(item.date, existing) existing[item.category] = item.value
return acc acc.set(item.date, existing)
}, new Map()).values() return acc
}, new Map())
.values()
).sort((a, b) => new Date(a.date) - new Date(b.date)) ).sort((a, b) => new Date(a.date) - new Date(b.date))
const customTimeRangeContent = ( const customTimeRangeContent = (
@ -334,89 +328,99 @@ const HistoryDisplay = ({
style={{ width: '100%' }} style={{ width: '100%' }}
styles={{ body: { padding: '12px', ...styles } }} styles={{ body: { padding: '12px', ...styles } }}
> >
{!startDate && !endDate && ( <Flex gap='small' vertical>
<Flex justify='space-between'> {!startDate && !endDate && (
<Flex align='center' gap='5px'> <Flex justify='space-between'>
<Popover <Flex align='center' gap='5px'>
content={customTimeRangeContent} <Popover
trigger='hover' content={customTimeRangeContent}
arrow={false} trigger='hover'
placement='bottomLeft' arrow={false}
styles={{ body: { borderRadius: '22.5px' } }} placement='bottomLeft'
> styles={{ body: { borderRadius: '22.5px' } }}
>
<Segmented
size='small'
options={[{ label: 'Custom', value: 'custom' }]}
value={timeRange}
onChange={setTimeRange}
disabled={loading}
/>
</Popover>
</Flex>
<Flex gap='middle'>
{loading == true && <LoadingOutlined />}
<Segmented <Segmented
size='small' size='small'
options={[{ label: 'Custom', value: 'custom' }]} options={[
{ label: '24hr', value: '24hrs' },
{ label: '12hr', value: '12hrs' },
{ label: '8hr', value: '8hrs' },
{ label: '4hr', value: '4hrs' },
{ label: '1hr', value: '1hrs' }
]}
value={timeRange} value={timeRange}
onChange={setTimeRange} onChange={setTimeRange}
disabled={loading} disabled={loading}
/> />
</Popover> </Flex>
</Flex> </Flex>
)}
<Segmented {chartRows.length > 0 && (
size='small' <div style={{ width: '100%', height: `${height}px` }}>
options={[ <ResponsiveContainer width='100%' height='100%'>
{ label: '24hr', value: '24hrs' }, <BarChart data={chartRows}>
{ label: '12hr', value: '12hrs' }, <CartesianGrid
{ label: '8hr', value: '8hrs' }, strokeDasharray='3 3'
{ label: '4hr', value: '4hrs' }, stroke={isDarkMode ? '#303030' : '#f0f0f0'}
{ label: '1hr', value: '1hrs' } />
]} <XAxis
value={timeRange} dataKey='dateFormatted'
onChange={setTimeRange} tick={{
disabled={loading} fill: isDarkMode ? '#d9d9d9' : '#595959',
/> fontSize: 12
</Flex> }}
)} />
{loading == true && ( <YAxis
<Flex justify='center' align='center' style={{ height: `${height}px` }}> tick={{
<LoadingPlaceholder message='Loading history data...' /> fill: isDarkMode ? '#d9d9d9' : '#595959',
</Flex> fontSize: 12
)} }}
{chartRows.length > 0 && ( />
<div style={{ width: '100%', height: `${height}px` }}> <Tooltip
<ResponsiveContainer width='100%' height='100%'> contentStyle={{
<BarChart data={chartRows}> backgroundColor: isDarkMode ? '#1f1f1f' : '#ffffff',
<CartesianGrid border: `1px solid ${isDarkMode ? '#303030' : '#f0f0f0'}`,
strokeDasharray='3 3' borderRadius: 8
stroke={isDarkMode ? '#303030' : '#f0f0f0'} }}
/> />
<XAxis <Legend />
dataKey='dateFormatted' {modelStats.map((statDef, index) => {
tick={{ fill: isDarkMode ? '#d9d9d9' : '#595959', fontSize: 12 }} const category = statDef.label || statDef.name
/> return (
<YAxis <Bar
tick={{ fill: isDarkMode ? '#d9d9d9' : '#595959', fontSize: 12 }} key={category}
/> dataKey={category}
<Tooltip stackId='history'
contentStyle={{ fill={colorRange[index] || colors.default}
backgroundColor: isDarkMode ? '#1f1f1f' : '#ffffff', />
border: `1px solid ${isDarkMode ? '#303030' : '#f0f0f0'}`, )
borderRadius: 8 })}
}} </BarChart>
/> </ResponsiveContainer>
<Legend /> </div>
{modelStats.map((statDef, index) => { )}
const category = statDef.label || statDef.name {loading == false && chartRows.length == 0 && (
return ( <Flex
<Bar justify='center'
key={category} align='center'
dataKey={category} style={{ height: `${height}px` }}
stackId='history' >
fill={colorRange[index] || colors.default} <MissingPlaceholder message='No data available.' />
/> </Flex>
) )}
})} </Flex>
</BarChart>
</ResponsiveContainer>
</div>
)}
{loading == false && chartRows.length == 0 && (
<Flex justify='center' align='center' style={{ height: `${height}px` }}>
<MissingPlaceholder message='No data available.' />
</Flex>
)}
</Card> </Card>
) )
} }