mirror of
https://github.com/hibiken/asynqmon.git
synced 2025-01-19 11:15:53 +08:00
Extract TableActions component
This commit is contained in:
parent
95bb6051d0
commit
68738ec962
@ -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}
|
||||||
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
97
ui/src/components/TableActions.tsx
Normal file
97
ui/src/components/TableActions.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
@ -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) => ({
|
||||||
|
Loading…
Reference in New Issue
Block a user