Skip to content

Commit

Permalink
Add OverwatcherTable to the overview page
Browse files Browse the repository at this point in the history
  • Loading branch information
albireox committed Aug 19, 2024
1 parent 8b0e112 commit 021e236
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 4 deletions.
5 changes: 4 additions & 1 deletion app/overview/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -25,6 +26,7 @@ export default function OverviewPage() {
tableArrangement = (
<>
<Stack gap="lg">
<OverwatcherTable />
<SpecTable />
<WeatherTable />
<ActorsTable />
Expand All @@ -40,12 +42,13 @@ export default function OverviewPage() {
tableArrangement = (
<>
<Stack gap="lg">
<OverwatcherTable />
<SpecTable />
<TelescopesTable />
<WeatherTable />
</Stack>
<Stack gap="lg">
<EnclosureTable />
<TelescopesTable />
<EphemerisTable />
</Stack>
<ActorsTable />
Expand Down
5 changes: 3 additions & 2 deletions src/actions/fetch-from-API.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@

export default async function fetchFromAPI<T>(
route: string,
baseURL: string | undefined = undefined
baseURL: string | undefined = undefined,
opts: RequestInit = {}
): Promise<T> {
if (!baseURL) {
baseURL = process.env.LVM_API_BASE_URL;
}

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}`);
}
Expand Down
5 changes: 4 additions & 1 deletion src/components/APITable/APITable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,13 @@ export default function APITable(props: {
colSpan={colspan}
ta={isSpan ? 'center' : undefined}
autoFocus={false}
maw={isSpan ? undefined : 160}
>
<Text size="sm">{isSpan ? value : element.label}</Text>
</Table.Td>
{!isSpan && <Table.Td>{getValue(element)}</Table.Td>}
{!isSpan && (
<Table.Td miw={isSpan ? undefined : 200}>{getValue(element)}</Table.Td>
)}
</Table.Tr>
);
});
Expand Down
125 changes: 125 additions & 0 deletions src/components/APITables/OverwatcherTable/OverwatcherTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* @Author: José Sánchez-Gallego ([email protected])
* @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 (
<Pill bg={colour}>
<APIStatusText nodata={nodata}>{text}</APIStatusText>
</Pill>
);
}

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 (
<Group>
<OverwatcherPill value={value} nodata={nodata} />
<Box style={{ flexGrow: 1 }} />
<Switch
size="md"
checked={isOn}
onChange={handleEnabledChange}
onLabel="ON"
offLabel="OFF"
/>
</Group>
);
}
export default function OverwatcherTable() {
const [data, , noData, refresh] = useAPICall<OverwatcherResponse>(
'/overwatcher/status',
{ interval: 10000 }
);

const elements = [
{
key: 'running',
label: 'Running',
value: <OverwatcherPill value={data?.running} nodata={noData} useErrorColour />,
},
{
key: 'enabled',
label: 'Enabled',
value: <EnabledGroup value={data?.enabled} nodata={noData} />,
},
{
key: 'observing',
label: 'Observing',
value: <OverwatcherPill value={data?.observing} nodata={noData} />,
},
{
key: 'calibrating',
label: 'Calibrating',
value: <OverwatcherPill value={data?.calibrating} nodata={noData} />,
},
{
key: 'allow_dome_calibrations',
label: 'Allow dome calibrations',
value: <OverwatcherPill value={data?.allow_dome_calibrations} nodata={noData} />,
},
];

return (
<APITable
title="Overwatcher"
elements={elements}
noData={noData}
icon={<IconRobot />}
refreshData={refresh}
/>
);
}

0 comments on commit 021e236

Please sign in to comment.