Extract TableActions component

This commit is contained in:
Ken Hibino 2020-12-18 12:48:05 -08:00
parent 95bb6051d0
commit 68738ec962
5 changed files with 281 additions and 201 deletions

View File

@ -5,7 +5,6 @@ import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody"; import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell"; import TableCell from "@material-ui/core/TableCell";
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
import ButtonGroup from "@material-ui/core/ButtonGroup";
import Checkbox from "@material-ui/core/Checkbox"; import Checkbox from "@material-ui/core/Checkbox";
import TableContainer from "@material-ui/core/TableContainer"; import TableContainer from "@material-ui/core/TableContainer";
import TableHead from "@material-ui/core/TableHead"; import TableHead from "@material-ui/core/TableHead";
@ -14,14 +13,11 @@ import Paper from "@material-ui/core/Paper";
import Box from "@material-ui/core/Box"; import Box from "@material-ui/core/Box";
import Collapse from "@material-ui/core/Collapse"; import Collapse from "@material-ui/core/Collapse";
import IconButton from "@material-ui/core/IconButton"; import IconButton from "@material-ui/core/IconButton";
import Menu from "@material-ui/core/Menu";
import MenuItem from "@material-ui/core/MenuItem";
import KeyboardArrowUpIcon from "@material-ui/icons/KeyboardArrowUp"; import KeyboardArrowUpIcon from "@material-ui/icons/KeyboardArrowUp";
import KeyboardArrowDownIcon from "@material-ui/icons/KeyboardArrowDown"; import KeyboardArrowDownIcon from "@material-ui/icons/KeyboardArrowDown";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import TableFooter from "@material-ui/core/TableFooter"; import TableFooter from "@material-ui/core/TableFooter";
import TablePagination from "@material-ui/core/TablePagination"; import TablePagination from "@material-ui/core/TablePagination";
import MoreHorizIcon from "@material-ui/icons/MoreHoriz";
import Alert from "@material-ui/lab/Alert"; import Alert from "@material-ui/lab/Alert";
import AlertTitle from "@material-ui/lab/AlertTitle"; import AlertTitle from "@material-ui/lab/AlertTitle";
import SyntaxHighlighter from "react-syntax-highlighter"; import SyntaxHighlighter from "react-syntax-highlighter";
@ -40,6 +36,7 @@ import TablePaginationActions, {
defaultPageSize, defaultPageSize,
rowsPerPageOptions, rowsPerPageOptions,
} from "./TablePaginationActions"; } from "./TablePaginationActions";
import TableActions from "./TableActions";
import { timeAgo } from "../timeutil"; import { timeAgo } from "../timeutil";
import { usePolling } from "../hooks"; import { usePolling } from "../hooks";
import { DeadTaskExtended } from "../reducers/tasksReducer"; import { DeadTaskExtended } from "../reducers/tasksReducer";
@ -48,12 +45,6 @@ const useStyles = makeStyles({
table: { table: {
minWidth: 650, minWidth: 650,
}, },
actionsContainer: {
padding: "4px",
},
moreIcon: {
marginRight: "8px",
},
}); });
const useRowStyles = makeStyles({ const useRowStyles = makeStyles({
@ -99,7 +90,6 @@ function DeadTasksTable(props: Props & ReduxProps) {
const [page, setPage] = useState(0); const [page, setPage] = useState(0);
const [pageSize, setPageSize] = useState(defaultPageSize); const [pageSize, setPageSize] = useState(defaultPageSize);
const [selectedKeys, setSelectedKeys] = useState<string[]>([]); const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
const [menuAnchor, setMenuAnchor] = useState<null | HTMLElement>(null);
const handleChangePage = ( const handleChangePage = (
event: React.MouseEvent<HTMLButtonElement> | null, event: React.MouseEvent<HTMLButtonElement> | null,
@ -124,20 +114,24 @@ function DeadTasksTable(props: Props & ReduxProps) {
} }
}; };
const handleMenuClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setMenuAnchor(event.currentTarget);
};
const handleMenuClose = () => setMenuAnchor(null);
const handleRunAllClick = () => { const handleRunAllClick = () => {
props.runAllDeadTasksAsync(queue); props.runAllDeadTasksAsync(queue);
setMenuAnchor(null);
}; };
const handleDeleteAllClick = () => { const handleDeleteAllClick = () => {
props.deleteAllDeadTasksAsync(queue); props.deleteAllDeadTasksAsync(queue);
setMenuAnchor(null); };
const handleBatchRunClick = () => {
props
.batchDeleteDeadTasksAsync(queue, selectedKeys)
.then(() => setSelectedKeys([]));
};
const handleBatchDeleteClick = () => {
props
.batchRunDeadTasksAsync(queue, selectedKeys)
.then(() => setSelectedKeys([]));
}; };
const fetchData = useCallback(() => { const fetchData = useCallback(() => {
@ -169,64 +163,15 @@ function DeadTasksTable(props: Props & ReduxProps) {
const numSelected = selectedKeys.length; const numSelected = selectedKeys.length;
return ( return (
<div> <div>
<div className={classes.actionsContainer}> <TableActions
<IconButton allActionPending={props.allActionPending}
aria-label="actions" batchActionPending={props.batchActionPending}
className={classes.moreIcon} showBatchActions={numSelected > 0}
onClick={handleMenuClick} onRunAllClick={handleRunAllClick}
> onDeleteAllClick={handleDeleteAllClick}
<MoreHorizIcon /> onBatchRunClick={handleBatchRunClick}
</IconButton> onBatchDeleteClick={handleBatchDeleteClick}
<Menu />
id="action-menu"
keepMounted
anchorEl={menuAnchor}
open={Boolean(menuAnchor)}
onClose={handleMenuClose}
>
<MenuItem
onClick={handleRunAllClick}
disabled={props.allActionPending}
>
Run All
</MenuItem>
<MenuItem
onClick={handleDeleteAllClick}
disabled={props.allActionPending}
>
Delete All
</MenuItem>
</Menu>
{numSelected > 0 && (
<ButtonGroup
variant="text"
color="primary"
aria-label="text primary button group"
>
<Button
disabled={props.batchActionPending}
onClick={() =>
props
.batchRunDeadTasksAsync(queue, selectedKeys)
.then(() => setSelectedKeys([]))
}
>
Run
</Button>
<Button>Kill</Button>
<Button
disabled={props.batchActionPending}
onClick={() =>
props
.batchDeleteDeadTasksAsync(queue, selectedKeys)
.then(() => setSelectedKeys([]))
}
>
Delete
</Button>
</ButtonGroup>
)}
</div>
<TableContainer component={Paper}> <TableContainer component={Paper}>
<Table <Table
stickyHeader={true} stickyHeader={true}

View File

@ -31,6 +31,7 @@ import TablePaginationActions, {
defaultPageSize, defaultPageSize,
rowsPerPageOptions, rowsPerPageOptions,
} from "./TablePaginationActions"; } from "./TablePaginationActions";
import TableActions from "./TableActions";
import { durationBefore } from "../timeutil"; import { durationBefore } from "../timeutil";
import { usePolling } from "../hooks"; import { usePolling } from "../hooks";
import { RetryTaskExtended } from "../reducers/tasksReducer"; import { RetryTaskExtended } from "../reducers/tasksReducer";
@ -45,6 +46,8 @@ function mapStateToProps(state: AppState) {
return { return {
loading: state.tasks.retryTasks.loading, loading: state.tasks.retryTasks.loading,
tasks: state.tasks.retryTasks.data, tasks: state.tasks.retryTasks.data,
batchActionPending: state.tasks.retryTasks.batchActionPending,
allActionPending: state.tasks.retryTasks.allActionPending,
pollInterval: state.settings.pollInterval, pollInterval: state.settings.pollInterval,
}; };
} }
@ -120,6 +123,16 @@ function RetryTasksTable(props: Props & ReduxProps) {
const rowCount = props.tasks.length; const rowCount = props.tasks.length;
const numSelected = selectedKeys.length; const numSelected = selectedKeys.length;
return ( return (
<div>
<TableActions
allActionPending={props.allActionPending}
batchActionPending={props.batchActionPending}
showBatchActions={numSelected > 0}
onRunAllClick={() => console.log("TODO")}
onDeleteAllClick={() => console.log("TODO")}
onBatchRunClick={() => console.log("TODO")}
onBatchDeleteClick={() => console.log("TODO")}
/>
<TableContainer component={Paper}> <TableContainer component={Paper}>
<Table <Table
stickyHeader={true} stickyHeader={true}
@ -185,6 +198,7 @@ function RetryTasksTable(props: Props & ReduxProps) {
</TableFooter> </TableFooter>
</Table> </Table>
</TableContainer> </TableContainer>
</div>
); );
} }

View File

@ -31,6 +31,7 @@ import TablePaginationActions, {
defaultPageSize, defaultPageSize,
rowsPerPageOptions, rowsPerPageOptions,
} from "./TablePaginationActions"; } from "./TablePaginationActions";
import TableActions from "./TableActions";
import { durationBefore } from "../timeutil"; import { durationBefore } from "../timeutil";
import { usePolling } from "../hooks"; import { usePolling } from "../hooks";
import { ScheduledTaskExtended } from "../reducers/tasksReducer"; import { ScheduledTaskExtended } from "../reducers/tasksReducer";
@ -45,6 +46,8 @@ function mapStateToProps(state: AppState) {
return { return {
loading: state.tasks.scheduledTasks.loading, loading: state.tasks.scheduledTasks.loading,
tasks: state.tasks.scheduledTasks.data, tasks: state.tasks.scheduledTasks.data,
batchActionPending: state.tasks.scheduledTasks.batchActionPending,
allActionPending: state.tasks.scheduledTasks.allActionPending,
pollInterval: state.settings.pollInterval, pollInterval: state.settings.pollInterval,
}; };
} }
@ -120,6 +123,16 @@ function ScheduledTasksTable(props: Props & ReduxProps) {
const rowCount = props.tasks.length; const rowCount = props.tasks.length;
const numSelected = selectedKeys.length; const numSelected = selectedKeys.length;
return ( return (
<div>
<TableActions
allActionPending={props.allActionPending}
batchActionPending={props.batchActionPending}
showBatchActions={numSelected > 0}
onRunAllClick={() => console.log("TODO")}
onDeleteAllClick={() => console.log("TODO")}
onBatchRunClick={() => console.log("TODO")}
onBatchDeleteClick={() => console.log("TODO")}
/>
<TableContainer component={Paper}> <TableContainer component={Paper}>
<Table <Table
stickyHeader={true} stickyHeader={true}
@ -185,6 +198,7 @@ function ScheduledTasksTable(props: Props & ReduxProps) {
</TableFooter> </TableFooter>
</Table> </Table>
</TableContainer> </TableContainer>
</div>
); );
} }

View File

@ -0,0 +1,97 @@
import React, { useState } from "react";
import { makeStyles } from "@material-ui/core/styles";
import Button from "@material-ui/core/Button";
import ButtonGroup from "@material-ui/core/ButtonGroup";
import IconButton from "@material-ui/core/IconButton";
import Menu from "@material-ui/core/Menu";
import MenuItem from "@material-ui/core/MenuItem";
import MoreHorizIcon from "@material-ui/icons/MoreHoriz";
const useStyles = makeStyles({
actionsContainer: {
padding: "4px",
},
moreIcon: {
marginRight: "8px",
},
});
interface Props {
allActionPending: boolean;
onRunAllClick: () => void;
onDeleteAllClick: () => void;
showBatchActions: boolean;
batchActionPending: boolean;
onBatchRunClick: () => void;
onBatchDeleteClick: () => void;
}
export default function TableActions(props: Props) {
const classes = useStyles();
const [menuAnchor, setMenuAnchor] = useState<null | HTMLElement>(null);
const handleMenuClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setMenuAnchor(event.currentTarget);
};
const closeMenu = () => setMenuAnchor(null);
return (
<div className={classes.actionsContainer}>
<IconButton
aria-label="actions"
className={classes.moreIcon}
onClick={handleMenuClick}
>
<MoreHorizIcon />
</IconButton>
<Menu
id="action-menu"
keepMounted
anchorEl={menuAnchor}
open={Boolean(menuAnchor)}
onClose={closeMenu}
>
<MenuItem
onClick={() => {
props.onRunAllClick();
closeMenu();
}}
disabled={props.allActionPending}
>
Run All
</MenuItem>
<MenuItem
onClick={() => {
props.onDeleteAllClick();
closeMenu();
}}
disabled={props.allActionPending}
>
Delete All
</MenuItem>
</Menu>
{props.showBatchActions && (
<ButtonGroup
variant="text"
color="primary"
aria-label="text primary button group"
>
<Button
disabled={props.batchActionPending}
onClick={props.onBatchRunClick}
>
Run
</Button>
<Button>Kill</Button>
<Button
disabled={props.batchActionPending}
onClick={props.onBatchDeleteClick}
>
Delete
</Button>
</ButtonGroup>
)}
</div>
);
}

View File

@ -92,11 +92,15 @@ interface TasksState {
}; };
scheduledTasks: { scheduledTasks: {
loading: boolean; loading: boolean;
batchActionPending: boolean;
allActionPending: boolean;
error: string; error: string;
data: ScheduledTaskExtended[]; data: ScheduledTaskExtended[];
}; };
retryTasks: { retryTasks: {
loading: boolean; loading: boolean;
batchActionPending: boolean;
allActionPending: boolean;
error: string; error: string;
data: RetryTaskExtended[]; data: RetryTaskExtended[];
}; };
@ -122,11 +126,15 @@ const initialState: TasksState = {
}, },
scheduledTasks: { scheduledTasks: {
loading: false, loading: false,
batchActionPending: false,
allActionPending: false,
error: "", error: "",
data: [], data: [],
}, },
retryTasks: { retryTasks: {
loading: false, loading: false,
batchActionPending: false,
allActionPending: false,
error: "", error: "",
data: [], data: [],
}, },
@ -222,6 +230,7 @@ function tasksReducer(
return { return {
...state, ...state,
scheduledTasks: { scheduledTasks: {
...state.scheduledTasks,
loading: false, loading: false,
error: "", error: "",
data: action.payload.tasks.map((task) => ({ data: action.payload.tasks.map((task) => ({
@ -255,6 +264,7 @@ function tasksReducer(
return { return {
...state, ...state,
retryTasks: { retryTasks: {
...state.retryTasks,
loading: false, loading: false,
error: "", error: "",
data: action.payload.tasks.map((task) => ({ data: action.payload.tasks.map((task) => ({