mirror of
https://github.com/optim-enterprises-bv/OptimCloud-gw-ui.git
synced 2025-11-01 02:37:45 +00:00
[WIFI-12613] Display reboot logs on device page
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",
|
"name": "ucentral-client",
|
||||||
"version": "2.10.0(41)",
|
"version": "2.10.0(42)",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "ucentral-client",
|
"name": "ucentral-client",
|
||||||
"version": "2.10.0(41)",
|
"version": "2.10.0(42)",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@chakra-ui/icons": "^2.0.18",
|
"@chakra-ui/icons": "^2.0.18",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ucentral-client",
|
"name": "ucentral-client",
|
||||||
"version": "2.10.0(41)",
|
"version": "2.10.0(42)",
|
||||||
"description": "",
|
"description": "",
|
||||||
"private": true,
|
"private": true,
|
||||||
"main": "index.tsx",
|
"main": "index.tsx",
|
||||||
|
|||||||
@@ -644,6 +644,7 @@
|
|||||||
"notifications": "Gerätebenachrichtigungen",
|
"notifications": "Gerätebenachrichtigungen",
|
||||||
"one": "Gerät",
|
"one": "Gerät",
|
||||||
"reassign_already_owned": "Geräte neu zuweisen, die bereits vorhanden sind und einem anderen Unternehmen/Veranstaltungsort/Abonnenten gehören?",
|
"reassign_already_owned": "Geräte neu zuweisen, die bereits vorhanden sind und einem anderen Unternehmen/Veranstaltungsort/Abonnenten gehören?",
|
||||||
|
"reboot_logs": "Neustartprotokolle",
|
||||||
"restricted": "Beschränkt",
|
"restricted": "Beschränkt",
|
||||||
"restricted_overriden": "Dies ist ein eingeschränktes Gerät, aber es befindet sich im Entwicklungsmodus. Alle Einschränkungen werden derzeit ignoriert",
|
"restricted_overriden": "Dies ist ein eingeschränktes Gerät, aber es befindet sich im Entwicklungsmodus. Alle Einschränkungen werden derzeit ignoriert",
|
||||||
"restrictions_overriden_title": "Dev-Modus",
|
"restrictions_overriden_title": "Dev-Modus",
|
||||||
|
|||||||
@@ -644,6 +644,7 @@
|
|||||||
"notifications": "Device Notifications",
|
"notifications": "Device Notifications",
|
||||||
"one": "Device",
|
"one": "Device",
|
||||||
"reassign_already_owned": "Reassign devices which already exist and are owned by another entity/venue/subscriber?",
|
"reassign_already_owned": "Reassign devices which already exist and are owned by another entity/venue/subscriber?",
|
||||||
|
"reboot_logs": "Reboot Logs",
|
||||||
"restricted": "Restricted",
|
"restricted": "Restricted",
|
||||||
"restricted_overriden": "This is a restricted device, but it is in development mode. All restrictions are currently ignored",
|
"restricted_overriden": "This is a restricted device, but it is in development mode. All restrictions are currently ignored",
|
||||||
"restrictions_overriden_title": "Dev Mode",
|
"restrictions_overriden_title": "Dev Mode",
|
||||||
|
|||||||
@@ -644,6 +644,7 @@
|
|||||||
"notifications": "notificaciones de dispositivos",
|
"notifications": "notificaciones de dispositivos",
|
||||||
"one": "Dispositivo",
|
"one": "Dispositivo",
|
||||||
"reassign_already_owned": "¿Reasignar dispositivos que ya existen y son propiedad de otra entidad/lugar/suscriptor?",
|
"reassign_already_owned": "¿Reasignar dispositivos que ya existen y son propiedad de otra entidad/lugar/suscriptor?",
|
||||||
|
"reboot_logs": "Reiniciar registros",
|
||||||
"restricted": "Restringido",
|
"restricted": "Restringido",
|
||||||
"restricted_overriden": "Este es un dispositivo restringido, pero está en modo de desarrollo. Actualmente se ignoran todas las restricciones.",
|
"restricted_overriden": "Este es un dispositivo restringido, pero está en modo de desarrollo. Actualmente se ignoran todas las restricciones.",
|
||||||
"restrictions_overriden_title": "MODO DE DESARROLLO",
|
"restrictions_overriden_title": "MODO DE DESARROLLO",
|
||||||
|
|||||||
@@ -644,6 +644,7 @@
|
|||||||
"notifications": "notifications de l'appareil",
|
"notifications": "notifications de l'appareil",
|
||||||
"one": "Dispositif",
|
"one": "Dispositif",
|
||||||
"reassign_already_owned": "Réattribuer des appareils qui existent déjà et qui appartiennent à une autre entité/salle/abonné ?",
|
"reassign_already_owned": "Réattribuer des appareils qui existent déjà et qui appartiennent à une autre entité/salle/abonné ?",
|
||||||
|
"reboot_logs": "Journaux de redémarrage",
|
||||||
"restricted": "Limité",
|
"restricted": "Limité",
|
||||||
"restricted_overriden": "Il s'agit d'un appareil restreint, mais il est en mode développement. Toutes les restrictions sont actuellement ignorées",
|
"restricted_overriden": "Il s'agit d'un appareil restreint, mais il est en mode développement. Toutes les restrictions sont actuellement ignorées",
|
||||||
"restrictions_overriden_title": "Mode développement",
|
"restrictions_overriden_title": "Mode développement",
|
||||||
|
|||||||
@@ -644,6 +644,7 @@
|
|||||||
"notifications": "Notificações do dispositivo",
|
"notifications": "Notificações do dispositivo",
|
||||||
"one": "Dispositivo",
|
"one": "Dispositivo",
|
||||||
"reassign_already_owned": "Reatribuir dispositivos que já existem e são de propriedade de outra entidade/local/assinante?",
|
"reassign_already_owned": "Reatribuir dispositivos que já existem e são de propriedade de outra entidade/local/assinante?",
|
||||||
|
"reboot_logs": "Registros de reinicialização",
|
||||||
"restricted": "Restrito",
|
"restricted": "Restrito",
|
||||||
"restricted_overriden": "Este é um dispositivo restrito, mas está em modo de desenvolvimento. Todas as restrições são atualmente ignoradas",
|
"restricted_overriden": "Este é um dispositivo restrito, mas está em modo de desenvolvimento. Todas as restrições são atualmente ignoradas",
|
||||||
"restrictions_overriden_title": "Modo de desenvolvedor",
|
"restrictions_overriden_title": "Modo de desenvolvedor",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export type DeviceLog = {
|
|||||||
severity: number;
|
severity: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getDeviceLogs = (limit: number, serialNumber?: string, logType?: 0 | 1) => async () =>
|
const getDeviceLogs = (limit: number, serialNumber?: string, logType?: 0 | 1 | 2) => async () =>
|
||||||
axiosGw
|
axiosGw
|
||||||
.get(`device/${serialNumber}/logs?newest=true&limit=${limit}&logType=${logType}`)
|
.get(`device/${serialNumber}/logs?newest=true&limit=${limit}&logType=${logType}`)
|
||||||
.then((response) => response.data) as Promise<{
|
.then((response) => response.data) as Promise<{
|
||||||
@@ -28,7 +28,7 @@ export const useGetDeviceLogs = ({
|
|||||||
serialNumber?: string;
|
serialNumber?: string;
|
||||||
limit: number;
|
limit: number;
|
||||||
onError?: (e: AxiosError) => void;
|
onError?: (e: AxiosError) => void;
|
||||||
logType?: 0 | 1;
|
logType?: 0 | 1 | 2;
|
||||||
}) =>
|
}) =>
|
||||||
useQuery(['devicelogs', serialNumber, { limit, logType }], getDeviceLogs(limit, serialNumber, logType ?? 0), {
|
useQuery(['devicelogs', serialNumber, { limit, logType }], getDeviceLogs(limit, serialNumber, logType ?? 0), {
|
||||||
keepPreviousData: true,
|
keepPreviousData: true,
|
||||||
@@ -44,7 +44,7 @@ const deleteLogs = async ({
|
|||||||
}: {
|
}: {
|
||||||
serialNumber: string;
|
serialNumber: string;
|
||||||
endDate: number;
|
endDate: number;
|
||||||
logType: 0 | 1;
|
logType: 0 | 1 | 2;
|
||||||
}) => axiosGw.delete(`device/${serialNumber}/logs?endDate=${endDate}&logType=${logType}`);
|
}) => axiosGw.delete(`device/${serialNumber}/logs?endDate=${endDate}&logType=${logType}`);
|
||||||
export const useDeleteLogs = () => {
|
export const useDeleteLogs = () => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
@@ -62,7 +62,7 @@ const getLogsBatch = (
|
|||||||
end?: number,
|
end?: number,
|
||||||
limit?: number,
|
limit?: number,
|
||||||
offset?: number,
|
offset?: number,
|
||||||
logType?: 0 | 1,
|
logType?: 0 | 1 | 2,
|
||||||
) =>
|
) =>
|
||||||
axiosGw
|
axiosGw
|
||||||
.get(
|
.get(
|
||||||
@@ -74,7 +74,7 @@ const getLogsBatch = (
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
const getDeviceLogsWithTimestamps =
|
const getDeviceLogsWithTimestamps =
|
||||||
(serialNumber?: string, start?: number, end?: number, logType?: 0 | 1) => async () => {
|
(serialNumber?: string, start?: number, end?: number, logType?: 0 | 1 | 2) => async () => {
|
||||||
let offset = 0;
|
let offset = 0;
|
||||||
const limit = 100;
|
const limit = 100;
|
||||||
let logs: DeviceLog[] = [];
|
let logs: DeviceLog[] = [];
|
||||||
@@ -104,7 +104,7 @@ export const useGetDeviceLogsWithTimestamps = ({
|
|||||||
start?: number;
|
start?: number;
|
||||||
end?: number;
|
end?: number;
|
||||||
onError?: (e: AxiosError) => void;
|
onError?: (e: AxiosError) => void;
|
||||||
logType?: 0 | 1;
|
logType?: 0 | 1 | 2;
|
||||||
}) =>
|
}) =>
|
||||||
useQuery(
|
useQuery(
|
||||||
['devicelogs', serialNumber, { start, end, logType }],
|
['devicelogs', serialNumber, { start, end, logType }],
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ const CrashLogs = ({ serialNumber }: Props) => {
|
|||||||
setHiddenColumns={setHiddenColumns}
|
setHiddenColumns={setHiddenColumns}
|
||||||
preference="gateway.device.logs.hiddenColumns"
|
preference="gateway.device.logs.hiddenColumns"
|
||||||
/>
|
/>
|
||||||
<DeleteLogModal serialNumber={serialNumber} logType={0} />
|
<DeleteLogModal serialNumber={serialNumber} logType={1} />
|
||||||
<RefreshButton isCompact isFetching={getLogs.isFetching} onClick={getLogs.refetch} colorScheme="blue" />
|
<RefreshButton isCompact isFetching={getLogs.isFetching} onClick={getLogs.refetch} colorScheme="blue" />
|
||||||
</HStack>
|
</HStack>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const CustomInputButton = React.forwardRef(
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
type Props = { serialNumber: string; logType: 0 | 1 };
|
type Props = { serialNumber: string; logType: 0 | 1 | 2 };
|
||||||
const DeleteLogModal = ({ serialNumber, logType }: Props) => {
|
const DeleteLogModal = ({ serialNumber, logType }: Props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|||||||
94
src/pages/Device/LogsCard/LogHistory/RebootLogs.tsx
Normal file
94
src/pages/Device/LogsCard/LogHistory/RebootLogs.tsx
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
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';
|
||||||
|
import { ColumnPicker } from 'components/DataTables/ColumnPicker';
|
||||||
|
import { DataTable } from 'components/DataTables/DataTable';
|
||||||
|
import { Column } from 'models/Table';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
serialNumber: string;
|
||||||
|
};
|
||||||
|
const RebootLogs = ({ serialNumber }: Props) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [limit, setLimit] = React.useState(25);
|
||||||
|
const [hiddenColumns, setHiddenColumns] = React.useState<string[]>([]);
|
||||||
|
const { time, setTime, getCustomLogs, getLogs, columns, modal } = useDeviceLogsTable({
|
||||||
|
serialNumber,
|
||||||
|
limit,
|
||||||
|
logType: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
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}
|
||||||
|
setHiddenColumns={setHiddenColumns}
|
||||||
|
preference="gateway.device.logs.hiddenColumns"
|
||||||
|
/>
|
||||||
|
<DeleteLogModal serialNumber={serialNumber} logType={2} />
|
||||||
|
<RefreshButton isCompact isFetching={getLogs.isFetching} onClick={getLogs.refetch} colorScheme="blue" />
|
||||||
|
</HStack>
|
||||||
|
</Flex>
|
||||||
|
<Box overflowY="auto" h="300px">
|
||||||
|
<DataTable
|
||||||
|
columns={
|
||||||
|
columns as {
|
||||||
|
id: string;
|
||||||
|
Header: string;
|
||||||
|
Footer: string;
|
||||||
|
accessor: string;
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
data={data}
|
||||||
|
isLoading={getLogs.isFetching || getCustomLogs.isFetching}
|
||||||
|
hiddenColumns={hiddenColumns}
|
||||||
|
obj={t('controller.devices.logs')}
|
||||||
|
// @ts-ignore
|
||||||
|
hideControls
|
||||||
|
showAllRows
|
||||||
|
/>
|
||||||
|
{getLogs.data !== undefined && (
|
||||||
|
<Center mt={1} hidden={getCustomLogs.data !== undefined}>
|
||||||
|
{!noMoreAvailable || getLogs.isFetching ? (
|
||||||
|
<Button colorScheme="blue" onClick={raiseLimit} isLoading={getLogs.isFetching}>
|
||||||
|
{t('controller.devices.show_more')}
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Heading size="sm">{t('controller.devices.no_more_available')}!</Heading>
|
||||||
|
)}
|
||||||
|
</Center>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
{modal}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RebootLogs;
|
||||||
@@ -10,7 +10,7 @@ import { Column } from 'models/Table';
|
|||||||
type Props = {
|
type Props = {
|
||||||
serialNumber: string;
|
serialNumber: string;
|
||||||
limit: number;
|
limit: number;
|
||||||
logType: 0 | 1;
|
logType: 0 | 1 | 2;
|
||||||
};
|
};
|
||||||
|
|
||||||
const useDeviceLogsTable = ({ serialNumber, limit, logType }: Props) => {
|
const useDeviceLogsTable = ({ serialNumber, limit, logType }: Props) => {
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Box, Tab, TabList, TabPanel, TabPanels, Tabs } from '@chakra-ui/react';
|
import { Box, Tab, TabList, TabPanel, TabPanels, Tabs, useBreakpoint } from '@chakra-ui/react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import CommandHistory from './CommandHistory';
|
import CommandHistory from './CommandHistory';
|
||||||
import HealthCheckHistory from './HealthCheckHistory';
|
import HealthCheckHistory from './HealthCheckHistory';
|
||||||
import LogHistory from './LogHistory';
|
import LogHistory from './LogHistory';
|
||||||
import CrashLogs from './LogHistory/CrashLogs';
|
import CrashLogs from './LogHistory/CrashLogs';
|
||||||
|
import RebootLogs from './LogHistory/RebootLogs';
|
||||||
import { Card } from 'components/Containers/Card';
|
import { Card } from 'components/Containers/Card';
|
||||||
import { CardBody } from 'components/Containers/Card/CardBody';
|
import { CardBody } from 'components/Containers/Card/CardBody';
|
||||||
|
|
||||||
@@ -13,12 +14,15 @@ type Props = {
|
|||||||
};
|
};
|
||||||
const DeviceLogsCard = ({ serialNumber }: Props) => {
|
const DeviceLogsCard = ({ serialNumber }: Props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const breakpoint = useBreakpoint();
|
||||||
const [tabIndex, setTabIndex] = React.useState(0);
|
const [tabIndex, setTabIndex] = React.useState(0);
|
||||||
|
|
||||||
const handleTabsChange = React.useCallback((index: number) => {
|
const handleTabsChange = React.useCallback((index: number) => {
|
||||||
setTabIndex(index);
|
setTabIndex(index);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const isCompact = breakpoint === 'base' || breakpoint === 'sm' || breakpoint === 'md' || breakpoint === 'lg';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card p={0} mb={4}>
|
<Card p={0} mb={4}>
|
||||||
<CardBody p={0}>
|
<CardBody p={0}>
|
||||||
@@ -34,7 +38,10 @@ const DeviceLogsCard = ({ serialNumber }: Props) => {
|
|||||||
{t('controller.devices.logs')}
|
{t('controller.devices.logs')}
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab fontSize="lg" fontWeight="bold">
|
<Tab fontSize="lg" fontWeight="bold">
|
||||||
{t('devices.crash_logs')}
|
{isCompact ? 'Crashes' : t('devices.crash_logs')}
|
||||||
|
</Tab>
|
||||||
|
<Tab fontSize="lg" fontWeight="bold">
|
||||||
|
{isCompact ? 'Reboots' : t('devices.reboot_logs')}
|
||||||
</Tab>
|
</Tab>
|
||||||
</TabList>
|
</TabList>
|
||||||
<TabPanels>
|
<TabPanels>
|
||||||
@@ -61,6 +68,9 @@ const DeviceLogsCard = ({ serialNumber }: Props) => {
|
|||||||
<TabPanel>
|
<TabPanel>
|
||||||
<CrashLogs serialNumber={serialNumber} />
|
<CrashLogs serialNumber={serialNumber} />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
<TabPanel>
|
||||||
|
<RebootLogs serialNumber={serialNumber} />
|
||||||
|
</TabPanel>
|
||||||
</TabPanels>
|
</TabPanels>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</CardBody>
|
</CardBody>
|
||||||
|
|||||||
Reference in New Issue
Block a user