fix: finish widget modernization audit
This commit is contained in:
1 parent
bbcfc505bc
commit
747ccdfa9e
27 files changed
+340
-115
No files matched your search
@@ -0,0 +1,11 @@
|
||||
.target {
|
||||
min-width: 24px;
|
||||
min-height: 24px;
|
||||
}
|
||||
|
||||
@media (pointer: coarse) {
|
||||
.target {
|
||||
min-width: 44px;
|
||||
min-height: 44px;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
import { Box, getDefaultZIndex, Group, HoverCard, Progress, Stack, Text, UnstyledButton } from "@mantine/core";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Box, Group, Popover, Progress, Stack, Text, UnstyledButton } from "@mantine/core";
|
||||
|
||||
import { useScopedI18n } from "@homarr/translation/client";
|
||||
|
||||
import type { BeszelSystemRow } from "./types";
|
||||
import { thresholdColor } from "./colors";
|
||||
import { formatPercent, getProgressTrackSize } from "./format";
|
||||
import classes from "./disk-usage.module.css";
|
||||
|
||||
interface DiskUsageProps {
|
||||
system: BeszelSystemRow;
|
||||
@@ -17,34 +21,44 @@ const mountLabel = (path: string) =>
|
||||
const severityColor = (value: number) => `var(--mantine-color-${thresholdColor(value)}-6)`;
|
||||
|
||||
export const DiskUsage = ({ system, fontSize, progressSize, valueMiw, valueGap = 6 }: DiskUsageProps) => {
|
||||
const t = useScopedI18n("common");
|
||||
const [opened, setOpened] = useState(false);
|
||||
const filesystems = Object.entries(system.extraFilesystems).filter(([path]) => path !== "/");
|
||||
const filesystemUsageLabel = t("filesystemUsage", { count: filesystems.length + 1 });
|
||||
const trackSize = getProgressTrackSize(progressSize);
|
||||
const dotSize = progressSize === "xs" ? 2 : 3;
|
||||
const dotGap = 2;
|
||||
|
||||
useEffect(() => {
|
||||
if (filesystems.length === 0) setOpened(false);
|
||||
}, [filesystems.length]);
|
||||
|
||||
return (
|
||||
<Group gap={valueGap} wrap="nowrap" style={{ flex: 1, minWidth: 0, marginLeft: "auto" }}>
|
||||
<Text size={fontSize} fw={500} w={valueMiw} ta="left" style={{ whiteSpace: "nowrap", flexShrink: 0 }}>
|
||||
{formatPercent(system.disk)}
|
||||
</Text>
|
||||
<HoverCard
|
||||
zIndex={getDefaultZIndex("modal") - 3}
|
||||
position="right"
|
||||
withArrow
|
||||
shadow="md"
|
||||
openDelay={200}
|
||||
closeDelay={100}
|
||||
disabled={filesystems.length === 0}
|
||||
>
|
||||
<HoverCard.Target>
|
||||
{filesystems.length > 0 ? (
|
||||
{filesystems.length > 0 ? (
|
||||
<Popover
|
||||
opened={opened}
|
||||
onChange={setOpened}
|
||||
zIndex="var(--homarr-z-index-widget-background-tooltip)"
|
||||
position="right"
|
||||
withArrow
|
||||
shadow="md"
|
||||
>
|
||||
<Popover.Target>
|
||||
<UnstyledButton
|
||||
aria-label={`Show usage for ${filesystems.length + 1} filesystems`}
|
||||
aria-label={filesystemUsageLabel}
|
||||
className={classes.target}
|
||||
onMouseEnter={() => setOpened(true)}
|
||||
onMouseLeave={() => setOpened(false)}
|
||||
onBlur={() => setOpened(false)}
|
||||
onClick={() => setOpened(true)}
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flex: 1,
|
||||
minWidth: 24,
|
||||
cursor: "pointer",
|
||||
}}
|
||||
>
|
||||
@@ -75,32 +89,32 @@ export const DiskUsage = ({ system, fontSize, progressSize, valueMiw, valueGap =
|
||||
</Group>
|
||||
</Box>
|
||||
</UnstyledButton>
|
||||
) : (
|
||||
<Box style={{ display: "flex", alignItems: "center", flex: 1, minWidth: 24 }}>
|
||||
<Box pos="relative" style={{ flex: 1, minWidth: 24 }}>
|
||||
<Progress value={system.disk} color={thresholdColor(system.disk)} size={trackSize} />
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</HoverCard.Target>
|
||||
<HoverCard.Dropdown p={8}>
|
||||
<Stack gap={6} miw={145}>
|
||||
{[["/", system.disk] as const, ...filesystems].map(([path, value]) => (
|
||||
<Stack key={path} gap={1}>
|
||||
<Text size="10px" c="dimmed" fw={500} lh={1.2}>
|
||||
{mountLabel(path)}
|
||||
</Text>
|
||||
<Group gap={8} wrap="nowrap">
|
||||
<Text size="sm" fw={600} miw={48} lh={1.25}>
|
||||
{formatPercent(value)}
|
||||
</Popover.Target>
|
||||
<Popover.Dropdown aria-label={filesystemUsageLabel} p={8}>
|
||||
<Stack gap={6} miw={145}>
|
||||
{[["/", system.disk] as const, ...filesystems].map(([path, value]) => (
|
||||
<Stack key={path} gap={1}>
|
||||
<Text size="10px" c="dimmed" fw={500} lh={1.2}>
|
||||
{mountLabel(path)}
|
||||
</Text>
|
||||
<Progress value={value} color={thresholdColor(value)} size="xs" style={{ flex: 1 }} />
|
||||
</Group>
|
||||
</Stack>
|
||||
))}
|
||||
</Stack>
|
||||
</HoverCard.Dropdown>
|
||||
</HoverCard>
|
||||
<Group gap={8} wrap="nowrap">
|
||||
<Text size="sm" fw={600} miw={48} lh={1.25}>
|
||||
{formatPercent(value)}
|
||||
</Text>
|
||||
<Progress value={value} color={thresholdColor(value)} size="xs" style={{ flex: 1 }} />
|
||||
</Group>
|
||||
</Stack>
|
||||
))}
|
||||
</Stack>
|
||||
</Popover.Dropdown>
|
||||
</Popover>
|
||||
) : (
|
||||
<Box style={{ display: "flex", alignItems: "center", flex: 1, minWidth: 24 }}>
|
||||
<Box pos="relative" style={{ flex: 1, minWidth: 24 }}>
|
||||
<Progress value={system.disk} color={thresholdColor(system.disk)} size={trackSize} />
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</Group>
|
||||
);
|
||||
};
|
||||
@@ -20,16 +20,23 @@ import {
|
||||
useSystemChartData,
|
||||
} from "./chart";
|
||||
import { chartAxisFormatters, formatByteRate, formatGB, formatPercent, formatStorageBytes } from "./format";
|
||||
import type { BeszelTooltipLayer } from "./tooltip";
|
||||
import { makeTooltipProps } from "./tooltip";
|
||||
import { useLiveStats } from "./use-live-stats";
|
||||
|
||||
const CHART_HEIGHT = 180;
|
||||
const MB = 1024 * 1024;
|
||||
const tooltipPercent = makeTooltipProps(formatPercent);
|
||||
const tooltipGB = makeTooltipProps(formatGB, true);
|
||||
const tooltipRate = makeTooltipProps(formatByteRate, true);
|
||||
const tooltipPercentTotal = makeTooltipProps(formatPercent, true);
|
||||
const tooltipBytesTotal = makeTooltipProps(formatStorageBytes, true);
|
||||
const makeTooltipSet = (layer: BeszelTooltipLayer) => ({
|
||||
percent: makeTooltipProps(formatPercent, false, layer),
|
||||
gigabytes: makeTooltipProps(formatGB, true, layer),
|
||||
rate: makeTooltipProps(formatByteRate, true, layer),
|
||||
percentTotal: makeTooltipProps(formatPercent, true, layer),
|
||||
bytesTotal: makeTooltipProps(formatStorageBytes, true, layer),
|
||||
});
|
||||
const tooltipSets = {
|
||||
background: makeTooltipSet("background"),
|
||||
modal: makeTooltipSet("modal"),
|
||||
};
|
||||
|
||||
const ChartSkeleton = () => (
|
||||
<Stack gap={4} style={{ minWidth: 0 }}>
|
||||
@@ -59,6 +66,7 @@ interface BeszelStatsViewProps {
|
||||
visibility: BeszelStatsVisibility;
|
||||
columns: 1 | 2;
|
||||
onSwitchToHistorical?: () => void;
|
||||
tooltipLayer?: BeszelTooltipLayer;
|
||||
}
|
||||
|
||||
const whenVisible = <T,>(visible: boolean, data: T | undefined) => (visible ? data : undefined);
|
||||
@@ -70,11 +78,13 @@ export function BeszelStatsView({
|
||||
visibility,
|
||||
columns,
|
||||
onSwitchToHistorical,
|
||||
tooltipLayer = "background",
|
||||
}: BeszelStatsViewProps) {
|
||||
const t = useScopedI18n("widget.beszelSystemStats");
|
||||
const locale = useCurrentIntlLocale();
|
||||
const showDocker = visibility.dockerCpu || visibility.dockerMemory || visibility.dockerNetwork;
|
||||
const isLive = timePeriod === "1m";
|
||||
const tooltips = tooltipSets[tooltipLayer];
|
||||
|
||||
const historicalQuery = clientApi.widget.beszel.getSystemStats.useQuery(
|
||||
{ integrationIds, systemId, timePeriod, includeDocker: showDocker },
|
||||
@@ -256,7 +266,7 @@ export function BeszelStatsView({
|
||||
series: series.cpu,
|
||||
yAxisFormatter: chartAxisFormatters.percent,
|
||||
yAxisDomain: CPU_Y_AXIS_DOMAIN,
|
||||
tooltipProps: tooltipPercent,
|
||||
tooltipProps: tooltips.percent,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -270,7 +280,7 @@ export function BeszelStatsView({
|
||||
type: "stacked",
|
||||
series: series.memory,
|
||||
yAxisFormatter: chartAxisFormatters.gb,
|
||||
tooltipProps: tooltipGB,
|
||||
tooltipProps: tooltips.gigabytes,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -284,7 +294,7 @@ export function BeszelStatsView({
|
||||
type: "stacked",
|
||||
series: diskSeries,
|
||||
yAxisFormatter: chartAxisFormatters.gb,
|
||||
tooltipProps: tooltipGB,
|
||||
tooltipProps: tooltips.gigabytes,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -297,7 +307,7 @@ export function BeszelStatsView({
|
||||
data: diskIOData,
|
||||
series: series.diskIO,
|
||||
yAxisFormatter: chartAxisFormatters.rate,
|
||||
tooltipProps: tooltipRate,
|
||||
tooltipProps: tooltips.rate,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -310,7 +320,7 @@ export function BeszelStatsView({
|
||||
data: networkData,
|
||||
series: series.network,
|
||||
yAxisFormatter: chartAxisFormatters.rate,
|
||||
tooltipProps: tooltipRate,
|
||||
tooltipProps: tooltips.rate,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -326,7 +336,7 @@ export function BeszelStatsView({
|
||||
type: "stacked",
|
||||
series: containerSeries,
|
||||
yAxisFormatter: chartAxisFormatters.percent,
|
||||
tooltipProps: tooltipPercentTotal,
|
||||
tooltipProps: tooltips.percentTotal,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -340,7 +350,7 @@ export function BeszelStatsView({
|
||||
type: "stacked",
|
||||
series: containerSeries,
|
||||
yAxisFormatter: chartAxisFormatters.bytes,
|
||||
tooltipProps: tooltipBytesTotal,
|
||||
tooltipProps: tooltips.bytesTotal,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -353,7 +363,7 @@ export function BeszelStatsView({
|
||||
data: dockerNetworkData,
|
||||
series: containerSeries,
|
||||
yAxisFormatter: chartAxisFormatters.rate,
|
||||
tooltipProps: tooltipRate,
|
||||
tooltipProps: tooltips.rate,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -50,6 +50,7 @@ export const BeszelSystemStatsModal = createModal<BeszelSystemStatsModalProps>((
|
||||
timePeriod={timePeriod}
|
||||
visibility={allCharts}
|
||||
columns={2}
|
||||
tooltipLayer="modal"
|
||||
onSwitchToHistorical={() => setTimePeriod("1h")}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
Reference in new issue
Block a user