diff --git a/ui/package.json b/ui/package.json index 75dfed0..82f33b9 100644 --- a/ui/package.json +++ b/ui/package.json @@ -19,7 +19,6 @@ "@types/react-router-dom": "5.1.6", "@types/react-syntax-highlighter": "13.5.0", "@types/recharts": "1.8.16", - "@types/styled-components": "5.1.4", "axios": "0.20.0", "clsx": "1.1.1", "lodash.uniqby": "4.7.0", @@ -31,7 +30,6 @@ "react-scripts": "3.4.3", "react-syntax-highlighter": "15.3.0", "recharts": "1.8.5", - "styled-components": "5.2.0", "typescript": "~3.7.2" }, "scripts": { diff --git a/ui/src/App.tsx b/ui/src/App.tsx index f01d13c..e6c4401 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -2,7 +2,7 @@ import React, { useState } from "react"; import { connect, ConnectedProps } from "react-redux"; import clsx from "clsx"; import { BrowserRouter as Router, Switch, Route } from "react-router-dom"; -import { makeStyles, ThemeProvider } from "@material-ui/core/styles"; +import { makeStyles, Theme, ThemeProvider } from "@material-ui/core/styles"; import AppBar from "@material-ui/core/AppBar"; import Drawer from "@material-ui/core/Drawer"; import Toolbar from "@material-ui/core/Toolbar"; @@ -39,91 +39,94 @@ import PageNotFoundView from "./views/PageNotFoundView"; const drawerWidth = 220; -const useStyles = makeStyles((theme) => ({ - root: { - display: "flex", - }, - toolbar: { - paddingRight: 24, // keep right padding when drawer closed - }, - toolbarIcon: { - display: "flex", - alignItems: "center", - justifyContent: "flex-end", - padding: "0 8px", - ...theme.mixins.toolbar, - }, - appBar: { - backgroundColor: theme.palette.background.paper, - zIndex: theme.zIndex.drawer + 1, - }, - menuButton: { - marginRight: theme.spacing(2), - color: theme.palette.grey[700], - }, - menuButtonHidden: { - display: "none", - }, - title: { - flexGrow: 1, - color: theme.palette.grey[800], - }, - drawerPaper: { - position: "relative", - whiteSpace: "nowrap", - width: drawerWidth, - transition: theme.transitions.create("width", { - easing: theme.transitions.easing.sharp, - duration: theme.transitions.duration.enteringScreen, - }), - border: "none", - }, - drawerPaperClose: { - overflowX: "hidden", - transition: theme.transitions.create("width", { - easing: theme.transitions.easing.sharp, - duration: theme.transitions.duration.leavingScreen, - }), - width: theme.spacing(7), - [theme.breakpoints.up("sm")]: { - width: theme.spacing(9), +// FIXME: For some reason, the following code does not work: +// makeStyles(theme => ({ /* use theme here */})); +// Using closure to work around this problem. +const useStyles = (theme: Theme) => + makeStyles({ + root: { + display: "flex", }, - }, - snackbar: { - background: theme.palette.grey["A400"], - color: "#ffffff", - }, - snackbarCloseIcon: { - color: theme.palette.grey[400], - }, - appBarSpacer: theme.mixins.toolbar, - mainContainer: { - display: "flex", - width: "100vw", - }, - content: { - flex: 1, - height: "100vh", - overflow: "hidden", - background: "#ffffff", - }, - contentWrapper: { - height: "100%", - display: "flex", - paddingTop: "64px", // app-bar height - overflow: "scroll", - }, - sidebarContainer: { - display: "flex", - justifyContent: "space-between", - height: "100%", - flexDirection: "column", - }, - listItem: { - borderTopRightRadius: "24px", - borderBottomRightRadius: "24px", - }, -})); + toolbar: { + paddingRight: 24, // keep right padding when drawer closed + }, + toolbarIcon: { + display: "flex", + alignItems: "center", + justifyContent: "flex-end", + padding: "0 8px", + ...theme.mixins.toolbar, + }, + appBar: { + backgroundColor: theme.palette.background.paper, + zIndex: theme.zIndex.drawer + 1, + }, + menuButton: { + marginRight: theme.spacing(2), + color: theme.palette.grey[700], + }, + menuButtonHidden: { + display: "none", + }, + title: { + flexGrow: 1, + }, + drawerPaper: { + position: "relative", + whiteSpace: "nowrap", + width: drawerWidth, + transition: theme.transitions.create("width", { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.enteringScreen, + }), + border: "none", + }, + drawerPaperClose: { + overflowX: "hidden", + transition: theme.transitions.create("width", { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.leavingScreen, + }), + width: theme.spacing(7), + [theme.breakpoints.up("sm")]: { + width: theme.spacing(9), + }, + }, + snackbar: { + background: theme.palette.grey["A400"], + color: "#ffffff", + }, + snackbarCloseIcon: { + color: theme.palette.grey[400], + }, + appBarSpacer: theme.mixins.toolbar, + mainContainer: { + display: "flex", + width: "100vw", + }, + content: { + flex: 1, + height: "100vh", + overflow: "hidden", + background: theme.palette.background.paper, + }, + contentWrapper: { + height: "100%", + display: "flex", + paddingTop: "64px", // app-bar height + overflow: "scroll", + }, + sidebarContainer: { + display: "flex", + justifyContent: "space-between", + height: "100%", + flexDirection: "column", + }, + listItem: { + borderTopRightRadius: "24px", + borderBottomRightRadius: "24px", + }, + }); function mapStateToProps(state: AppState) { return { @@ -143,10 +146,10 @@ function SlideUpTransition(props: TransitionProps) { } function App(props: ConnectedProps) { - const classes = useStyles(); + const theme = makeTheme(props.isDarkTheme); + const classes = useStyles(theme)(); const [open, setOpen] = useState(true); const toggleDrawer = () => setOpen(!open); - const theme = makeTheme(props.isDarkTheme); return ( @@ -169,9 +172,9 @@ function App(props: ConnectedProps) { Asynq Monitoring diff --git a/ui/src/components/ActiveTasksTable.tsx b/ui/src/components/ActiveTasksTable.tsx index be43849..736c725 100644 --- a/ui/src/components/ActiveTasksTable.tsx +++ b/ui/src/components/ActiveTasksTable.tsx @@ -41,11 +41,14 @@ import { ActiveTaskExtended } from "../reducers/tasksReducer"; import { uuidPrefix } from "../utils"; import { TableColumn } from "../types/table"; -const useStyles = makeStyles({ +const useStyles = makeStyles((theme) => ({ table: { minWidth: 650, }, -}); + stickyHeaderCell: { + background: theme.palette.background.paper, + }, +})); function mapStateToProps(state: AppState) { return { @@ -168,7 +171,10 @@ function ActiveTasksTable(props: Props & ReduxProps) { > - + 0 && numSelected < rowCount} checked={rowCount > 0 && numSelected === rowCount} @@ -179,7 +185,11 @@ function ActiveTasksTable(props: Props & ReduxProps) { /> {columns.map((col) => ( - + {col.label} ))} diff --git a/ui/src/components/ArchivedTasksTable.tsx b/ui/src/components/ArchivedTasksTable.tsx index 02910b3..98bb85d 100644 --- a/ui/src/components/ArchivedTasksTable.tsx +++ b/ui/src/components/ArchivedTasksTable.tsx @@ -46,11 +46,14 @@ import { usePolling } from "../hooks"; import { ArchivedTaskExtended } from "../reducers/tasksReducer"; import { TableColumn } from "../types/table"; -const useStyles = makeStyles({ +const useStyles = makeStyles((theme) => ({ table: { minWidth: 650, }, -}); + stickyHeaderCell: { + background: theme.palette.background.paper, + }, +})); const useRowStyles = makeStyles({ root: { @@ -214,7 +217,10 @@ function ArchivedTasksTable(props: Props & ReduxProps) { > - + 0 && numSelected < rowCount} checked={rowCount > 0 && numSelected === rowCount} @@ -225,7 +231,11 @@ function ArchivedTasksTable(props: Props & ReduxProps) { /> {columns.map((col) => ( - + {col.label} ))} diff --git a/ui/src/components/PendingTasksTable.tsx b/ui/src/components/PendingTasksTable.tsx index 1fb22ac..0f5ee0a 100644 --- a/ui/src/components/PendingTasksTable.tsx +++ b/ui/src/components/PendingTasksTable.tsx @@ -32,11 +32,14 @@ import { usePolling } from "../hooks"; import { uuidPrefix } from "../utils"; import { TableColumn } from "../types/table"; -const useStyles = makeStyles({ +const useStyles = makeStyles((theme) => ({ table: { minWidth: 650, }, -}); + stickyHeaderCell: { + background: theme.palette.background.paper, + }, +})); function mapStateToProps(state: AppState) { return { @@ -110,7 +113,11 @@ function PendingTasksTable(props: Props & ReduxProps) { {columns.map((col) => ( - + {col.label} ))} diff --git a/ui/src/components/QueuesOverviewTable.tsx b/ui/src/components/QueuesOverviewTable.tsx index df9a051..d471c7b 100644 --- a/ui/src/components/QueuesOverviewTable.tsx +++ b/ui/src/components/QueuesOverviewTable.tsx @@ -27,6 +27,7 @@ const useStyles = makeStyles((theme) => ({ }, linkCell: { textDecoration: "none", + color: theme.palette.text.primary, }, footerCell: { fontWeight: 600, @@ -40,7 +41,7 @@ const useStyles = makeStyles((theme) => ({ position: "sticky", zIndex: 1, left: 0, - background: theme.palette.common.white, + background: theme.palette.background.paper, }, actionIconsContainer: { display: "flex", @@ -211,7 +212,10 @@ export default function QueuesOverviewTable(props: Props) { scope="row" className={clsx(classes.boldCell, classes.fixedCell)} > - + {q.queue} {q.paused ? " (paused)" : ""} diff --git a/ui/src/components/RetryTasksTable.tsx b/ui/src/components/RetryTasksTable.tsx index 02b7084..3c75cfa 100644 --- a/ui/src/components/RetryTasksTable.tsx +++ b/ui/src/components/RetryTasksTable.tsx @@ -50,11 +50,14 @@ import { RetryTaskExtended } from "../reducers/tasksReducer"; import clsx from "clsx"; import { TableColumn } from "../types/table"; -const useStyles = makeStyles({ +const useStyles = makeStyles((theme) => ({ table: { minWidth: 650, }, -}); + stickyHeaderCell: { + background: theme.palette.background.paper, + }, +})); function mapStateToProps(state: AppState) { return { @@ -229,7 +232,10 @@ function RetryTasksTable(props: Props & ReduxProps) { > - + 0 && numSelected < rowCount} checked={rowCount > 0 && numSelected === rowCount} @@ -240,7 +246,11 @@ function RetryTasksTable(props: Props & ReduxProps) { /> {columns.map((col) => ( - + {col.label} ))} diff --git a/ui/src/components/ScheduledTasksTable.tsx b/ui/src/components/ScheduledTasksTable.tsx index d115eb4..9dcc73c 100644 --- a/ui/src/components/ScheduledTasksTable.tsx +++ b/ui/src/components/ScheduledTasksTable.tsx @@ -50,11 +50,14 @@ import { usePolling } from "../hooks"; import { ScheduledTaskExtended } from "../reducers/tasksReducer"; import { TableColumn } from "../types/table"; -const useStyles = makeStyles({ +const useStyles = makeStyles((theme) => ({ table: { minWidth: 650, }, -}); + stickyHeaderCell: { + background: theme.palette.background.paper, + }, +})); function mapStateToProps(state: AppState) { return { @@ -226,7 +229,10 @@ function ScheduledTasksTable(props: Props & ReduxProps) { > - + 0 && numSelected < rowCount} checked={rowCount > 0 && numSelected === rowCount} @@ -237,7 +243,11 @@ function ScheduledTasksTable(props: Props & ReduxProps) { /> {columns.map((col) => ( - + {col.label} ))} diff --git a/ui/src/components/ServersTable.tsx b/ui/src/components/ServersTable.tsx index 5300ff0..5aceccc 100644 --- a/ui/src/components/ServersTable.tsx +++ b/ui/src/components/ServersTable.tsx @@ -1,7 +1,7 @@ import React, { useState } from "react"; import { Link } from "react-router-dom"; import clsx from "clsx"; -import { makeStyles } from "@material-ui/core/styles"; +import { makeStyles, useTheme, Theme } from "@material-ui/core/styles"; import Grid from "@material-ui/core/Grid"; import Box from "@material-ui/core/Box"; import Collapse from "@material-ui/core/Collapse"; @@ -19,7 +19,8 @@ import KeyboardArrowUpIcon from "@material-ui/icons/KeyboardArrowUp"; import Alert from "@material-ui/lab/Alert"; import AlertTitle from "@material-ui/lab/AlertTitle"; import SyntaxHighlighter from "react-syntax-highlighter"; -import syntaxHighlightStyle from "react-syntax-highlighter/dist/esm/styles/hljs/github"; +import syntaxHighlightStyleDark from "react-syntax-highlighter/dist/esm/styles/hljs/atom-one-dark"; +import syntaxHighlightStyleLight from "react-syntax-highlighter/dist/esm/styles/hljs/atom-one-light"; import { ServerInfo } from "../api"; import { SortDirection, SortableTableColumn } from "../types/table"; import { timeAgo, uuidPrefix } from "../utils"; @@ -34,7 +35,7 @@ const useStyles = makeStyles((theme) => ({ position: "sticky", zIndex: 1, left: 0, - background: theme.palette.common.white, + background: theme.palette.background.paper, }, })); @@ -208,10 +209,15 @@ const useRowStyles = makeStyles((theme) => ({ noBorder: { border: "none", }, + link: { + color: theme.palette.text.primary, + }, })); function Row(props: RowProps) { const classes = useRowStyles(); + const theme = useTheme(); + const isDarkTheme = theme.palette.type === "dark"; const { server } = props; const [open, setOpen] = useState(false); const qnames = Object.keys(server.queue_priorities); @@ -226,7 +232,9 @@ function Row(props: RowProps) { {qnames.map((qname, idx) => ( - {qname} + + {qname} + {idx === qnames.length - 1 ? "" : ", "} ))} @@ -276,7 +284,11 @@ function Row(props: RowProps) { {JSON.stringify(worker.task.payload)} @@ -308,7 +320,12 @@ function Row(props: RowProps) { {qnames.map((qname) => ( - {qname} + + {qname} + {server.queue_priorities[qname]} diff --git a/ui/src/components/TasksTable.tsx b/ui/src/components/TasksTable.tsx index 31e7891..604d16e 100644 --- a/ui/src/components/TasksTable.tsx +++ b/ui/src/components/TasksTable.tsx @@ -1,9 +1,10 @@ import React from "react"; import { connect, ConnectedProps } from "react-redux"; -import styled from "styled-components"; import { makeStyles } from "@material-ui/core/styles"; import Tabs from "@material-ui/core/Tabs"; import Tab from "@material-ui/core/Tab"; +import Typography from "@material-ui/core/Typography"; +import Paper from "@material-ui/core/Paper"; import ActiveTasksTable from "./ActiveTasksTable"; import PendingTasksTable from "./PendingTasksTable"; import ScheduledTasksTable from "./ScheduledTasksTable"; @@ -11,8 +12,6 @@ import RetryTasksTable from "./RetryTasksTable"; import ArchivedTasksTable from "./ArchivedTasksTable"; import { useHistory } from "react-router-dom"; import { queueDetailsPath } from "../paths"; -import { Typography } from "@material-ui/core"; -import Paper from "@material-ui/core/Paper/Paper"; import { QueueInfo } from "../reducers/queuesReducer"; import { AppState } from "../store"; @@ -22,24 +21,20 @@ interface TabPanelProps { value: string; // tab panel will be shown if selected value equals to the value } -const TabPanelRoot = styled.div` - flex: 1; - overflow-y: scroll; -`; - function TabPanel(props: TabPanelProps) { const { children, value, selected, ...other } = props; return ( - + ); } @@ -50,67 +45,13 @@ function a11yProps(value: string) { }; } -const Container = styled.div` - display: flex; - width: 100%; - height: 100%; -`; - -const TaskCount = styled.div` - font-size: 2rem; - font-weight: 600; - margin: 0; -`; - -const Heading = styled.div` - opacity: 0.7; - font-size: 1.7rem; - font-weight: 500; - background: #f5f7f9; - padding-left: 28px; - padding-top: 28px; - padding-bottom: 28px; -`; - -const PanelContainer = styled.div` - padding: 24px; - background: #ffffff; -`; - -const TabsContainer = styled.div` - background: #f5f7f9; -`; - -const useStyles = makeStyles((theme) => ({ +const usePanelHeadingStyles = makeStyles((theme) => ({ paper: { padding: theme.spacing(2), marginBottom: theme.spacing(2), display: "flex", justifyContent: "space-between", }, - heading: { - padingLeft: theme.spacing(2), - }, - tabsRoot: { - paddingLeft: theme.spacing(2), - background: theme.palette.background.default, - }, - tabsIndicator: { - right: "auto", - left: "0", - }, - tabroot: { - width: "204px", - textAlign: "left", - padding: theme.spacing(2), - }, - tabwrapper: { - alignItems: "flex-start", - }, - tabSelected: { - background: theme.palette.common.white, - boxShadow: theme.shadows[1], - }, })); function PanelHeading(props: { @@ -119,9 +60,9 @@ function PanelHeading(props: { failed: number; paused: boolean; }) { - const classes = useStyles(); + const classes = usePanelHeadingStyles(); return ( - +
Queue Name @@ -183,15 +124,66 @@ interface Props { selected: string; } +const useStyles = makeStyles((theme) => ({ + container: { + display: "flex", + width: "100%", + height: "100%", + }, + heading: { + opacity: 0.7, + fontSize: "1.7rem", + fontWeight: 500, + backgroundColor: theme.palette.background.paper, + paddingLeft: "28px", // TODO: maybe use theme.spacing(3), + paddingTop: "28px", + paddingBottom: "28px", + color: theme.palette.text.primary, + }, + tabsContainer: { + background: theme.palette.background.paper, + }, + tabsRoot: { + paddingLeft: theme.spacing(2), + background: theme.palette.background.paper, + }, + tabsIndicator: { + right: "auto", + left: "0", + }, + tabroot: { + width: "204px", + textAlign: "left", + padding: theme.spacing(2), + }, + tabwrapper: { + alignItems: "flex-start", + color: theme.palette.text.primary, + }, + tabSelected: { + background: theme.palette.action.selected, + boxShadow: theme.shadows[1], + }, + panelContainer: { + padding: "24px", + background: theme.palette.background.paper, + }, + taskCount: { + fontSize: "2rem", + fontWeight: 600, + margin: 0, + }, +})); + function TasksTable(props: Props & ReduxProps) { const { currentStats } = props; const classes = useStyles(); const history = useHistory(); return ( - - - Tasks +
+
+
Tasks
@@ -204,7 +196,9 @@ function TasksTable(props: Props & ReduxProps) { {currentStats.active}} + icon={ +
{currentStats.active}
+ } classes={{ root: classes.tabroot, wrapper: classes.tabwrapper, @@ -215,7 +209,9 @@ function TasksTable(props: Props & ReduxProps) { {currentStats.pending}} + icon={ +
{currentStats.pending}
+ } classes={{ root: classes.tabroot, wrapper: classes.tabwrapper, @@ -226,7 +222,9 @@ function TasksTable(props: Props & ReduxProps) { {currentStats.scheduled}} + icon={ +
{currentStats.scheduled}
+ } classes={{ root: classes.tabroot, wrapper: classes.tabwrapper, @@ -237,7 +235,7 @@ function TasksTable(props: Props & ReduxProps) { {currentStats.retry}} + icon={
{currentStats.retry}
} classes={{ root: classes.tabroot, wrapper: classes.tabwrapper, @@ -248,7 +246,9 @@ function TasksTable(props: Props & ReduxProps) { {currentStats.archived}} + icon={ +
{currentStats.archived}
+ } classes={{ root: classes.tabroot, wrapper: classes.tabwrapper, @@ -257,9 +257,9 @@ function TasksTable(props: Props & ReduxProps) { {...a11yProps("archived")} />
- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
); } diff --git a/ui/src/reducers/settingsReducer.ts b/ui/src/reducers/settingsReducer.ts index 34edd7c..4e0f50a 100644 --- a/ui/src/reducers/settingsReducer.ts +++ b/ui/src/reducers/settingsReducer.ts @@ -1,4 +1,8 @@ -import {POLL_INTERVAL_CHANGE, SettingsActionTypes, TOGGLE_DARK_THEME,} from '../actions/settingsActions'; +import { + POLL_INTERVAL_CHANGE, + SettingsActionTypes, + TOGGLE_DARK_THEME, +} from "../actions/settingsActions"; interface SettingsState { pollInterval: number; @@ -7,18 +11,21 @@ interface SettingsState { const initialState: SettingsState = { pollInterval: 8, - isDarkTheme: false, + isDarkTheme: true, }; function settingsReducer( - state = initialState, action: SettingsActionTypes): SettingsState { + state = initialState, + action: SettingsActionTypes +): SettingsState { switch (action.type) { case POLL_INTERVAL_CHANGE: - return {...state, pollInterval: action.value}; + return { ...state, pollInterval: action.value }; case TOGGLE_DARK_THEME: return { - ...state, isDarkTheme: !state.isDarkTheme - } + ...state, + isDarkTheme: !state.isDarkTheme, + }; default: return state; } diff --git a/ui/src/views/RedisInfoView.tsx b/ui/src/views/RedisInfoView.tsx index 450c78c..35c6d78 100644 --- a/ui/src/views/RedisInfoView.tsx +++ b/ui/src/views/RedisInfoView.tsx @@ -9,7 +9,8 @@ import CardContent from "@material-ui/core/CardContent"; import Alert from "@material-ui/lab/Alert"; import AlertTitle from "@material-ui/lab/AlertTitle"; import SyntaxHighlighter from "react-syntax-highlighter"; -import syntaxHighlightStyle from "react-syntax-highlighter/dist/esm/styles/hljs/github"; +import syntaxHighlightStyleDark from "react-syntax-highlighter/dist/esm/styles/hljs/atom-one-dark"; +import syntaxHighlightStyleLight from "react-syntax-highlighter/dist/esm/styles/hljs/atom-one-light"; import { getRedisInfoAsync } from "../actions/redisInfoActions"; import { usePolling } from "../hooks"; import { AppState } from "../store"; @@ -30,6 +31,7 @@ function mapStateToProps(state: AppState) { redisAddress: state.redis.address, redisInfoRaw: state.redis.rawData, pollInterval: state.settings.pollInterval, + isDarkTheme: state.settings.isDarkTheme, }; } @@ -38,7 +40,13 @@ type Props = ConnectedProps; function RedisInfoView(props: Props) { const classes = useStyles(); - const { pollInterval, getRedisInfoAsync, redisInfo, redisInfoRaw } = props; + const { + pollInterval, + getRedisInfoAsync, + redisInfo, + redisInfoRaw, + isDarkTheme, + } = props; usePolling(getRedisInfoAsync, pollInterval); @@ -56,7 +64,9 @@ function RedisInfoView(props: Props) { {props.error === "" ? ( <> - Redis Info + + Redis Info + Connected to: {props.redisAddress} @@ -153,7 +163,11 @@ function RedisInfoView(props: Props) {
{redisInfoRaw} diff --git a/ui/src/views/SettingsView.tsx b/ui/src/views/SettingsView.tsx index 861ca34..8230b67 100644 --- a/ui/src/views/SettingsView.tsx +++ b/ui/src/views/SettingsView.tsx @@ -60,7 +60,9 @@ function SettingsView(props: PropsFromRedux) { - Settings + + Settings +