add an error modal for failed requests

This commit is contained in:
Rasmus Moorats 2024-07-16 17:16:15 +03:00
parent 1ee9c93230
commit 4bd02923c9
Signed by: xx
GPG key ID: FE14255A6AE7241C
5 changed files with 130 additions and 37 deletions

View file

@ -0,0 +1,26 @@
import { Button, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader } from "@nextui-org/react";
interface ErrorModalProps {
error: string | null;
onClose: () => void;
}
export function ErrorModal({ error, onClose }: ErrorModalProps) {
return (
<Modal backdrop="blur" placement="auto" isOpen={error != null} onClose={onClose}>
<ModalContent>
<>
<ModalHeader>Error</ModalHeader>
<ModalBody>
<p>{error}</p>
</ModalBody>
<ModalFooter>
<Button color="danger" variant="light" onPress={onClose}>
Close
</Button>
</ModalFooter>
</>
</ModalContent>
</Modal>
);
}

View file

@ -2,49 +2,63 @@ import {useState} from "react";
import {Button, Popover, PopoverContent, PopoverTrigger} from "@nextui-org/react";
import axios from "axios";
import PowerIcon from "./assets/PowerIcon.tsx";
import {ErrorModal} from "./ErrorModal.tsx";
import {makePostRequest} from "./requests.ts";
export function RebootButton() {
const [isRebooting, setIsRebooting] = useState(false);
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const [error, setError] = useState<string | null>(null);
const reboot = async () => {
setIsPopoverOpen(false);
setIsRebooting(true);
setError(null); // Clear any previous errors
// hardcode URL for now
await axios.post("https://panel.mordor.ee/api/reboot").catch((err) => {
console.error(err);
});
const errorMessage = await makePostRequest("https://panel.mordor.ee/api/reboot");
if (errorMessage) {
setError(errorMessage);
setIsRebooting(false);
return;
}
let isOnline = false;
while (!isOnline) {
// sleep for 5 seconds
await new Promise(r => setTimeout(r, 5000));
await axios.get("https://panel.mordor.ee/api/online", {timeout: 2000}).then((res) => {
// machine might not have started rebooting yet.
// if this is the case, the response will be 200 OK with "rebooting" as the body.
// if the machine is online, the response will be 200 OK with "online" as the body.
if (res.status === 200 && res.data === "online")
try {
const res = await axios.get("http://panel.mordor.ee/api/online", {timeout: 2000});
if (res.status === 200 && res.data === "online") {
isOnline = true;
}).catch((err) => {
}
} catch (err) {
// this is expected when rebooting
console.error(err);
});
}
}
setIsRebooting(false);
}
};
return <Popover placement="top" backdrop="blur" isOpen={isPopoverOpen}
onOpenChange={(open) => setIsPopoverOpen(open)}>
<PopoverTrigger>
<Button startContent={<PowerIcon/>} className="w-52" color="danger" isLoading={isRebooting} variant="shadow" size="lg">Reboot</Button>
</PopoverTrigger>
<PopoverContent>
<div className="flex flex-col gap-3 items-center p-3">
<p>Really reboot?</p>
<Button color="danger" onPress={reboot} variant="shadow" className="w-0">Yes</Button>
</div>
</PopoverContent>
</Popover>
return (
<>
<Popover placement="top" backdrop="blur" isOpen={isPopoverOpen}
onOpenChange={(open) => setIsPopoverOpen(open)}>
<PopoverTrigger>
<Button startContent={<PowerIcon/>} className="w-52" color="danger" isLoading={isRebooting}
variant="shadow" size="lg">
Reboot
</Button>
</PopoverTrigger>
<PopoverContent>
<div className="flex flex-col gap-3 items-center p-3">
<p>Really reboot?</p>
<Button color="danger" onPress={reboot} variant="shadow" className="w-0">Yes</Button>
</div>
</PopoverContent>
</Popover>
<ErrorModal error={error} onClose={() => setError(null)}/>
</>
);
}

View file

@ -1,21 +1,34 @@
import {useState} from "react";
import axios from "axios";
import {Button} from "@nextui-org/react";
import KodiIcon from "./assets/KodiIcon.tsx";
import {ErrorModal} from "./ErrorModal.tsx";
import {makePostRequest} from "./requests.ts";
export function RestartKodiButton() {
const [isRestarting, setIsRestarting] = useState(false);
const [error, setError] = useState<string | null>(null);
const restart = async () => {
setIsRestarting(true);
// hardcode URL for now
await axios.post("https://panel.mordor.ee/api/restart-kodi").catch((err) => {
console.error(err);
});
setError(null);
setError(await makePostRequest("http://panel.mordor.ee/api/restart-kodi"));
setIsRestarting(false);
}
return <Button startContent={<KodiIcon/>} className="w-52" color="primary" variant="shadow" isLoading={isRestarting}
size="lg" onPress={restart}>Restart Kodi</Button>
return (
<>
<Button
startContent={<KodiIcon/>}
className="w-52"
color="primary"
variant="shadow"
isLoading={isRestarting}
size="lg"
onPress={restart}
>
Restart Kodi
</Button>
<ErrorModal error={error} onClose={() => setError(null)}/>
</>
);
}

View file

@ -1,18 +1,34 @@
import {useState} from "react";
import {Button} from "@nextui-org/react";
import axios from "axios";
import PipeWireIcon from "./assets/PipeWireIcon.tsx";
import {makePostRequest} from "./requests.ts";
import {ErrorModal} from "./ErrorModal.tsx";
export function RestartPipeWireButton() {
const [isRestarting, setIsRestarting] = useState(false);
const [error, setError] = useState<string | null>(null);
const restart = async () => {
setIsRestarting(true);
await axios.post("https://panel.mordor.ee/api/restart-pipewire").catch((err) => {
console.error(err);
});
setError(null);
setError(await makePostRequest("http://panel.mordor.ee/api/restart-pipewire"));
setIsRestarting(false);
}
return <Button startContent={<PipeWireIcon/>} className="w-52" color="primary" variant="shadow" isLoading={isRestarting} size="lg" onPress={restart}>Restart PipeWire</Button>
return (
<>
<Button
startContent={<PipeWireIcon/>}
className="w-52"
color="primary"
variant="shadow"
isLoading={isRestarting}
size="lg"
onPress={restart}
>
Restart PipeWire
</Button>
<ErrorModal error={error} onClose={() => setError(null)}/>
</>
);
}

24
frontend/src/requests.ts Normal file
View file

@ -0,0 +1,24 @@
import axios from "axios";
export const makePostRequest = async (url: string): Promise<string | null> => {
try {
const response = await axios.post(url);
if (response.status !== 200) {
return response.data;
}
return null;
} catch (err: unknown) {
console.error(err);
if (axios.isAxiosError(err)) {
if (err.response) {
return err.response.data;
} else if (err.request) {
return "No response from server. Please try again.";
} else {
return err.message;
}
} else {
return (err as Error).message;
}
}
};