mirror of
https://github.com/ajnart/homarr.git
synced 2025-10-26 08:06:12 +01:00
feat: add Proxmox Uptime View (#2092)
* feat: add Proxmox Uptime View * fix: Proxmox Uptime * fix: Proxmox Uptime * fix: add env.example, make formattedUptime a constant * fix: Uptime * fix: Implement dayjs * fix: removed unused import * fix: Uptime
This commit is contained in:
@@ -86,7 +86,7 @@
|
||||
},
|
||||
"info": {
|
||||
"uptime": "Uptime",
|
||||
"uptimeFormat": "{{days}} days, {{hours}} hours",
|
||||
"uptimeFormat": "{{days}} days, {{hours}} hours, {{minutes}} minutes",
|
||||
"updates": "Updates Available",
|
||||
"reboot": "Reboot"
|
||||
},
|
||||
|
||||
@@ -6,6 +6,8 @@ import {
|
||||
IconInfoSquare,
|
||||
IconStatusChange,
|
||||
} from '@tabler/icons-react';
|
||||
import dayjs from 'dayjs';
|
||||
import duration from 'dayjs/plugin/duration';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useConfigContext } from '~/config/provider';
|
||||
import { api } from '~/utils/api';
|
||||
@@ -18,6 +20,8 @@ import HealthMonitoringFileSystem from './HealthMonitoringFileSystem';
|
||||
import HealthMonitoringMemory from './HealthMonitoringMemory';
|
||||
import { ClusterStatusTile } from './cluster/HealthMonitoringClusterTile';
|
||||
|
||||
dayjs.extend(duration);
|
||||
|
||||
const defaultViewStates = ['none', 'node', 'vm', 'lxc', 'storage'] as const;
|
||||
type DefaultViewState = (typeof defaultViewStates)[number];
|
||||
|
||||
@@ -186,12 +190,6 @@ function HealthMonitoringWidgetTile({ widget }: HealthMonitoringWidgetProps) {
|
||||
const SystemStatusTile = ({ data, properties }: { data: any; properties: any }) => {
|
||||
const { t } = useTranslation('modules/health-monitoring');
|
||||
|
||||
const formatUptime = (uptime: number) => {
|
||||
const days = Math.floor(uptime / (60 * 60 * 24));
|
||||
const remainingHours = Math.floor((uptime % (60 * 60 * 24)) / 3600);
|
||||
return t('info.uptimeFormat', { days: days, hours: remainingHours})
|
||||
};
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<Card>
|
||||
@@ -268,3 +266,13 @@ const useStatusQuery = (node: string, ignoreCerts: boolean) => {
|
||||
};
|
||||
|
||||
export default definition;
|
||||
|
||||
export const formatUptime = (uptime: number) => {
|
||||
const { t } = useTranslation('modules/health-monitoring');
|
||||
const time = dayjs.duration(uptime, 's');
|
||||
return t('info.uptimeFormat', {
|
||||
days: Math.floor(time.asDays()),
|
||||
hours: time.hours(),
|
||||
minutes: time.minutes(),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,24 +1,20 @@
|
||||
import { Accordion, Center, Flex, Group, RingProgress, Stack, Text } from '@mantine/core';
|
||||
import { Accordion, Card, Center, Flex, Group, RingProgress, Stack, Text } from '@mantine/core';
|
||||
import {
|
||||
IconBrain,
|
||||
IconCpu,
|
||||
IconCube,
|
||||
IconDatabase,
|
||||
IconDeviceLaptop,
|
||||
IconInfoSquare,
|
||||
IconServer,
|
||||
} from '@tabler/icons-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ResourceData, ResourceSummary } from '~/widgets/health-monitoring/cluster/types';
|
||||
import { ResourceData } from '~/widgets/health-monitoring/cluster/types';
|
||||
|
||||
import { formatUptime } from '../HealthMonitoringTile';
|
||||
import { ResourceType } from './HealthMonitoringClusterResourceRow';
|
||||
|
||||
export const ClusterStatusTile = ({
|
||||
data,
|
||||
properties,
|
||||
}: {
|
||||
data: ResourceSummary;
|
||||
properties: any;
|
||||
}) => {
|
||||
export const ClusterStatusTile = ({ data, properties }: { data: any; properties: any }) => {
|
||||
const { t } = useTranslation('modules/health-monitoring');
|
||||
|
||||
const running = (total: number, current: ResourceData) => {
|
||||
@@ -46,12 +42,26 @@ export const ClusterStatusTile = ({
|
||||
(sum: number, item: ResourceData) => (item.running ? item.cpu * item.maxCpu + sum : sum),
|
||||
0
|
||||
);
|
||||
const uptime = data.nodes.reduce(
|
||||
(sum: number, { uptime }: ResourceData) => (sum > uptime ? sum : uptime),
|
||||
0
|
||||
);
|
||||
|
||||
const cpuPercent = (usedCpu / maxCpu) * 100;
|
||||
const memPercent = (usedMem / maxMem) * 100;
|
||||
|
||||
return (
|
||||
<Stack h="100%">
|
||||
<Card>
|
||||
<Group position="center">
|
||||
<IconInfoSquare size={40} />
|
||||
<Text fz="lg" tt="uppercase" fw={700} c="dimmed" align="center">
|
||||
{t('info.uptime')}:
|
||||
<br />
|
||||
{formatUptime(uptime)}
|
||||
</Text>
|
||||
</Group>
|
||||
</Card>
|
||||
<SummaryHeader cpu={cpuPercent} memory={memPercent} include={properties.summary} />
|
||||
<Accordion
|
||||
variant="contained"
|
||||
@@ -123,9 +133,8 @@ interface SummaryHeaderProps {
|
||||
|
||||
const SummaryHeader = ({ cpu, memory, include }: SummaryHeaderProps) => {
|
||||
const { t } = useTranslation('modules/health-monitoring');
|
||||
if (!include) {
|
||||
return null;
|
||||
}
|
||||
if (!include) return null;
|
||||
|
||||
return (
|
||||
<Center>
|
||||
<Group noWrap>
|
||||
@@ -142,7 +151,7 @@ const SummaryHeader = ({ cpu, memory, include }: SummaryHeaderProps) => {
|
||||
sections={[{ value: cpu, color: cpu > 75 ? 'orange' : 'green' }]}
|
||||
/>
|
||||
<Stack align="center" justify="center" spacing={0}>
|
||||
<Text>{t('cluster.summary.cpu')}</Text>
|
||||
<Text weight={500}>{t('cluster.summary.cpu')}</Text>
|
||||
<Text>{cpu.toFixed(1)}%</Text>
|
||||
</Stack>
|
||||
</Flex>
|
||||
@@ -159,7 +168,7 @@ const SummaryHeader = ({ cpu, memory, include }: SummaryHeaderProps) => {
|
||||
sections={[{ value: memory, color: memory > 75 ? 'orange' : 'green' }]}
|
||||
/>
|
||||
<Stack align="center" justify="center" spacing={0}>
|
||||
<Text>{t('cluster.summary.ram')}</Text>
|
||||
<Text weight={500}>{t('cluster.summary.ram')}</Text>
|
||||
<Text>{memory.toFixed(1)}%</Text>
|
||||
</Stack>
|
||||
</Flex>
|
||||
|
||||
Reference in New Issue
Block a user