Enhanced HistoryDisplay component with custom date range selection and improved loading states.
This commit is contained in:
parent
2d2aff125c
commit
3d17a08a71
@ -1,6 +1,5 @@
|
|||||||
import { useEffect, useState, useContext, useMemo } from 'react'
|
import { useEffect, useState, useContext, useMemo } from 'react'
|
||||||
import { Card, Spin, Segmented, Flex } from 'antd'
|
import { Card, Segmented, Flex, Popover, DatePicker, Button, Space } from 'antd'
|
||||||
import { LoadingOutlined } from '@ant-design/icons'
|
|
||||||
import { Column } from '@ant-design/charts'
|
import { Column } from '@ant-design/charts'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { getModelByName } from '../../../database/ObjectModels'
|
import { getModelByName } from '../../../database/ObjectModels'
|
||||||
@ -8,14 +7,25 @@ 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 CheckIcon from '../../Icons/CheckIcon'
|
||||||
|
|
||||||
const HistoryDisplay = ({ objectType, startDate, endDate, styles }) => {
|
const HistoryDisplay = ({
|
||||||
|
objectType,
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
|
styles,
|
||||||
|
height = 400
|
||||||
|
}) => {
|
||||||
const { getModelHistory, connected } = useContext(ApiServerContext)
|
const { getModelHistory, connected } = useContext(ApiServerContext)
|
||||||
const { token } = useContext(AuthContext)
|
const { token } = useContext(AuthContext)
|
||||||
const [historyData, setHistoryData] = useState([])
|
const [historyData, setHistoryData] = useState([])
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
const [error, setError] = useState(null)
|
const [error, setError] = useState(null)
|
||||||
const [timeRange, setTimeRange] = useState('4hrs')
|
const [timeRange, setTimeRange] = useState('4hrs')
|
||||||
|
const [startCustomDate, setStartCustomDate] = useState(null)
|
||||||
|
const [endCustomDate, setEndCustomDate] = useState(null)
|
||||||
const { isDarkMode, getColors } = useThemeContext()
|
const { isDarkMode, getColors } = useThemeContext()
|
||||||
// Calculate dates based on selected time range or provided props
|
// Calculate dates based on selected time range or provided props
|
||||||
const { defaultStartDate, defaultEndDate } = useMemo(() => {
|
const { defaultStartDate, defaultEndDate } = useMemo(() => {
|
||||||
@ -30,6 +40,14 @@ const HistoryDisplay = ({ objectType, startDate, endDate, styles }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle custom date range
|
||||||
|
if (timeRange === 'custom' && startCustomDate && endCustomDate) {
|
||||||
|
return {
|
||||||
|
defaultStartDate: startCustomDate.toDate(),
|
||||||
|
defaultEndDate: endCustomDate.toDate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Otherwise, calculate based on selected time range
|
// Otherwise, calculate based on selected time range
|
||||||
const hoursMap = {
|
const hoursMap = {
|
||||||
'8hrs': 8,
|
'8hrs': 8,
|
||||||
@ -43,7 +61,7 @@ const HistoryDisplay = ({ objectType, startDate, endDate, styles }) => {
|
|||||||
defaultStartDate: new Date(now.getTime() - hours * 60 * 60 * 1000),
|
defaultStartDate: new Date(now.getTime() - hours * 60 * 60 * 1000),
|
||||||
defaultEndDate: now
|
defaultEndDate: now
|
||||||
}
|
}
|
||||||
}, [startDate, endDate, timeRange])
|
}, [startDate, endDate, timeRange, startCustomDate, endCustomDate])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!objectType || !getModelHistory || !token || !connected) {
|
if (!objectType || !getModelHistory || !token || !connected) {
|
||||||
@ -251,6 +269,7 @@ const HistoryDisplay = ({ objectType, startDate, endDate, styles }) => {
|
|||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
data: chartData,
|
data: chartData,
|
||||||
|
height,
|
||||||
xField: 'dateFormatted',
|
xField: 'dateFormatted',
|
||||||
yField: 'value',
|
yField: 'value',
|
||||||
theme: {
|
theme: {
|
||||||
@ -282,31 +301,85 @@ const HistoryDisplay = ({ objectType, startDate, endDate, styles }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const customTimeRangeContent = (
|
||||||
|
<Space.Compact>
|
||||||
|
<DatePicker.RangePicker
|
||||||
|
onChange={(dates) => {
|
||||||
|
if (dates) {
|
||||||
|
setStartCustomDate(dates[0])
|
||||||
|
setEndCustomDate(dates[1])
|
||||||
|
} else {
|
||||||
|
setStartCustomDate(null)
|
||||||
|
setEndCustomDate(null)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
value={[startCustomDate, endCustomDate]}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type='primary'
|
||||||
|
onClick={() => {
|
||||||
|
if (startCustomDate && endCustomDate) {
|
||||||
|
setTimeRange('custom')
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
disabled={!startCustomDate || !endCustomDate}
|
||||||
|
icon={<CheckIcon />}
|
||||||
|
></Button>
|
||||||
|
</Space.Compact>
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Spin spinning={loading} indicator={<LoadingOutlined spin />}>
|
<Card
|
||||||
<Card
|
style={{ width: '100%' }}
|
||||||
style={{ width: '100%' }}
|
styles={{ body: { padding: '12px', ...styles } }}
|
||||||
styles={{ body: { padding: '12px', ...styles } }}
|
>
|
||||||
>
|
{!startDate && !endDate && (
|
||||||
{!startDate && !endDate && (
|
<Flex justify='space-between'>
|
||||||
<Flex justify='flex-end'>
|
<Flex align='center' gap='5px'>
|
||||||
<Segmented
|
<Popover
|
||||||
size='small'
|
content={customTimeRangeContent}
|
||||||
options={[
|
trigger='hover'
|
||||||
{ label: '24hr', value: '24hrs' },
|
arrow={false}
|
||||||
{ label: '12hr', value: '12hrs' },
|
placement='bottomLeft'
|
||||||
{ label: '8hr', value: '8hrs' },
|
styles={{ body: { borderRadius: '22.5px' } }}
|
||||||
{ label: '4hr', value: '4hrs' },
|
>
|
||||||
{ label: '1hr', value: '1hrs' }
|
<Segmented
|
||||||
]}
|
size='small'
|
||||||
value={timeRange}
|
options={[{ label: 'Custom', value: 'custom' }]}
|
||||||
onChange={setTimeRange}
|
value={timeRange}
|
||||||
/>
|
onChange={setTimeRange}
|
||||||
|
disabled={loading}
|
||||||
|
/>
|
||||||
|
</Popover>
|
||||||
</Flex>
|
</Flex>
|
||||||
)}
|
|
||||||
<Column {...config} />
|
<Segmented
|
||||||
</Card>
|
size='small'
|
||||||
</Spin>
|
options={[
|
||||||
|
{ label: '24hr', value: '24hrs' },
|
||||||
|
{ label: '12hr', value: '12hrs' },
|
||||||
|
{ label: '8hr', value: '8hrs' },
|
||||||
|
{ label: '4hr', value: '4hrs' },
|
||||||
|
{ label: '1hr', value: '1hrs' }
|
||||||
|
]}
|
||||||
|
value={timeRange}
|
||||||
|
onChange={setTimeRange}
|
||||||
|
disabled={loading}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
{loading == true && (
|
||||||
|
<Flex justify='center' align='center' style={{ height: `${height}px` }}>
|
||||||
|
<LoadingPlaceholder message='Loading history data...' />
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
{chartData.length > 0 && <Column {...config} />}
|
||||||
|
{loading == false && chartData.length == 0 && (
|
||||||
|
<Flex justify='center' align='center' style={{ height: `${height}px` }}>
|
||||||
|
<MissingPlaceholder message='No data available.' />
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,7 +390,8 @@ HistoryDisplay.propTypes = {
|
|||||||
PropTypes.instanceOf(Date)
|
PropTypes.instanceOf(Date)
|
||||||
]),
|
]),
|
||||||
styles: PropTypes.object,
|
styles: PropTypes.object,
|
||||||
endDate: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)])
|
endDate: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]),
|
||||||
|
height: PropTypes.string
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HistoryDisplay
|
export default HistoryDisplay
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user