diff --git a/app/overview/page.tsx b/app/overview/page.tsx index 88d6452..dffd2e6 100644 --- a/app/overview/page.tsx +++ b/app/overview/page.tsx @@ -10,6 +10,7 @@ import ActorsTable from '@/src/components/APITables/ActorsTable/ActorsTable'; import EnclosureTable from '@/src/components/APITables/EnclosureTable/EnclosureTable'; import EphemerisTable from '@/src/components/APITables/EphemerisTable/EphemerisTable'; +import OverwatcherTable from '@/src/components/APITables/OverwatcherTable/OverwatcherTable'; import SpecTable from '@/src/components/APITables/SpecTable/SpecTable'; import TelescopesTable from '@/src/components/APITables/TelescopesTable/TelescopesTable'; import WeatherTable from '@/src/components/APITables/WeatherTable/WeatherTable'; @@ -25,6 +26,7 @@ export default function OverviewPage() { tableArrangement = ( <> + @@ -40,12 +42,13 @@ export default function OverviewPage() { tableArrangement = ( <> + - + diff --git a/src/actions/fetch-from-API.ts b/src/actions/fetch-from-API.ts index cf67c35..3c42cc3 100644 --- a/src/actions/fetch-from-API.ts +++ b/src/actions/fetch-from-API.ts @@ -9,7 +9,8 @@ export default async function fetchFromAPI( route: string, - baseURL: string | undefined = undefined + baseURL: string | undefined = undefined, + opts: RequestInit = {} ): Promise { if (!baseURL) { baseURL = process.env.LVM_API_BASE_URL; @@ -17,7 +18,7 @@ export default async function fetchFromAPI( const url = new URL(route, baseURL).toString(); - const response = await fetch(url, { cache: 'no-store' }); + const response = await fetch(url, opts); if (!response.ok) { throw new Error(`Failed to fetch from API: ${response.statusText}`); } diff --git a/src/components/APITable/APITable.tsx b/src/components/APITable/APITable.tsx index 1902733..eb0355a 100644 --- a/src/components/APITable/APITable.tsx +++ b/src/components/APITable/APITable.tsx @@ -125,10 +125,13 @@ export default function APITable(props: { colSpan={colspan} ta={isSpan ? 'center' : undefined} autoFocus={false} + maw={isSpan ? undefined : 160} > {isSpan ? value : element.label} - {!isSpan && {getValue(element)}} + {!isSpan && ( + {getValue(element)} + )} ); }); diff --git a/src/components/APITables/OverwatcherTable/OverwatcherTable.tsx b/src/components/APITables/OverwatcherTable/OverwatcherTable.tsx new file mode 100644 index 0000000..28e818d --- /dev/null +++ b/src/components/APITables/OverwatcherTable/OverwatcherTable.tsx @@ -0,0 +1,125 @@ +/* + * @Author: José Sánchez-Gallego (gallegoj@uw.edu) + * @Date: 2024-08-19 + * @Filename: OverwatcherTable.tsx + * @License: BSD 3-clause (http://www.opensource.org/licenses/BSD-3-Clause) + */ + +'use client'; + +import fetchFromAPI from '@/src/actions/fetch-from-API'; +import useAPICall from '@/src/hooks/use-api-call'; +import { Box, Group, Pill, Switch } from '@mantine/core'; +import { IconRobot } from '@tabler/icons-react'; +import React from 'react'; +import APIStatusText from '../../APITable/APIStatusText/APIStatusText'; +import APITable from '../../APITable/APITable'; + +type OverwatcherResponse = { + running: boolean; + enabled: boolean; + observing: boolean; + calibrating: boolean; + allow_dome_calibrations: boolean; +}; + +type OverwatcherPillProps = { + value: boolean | undefined; + nodata: boolean; + useErrorColour?: boolean; +}; + +function OverwatcherPill(props: OverwatcherPillProps) { + const { value, nodata, useErrorColour = false } = props; + + const text = value ? 'Yes' : 'No'; + + let colour: string; + if (useErrorColour && !value) { + colour = 'red.9'; + } else { + colour = value ? 'lime.9' : 'dark.5'; + } + + return ( + + {text} + + ); +} + +function EnabledGroup(props: OverwatcherPillProps) { + const { value, nodata } = props; + + const [isOn, setOn] = React.useState(value); + + React.useEffect(() => { + setOn(value); + }, [value]); + + const handleEnabledChange = React.useCallback(() => { + // Send API request to change value + const route = isOn ? '/overwatcher/status/disable' : '/overwatcher/status/enable'; + fetchFromAPI(route, undefined, { method: 'PUT' }) + .then(() => setOn((prev) => !prev)) + .catch(() => {}); + }, [isOn]); + + return ( + + + + + + ); +} +export default function OverwatcherTable() { + const [data, , noData, refresh] = useAPICall( + '/overwatcher/status', + { interval: 10000 } + ); + + const elements = [ + { + key: 'running', + label: 'Running', + value: , + }, + { + key: 'enabled', + label: 'Enabled', + value: , + }, + { + key: 'observing', + label: 'Observing', + value: , + }, + { + key: 'calibrating', + label: 'Calibrating', + value: , + }, + { + key: 'allow_dome_calibrations', + label: 'Allow dome calibrations', + value: , + }, + ]; + + return ( + } + refreshData={refresh} + /> + ); +}