fix(deps): update dependency eslint-plugin-react-hooks to v5 (#1280)

* fix(deps): update dependency eslint-plugin-react-hooks to v5

* fix: lint issues after reenabling hook rules

* fix: format issues

---------

Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
Co-authored-by: Meier Lukas <meierschlumpf@gmail.com>
This commit is contained in:
homarr-renovate[bot]
2024-10-16 21:43:51 +02:00
committed by GitHub
parent ea43ed0ca4
commit a87c937b69
39 changed files with 251 additions and 224 deletions

View File

@@ -46,7 +46,7 @@ export const WidgetLocationInput = ({ property, kind }: CommonWidgetInputProps<"
form.clearFieldError(`options.${property}.latitude`);
form.clearFieldError(`options.${property}.longitude`);
},
[handleChange],
[form, handleChange, property],
);
const onSearch = useCallback(() => {

View File

@@ -39,7 +39,7 @@ export const WidgetMultiTextInput = ({ property, kind, options }: CommonWidgetIn
success: validationResult.success,
result: validationResult,
};
}, [search]);
}, [options.validate, search]);
const error = React.useMemo(() => {
/* hide the error when nothing is being typed since "" is not valid but is not an explicit error */

View File

@@ -2,7 +2,7 @@
import "../widgets-common.css";
import { useMemo, useState } from "react";
import { useCallback, useMemo, useState } from "react";
import type { MantineStyleProp } from "@mantine/core";
import {
ActionIcon,
@@ -233,7 +233,19 @@ export default function DownloadClientsWidget({
)
//flatMap already sorts by integration by nature, add sorting by integration type (usenet | torrent)
.sort(({ type: typeA }, { type: typeB }) => typeA.length - typeB.length),
[currentItems, integrationIds, options],
[
currentItems,
integrationIds,
integrationsWithInteractions,
mutateDeleteItem,
mutatePauseItem,
mutateResumeItem,
options.activeTorrentThreshold,
options.categoryFilter,
options.filterIsWhitelist,
options.showCompletedTorrent,
options.showCompletedUsenet,
],
);
//Flatten Clients Array for which each elements has the integration and general client infos.
@@ -278,7 +290,14 @@ export default function DownloadClientsWidget({
({ status: statusA }, { status: statusB }) =>
(statusA?.type.length ?? Infinity) - (statusB?.type.length ?? Infinity),
),
[currentItems, integrationIds, options],
[
currentItems,
integrationIds,
integrationsWithInteractions,
options.applyFilterToRatio,
options.categoryFilter,
options.filterIsWhitelist,
],
);
//Check existing types between torrents and usenet
@@ -333,37 +352,40 @@ export default function DownloadClientsWidget({
};
//Base element in common with all columns
const columnsDefBase = ({
key,
showHeader,
align,
}: {
key: keyof ExtendedDownloadClientItem;
showHeader: boolean;
align?: "center" | "left" | "right" | "justify" | "char";
}): MRT_ColumnDef<ExtendedDownloadClientItem> => {
const style: MantineStyleProp = {
minWidth: 0,
width: "var(--column-width)",
height: "var(--ratio-width)",
padding: "var(--space-size)",
transition: "unset",
"--key-width": columnsRatios[key],
"--column-width": "calc((var(--key-width)/var(--total-width) * 100cqw))",
};
return {
id: key,
accessorKey: key,
header: key,
size: columnsRatios[key],
mantineTableBodyCellProps: { style, align },
mantineTableHeadCellProps: {
style,
align: isEditMode ? "center" : align,
},
Header: () => (showHeader && !isEditMode ? <Text fw={700}>{t(`items.${key}.columnTitle`)}</Text> : ""),
};
};
const columnsDefBase = useCallback(
({
key,
showHeader,
align,
}: {
key: keyof ExtendedDownloadClientItem;
showHeader: boolean;
align?: "center" | "left" | "right" | "justify" | "char";
}): MRT_ColumnDef<ExtendedDownloadClientItem> => {
const style: MantineStyleProp = {
minWidth: 0,
width: "var(--column-width)",
height: "var(--ratio-width)",
padding: "var(--space-size)",
transition: "unset",
"--key-width": columnsRatios[key],
"--column-width": "calc((var(--key-width)/var(--total-width) * 100cqw))",
};
return {
id: key,
accessorKey: key,
header: key,
size: columnsRatios[key],
mantineTableBodyCellProps: { style, align },
mantineTableHeadCellProps: {
style,
align: isEditMode ? "center" : align,
},
Header: () => (showHeader && !isEditMode ? <Text fw={700}>{t(`items.${key}.columnTitle`)}</Text> : ""),
};
},
[isEditMode, t],
);
//Make columns and cell elements, Memoized to data with deps on data and EditMode
const columns = useMemo<MRT_ColumnDef<ExtendedDownloadClientItem>[]>(
@@ -580,7 +602,7 @@ export default function DownloadClientsWidget({
},
},
],
[clickedIndex, isEditMode, data, integrationIds, options],
[columnsDefBase, t, tCommon],
);
//Table build and config
@@ -704,10 +726,7 @@ interface ItemInfoModalProps {
}
const ItemInfoModal = ({ items, currentIndex, opened, onClose }: ItemInfoModalProps) => {
const item = useMemo<ExtendedDownloadClientItem | undefined>(
() => items[currentIndex],
[items, currentIndex, opened],
);
const item = useMemo<ExtendedDownloadClientItem | undefined>(() => items[currentIndex], [items, currentIndex]);
const t = useScopedI18n("widget.downloads.states");
//The use case for "No item found" should be impossible, hence no translation
return (

View File

@@ -57,22 +57,19 @@ export default function HealthMonitoringWidget({ options, integrationIds }: Widg
throw new NoIntegrationSelectedError();
}
return (
<Box h="100%" className="health-monitoring">
<Stack h="100%" gap="2.5cqmin" className="health-monitoring">
{healthData.map(({ integrationId, integrationName, healthInfo }) => {
const memoryUsage = formatMemoryUsage(healthInfo.memAvailable, healthInfo.memUsed);
const disksData = matchFileSystemAndSmart(healthInfo.fileSystem, healthInfo.smart);
const { ref, width } = useElementSize();
const ringSize = width * 0.95;
const ringThickness = width / 10;
const progressSize = width * 0.2;
const memoryUsage = formatMemoryUsage(healthInfo.memAvailable, healthInfo.memUsed);
return (
<Box
<Stack
gap="2.5cqmin"
key={integrationId}
h="100%"
className={`health-monitoring-information health-monitoring-${integrationName}`}
p="2.5cqmin"
>
<Card className="health-monitoring-information-card" m="2.5cqmin" p="2.5cqmin" withBorder>
<Card className="health-monitoring-information-card" p="2.5cqmin" withBorder>
<Flex
className="health-monitoring-information-card-elements"
h="100%"
@@ -155,95 +152,17 @@ export default function HealthMonitoringWidget({ options, integrationIds }: Widg
</Stack>
</Modal>
</Box>
{options.cpu && (
<Box ref={ref} w="100%" h="100%" className="health-monitoring-cpu">
<RingProgress
className="health-monitoring-cpu-utilization"
roundCaps
size={ringSize}
thickness={ringThickness}
label={
<Center style={{ flexDirection: "column" }}>
<Text
className="health-monitoring-cpu-utilization-value"
size="3cqmin"
>{`${healthInfo.cpuUtilization.toFixed(2)}%`}</Text>
<IconCpu className="health-monitoring-cpu-utilization-icon" size="7cqmin" />
</Center>
}
sections={[
{
value: Number(healthInfo.cpuUtilization.toFixed(2)),
color: progressColor(Number(healthInfo.cpuUtilization.toFixed(2))),
},
]}
/>
</Box>
)}
{options.cpu && <CpuRing cpuUtilization={healthInfo.cpuUtilization} />}
{healthInfo.cpuTemp && options.cpu && (
<Box ref={ref} w="100%" h="100%" className="health-monitoring-cpu-temperature">
<RingProgress
ref={ref}
className="health-monitoring-cpu-temp"
roundCaps
size={ringSize}
thickness={ringThickness}
label={
<Center style={{ flexDirection: "column" }}>
<Text className="health-monitoring-cpu-temp-value" size="3cqmin">
{options.fahrenheit
? `${(healthInfo.cpuTemp * 1.8 + 32).toFixed(1)}°F`
: `${healthInfo.cpuTemp}°C`}
</Text>
<IconCpu className="health-monitoring-cpu-temp-icon" size="7cqmin" />
</Center>
}
sections={[
{
value: healthInfo.cpuTemp,
color: progressColor(healthInfo.cpuTemp),
},
]}
/>
</Box>
)}
{options.memory && (
<Box ref={ref} w="100%" h="100%" className="health-monitoring-memory">
<RingProgress
className="health-monitoring-memory-use"
roundCaps
size={ringSize}
thickness={ringThickness}
label={
<Center style={{ flexDirection: "column" }}>
<Text className="health-monitoring-memory-value" size="3cqmin">
{memoryUsage.memUsed.GB}GiB
</Text>
<IconBrain className="health-monitoring-memory-icon" size="7cqmin" />
</Center>
}
sections={[
{
value: Number(memoryUsage.memUsed.percent),
color: progressColor(Number(memoryUsage.memUsed.percent)),
tooltip: `${memoryUsage.memUsed.percent}%`,
},
]}
/>
</Box>
<CpuTempRing fahrenheit={options.fahrenheit} cpuTemp={healthInfo.cpuTemp} />
)}
{options.memory && <MemoryRing available={healthInfo.memAvailable} used={healthInfo.memUsed} />}
</Flex>
</Card>
{options.fileSystem &&
disksData.map((disk) => {
return (
<Card
className="health-monitoring-disk-card"
key={disk.deviceName}
m="2.5cqmin"
p="2.5cqmin"
withBorder
>
<Card className="health-monitoring-disk-card" key={disk.deviceName} p="2.5cqmin" withBorder>
<Flex className="health-monitoring-disk-status" justify="space-between" align="center" m="1.5cqmin">
<Group gap="1cqmin">
<IconServer className="health-monitoring-disk-icon" size="5cqmin" />
@@ -266,14 +185,14 @@ export default function HealthMonitoringWidget({ options, integrationIds }: Widg
</Text>
</Group>
</Flex>
<Progress.Root className="health-monitoring-disk-use" size={progressSize}>
<Progress.Root className="health-monitoring-disk-use" h="6cqmin">
<Tooltip label={disk.used}>
<Progress.Section
value={disk.percentage}
color={progressColor(disk.percentage)}
className="health-monitoring-disk-use-percentage"
>
<Progress.Label className="health-monitoring-disk-use-value">
<Progress.Label className="health-monitoring-disk-use-value" fz="2.5cqmin">
{t("widget.healthMonitoring.popover.used")}
</Progress.Label>
</Progress.Section>
@@ -291,7 +210,7 @@ export default function HealthMonitoringWidget({ options, integrationIds }: Widg
value={100 - disk.percentage}
color="default"
>
<Progress.Label className="health-monitoring-disk-available-value">
<Progress.Label className="health-monitoring-disk-available-value" fz="2.5cqmin">
{t("widget.healthMonitoring.popover.diskAvailable")}
</Progress.Label>
</Progress.Section>
@@ -300,10 +219,10 @@ export default function HealthMonitoringWidget({ options, integrationIds }: Widg
</Card>
);
})}
</Box>
</Stack>
);
})}
</Box>
</Stack>
);
}
@@ -349,6 +268,95 @@ export const matchFileSystemAndSmart = (fileSystems: FileSystem[], smartData: Sm
});
};
const CpuRing = ({ cpuUtilization }: { cpuUtilization: number }) => {
const { width, ref } = useElementSize();
return (
<Box ref={ref} w="100%" h="100%" className="health-monitoring-cpu">
<RingProgress
className="health-monitoring-cpu-utilization"
roundCaps
size={width * 0.95}
thickness={width / 10}
label={
<Center style={{ flexDirection: "column" }}>
<Text
className="health-monitoring-cpu-utilization-value"
size="3cqmin"
>{`${cpuUtilization.toFixed(2)}%`}</Text>
<IconCpu className="health-monitoring-cpu-utilization-icon" size="7cqmin" />
</Center>
}
sections={[
{
value: Number(cpuUtilization.toFixed(2)),
color: progressColor(Number(cpuUtilization.toFixed(2))),
},
]}
/>
</Box>
);
};
const CpuTempRing = ({ fahrenheit, cpuTemp }: { fahrenheit: boolean; cpuTemp: number }) => {
const { width, ref } = useElementSize();
return (
<Box ref={ref} w="100%" h="100%" className="health-monitoring-cpu-temperature">
<RingProgress
className="health-monitoring-cpu-temp"
roundCaps
size={width * 0.95}
thickness={width / 10}
label={
<Center style={{ flexDirection: "column" }}>
<Text className="health-monitoring-cpu-temp-value" size="3cqmin">
{fahrenheit ? `${(cpuTemp * 1.8 + 32).toFixed(1)}°F` : `${cpuTemp}°C`}
</Text>
<IconCpu className="health-monitoring-cpu-temp-icon" size="7cqmin" />
</Center>
}
sections={[
{
value: cpuTemp,
color: progressColor(cpuTemp),
},
]}
/>
</Box>
);
};
const MemoryRing = ({ available, used }: { available: string; used: string }) => {
const { width, ref } = useElementSize();
const memoryUsage = formatMemoryUsage(available, used);
return (
<Box ref={ref} w="100%" h="100%" className="health-monitoring-memory">
<RingProgress
className="health-monitoring-memory-use"
roundCaps
size={width * 0.95}
thickness={width / 10}
label={
<Center style={{ flexDirection: "column" }}>
<Text className="health-monitoring-memory-value" size="3cqmin">
{memoryUsage.memUsed.GB}GiB
</Text>
<IconBrain className="health-monitoring-memory-icon" size="7cqmin" />
</Center>
}
sections={[
{
value: Number(memoryUsage.memUsed.percent),
color: progressColor(Number(memoryUsage.memUsed.percent)),
tooltip: `${memoryUsage.memUsed.percent}%`,
},
]}
/>
</Box>
);
};
export const formatMemoryUsage = (memFree: string, memUsed: string) => {
const memFreeBytes = Number(memFree);
const memUsedBytes = Number(memUsed);

View File

@@ -46,7 +46,7 @@ export default function MediaServerWidget({
}
return 0;
}),
[mediaRequests, integrationIds],
[mediaRequests],
);
const { mutate: mutateRequestAnswer } = clientApi.widget.mediaRequests.answerRequest.useMutation();

View File

@@ -189,17 +189,31 @@ export function Notebook({ options, isEditMode, boardId, itemId }: WidgetCompone
addEventListener("onReadOnlyCheck", handleOnReadOnlyCheck);
const handleEditToggleCallback = (previous: boolean) => {
const current = !previous;
if (!editor) return current;
editor.setEditable(current);
const handleContentUpdate = useCallback(
(contentUpdate: string) => {
setToSaveContent(contentUpdate);
// This is not available in preview mode
if (boardId && itemId) {
void mutateAsync({ boardId, itemId, content: contentUpdate });
}
},
[boardId, itemId, mutateAsync],
);
handleContentUpdate(content);
const handleEditToggleCallback = useCallback(
(previous: boolean) => {
const current = !previous;
if (!editor) return current;
editor.setEditable(current);
return current;
};
handleContentUpdate(content);
const handleEditCancelCallback = () => {
return current;
},
[content, editor, handleContentUpdate],
);
const handleEditCancelCallback = useCallback(() => {
if (!editor) return false;
editor.setEditable(false);
@@ -207,20 +221,12 @@ export function Notebook({ options, isEditMode, boardId, itemId }: WidgetCompone
editor.commands.setContent(toSaveContent);
return false;
};
}, [editor, toSaveContent]);
const handleEditCancel = useCallback(() => {
setIsEditing(handleEditCancelCallback);
}, [setIsEditing, handleEditCancelCallback]);
const handleContentUpdate = (contentUpdate: string) => {
setToSaveContent(contentUpdate);
// This is not available in preview mode
if (boardId && itemId) {
void mutateAsync({ boardId, itemId, content: contentUpdate });
}
};
const handleEditToggle = useCallback(() => {
setIsEditing(handleEditToggleCallback);
}, [setIsEditing, handleEditToggleCallback]);

View File

@@ -1,6 +1,6 @@
"use client";
import React, { useState } from "react";
import React, { useCallback, useState } from "react";
import { Center, Stack, Text, UnstyledButton } from "@mantine/core";
import { clientApi } from "@homarr/api/client";
@@ -38,7 +38,7 @@ export default function SmartHomeEntityStateWidget({
const attribute = options.entityUnit.length > 0 ? " " + options.entityUnit : "";
const handleClick = React.useCallback(() => {
const handleClick = useCallback(() => {
if (isEditMode) {
return;
}
@@ -51,7 +51,7 @@ export default function SmartHomeEntityStateWidget({
entityId: options.entityId,
integrationId: integrationIds[0] ?? "",
});
}, []);
}, [integrationIds, isEditMode, mutate, options.clickable, options.entityId]);
return (
<UnstyledButton

View File

@@ -31,7 +31,7 @@ export default function SmartHomeTriggerAutomationWidget({
automationId: options.automationId,
integrationId: integrationIds[0] ?? "",
});
}, [isEditMode]);
}, [integrationIds, isEditMode, mutateAsync, options.automationId]);
return (
<UnstyledButton onClick={handleClick} style={{ cursor: !isEditMode ? "pointer" : "initial" }} w="100%" h="100%">
{isShowSuccess && (

View File

@@ -72,7 +72,7 @@ const Feed = ({ options }: Pick<WidgetComponentProps<"video">, "options">) => {
() => undefined,
);
}
}, [videoRef]);
}, [options.hasAutoPlay, options.hasControls, options.isMuted, videoRef]);
return (
<Group justify="center" w="100%" h="100%" pos="relative">