github.com/wfusion/gofusion@v1.1.14/common/infra/asynq/asynqmon/ui/src/App.tsx (about)

     1  import React from "react";
     2  import { connect, ConnectedProps } from "react-redux";
     3  import clsx from "clsx";
     4  import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
     5  import { makeStyles, Theme, ThemeProvider } from "@material-ui/core/styles";
     6  import AppBar from "@material-ui/core/AppBar";
     7  import Drawer from "@material-ui/core/Drawer";
     8  import Toolbar from "@material-ui/core/Toolbar";
     9  import List from "@material-ui/core/List";
    10  import ListItem from "@material-ui/core/ListItem";
    11  import ListItemIcon from "@material-ui/core/ListItemIcon";
    12  import ListItemText from "@material-ui/core/ListItemText";
    13  import Snackbar from "@material-ui/core/Snackbar";
    14  import SnackbarContent from "@material-ui/core/SnackbarContent";
    15  import IconButton from "@material-ui/core/IconButton";
    16  import Slide from "@material-ui/core/Slide";
    17  import { TransitionProps } from "@material-ui/core/transitions";
    18  import MenuIcon from "@material-ui/icons/Menu";
    19  import BarChartIcon from "@material-ui/icons/BarChart";
    20  import LayersIcon from "@material-ui/icons/Layers";
    21  import SettingsIcon from "@material-ui/icons/Settings";
    22  import ScheduleIcon from "@material-ui/icons/Schedule";
    23  import FeedbackIcon from "@material-ui/icons/Feedback";
    24  import TimelineIcon from "@material-ui/icons/Timeline";
    25  import DoubleArrowIcon from "@material-ui/icons/DoubleArrow";
    26  import CloseIcon from "@material-ui/icons/Close";
    27  import { AppState } from "./store";
    28  import { paths as getPaths } from "./paths";
    29  import { isDarkTheme, useTheme } from "./theme";
    30  import { closeSnackbar } from "./actions/snackbarActions";
    31  import { toggleDrawer } from "./actions/settingsActions";
    32  import ListItemLink from "./components/ListItemLink";
    33  import SchedulersView from "./views/SchedulersView";
    34  import DashboardView from "./views/DashboardView";
    35  import TasksView from "./views/TasksView";
    36  import TaskDetailsView from "./views/TaskDetailsView";
    37  import SettingsView from "./views/SettingsView";
    38  import ServersView from "./views/ServersView";
    39  import RedisInfoView from "./views/RedisInfoView";
    40  import MetricsView from "./views/MetricsView";
    41  import PageNotFoundView from "./views/PageNotFoundView";
    42  import { ReactComponent as Logo } from "./images/logo-color.svg";
    43  import { ReactComponent as LogoDarkTheme } from "./images/logo-white.svg";
    44  
    45  const drawerWidth = 220;
    46  
    47  // FIXME: For some reason, the following code does not work:
    48  //     makeStyles(theme => ({ /* use theme here */}));
    49  // Using closure to work around this problem.
    50  const useStyles = (theme: Theme) =>
    51    makeStyles({
    52      root: {
    53        display: "flex",
    54      },
    55      toolbar: {
    56        paddingRight: 24, // keep right padding when drawer closed
    57      },
    58      toolbarIcon: {
    59        display: "flex",
    60        alignItems: "center",
    61        justifyContent: "flex-end",
    62        padding: "0 8px",
    63        ...theme.mixins.toolbar,
    64      },
    65      appBar: {
    66        backgroundColor: theme.palette.background.paper,
    67        zIndex: theme.zIndex.drawer + 1,
    68      },
    69      menuButton: {
    70        marginRight: theme.spacing(1),
    71        color: isDarkTheme(theme)
    72          ? theme.palette.grey[100]
    73          : theme.palette.grey[700],
    74      },
    75      menuButtonHidden: {
    76        display: "none",
    77      },
    78      drawerPaper: {
    79        position: "relative",
    80        whiteSpace: "nowrap",
    81        width: drawerWidth,
    82        transition: theme.transitions.create("width", {
    83          easing: theme.transitions.easing.sharp,
    84          duration: theme.transitions.duration.enteringScreen,
    85        }),
    86        border: "none",
    87      },
    88      drawerPaperClose: {
    89        overflowX: "hidden",
    90        transition: theme.transitions.create("width", {
    91          easing: theme.transitions.easing.sharp,
    92          duration: theme.transitions.duration.leavingScreen,
    93        }),
    94        width: theme.spacing(7),
    95        [theme.breakpoints.up("sm")]: {
    96          width: theme.spacing(9),
    97        },
    98      },
    99      snackbar: {
   100        background: theme.palette.grey["A400"],
   101        color: "#ffffff",
   102      },
   103      snackbarCloseIcon: {
   104        color: theme.palette.grey[400],
   105      },
   106      appBarSpacer: theme.mixins.toolbar,
   107      mainContainer: {
   108        display: "flex",
   109        width: "100vw",
   110      },
   111      content: {
   112        flex: 1,
   113        height: "100vh",
   114        overflow: "hidden",
   115        background: theme.palette.background.paper,
   116      },
   117      contentWrapper: {
   118        height: "100%",
   119        display: "flex",
   120        paddingTop: "64px", // app-bar height
   121        overflow: "scroll",
   122      },
   123      sidebarContainer: {
   124        display: "flex",
   125        justifyContent: "space-between",
   126        height: "100%",
   127        flexDirection: "column",
   128      },
   129      listItem: {
   130        borderTopRightRadius: "24px",
   131        borderBottomRightRadius: "24px",
   132      },
   133    });
   134  
   135  function mapStateToProps(state: AppState) {
   136    return {
   137      snackbar: state.snackbar,
   138      themePreference: state.settings.themePreference,
   139      isDrawerOpen: state.settings.isDrawerOpen,
   140    };
   141  }
   142  
   143  const mapDispatchToProps = {
   144    closeSnackbar,
   145    toggleDrawer,
   146  };
   147  
   148  const connector = connect(mapStateToProps, mapDispatchToProps);
   149  
   150  function SlideUpTransition(props: TransitionProps) {
   151    return <Slide {...props} direction="up" />;
   152  }
   153  
   154  function App(props: ConnectedProps<typeof connector>) {
   155    const theme = useTheme(props.themePreference);
   156    const classes = useStyles(theme)();
   157    const paths = getPaths();
   158    return (
   159      <ThemeProvider theme={theme}>
   160        <Router>
   161          <div className={classes.root}>
   162            <AppBar
   163              position="absolute"
   164              className={classes.appBar}
   165              variant="outlined"
   166            >
   167              <Toolbar className={classes.toolbar}>
   168                <IconButton
   169                  edge="start"
   170                  color="inherit"
   171                  aria-label="open drawer"
   172                  onClick={props.toggleDrawer}
   173                  className={classes.menuButton}
   174                >
   175                  <MenuIcon />
   176                </IconButton>
   177                {isDarkTheme(theme) ? (
   178                  <LogoDarkTheme width={200} height={48} />
   179                ) : (
   180                  <Logo width={200} height={48} />
   181                )}
   182              </Toolbar>
   183            </AppBar>
   184            <div className={classes.mainContainer}>
   185              <Drawer
   186                variant="permanent"
   187                classes={{
   188                  paper: clsx(
   189                    classes.drawerPaper,
   190                    !props.isDrawerOpen && classes.drawerPaperClose
   191                  ),
   192                }}
   193                open={props.isDrawerOpen}
   194              >
   195                <Snackbar
   196                  anchorOrigin={{ vertical: "bottom", horizontal: "left" }}
   197                  open={props.snackbar.isOpen}
   198                  autoHideDuration={6000}
   199                  onClose={props.closeSnackbar}
   200                  TransitionComponent={SlideUpTransition}
   201                >
   202                  <SnackbarContent
   203                    message={props.snackbar.message}
   204                    className={classes.snackbar}
   205                    action={
   206                      <IconButton
   207                        size="small"
   208                        aria-label="close"
   209                        color="inherit"
   210                        onClick={props.closeSnackbar}
   211                      >
   212                        <CloseIcon
   213                          className={classes.snackbarCloseIcon}
   214                          fontSize="small"
   215                        />
   216                      </IconButton>
   217                    }
   218                  />
   219                </Snackbar>
   220                <div className={classes.appBarSpacer} />
   221                <div className={classes.sidebarContainer}>
   222                  <List>
   223                    <div>
   224                      <ListItemLink
   225                        to={paths.HOME}
   226                        primary="Queues"
   227                        icon={<BarChartIcon />}
   228                      />
   229                      <ListItemLink
   230                        to={paths.SERVERS}
   231                        primary="Servers"
   232                        icon={<DoubleArrowIcon />}
   233                      />
   234                      <ListItemLink
   235                        to={paths.SCHEDULERS}
   236                        primary="Schedulers"
   237                        icon={<ScheduleIcon />}
   238                      />
   239                      <ListItemLink
   240                        to={paths.REDIS}
   241                        primary="Redis"
   242                        icon={<LayersIcon />}
   243                      />
   244                      {window.PROMETHEUS_SERVER_ADDRESS && (
   245                        <ListItemLink
   246                          to={paths.QUEUE_METRICS}
   247                          primary="Metrics"
   248                          icon={<TimelineIcon />}
   249                        />
   250                      )}
   251                    </div>
   252                  </List>
   253                  <List>
   254                    <ListItemLink
   255                      to={paths.SETTINGS}
   256                      primary="Settings"
   257                      icon={<SettingsIcon />}
   258                    />
   259                    <ListItem
   260                      button
   261                      component="a"
   262                      className={classes.listItem}
   263                      href="https://github.com/hibiken/asynqmon/issues"
   264                      target="_blank"
   265                    >
   266                      <ListItemIcon>
   267                        <FeedbackIcon />
   268                      </ListItemIcon>
   269                      <ListItemText primary="Send Feedback" />
   270                    </ListItem>
   271                  </List>
   272                </div>
   273              </Drawer>
   274              <main className={classes.content}>
   275                <div className={classes.contentWrapper}>
   276                  <Switch>
   277                    <Route exact path={paths.TASK_DETAILS}>
   278                      <TaskDetailsView />
   279                    </Route>
   280                    <Route exact path={paths.QUEUE_DETAILS}>
   281                      <TasksView />
   282                    </Route>
   283                    <Route exact path={paths.SCHEDULERS}>
   284                      <SchedulersView />
   285                    </Route>
   286                    <Route exact path={paths.SERVERS}>
   287                      <ServersView />
   288                    </Route>
   289                    <Route exact path={paths.REDIS}>
   290                      <RedisInfoView />
   291                    </Route>
   292                    <Route exact path={paths.SETTINGS}>
   293                      <SettingsView />
   294                    </Route>
   295                    <Route exact path={paths.HOME}>
   296                      <DashboardView />
   297                    </Route>
   298                    <Route exact path={paths.QUEUE_METRICS}>
   299                      <MetricsView />
   300                    </Route>
   301                    <Route path="*">
   302                      <PageNotFoundView />
   303                    </Route>
   304                  </Switch>
   305                </div>
   306              </main>
   307            </div>
   308          </div>
   309        </Router>
   310      </ThemeProvider>
   311    );
   312  }
   313  
   314  export default connector(App);