mirror of
https://github.com/optim-enterprises-bv/OptimCloud-gw-ui.git
synced 2025-10-30 01:42:19 +00:00
[WIFI-11875] Added timestamps selection for device commands, logs and healthchecks
Signed-off-by: Charles <charles.bourque96@gmail.com>
This commit is contained in:
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "ucentral-client",
|
||||
"version": "2.8.0(36)",
|
||||
"version": "2.8.0(37)",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "ucentral-client",
|
||||
"version": "2.8.0(36)",
|
||||
"version": "2.8.0(37)",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@chakra-ui/icons": "^2.0.11",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ucentral-client",
|
||||
"version": "2.8.0(36)",
|
||||
"version": "2.8.0(37)",
|
||||
"description": "",
|
||||
"private": true,
|
||||
"main": "index.tsx",
|
||||
|
||||
@@ -57,6 +57,29 @@ export const useGetCommandHistory = ({
|
||||
onError,
|
||||
});
|
||||
|
||||
const getCommandsWithTimestamps = (serialNumber?: string, start?: number, end?: number) => async () =>
|
||||
axiosGw
|
||||
.get(`commands?serialNumber=${serialNumber}&startDate=${start}&endDate=${end}`)
|
||||
.then((response) => response.data) as Promise<{
|
||||
commands: DeviceCommandHistory[];
|
||||
}>;
|
||||
export const useGetCommandHistoryWithTimestamps = ({
|
||||
serialNumber,
|
||||
start,
|
||||
end,
|
||||
onError,
|
||||
}: {
|
||||
serialNumber?: string;
|
||||
start?: number;
|
||||
end?: number;
|
||||
onError?: (e: AxiosError) => void;
|
||||
}) =>
|
||||
useQuery(['commands', serialNumber, { start, end }], getCommandsWithTimestamps(serialNumber, start, end), {
|
||||
enabled: serialNumber !== undefined && serialNumber !== '' && start !== undefined && end !== undefined,
|
||||
staleTime: 1000 * 60,
|
||||
onError,
|
||||
});
|
||||
|
||||
const deleteCommandHistory = async (id: string) => axiosGw.delete(`command/${id}`);
|
||||
export const useDeleteCommand = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
@@ -40,7 +40,31 @@ export const useDeleteLogs = () => {
|
||||
|
||||
return useMutation(deleteLogs, {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries('devicelogs');
|
||||
queryClient.invalidateQueries(['devicelogs']);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const getDeviceLogsWithTimestamps = (serialNumber?: string, start?: number, end?: number) => async () =>
|
||||
axiosGw
|
||||
.get(`device/${serialNumber}/logs?startDate=${start}&endDate=${end}`)
|
||||
.then((response) => response.data) as Promise<{
|
||||
values: DeviceLog[];
|
||||
serialNumber: string;
|
||||
}>;
|
||||
export const useGetDeviceLogsWithTimestamps = ({
|
||||
serialNumber,
|
||||
start,
|
||||
end,
|
||||
onError,
|
||||
}: {
|
||||
serialNumber?: string;
|
||||
start?: number;
|
||||
end?: number;
|
||||
onError?: (e: AxiosError) => void;
|
||||
}) =>
|
||||
useQuery(['devicelogs', serialNumber, { start, end }], getDeviceLogsWithTimestamps(serialNumber, start, end), {
|
||||
enabled: serialNumber !== undefined && serialNumber !== '' && start !== undefined && end !== undefined,
|
||||
staleTime: 1000 * 60,
|
||||
onError,
|
||||
});
|
||||
|
||||
@@ -33,6 +33,30 @@ export const useGetHealthChecks = ({
|
||||
onError,
|
||||
});
|
||||
|
||||
const getHealthChecksWithTimestamps = (serialNumber?: string, start?: number, end?: number) => async () =>
|
||||
axiosGw
|
||||
.get(`device/${serialNumber}/healthchecks?startDate=${start}&endDate=${end}`)
|
||||
.then((response) => response.data) as Promise<{
|
||||
values: HealthCheck[];
|
||||
serialNumber: string;
|
||||
}>;
|
||||
export const useGetHealthChecksWithTimestamps = ({
|
||||
serialNumber,
|
||||
start,
|
||||
end,
|
||||
onError,
|
||||
}: {
|
||||
serialNumber?: string;
|
||||
start?: number;
|
||||
end?: number;
|
||||
onError?: (e: AxiosError) => void;
|
||||
}) =>
|
||||
useQuery(['healthchecks', serialNumber, { start, end }], getHealthChecksWithTimestamps(serialNumber, start, end), {
|
||||
enabled: serialNumber !== undefined && serialNumber !== '' && start !== undefined && end !== undefined,
|
||||
staleTime: 1000 * 60,
|
||||
onError,
|
||||
});
|
||||
|
||||
const deleteHealthChecks = async ({ serialNumber, endDate }: { serialNumber: string; endDate: number }) =>
|
||||
axiosGw.delete(`device/${serialNumber}/healthchecks?endDate=${endDate}`);
|
||||
export const useDeleteHealthChecks = () => {
|
||||
@@ -40,7 +64,7 @@ export const useDeleteHealthChecks = () => {
|
||||
|
||||
return useMutation(deleteHealthChecks, {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries('healthchecks');
|
||||
queryClient.invalidateQueries(['healthchecks']);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { Box, Button, Center, Heading } from '@chakra-ui/react';
|
||||
import { Box, Button, Center, Heading, HStack, Spacer } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import HistoryDatePickers from '../DatePickers';
|
||||
import CommandResultModal from './ResultModal';
|
||||
import useCommandHistoryTable from './useCommandHistoryTable';
|
||||
import { RefreshButton } from 'components/Buttons/RefreshButton';
|
||||
@@ -15,24 +16,48 @@ const CommandHistory = ({ serialNumber }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const [limit, setLimit] = React.useState(25);
|
||||
const [hiddenColumns, setHiddenColumns] = React.useState<string[]>([]);
|
||||
const { getCommands, columns, selectedCommand, detailsModalProps } = useCommandHistoryTable({ serialNumber, limit });
|
||||
const { time, setTime, getCustomCommands, getCommands, columns, selectedCommand, detailsModalProps } =
|
||||
useCommandHistoryTable({ serialNumber, limit });
|
||||
|
||||
const raiseLimit = () => {
|
||||
setLimit(limit + 25);
|
||||
};
|
||||
|
||||
const noMoreAvailable = getCommands.data !== undefined && getCommands.data.commands.length < limit;
|
||||
const setNewTime = (start: Date, end: Date) => {
|
||||
setTime({ start, end });
|
||||
};
|
||||
const onClear = () => {
|
||||
setTime(undefined);
|
||||
};
|
||||
|
||||
const noMoreAvailable =
|
||||
getCustomCommands.data || (getCommands.data !== undefined && getCommands.data.commands.length < limit);
|
||||
|
||||
const data = React.useMemo(() => {
|
||||
if (getCustomCommands.data) return getCustomCommands.data.commands.sort((a, b) => b.submitted - a.submitted);
|
||||
if (getCommands.data) return getCommands.data.commands;
|
||||
return [];
|
||||
}, [getCustomCommands.data, getCommands.data]);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box textAlign="right">
|
||||
<ColumnPicker
|
||||
columns={columns as Column<unknown>[]}
|
||||
hiddenColumns={hiddenColumns}
|
||||
setHiddenColumns={setHiddenColumns}
|
||||
preference="gateway.device.commandshistory.hiddenColumns"
|
||||
/>
|
||||
<RefreshButton isCompact isFetching={getCommands.isFetching} onClick={getCommands.refetch} ml={2} />
|
||||
<Box textAlign="right" display="flex">
|
||||
<Spacer />
|
||||
<HStack>
|
||||
<HistoryDatePickers defaults={time} setTime={setNewTime} onClear={onClear} />
|
||||
<ColumnPicker
|
||||
columns={columns as Column<unknown>[]}
|
||||
hiddenColumns={hiddenColumns}
|
||||
setHiddenColumns={setHiddenColumns}
|
||||
preference="gateway.device.commandshistory.hiddenColumns"
|
||||
/>
|
||||
<RefreshButton
|
||||
isCompact
|
||||
isFetching={getCommands.isFetching}
|
||||
onClick={getCommands.refetch}
|
||||
colorScheme="blue"
|
||||
/>
|
||||
</HStack>
|
||||
</Box>
|
||||
<Box overflowY="auto" h="300px">
|
||||
<DataTable
|
||||
@@ -44,16 +69,16 @@ const CommandHistory = ({ serialNumber }: Props) => {
|
||||
accessor: string;
|
||||
}[]
|
||||
}
|
||||
data={getCommands.data?.commands ?? []}
|
||||
isLoading={getCommands.isFetching}
|
||||
data={data}
|
||||
isLoading={getCommands.isFetching || getCustomCommands.isFetching}
|
||||
hiddenColumns={hiddenColumns}
|
||||
obj={t('controller.devices.commands')}
|
||||
// @ts-ignore
|
||||
hideControls
|
||||
showAllRows
|
||||
/>
|
||||
{getCommands.data !== undefined && (
|
||||
<Center mt={2}>
|
||||
{data !== undefined && (
|
||||
<Center mt={2} hidden={getCustomCommands.data !== undefined}>
|
||||
{!noMoreAvailable || getCommands.isFetching ? (
|
||||
<Button colorScheme="blue" onClick={raiseLimit} isLoading={getCommands.isFetching}>
|
||||
{t('controller.devices.show_more')}
|
||||
|
||||
@@ -4,7 +4,12 @@ import { MagnifyingGlass, Trash } from 'phosphor-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import FormattedDate from 'components/InformationDisplays/FormattedDate';
|
||||
import { uppercaseFirstLetter } from 'helpers/stringHelper';
|
||||
import { DeviceCommandHistory, useDeleteCommand, useGetCommandHistory } from 'hooks/Network/Commands';
|
||||
import {
|
||||
DeviceCommandHistory,
|
||||
useDeleteCommand,
|
||||
useGetCommandHistory,
|
||||
useGetCommandHistoryWithTimestamps,
|
||||
} from 'hooks/Network/Commands';
|
||||
import { AxiosError } from 'models/Axios';
|
||||
import { Column } from 'models/Table';
|
||||
|
||||
@@ -15,6 +20,12 @@ type Props = {
|
||||
|
||||
const useCommandHistoryTable = ({ serialNumber, limit }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const [time, setTime] = React.useState<{ start: Date; end: Date } | undefined>();
|
||||
const getCustomCommands = useGetCommandHistoryWithTimestamps({
|
||||
serialNumber,
|
||||
start: time ? Math.floor(time.start.getTime() / 1000) : undefined,
|
||||
end: time ? Math.floor(time.end.getTime() / 1000) : undefined,
|
||||
});
|
||||
const getCommands = useGetCommandHistory({ serialNumber, limit });
|
||||
const deleteCommand = useDeleteCommand();
|
||||
const [selectedCommand, setSelectedCommand] = React.useState<DeviceCommandHistory | undefined>();
|
||||
@@ -185,8 +196,11 @@ const useCommandHistoryTable = ({ serialNumber, limit }: Props) => {
|
||||
return {
|
||||
columns,
|
||||
getCommands,
|
||||
getCustomCommands,
|
||||
selectedCommand,
|
||||
detailsModalProps,
|
||||
time,
|
||||
setTime,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
188
src/pages/Device/LogsCard/DatePickers.tsx
Normal file
188
src/pages/Device/LogsCard/DatePickers.tsx
Normal file
@@ -0,0 +1,188 @@
|
||||
import * as React from 'react';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Flex,
|
||||
Heading,
|
||||
HStack,
|
||||
IconButton,
|
||||
Popover,
|
||||
PopoverArrow,
|
||||
PopoverBody,
|
||||
PopoverContent,
|
||||
PopoverHeader,
|
||||
PopoverTrigger,
|
||||
Spacer,
|
||||
Tooltip,
|
||||
useBreakpoint,
|
||||
} from '@chakra-ui/react';
|
||||
import { Clock, Prohibit } from 'phosphor-react';
|
||||
import ReactDatePicker from 'react-datepicker';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { CloseButton } from 'components/Buttons/CloseButton';
|
||||
import { SaveButton } from 'components/Buttons/SaveButton';
|
||||
|
||||
const CustomInputButton = React.forwardRef(
|
||||
({ value, onClick }: { value: string; onClick: () => void }, ref: React.LegacyRef<HTMLButtonElement>) => (
|
||||
<Button colorScheme="gray" size="sm" onClick={onClick} ref={ref} mt={1}>
|
||||
{value}
|
||||
</Button>
|
||||
),
|
||||
);
|
||||
|
||||
const getStart = () => {
|
||||
const date = new Date();
|
||||
date.setHours(date.getHours() - 1);
|
||||
return date;
|
||||
};
|
||||
type Props = {
|
||||
defaults?: { start: Date; end: Date };
|
||||
setTime: (start: Date, end: Date) => void;
|
||||
onClear: () => void;
|
||||
};
|
||||
|
||||
const HistoryDatePickers = ({ defaults, setTime, onClear }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const [start, setStart] = React.useState<Date>(defaults?.start ?? getStart());
|
||||
const [end, setEnd] = React.useState<Date>(defaults?.end ?? new Date());
|
||||
const breakpoint = useBreakpoint();
|
||||
|
||||
const onStartChange = (newDate: Date) => {
|
||||
setStart(newDate);
|
||||
};
|
||||
const onEndChange = (newDate: Date) => {
|
||||
setEnd(newDate);
|
||||
};
|
||||
const clear = (onClose: () => void) => () => {
|
||||
onClear();
|
||||
onClose();
|
||||
};
|
||||
const onSave = (onClose: () => void) => () => {
|
||||
onClose();
|
||||
setTime(start, end);
|
||||
};
|
||||
|
||||
const width = (isOpen: boolean) => {
|
||||
if (isOpen) {
|
||||
return breakpoint === 'base' ? '360px' : '460px';
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
setStart(defaults?.start ?? getStart());
|
||||
setEnd(defaults?.end ?? new Date());
|
||||
}, [defaults]);
|
||||
|
||||
return (
|
||||
<Popover>
|
||||
{({ isOpen, onClose }) => (
|
||||
<>
|
||||
<PopoverTrigger>
|
||||
<Box>
|
||||
<Tooltip label={t('controller.crud.choose_time')}>
|
||||
<IconButton aria-label={t('controller.crud.choose_time')} icon={<Clock />} />
|
||||
</Tooltip>
|
||||
</Box>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent w={width(isOpen)}>
|
||||
<PopoverArrow />
|
||||
<PopoverHeader display="flex">
|
||||
<Heading size="sm" my="auto">
|
||||
{t('controller.crud.choose_time')}
|
||||
</Heading>
|
||||
<Spacer />
|
||||
<HStack>
|
||||
<Tooltip label={t('controller.crud.clear_time')}>
|
||||
<IconButton
|
||||
colorScheme="red"
|
||||
aria-label={t('controller.crud.clear_time')}
|
||||
onClick={clear(onClose)}
|
||||
icon={<Prohibit />}
|
||||
/>
|
||||
</Tooltip>
|
||||
<SaveButton onClick={onSave(onClose)} isCompact />
|
||||
<CloseButton onClick={onClose} />
|
||||
</HStack>
|
||||
</PopoverHeader>
|
||||
<PopoverBody>
|
||||
{breakpoint === 'base' ? (
|
||||
<Box>
|
||||
<Flex>
|
||||
<Heading size="sm" my="auto" mr={2}>
|
||||
{t('system.start')}:{' '}
|
||||
</Heading>
|
||||
<Box w="170px">
|
||||
<ReactDatePicker
|
||||
selected={start}
|
||||
onChange={onStartChange}
|
||||
timeInputLabel={`${t('common.time')}: `}
|
||||
dateFormat="dd/MM/yyyy hh:mm aa"
|
||||
timeFormat="p"
|
||||
showTimeSelect
|
||||
// @ts-ignore
|
||||
customInput={<CustomInputButton />}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Heading size="sm" my="auto" mr={4}>
|
||||
{t('common.end')}:{' '}
|
||||
</Heading>
|
||||
<Box w="170px">
|
||||
<ReactDatePicker
|
||||
selected={end}
|
||||
onChange={onEndChange}
|
||||
timeInputLabel={`${t('common.time')}: `}
|
||||
dateFormat="dd/MM/yyyy hh:mm aa"
|
||||
timeFormat="p"
|
||||
showTimeSelect
|
||||
// @ts-ignore
|
||||
customInput={<CustomInputButton />}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
</Box>
|
||||
) : (
|
||||
<Flex>
|
||||
<Heading size="sm" my="auto" mr={2}>
|
||||
{t('system.start')}:{' '}
|
||||
</Heading>
|
||||
<Box w="170px">
|
||||
<ReactDatePicker
|
||||
selected={start}
|
||||
onChange={onStartChange}
|
||||
timeInputLabel={`${t('common.time')}: `}
|
||||
dateFormat="dd/MM/yyyy hh:mm aa"
|
||||
timeFormat="p"
|
||||
showTimeSelect
|
||||
// @ts-ignore
|
||||
customInput={<CustomInputButton />}
|
||||
/>
|
||||
</Box>
|
||||
<Heading size="sm" my="auto" mr={2}>
|
||||
{t('common.end')}:{' '}
|
||||
</Heading>
|
||||
<Box w="170px">
|
||||
<ReactDatePicker
|
||||
selected={end}
|
||||
onChange={onEndChange}
|
||||
timeInputLabel={`${t('common.time')}: `}
|
||||
dateFormat="dd/MM/yyyy hh:mm aa"
|
||||
timeFormat="p"
|
||||
showTimeSelect
|
||||
// @ts-ignore
|
||||
customInput={<CustomInputButton />}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
</PopoverBody>
|
||||
</PopoverContent>
|
||||
</>
|
||||
)}
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
export default HistoryDatePickers;
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { Box, Button, Center, Flex, Heading, HStack, Spacer } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import HistoryDatePickers from '../DatePickers';
|
||||
import DeleteHealthChecksModal from './DeleteModal';
|
||||
import useHealthCheckTable from './useHealthCheckTable';
|
||||
import { RefreshButton } from 'components/Buttons/RefreshButton';
|
||||
@@ -15,19 +16,35 @@ const HealthCheckHistory = ({ serialNumber }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const [limit, setLimit] = React.useState(25);
|
||||
const [hiddenColumns, setHiddenColumns] = React.useState<string[]>([]);
|
||||
const { getHealthChecks, columns } = useHealthCheckTable({ serialNumber, limit });
|
||||
const { time, setTime, getCustomHealthChecks, getHealthChecks, columns } = useHealthCheckTable({
|
||||
serialNumber,
|
||||
limit,
|
||||
});
|
||||
|
||||
const setNewTime = (start: Date, end: Date) => {
|
||||
setTime({ start, end });
|
||||
};
|
||||
const onClear = () => {
|
||||
setTime(undefined);
|
||||
};
|
||||
const raiseLimit = () => {
|
||||
setLimit(limit + 25);
|
||||
};
|
||||
|
||||
const noMoreAvailable = getHealthChecks.data !== undefined && getHealthChecks.data.values.length < limit;
|
||||
|
||||
const data = React.useMemo(() => {
|
||||
if (getCustomHealthChecks.data) return getCustomHealthChecks.data.values.sort((a, b) => b.recorded - a.recorded);
|
||||
if (getHealthChecks.data) return getHealthChecks.data.values;
|
||||
return [];
|
||||
}, [getHealthChecks.data, getCustomHealthChecks.data]);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Flex>
|
||||
<Spacer />
|
||||
<HStack>
|
||||
<HistoryDatePickers defaults={time} setTime={setNewTime} onClear={onClear} />
|
||||
<ColumnPicker
|
||||
columns={columns as Column<unknown>[]}
|
||||
hiddenColumns={hiddenColumns}
|
||||
@@ -35,7 +52,13 @@ const HealthCheckHistory = ({ serialNumber }: Props) => {
|
||||
preference="gateway.device.healthchecks.hiddenColumns"
|
||||
/>
|
||||
<DeleteHealthChecksModal serialNumber={serialNumber} />
|
||||
<RefreshButton isCompact isFetching={getHealthChecks.isFetching} onClick={getHealthChecks.refetch} ml={2} />
|
||||
<RefreshButton
|
||||
isCompact
|
||||
isFetching={getHealthChecks.isFetching || getCustomHealthChecks.isFetching}
|
||||
onClick={getHealthChecks.refetch}
|
||||
ml={2}
|
||||
colorScheme="blue"
|
||||
/>
|
||||
</HStack>
|
||||
</Flex>
|
||||
<Box overflowY="auto" h="300px">
|
||||
@@ -48,8 +71,8 @@ const HealthCheckHistory = ({ serialNumber }: Props) => {
|
||||
accessor: string;
|
||||
}[]
|
||||
}
|
||||
data={getHealthChecks.data?.values ?? []}
|
||||
isLoading={getHealthChecks.isFetching}
|
||||
data={data}
|
||||
isLoading={getHealthChecks.isFetching || getCustomHealthChecks.isFetching}
|
||||
hiddenColumns={hiddenColumns}
|
||||
obj={t('controller.devices.healthchecks')}
|
||||
// @ts-ignore
|
||||
@@ -57,7 +80,7 @@ const HealthCheckHistory = ({ serialNumber }: Props) => {
|
||||
showAllRows
|
||||
/>
|
||||
{getHealthChecks.data !== undefined && (
|
||||
<Center mt={2}>
|
||||
<Center mt={2} hidden={getCustomHealthChecks.data !== undefined}>
|
||||
{!noMoreAvailable || getHealthChecks.isFetching ? (
|
||||
<Button colorScheme="blue" onClick={raiseLimit} isLoading={getHealthChecks.isFetching}>
|
||||
{t('controller.devices.show_more')}
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as React from 'react';
|
||||
import { Badge, Box } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import FormattedDate from 'components/InformationDisplays/FormattedDate';
|
||||
import { HealthCheck, useGetHealthChecks } from 'hooks/Network/HealthChecks';
|
||||
import { HealthCheck, useGetHealthChecks, useGetHealthChecksWithTimestamps } from 'hooks/Network/HealthChecks';
|
||||
import { Column } from 'models/Table';
|
||||
|
||||
type Props = {
|
||||
@@ -13,6 +13,12 @@ type Props = {
|
||||
const useHealthCheckTable = ({ serialNumber, limit }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const getHealthChecks = useGetHealthChecks({ serialNumber, limit });
|
||||
const [time, setTime] = React.useState<{ start: Date; end: Date } | undefined>();
|
||||
const getCustomHealthChecks = useGetHealthChecksWithTimestamps({
|
||||
serialNumber,
|
||||
start: time ? Math.floor(time.start.getTime() / 1000) : undefined,
|
||||
end: time ? Math.floor(time.end.getTime() / 1000) : undefined,
|
||||
});
|
||||
|
||||
const dateCell = React.useCallback(
|
||||
(v: number) => (
|
||||
@@ -80,6 +86,9 @@ const useHealthCheckTable = ({ serialNumber, limit }: Props) => {
|
||||
return {
|
||||
columns,
|
||||
getHealthChecks,
|
||||
getCustomHealthChecks,
|
||||
time,
|
||||
setTime,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { Box, Button, Center, Flex, Heading, HStack, Spacer } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import HistoryDatePickers from '../DatePickers';
|
||||
import DeleteLogModal from './DeleteModal';
|
||||
import useDeviceLogsTable from './useDeviceLogsTable';
|
||||
import { RefreshButton } from 'components/Buttons/RefreshButton';
|
||||
@@ -15,19 +16,32 @@ const LogHistory = ({ serialNumber }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const [limit, setLimit] = React.useState(25);
|
||||
const [hiddenColumns, setHiddenColumns] = React.useState<string[]>([]);
|
||||
const { getLogs, columns } = useDeviceLogsTable({ serialNumber, limit });
|
||||
const { time, setTime, getCustomLogs, getLogs, columns } = useDeviceLogsTable({ serialNumber, limit });
|
||||
|
||||
const setNewTime = (start: Date, end: Date) => {
|
||||
setTime({ start, end });
|
||||
};
|
||||
const onClear = () => {
|
||||
setTime(undefined);
|
||||
};
|
||||
const raiseLimit = () => {
|
||||
setLimit(limit + 25);
|
||||
};
|
||||
|
||||
const noMoreAvailable = getLogs.data !== undefined && getLogs.data.values.length < limit;
|
||||
|
||||
const data = React.useMemo(() => {
|
||||
if (getCustomLogs.data) return getCustomLogs.data.values.sort((a, b) => b.recorded - a.recorded);
|
||||
if (getLogs.data) return getLogs.data.values;
|
||||
return [];
|
||||
}, [getLogs.data, getCustomLogs.data]);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Flex>
|
||||
<Spacer />
|
||||
<HStack>
|
||||
<HistoryDatePickers defaults={time} setTime={setNewTime} onClear={onClear} />
|
||||
<ColumnPicker
|
||||
columns={columns as Column<unknown>[]}
|
||||
hiddenColumns={hiddenColumns}
|
||||
@@ -35,7 +49,7 @@ const LogHistory = ({ serialNumber }: Props) => {
|
||||
preference="gateway.device.logs.hiddenColumns"
|
||||
/>
|
||||
<DeleteLogModal serialNumber={serialNumber} />
|
||||
<RefreshButton isCompact isFetching={getLogs.isFetching} onClick={getLogs.refetch} ml={2} />
|
||||
<RefreshButton isCompact isFetching={getLogs.isFetching} onClick={getLogs.refetch} colorScheme="blue" />
|
||||
</HStack>
|
||||
</Flex>
|
||||
<Box overflowY="auto" h="300px">
|
||||
@@ -48,8 +62,8 @@ const LogHistory = ({ serialNumber }: Props) => {
|
||||
accessor: string;
|
||||
}[]
|
||||
}
|
||||
data={getLogs.data?.values ?? []}
|
||||
isLoading={getLogs.isFetching}
|
||||
data={data}
|
||||
isLoading={getLogs.isFetching || getCustomLogs.isFetching}
|
||||
hiddenColumns={hiddenColumns}
|
||||
obj={t('controller.devices.logs')}
|
||||
// @ts-ignore
|
||||
@@ -57,7 +71,7 @@ const LogHistory = ({ serialNumber }: Props) => {
|
||||
showAllRows
|
||||
/>
|
||||
{getLogs.data !== undefined && (
|
||||
<Center mt={2}>
|
||||
<Center mt={2} hidden={getCustomLogs.data !== undefined}>
|
||||
{!noMoreAvailable || getLogs.isFetching ? (
|
||||
<Button colorScheme="blue" onClick={raiseLimit} isLoading={getLogs.isFetching}>
|
||||
{t('controller.devices.show_more')}
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as React from 'react';
|
||||
import { Box } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import FormattedDate from 'components/InformationDisplays/FormattedDate';
|
||||
import { DeviceLog, useGetDeviceLogs } from 'hooks/Network/DeviceLogs';
|
||||
import { DeviceLog, useGetDeviceLogs, useGetDeviceLogsWithTimestamps } from 'hooks/Network/DeviceLogs';
|
||||
import { Column } from 'models/Table';
|
||||
|
||||
type Props = {
|
||||
@@ -13,6 +13,12 @@ type Props = {
|
||||
const useDeviceLogsTable = ({ serialNumber, limit }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const getLogs = useGetDeviceLogs({ serialNumber, limit });
|
||||
const [time, setTime] = React.useState<{ start: Date; end: Date } | undefined>();
|
||||
const getCustomLogs = useGetDeviceLogsWithTimestamps({
|
||||
serialNumber,
|
||||
start: time ? Math.floor(time.start.getTime() / 1000) : undefined,
|
||||
end: time ? Math.floor(time.end.getTime() / 1000) : undefined,
|
||||
});
|
||||
|
||||
const dateCell = React.useCallback(
|
||||
(v: number) => (
|
||||
@@ -76,6 +82,9 @@ const useDeviceLogsTable = ({ serialNumber, limit }: Props) => {
|
||||
return {
|
||||
columns,
|
||||
getLogs,
|
||||
getCustomLogs,
|
||||
time,
|
||||
setTime,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user