diff --git a/ui/src/App.tsx b/ui/src/App.tsx index 478d8bd..78cd30f 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -20,6 +20,7 @@ import MenuIcon from "@material-ui/icons/Menu"; import BarChartIcon from "@material-ui/icons/BarChart"; import LayersIcon from "@material-ui/icons/Layers"; import SettingsIcon from "@material-ui/icons/Settings"; +import ScheduleIcon from "@material-ui/icons/Schedule"; import FeedbackIcon from "@material-ui/icons/Feedback"; import CloseIcon from "@material-ui/icons/Close"; import { AppState } from "./store"; @@ -30,6 +31,7 @@ import SchedulersView from "./views/SchedulersView"; import DashboardView from "./views/DashboardView"; import TasksView from "./views/TasksView"; import SettingsView from "./views/SettingsView"; +import ServersView from "./views/ServersView"; const drawerWidth = 220; @@ -213,10 +215,15 @@ function App(props: ConnectedProps) { primary="Queues" icon={} /> + } + /> } + icon={} /> @@ -250,6 +257,9 @@ function App(props: ConnectedProps) { + + + diff --git a/ui/src/api.ts b/ui/src/api.ts index f154dad..cabda3a 100644 --- a/ui/src/api.ts +++ b/ui/src/api.ts @@ -128,6 +128,10 @@ export interface DeadTask extends BaseTask { error_message: string; } +export interface ServerInfo { + // TODO: fill this out +} + export interface SchedulerEntry { id: string; spec: string; diff --git a/ui/src/components/ServersTable.tsx b/ui/src/components/ServersTable.tsx new file mode 100644 index 0000000..7b078af --- /dev/null +++ b/ui/src/components/ServersTable.tsx @@ -0,0 +1,147 @@ +import React, { useState } from "react"; +import clsx from "clsx"; +import { makeStyles } from "@material-ui/core/styles"; +import IconButton from "@material-ui/core/IconButton"; +import Table from "@material-ui/core/Table"; +import TableBody from "@material-ui/core/TableBody"; +import TableCell from "@material-ui/core/TableCell"; +import TableContainer from "@material-ui/core/TableContainer"; +import TableHead from "@material-ui/core/TableHead"; +import TableRow from "@material-ui/core/TableRow"; +import TableSortLabel from "@material-ui/core/TableSortLabel"; +import Alert from "@material-ui/lab/Alert"; +import AlertTitle from "@material-ui/lab/AlertTitle"; +import { ServerInfo } from "../api"; +import { SortDirection, SortableTableColumn } from "../types/table"; + +const useStyles = makeStyles((theme) => ({ + table: { + minWidth: 650, + }, + fixedCell: { + position: "sticky", + zIndex: 1, + left: 0, + background: theme.palette.common.white, + }, +})); + +enum SortBy { + Host, + PID, + Status, + ActiveWorkers, + Queues, + Started, +} +const colConfigs: SortableTableColumn[] = [ + { + label: "Host", + key: "host", + sortBy: SortBy.Host, + align: "left", + }, + { + label: "PID", + key: "pid", + sortBy: SortBy.PID, + align: "left", + }, + { + label: "Status", + key: "status", + sortBy: SortBy.Status, + align: "left", + }, + { + label: "Active Workers", + key: "workers", + sortBy: SortBy.ActiveWorkers, + align: "left", + }, + { + label: "Queues", + key: "queues", + sortBy: SortBy.Queues, + align: "left", + }, + { + label: "Started", + key: "started", + sortBy: SortBy.Started, + align: "left", + }, +]; + +// sortServers takes a array of server-infos and return a sorted array. +// It returns a new array and leave the original array untouched. +function sortServerInfos( + entries: ServerInfo[], + cmpFn: (first: ServerInfo, second: ServerInfo) => number +): ServerInfo[] { + let copy = [...entries]; + copy.sort(cmpFn); + return copy; +} + +interface Props { + servers: ServerInfo[]; +} + +export default function ServersTable(props: Props) { + const classes = useStyles(); + const [sortBy, setSortBy] = useState(SortBy.Host); + const [sortDir, setSortDir] = useState(SortDirection.Asc); + + const createSortClickHandler = (sortKey: SortBy) => (e: React.MouseEvent) => { + if (sortKey === sortBy) { + // Toggle sort direction. + const nextSortDir = + sortDir === SortDirection.Asc ? SortDirection.Desc : SortDirection.Asc; + setSortDir(nextSortDir); + } else { + // Change the sort key. + setSortBy(sortKey); + } + }; + + const cmpFunc = (s1: ServerInfo, s2: ServerInfo): number => { + return 0; // TODO: implement this + }; + + if (props.servers.length === 0) { + return ( + + Info + No servers found at this time. + + ); + } + + return ( + + + + + {colConfigs.map((cfg, i) => ( + + + {cfg.label} + + + ))} + + + +
+
+ ); +} diff --git a/ui/src/paths.ts b/ui/src/paths.ts index 14aaf3e..9a69061 100644 --- a/ui/src/paths.ts +++ b/ui/src/paths.ts @@ -1,6 +1,7 @@ export const paths = { HOME: "/", SETTINGS: "/settings", + SERVERS: "/servers", SCHEDULERS: "/schedulers", QUEUE_DETAILS: "/queues/:qname", }; diff --git a/ui/src/views/ServersView.tsx b/ui/src/views/ServersView.tsx new file mode 100644 index 0000000..a7f6b1a --- /dev/null +++ b/ui/src/views/ServersView.tsx @@ -0,0 +1,42 @@ +import React from "react"; +import Container from "@material-ui/core/Container"; +import { makeStyles } from "@material-ui/core/styles"; +import Grid from "@material-ui/core/Grid"; +import Paper from "@material-ui/core/Paper"; +import Typography from "@material-ui/core/Typography"; +import ServersTable from "../components/ServersTable"; + +const useStyles = makeStyles((theme) => ({ + container: { + paddingTop: theme.spacing(4), + paddingBottom: theme.spacing(4), + }, + paper: { + padding: theme.spacing(2), + display: "flex", + overflow: "auto", + flexDirection: "column", + }, + heading: { + paddingLeft: theme.spacing(2), + marginBottom: theme.spacing(1), + }, +})); + +export default function ServersView() { + const classes = useStyles(); + return ( + + + + + + Servers + + + + + + + ); +}