mirror of
https://github.com/ajnart/homarr.git
synced 2025-11-06 21:45:47 +01:00
📱 Make the design way more responsive for mobile
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { Aside as MantineAside, Group } from '@mantine/core';
|
import { Aside as MantineAside, createStyles, Group } from '@mantine/core';
|
||||||
|
import { useMediaQuery } from '@mantine/hooks';
|
||||||
import {
|
import {
|
||||||
WeatherModule,
|
WeatherModule,
|
||||||
DateModule,
|
DateModule,
|
||||||
@@ -8,12 +9,29 @@ import {
|
|||||||
} from '../modules';
|
} from '../modules';
|
||||||
import { ModuleWrapper } from '../modules/moduleWrapper';
|
import { ModuleWrapper } from '../modules/moduleWrapper';
|
||||||
|
|
||||||
|
const useStyles = createStyles((theme) => ({
|
||||||
|
hide: {
|
||||||
|
[theme.fn.smallerThan('xs')]: {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
burger: {
|
||||||
|
[theme.fn.largerThan('sm')]: {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
export default function Aside(props: any) {
|
export default function Aside(props: any) {
|
||||||
|
const { classes, cx } = useStyles();
|
||||||
|
const matches = useMediaQuery('(min-width: 800px)');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MantineAside
|
<MantineAside
|
||||||
pr="md"
|
pr="md"
|
||||||
hiddenBreakpoint="md"
|
hiddenBreakpoint="sm"
|
||||||
hidden
|
hidden
|
||||||
|
className={cx(classes.hide)}
|
||||||
style={{
|
style={{
|
||||||
border: 'none',
|
border: 'none',
|
||||||
}}
|
}}
|
||||||
@@ -21,6 +39,7 @@ export default function Aside(props: any) {
|
|||||||
base: 'auto',
|
base: 'auto',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{matches && (
|
||||||
<Group my="sm" grow direction="column" style={{ width: 300 }}>
|
<Group my="sm" grow direction="column" style={{ width: 300 }}>
|
||||||
<ModuleWrapper module={CalendarModule} />
|
<ModuleWrapper module={CalendarModule} />
|
||||||
<ModuleWrapper module={TotalDownloadsModule} />
|
<ModuleWrapper module={TotalDownloadsModule} />
|
||||||
@@ -28,6 +47,7 @@ export default function Aside(props: any) {
|
|||||||
<ModuleWrapper module={DateModule} />
|
<ModuleWrapper module={DateModule} />
|
||||||
<ModuleWrapper module={SystemModule} />
|
<ModuleWrapper module={SystemModule} />
|
||||||
</Group>
|
</Group>
|
||||||
|
)}
|
||||||
</MantineAside>
|
</MantineAside>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,29 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { createStyles, Header as Head, Group, Box } from '@mantine/core';
|
import {
|
||||||
|
createStyles,
|
||||||
|
Header as Head,
|
||||||
|
Group,
|
||||||
|
Box,
|
||||||
|
Burger,
|
||||||
|
Drawer,
|
||||||
|
Title,
|
||||||
|
ScrollArea,
|
||||||
|
ActionIcon,
|
||||||
|
Transition,
|
||||||
|
} from '@mantine/core';
|
||||||
|
import { useBooleanToggle } from '@mantine/hooks';
|
||||||
import { Logo } from './Logo';
|
import { Logo } from './Logo';
|
||||||
import SearchBar from '../modules/search/SearchModule';
|
import SearchBar from '../modules/search/SearchModule';
|
||||||
import { AddItemShelfButton } from '../AppShelf/AddAppShelfItem';
|
import { AddItemShelfButton } from '../AppShelf/AddAppShelfItem';
|
||||||
import { SettingsMenuButton } from '../Settings/SettingsMenu';
|
import { SettingsMenuButton } from '../Settings/SettingsMenu';
|
||||||
|
import { ModuleWrapper } from '../modules/moduleWrapper';
|
||||||
|
import {
|
||||||
|
CalendarModule,
|
||||||
|
TotalDownloadsModule,
|
||||||
|
WeatherModule,
|
||||||
|
DateModule,
|
||||||
|
SystemModule,
|
||||||
|
} from '../modules';
|
||||||
|
|
||||||
const HEADER_HEIGHT = 60;
|
const HEADER_HEIGHT = 60;
|
||||||
|
|
||||||
@@ -13,10 +33,18 @@ const useStyles = createStyles((theme) => ({
|
|||||||
display: 'none',
|
display: 'none',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
burger: {
|
||||||
|
[theme.fn.largerThan('sm')]: {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export function Header(props: any) {
|
export function Header(props: any) {
|
||||||
|
const [opened, toggleOpened] = useBooleanToggle(false);
|
||||||
const { classes, cx } = useStyles();
|
const { classes, cx } = useStyles();
|
||||||
|
const [hidden, toggleHidden] = useBooleanToggle(true);
|
||||||
|
const drawerModule = CalendarModule;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Head height="auto">
|
<Head height="auto">
|
||||||
@@ -28,6 +56,48 @@ export function Header(props: any) {
|
|||||||
<SearchBar />
|
<SearchBar />
|
||||||
<SettingsMenuButton />
|
<SettingsMenuButton />
|
||||||
<AddItemShelfButton />
|
<AddItemShelfButton />
|
||||||
|
<ActionIcon className={classes.burger} variant="default" radius="md" size="xl">
|
||||||
|
<Burger
|
||||||
|
opened={!hidden}
|
||||||
|
onClick={(_) => {
|
||||||
|
toggleHidden();
|
||||||
|
toggleOpened();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</ActionIcon>
|
||||||
|
<Drawer
|
||||||
|
size="auto"
|
||||||
|
padding="xl"
|
||||||
|
position="right"
|
||||||
|
hidden={hidden}
|
||||||
|
title={<Title order={3}>Modules</Title>}
|
||||||
|
opened
|
||||||
|
onClose={() => {
|
||||||
|
toggleHidden();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Transition
|
||||||
|
mounted={opened}
|
||||||
|
transition="pop-top-right"
|
||||||
|
duration={300}
|
||||||
|
timingFunction="ease"
|
||||||
|
onExit={() => toggleOpened()}
|
||||||
|
>
|
||||||
|
{(styles) => (
|
||||||
|
<div style={styles}>
|
||||||
|
<ScrollArea style={{ height: '90vh' }}>
|
||||||
|
<Group my="sm" grow direction="column" style={{ width: 300 }}>
|
||||||
|
<ModuleWrapper module={drawerModule} />
|
||||||
|
<ModuleWrapper module={TotalDownloadsModule} />
|
||||||
|
<ModuleWrapper module={WeatherModule} />
|
||||||
|
<ModuleWrapper module={DateModule} />
|
||||||
|
<ModuleWrapper module={SystemModule} />
|
||||||
|
</Group>
|
||||||
|
</ScrollArea>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Transition>
|
||||||
|
</Drawer>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</Head>
|
</Head>
|
||||||
|
|||||||
@@ -1,16 +1,37 @@
|
|||||||
import { AppShell, createStyles } from '@mantine/core';
|
import { AppShell, createStyles, Group } from '@mantine/core';
|
||||||
import { Header } from './Header';
|
import { Header } from './Header';
|
||||||
import { Footer } from './Footer';
|
import { Footer } from './Footer';
|
||||||
import Aside from './Aside';
|
import Aside from './Aside';
|
||||||
|
import { ModuleWrapper } from '../modules/moduleWrapper';
|
||||||
|
import {
|
||||||
|
CalendarModule,
|
||||||
|
TotalDownloadsModule,
|
||||||
|
WeatherModule,
|
||||||
|
DateModule,
|
||||||
|
SystemModule,
|
||||||
|
} from '../modules';
|
||||||
|
|
||||||
const useStyles = createStyles((theme) => ({
|
const useStyles = createStyles((theme) => ({
|
||||||
main: {},
|
main: {},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export default function Layout({ children, style }: any) {
|
export default function Layout({ children, style }: any) {
|
||||||
|
const drawerContent = (
|
||||||
|
<Group my="sm" grow direction="column" style={{ width: 300 }}>
|
||||||
|
<ModuleWrapper module={CalendarModule} />
|
||||||
|
<ModuleWrapper module={TotalDownloadsModule} />
|
||||||
|
<ModuleWrapper module={WeatherModule} />
|
||||||
|
<ModuleWrapper module={DateModule} />
|
||||||
|
<ModuleWrapper module={SystemModule} />
|
||||||
|
</Group>
|
||||||
|
);
|
||||||
const { classes, cx } = useStyles();
|
const { classes, cx } = useStyles();
|
||||||
return (
|
return (
|
||||||
<AppShell aside={<Aside />} header={<Header />} footer={<Footer links={[]} />}>
|
<AppShell
|
||||||
|
aside={<Aside />}
|
||||||
|
header={<Header data={drawerContent} />}
|
||||||
|
footer={<Footer links={[]} />}
|
||||||
|
>
|
||||||
<main
|
<main
|
||||||
className={cx(classes.main)}
|
className={cx(classes.main)}
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ function DayComponent(props: any) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Popover
|
<Popover
|
||||||
position="left"
|
position="bottom"
|
||||||
radius="lg"
|
radius="lg"
|
||||||
shadow="xl"
|
shadow="xl"
|
||||||
transition="pop"
|
transition="pop"
|
||||||
@@ -176,7 +176,7 @@ function DayComponent(props: any) {
|
|||||||
boxShadow: '0 0 14px 14px rgba(0, 0, 0, 0.1), 0 14px 11px rgba(0, 0, 0, 0.1)',
|
boxShadow: '0 0 14px 14px rgba(0, 0, 0, 0.1), 0 14px 11px rgba(0, 0, 0, 0.1)',
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
width={700}
|
width="auto"
|
||||||
onClose={() => setOpened(false)}
|
onClose={() => setOpened(false)}
|
||||||
opened={opened}
|
opened={opened}
|
||||||
target={day}
|
target={day}
|
||||||
@@ -197,12 +197,18 @@ function DayComponent(props: any) {
|
|||||||
{index < radarrFiltered.length - 1 && <Divider variant="dashed" my="xl" />}
|
{index < radarrFiltered.length - 1 && <Divider variant="dashed" my="xl" />}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
|
{sonarrFiltered.length > 0 && lidarrFiltered.length > 0 && (
|
||||||
|
<Divider variant="dashed" my="xl" />
|
||||||
|
)}
|
||||||
{lidarrFiltered.map((media: any, index: number) => (
|
{lidarrFiltered.map((media: any, index: number) => (
|
||||||
<React.Fragment key={index}>
|
<React.Fragment key={index}>
|
||||||
<LidarrMediaDisplay media={media} />
|
<LidarrMediaDisplay media={media} />
|
||||||
{index < lidarrFiltered.length - 1 && <Divider variant="dashed" my="xl" />}
|
{index < lidarrFiltered.length - 1 && <Divider variant="dashed" my="xl" />}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
|
{lidarrFiltered.length > 0 && readarrFiltered.length > 0 && (
|
||||||
|
<Divider variant="dashed" my="xl" />
|
||||||
|
)}
|
||||||
{readarrFiltered.map((media: any, index: number) => (
|
{readarrFiltered.map((media: any, index: number) => (
|
||||||
<React.Fragment key={index}>
|
<React.Fragment key={index}>
|
||||||
<ReadarrMediaDisplay media={media} />
|
<ReadarrMediaDisplay media={media} />
|
||||||
|
|||||||
@@ -1,4 +1,14 @@
|
|||||||
import { Image, Group, Title, Badge, Text, ActionIcon, Anchor, ScrollArea } from '@mantine/core';
|
import {
|
||||||
|
Image,
|
||||||
|
Group,
|
||||||
|
Title,
|
||||||
|
Badge,
|
||||||
|
Text,
|
||||||
|
ActionIcon,
|
||||||
|
Anchor,
|
||||||
|
ScrollArea,
|
||||||
|
createStyles,
|
||||||
|
} from '@mantine/core';
|
||||||
import { IconLink as Link } from '@tabler/icons';
|
import { IconLink as Link } from '@tabler/icons';
|
||||||
import { useConfig } from '../../../tools/state';
|
import { useConfig } from '../../../tools/state';
|
||||||
import { serviceItem } from '../../../tools/types';
|
import { serviceItem } from '../../../tools/types';
|
||||||
@@ -14,13 +24,31 @@ export interface IMedia {
|
|||||||
episodeNumber?: number;
|
episodeNumber?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const useStyles = createStyles((theme) => ({
|
||||||
|
poster: {
|
||||||
|
[theme.fn.smallerThan('sm')]: {
|
||||||
|
maxWidth: '20%',
|
||||||
|
},
|
||||||
|
[theme.fn.largerThan('sm')]: {
|
||||||
|
maxWidth: 300,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
overview: {
|
||||||
|
[theme.fn.largerThan('sm')]: {
|
||||||
|
width: 400,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
export function MediaDisplay(props: { media: IMedia }) {
|
export function MediaDisplay(props: { media: IMedia }) {
|
||||||
const { media }: { media: IMedia } = props;
|
const { media }: { media: IMedia } = props;
|
||||||
|
const { classes, cx } = useStyles();
|
||||||
return (
|
return (
|
||||||
<Group position="apart">
|
<Group position="apart">
|
||||||
<Text>
|
<Text>
|
||||||
{media.poster && (
|
{media.poster && (
|
||||||
<Image
|
<Image
|
||||||
|
className={classes.poster}
|
||||||
style={{
|
style={{
|
||||||
float: 'right',
|
float: 'right',
|
||||||
}}
|
}}
|
||||||
@@ -28,12 +56,10 @@ export function MediaDisplay(props: { media: IMedia }) {
|
|||||||
fit="cover"
|
fit="cover"
|
||||||
src={media.poster}
|
src={media.poster}
|
||||||
alt={media.title}
|
alt={media.title}
|
||||||
width={250}
|
|
||||||
height={400}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Group direction="column">
|
<Group direction="column">
|
||||||
<Group noWrap mr="sm" style={{ minWidth: 400 }}>
|
<Group noWrap mr="sm" className={classes.overview}>
|
||||||
<Title order={3}>{media.title}</Title>
|
<Title order={3}>{media.title}</Title>
|
||||||
{media.imdbId && (
|
{media.imdbId && (
|
||||||
<Anchor href={`https://www.imdb.com/title/${media.imdbId}`} target="_blank">
|
<Anchor href={`https://www.imdb.com/title/${media.imdbId}`} target="_blank">
|
||||||
@@ -65,7 +91,7 @@ export function MediaDisplay(props: { media: IMedia }) {
|
|||||||
)}
|
)}
|
||||||
</Group>
|
</Group>
|
||||||
<Group direction="column" position="apart">
|
<Group direction="column" position="apart">
|
||||||
<ScrollArea style={{ height: 250 }}>{media.overview}</ScrollArea>
|
<ScrollArea style={{ maxHeight: 250, maxWidth: 700 }}>{media.overview}</ScrollArea>
|
||||||
<Group align="center" position="center" spacing="xs">
|
<Group align="center" position="center" spacing="xs">
|
||||||
{media.genres.map((genre: string, i: number) => (
|
{media.genres.map((genre: string, i: number) => (
|
||||||
<Badge size="sm" key={i}>
|
<Badge size="sm" key={i}>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useEffect, useState } from 'react';
|
|||||||
import { IconClock as Clock } from '@tabler/icons';
|
import { IconClock as Clock } from '@tabler/icons';
|
||||||
import { useConfig } from '../../../tools/state';
|
import { useConfig } from '../../../tools/state';
|
||||||
import { IModule } from '../modules';
|
import { IModule } from '../modules';
|
||||||
|
import { useSetSafeInterval } from '../../../tools/hooks/useSetSafeInterval';
|
||||||
|
|
||||||
export const DateModule: IModule = {
|
export const DateModule: IModule = {
|
||||||
title: 'Date',
|
title: 'Date',
|
||||||
@@ -20,13 +21,14 @@ export const DateModule: IModule = {
|
|||||||
|
|
||||||
export default function DateComponent(props: any) {
|
export default function DateComponent(props: any) {
|
||||||
const [date, setDate] = useState(new Date());
|
const [date, setDate] = useState(new Date());
|
||||||
|
const setSafeInterval = useSetSafeInterval();
|
||||||
const { config } = useConfig();
|
const { config } = useConfig();
|
||||||
const isFullTime = config?.modules?.[DateModule.title]?.options?.full?.value ?? false;
|
const isFullTime = config?.modules?.[DateModule.title]?.options?.full?.value ?? false;
|
||||||
const formatString = isFullTime ? 'HH:mm' : 'h:mm A';
|
const formatString = isFullTime ? 'HH:mm' : 'h:mm A';
|
||||||
// Change date on minute change
|
// Change date on minute change
|
||||||
// Note: Using 10 000ms instead of 1000ms to chill a little :)
|
// Note: Using 10 000ms instead of 1000ms to chill a little :)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setInterval(() => {
|
setSafeInterval(() => {
|
||||||
setDate(new Date());
|
setDate(new Date());
|
||||||
}, 1000 * 60);
|
}, 1000 * 60);
|
||||||
}, []);
|
}, []);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { NormalizedTorrent } from '@ctrl/shared-torrent';
|
|||||||
import { IModule } from '../modules';
|
import { IModule } from '../modules';
|
||||||
import { useConfig } from '../../../tools/state';
|
import { useConfig } from '../../../tools/state';
|
||||||
import { AddItemShelfButton } from '../../AppShelf/AddAppShelfItem';
|
import { AddItemShelfButton } from '../../AppShelf/AddAppShelfItem';
|
||||||
|
import { useSetSafeInterval } from '../../../tools/hooks/useSetSafeInterval';
|
||||||
|
|
||||||
export const DownloadsModule: IModule = {
|
export const DownloadsModule: IModule = {
|
||||||
title: 'Torrent',
|
title: 'Torrent',
|
||||||
@@ -31,10 +32,10 @@ export default function DownloadComponent() {
|
|||||||
|
|
||||||
const [delugeTorrents, setDelugeTorrents] = useState<NormalizedTorrent[]>([]);
|
const [delugeTorrents, setDelugeTorrents] = useState<NormalizedTorrent[]>([]);
|
||||||
const [qBittorrentTorrents, setqBittorrentTorrents] = useState<NormalizedTorrent[]>([]);
|
const [qBittorrentTorrents, setqBittorrentTorrents] = useState<NormalizedTorrent[]>([]);
|
||||||
|
const setSafeInterval = useSetSafeInterval();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (qBittorrentService) {
|
if (qBittorrentService) {
|
||||||
setInterval(() => {
|
setSafeInterval(() => {
|
||||||
axios
|
axios
|
||||||
.post('/api/modules/downloads?dlclient=qbit', { ...qBittorrentService })
|
.post('/api/modules/downloads?dlclient=qbit', { ...qBittorrentService })
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
@@ -43,7 +44,7 @@ export default function DownloadComponent() {
|
|||||||
}, 3000);
|
}, 3000);
|
||||||
}
|
}
|
||||||
if (delugeService) {
|
if (delugeService) {
|
||||||
setInterval(() => {
|
setSafeInterval(() => {
|
||||||
axios.post('/api/modules/downloads?dlclient=deluge', { ...delugeService }).then((res) => {
|
axios.post('/api/modules/downloads?dlclient=deluge', { ...delugeService }).then((res) => {
|
||||||
setDelugeTorrents(res.data.torrents);
|
setDelugeTorrents(res.data.torrents);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { useListState } from '@mantine/hooks';
|
|||||||
import { AddItemShelfButton } from '../../AppShelf/AddAppShelfItem';
|
import { AddItemShelfButton } from '../../AppShelf/AddAppShelfItem';
|
||||||
import { useConfig } from '../../../tools/state';
|
import { useConfig } from '../../../tools/state';
|
||||||
import { IModule } from '../modules';
|
import { IModule } from '../modules';
|
||||||
|
import { useSetSafeInterval } from '../../../tools/hooks/useSetSafeInterval';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format bytes as human-readable text.
|
* Format bytes as human-readable text.
|
||||||
@@ -74,9 +75,9 @@ export default function TotalDownloadsComponent() {
|
|||||||
|
|
||||||
const totalDownloadSpeed = torrents.reduce((acc, torrent) => acc + torrent.downloadSpeed, 0);
|
const totalDownloadSpeed = torrents.reduce((acc, torrent) => acc + torrent.downloadSpeed, 0);
|
||||||
const totalUploadSpeed = torrents.reduce((acc, torrent) => acc + torrent.uploadSpeed, 0);
|
const totalUploadSpeed = torrents.reduce((acc, torrent) => acc + torrent.uploadSpeed, 0);
|
||||||
|
const setSafeInterval = useSetSafeInterval();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const interval = setInterval(() => {
|
setSafeInterval(() => {
|
||||||
// Get the current download speed of qBittorrent.
|
// Get the current download speed of qBittorrent.
|
||||||
if (qBittorrentService) {
|
if (qBittorrentService) {
|
||||||
axios
|
axios
|
||||||
|
|||||||
@@ -1,16 +1,11 @@
|
|||||||
import {
|
import { Center, Group, RingProgress, Title, useMantineTheme } from '@mantine/core';
|
||||||
Center,
|
|
||||||
Group,
|
|
||||||
RingProgress,
|
|
||||||
Title,
|
|
||||||
useMantineTheme,
|
|
||||||
} from '@mantine/core';
|
|
||||||
import { IconCpu } from '@tabler/icons';
|
import { IconCpu } from '@tabler/icons';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import si from 'systeminformation';
|
import si from 'systeminformation';
|
||||||
import { useListState } from '@mantine/hooks';
|
import { useListState } from '@mantine/hooks';
|
||||||
import { IModule } from '../modules';
|
import { IModule } from '../modules';
|
||||||
|
import { useSetSafeInterval } from '../../../tools/hooks/useSetSafeInterval';
|
||||||
|
|
||||||
export const SystemModule: IModule = {
|
export const SystemModule: IModule = {
|
||||||
title: 'System info',
|
title: 'System info',
|
||||||
@@ -28,13 +23,13 @@ interface ApiResponse {
|
|||||||
|
|
||||||
export default function SystemInfo(args: any) {
|
export default function SystemInfo(args: any) {
|
||||||
const [data, setData] = useState<ApiResponse>();
|
const [data, setData] = useState<ApiResponse>();
|
||||||
|
const setSafeInterval = useSetSafeInterval();
|
||||||
// Refresh data every second
|
// Refresh data every second
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setInterval(() => {
|
setSafeInterval(() => {
|
||||||
axios.get('/api/modules/systeminfo').then((res) => setData(res.data));
|
axios.get('/api/modules/systeminfo').then((res) => setData(res.data));
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}, [args]);
|
}, []);
|
||||||
|
|
||||||
// Update data every time data changes
|
// Update data every time data changes
|
||||||
const [cpuLoadHistory, cpuLoadHistoryHandlers] =
|
const [cpuLoadHistory, cpuLoadHistoryHandlers] =
|
||||||
|
|||||||
Reference in New Issue
Block a user