fix: DnsHole controls timer (#953)

* fix: DnsHole controls timer

* fix: use plural naming

* fix: reviewed changes

* fix: change ControlsCard to jsx component

* fix: DeepSource
This commit is contained in:
Yossi Hillali
2024-08-28 11:26:36 +03:00
committed by GitHub
parent 3771a61c49
commit 69e69ee315
3 changed files with 73 additions and 29 deletions

View File

@@ -123,7 +123,7 @@ export class AdGuardHomeIntegration extends Integration implements DnsHoleSummar
} }
} }
public async disableAsync(duration?: number): Promise<void> { public async disableAsync(duration = 0): Promise<void> {
const response = await fetch(`${this.integration.url}/control/protection`, { const response = await fetch(`${this.integration.url}/control/protection`, {
method: "POST", method: "POST",
headers: { headers: {
@@ -132,7 +132,7 @@ export class AdGuardHomeIntegration extends Integration implements DnsHoleSummar
}, },
body: JSON.stringify({ body: JSON.stringify({
enabled: false, enabled: false,
duration: duration, duration: duration * 1000,
}), }),
}); });
if (!response.ok) { if (!response.ok) {

View File

@@ -8,11 +8,11 @@ import { useI18n } from "@homarr/translation/client";
interface TimerModalProps { interface TimerModalProps {
opened: boolean; opened: boolean;
close: () => void; close: () => void;
integrationIds: string[]; selectedIntegrationIds: string[];
disableDns: (data: { duration: number; integrationId: string }) => void; disableDns: (data: { duration: number; integrationId: string }) => void;
} }
const TimerModal = ({ opened, close, integrationIds, disableDns }: TimerModalProps) => { const TimerModal = ({ opened, close, selectedIntegrationIds, disableDns }: TimerModalProps) => {
const t = useI18n(); const t = useI18n();
const [hours, setHours] = useState(0); const [hours, setHours] = useState(0);
const [minutes, setMinutes] = useState(0); const [minutes, setMinutes] = useState(0);
@@ -21,7 +21,7 @@ const TimerModal = ({ opened, close, integrationIds, disableDns }: TimerModalPro
const handleSetTimer = () => { const handleSetTimer = () => {
const duration = hours * 3600 + minutes * 60; const duration = hours * 3600 + minutes * 60;
integrationIds.forEach((integrationId) => { selectedIntegrationIds.forEach((integrationId) => {
disableDns({ duration, integrationId }); disableDns({ duration, integrationId });
}); });
setHours(0); setHours(0);

View File

@@ -24,6 +24,7 @@ export default function DnsHoleControlsWidget({ options, integrationIds }: Widge
const [status, setStatus] = useState<{ integrationId: string; enabled: boolean }[]>( const [status, setStatus] = useState<{ integrationId: string; enabled: boolean }[]>(
integrationIds.map((id) => ({ integrationId: id, enabled: false })), integrationIds.map((id) => ({ integrationId: id, enabled: false })),
); );
const [selectedIntegrationIds, setSelectedIntegrationIds] = useState<string[]>([]);
const [opened, { close, open }] = useDisclosure(false); const [opened, { close, open }] = useDisclosure(false);
const [data] = clientApi.widget.dnsHole.summary.useSuspenseQuery( const [data] = clientApi.widget.dnsHole.summary.useSuspenseQuery(
@@ -67,8 +68,10 @@ export default function DnsHoleControlsWidget({ options, integrationIds }: Widge
} }
}; };
const allEnabled = status.every((item) => item.enabled); const enabledIntegrations = integrationIds.filter((id) => status.find((item) => item.integrationId === id)?.enabled);
const allDisabled = status.every((item) => !item.enabled); const disabledIntegrations = integrationIds.filter(
(id) => !status.find((item) => item.integrationId === id)?.enabled,
);
return ( return (
<Flex h="100%" direction="column" gap={0} p="2.5cqmin"> <Flex h="100%" direction="column" gap={0} p="2.5cqmin">
@@ -76,10 +79,8 @@ export default function DnsHoleControlsWidget({ options, integrationIds }: Widge
<Flex gap="2.5cqmin"> <Flex gap="2.5cqmin">
<Tooltip label={t("widget.dnsHoleControls.controls.enableAll")}> <Tooltip label={t("widget.dnsHoleControls.controls.enableAll")}>
<Button <Button
onClick={() => { onClick={() => disabledIntegrations.forEach((integrationId) => enableDns({ integrationId }))}
integrationIds.forEach((integrationId) => enableDns({ integrationId })); disabled={disabledIntegrations.length === 0}
}}
disabled={allEnabled}
variant="light" variant="light"
color="green" color="green"
fullWidth fullWidth
@@ -90,17 +91,25 @@ export default function DnsHoleControlsWidget({ options, integrationIds }: Widge
</Tooltip> </Tooltip>
<Tooltip label={t("widget.dnsHoleControls.controls.setTimer")}> <Tooltip label={t("widget.dnsHoleControls.controls.setTimer")}>
<Button onClick={open} disabled={allDisabled} variant="light" color="yellow" fullWidth h="2rem"> <Button
onClick={() => {
setSelectedIntegrationIds(enabledIntegrations);
open();
}}
disabled={enabledIntegrations.length === 0}
variant="light"
color="yellow"
fullWidth
h="2rem"
>
<IconClockPause size={20} /> <IconClockPause size={20} />
</Button> </Button>
</Tooltip> </Tooltip>
<Tooltip label={t("widget.dnsHoleControls.controls.disableAll")}> <Tooltip label={t("widget.dnsHoleControls.controls.disableAll")}>
<Button <Button
onClick={() => { onClick={() => enabledIntegrations.forEach((integrationId) => disableDns({ integrationId, duration: 0 }))}
integrationIds.forEach((integrationId) => disableDns({ integrationId, duration: 0 })); disabled={enabledIntegrations.length === 0}
}}
disabled={allDisabled}
variant="light" variant="light"
color="red" color="red"
fullWidth fullWidth
@@ -113,24 +122,49 @@ export default function DnsHoleControlsWidget({ options, integrationIds }: Widge
)} )}
<Stack gap="2.5cqmin" flex={1} justify={options.showToggleAllButtons ? "flex-end" : "space-evenly"}> <Stack gap="2.5cqmin" flex={1} justify={options.showToggleAllButtons ? "flex-end" : "space-evenly"}>
{data.map((integrationData) => {data.map((integrationData) => (
ControlsCard(integrationData.integrationId, integrationData.integrationKind, toggleDns, status, open, t), <ControlsCard
)} key={integrationData.integrationId}
integrationId={integrationData.integrationId}
integrationKind={integrationData.integrationKind}
toggleDns={toggleDns}
status={status}
setSelectedIntegrationIds={setSelectedIntegrationIds}
open={open}
t={t}
/>
))}
</Stack> </Stack>
<TimerModal opened={opened} close={close} integrationIds={integrationIds} disableDns={disableDns} /> <TimerModal
opened={opened}
close={close}
selectedIntegrationIds={selectedIntegrationIds}
disableDns={disableDns}
/>
</Flex> </Flex>
); );
} }
const ControlsCard = ( interface ControlsCardProps {
integrationId: string, integrationId: string;
integrationKind: string, integrationKind: string;
toggleDns: (integrationId: string) => void, toggleDns: (integrationId: string) => void;
status: { integrationId: string; enabled: boolean }[], status: { integrationId: string; enabled: boolean }[];
open: () => void, setSelectedIntegrationIds: (integrationId: string[]) => void;
t: TranslationFunction, open: () => void;
) => { t: TranslationFunction;
}
const ControlsCard: React.FC<ControlsCardProps> = ({
integrationId,
integrationKind,
toggleDns,
status,
setSelectedIntegrationIds,
open,
t,
}) => {
const integrationStatus = status.find((item) => item.integrationId === integrationId); const integrationStatus = status.find((item) => item.integrationId === integrationId);
const isEnabled = integrationStatus?.enabled ?? false; const isEnabled = integrationStatus?.enabled ?? false;
const integrationDef = integrationKind === "piHole" ? integrationDefs.piHole : integrationDefs.adGuardHome; const integrationDef = integrationKind === "piHole" ? integrationDefs.piHole : integrationDefs.adGuardHome;
@@ -149,7 +183,17 @@ const ControlsCard = (
{t(`widget.dnsHoleControls.controls.${isEnabled ? "enabled" : "disabled"}`)} {t(`widget.dnsHoleControls.controls.${isEnabled ? "enabled" : "disabled"}`)}
</Badge> </Badge>
</UnstyledButton> </UnstyledButton>
<ActionIcon disabled={!isEnabled} size={20} radius="xl" top="2.67px" variant="default" onClick={open}> <ActionIcon
disabled={!isEnabled}
size={20}
radius="xl"
top="2.67px"
variant="default"
onClick={() => {
setSelectedIntegrationIds([integrationId]);
open();
}}
>
<IconClockPause size={20} color="red" /> <IconClockPause size={20} color="red" />
</ActionIcon> </ActionIcon>
</Flex> </Flex>