[Dashboard] Update dependencies and add linting rules (#7779)

This commit is contained in:
Mitchell Stern 2020-03-27 16:53:49 -07:00 committed by GitHub
parent 0cfb6488a7
commit 090a8474b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 6296 additions and 3109 deletions

File diff suppressed because it is too large Load diff

View file

@ -3,27 +3,29 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@material-ui/core": "^4.3.3", "@material-ui/core": "^4.9.7",
"@material-ui/icons": "^4.2.1", "@material-ui/icons": "^4.9.1",
"@reduxjs/toolkit": "^1.0.4", "@reduxjs/toolkit": "^1.3.1",
"@types/classnames": "^2.2.9", "@types/classnames": "^2.2.10",
"@types/jest": "24.0.18", "@types/jest": "25.1.4",
"@types/node": "12.7.2", "@types/node": "13.9.5",
"@types/react": "16.9.2", "@types/react": "16.9.26",
"@types/react-dom": "16.9.0", "@types/react-dom": "16.9.5",
"@types/react-redux": "^7.1.5", "@types/react-redux": "^7.1.7",
"@types/react-router-dom": "^4.3.5", "@types/react-router-dom": "^5.1.3",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"react": "^16.9.0", "react": "^16.13.1",
"react-dom": "^16.9.0", "react-dom": "^16.13.1",
"react-redux": "^7.1.3", "react-redux": "^7.2.0",
"react-router-dom": "^5.0.1", "react-router-dom": "^5.1.2",
"react-scripts": "3.1.2", "react-scripts": "3.4.1",
"typeface-roboto": "0.0.75", "typeface-roboto": "0.0.75",
"typescript": "3.5.3" "typescript": "3.8.3"
}, },
"devDependencies": { "devDependencies": {
"prettier": "^1.18.2" "eslint-plugin-import": "^2.20.1",
"eslint-plugin-prefer-arrow": "^1.1.7",
"prettier": "^2.0.2"
}, },
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",
@ -32,7 +34,64 @@
"eject": "react-scripts eject" "eject": "react-scripts eject"
}, },
"eslintConfig": { "eslintConfig": {
"extends": "react-app" "extends": [
"plugin:import/warnings",
"react-app"
],
"plugins": [
"prefer-arrow"
],
"rules": {
"@typescript-eslint/consistent-type-definitions": [
"error",
"type"
],
"comma-dangle": [
"warn",
"always-multiline"
],
"curly": [
"warn",
"all"
],
"eqeqeq": [
"error",
"always"
],
"import/order": [
"warn",
{
"alphabetize": {
"order": "asc",
"caseInsensitive": true
}
}
],
"no-var": "error",
"prefer-arrow/prefer-arrow-functions": [
"warn",
{
"disallowPrototype": true,
"singleReturnOnly": false,
"classPropertiesAllowed": false
}
],
"prefer-const": "error",
"react/jsx-fragments": [
"warn",
"element"
],
"sort-imports": [
"warn",
{
"ignoreCase": true,
"ignoreDeclarationSort": true
}
]
}
},
"prettier": {
"trailingComma": "all"
}, },
"browserslist": { "browserslist": {
"production": [ "production": [

View file

@ -1,4 +1,4 @@
import CssBaseline from "@material-ui/core/CssBaseline"; import { CssBaseline } from "@material-ui/core";
import React from "react"; import React from "react";
import { Provider } from "react-redux"; import { Provider } from "react-redux";
import { BrowserRouter, Route } from "react-router-dom"; import { BrowserRouter, Route } from "react-router-dom";

View file

@ -22,7 +22,7 @@ const get = async <T>(path: string, params: { [key: string]: any }) => {
return result as T; return result as T;
}; };
export interface RayConfigResponse { export type RayConfigResponse = {
min_workers: number; min_workers: number;
max_workers: number; max_workers: number;
initial_workers: number; initial_workers: number;
@ -30,11 +30,11 @@ export interface RayConfigResponse {
idle_timeout_minutes: number; idle_timeout_minutes: number;
head_type: string; head_type: string;
worker_type: string; worker_type: string;
} };
export const getRayConfig = () => get<RayConfigResponse>("/api/ray_config", {}); export const getRayConfig = () => get<RayConfigResponse>("/api/ray_config", {});
export interface NodeInfoResponse { export type NodeInfoResponse = {
clients: Array<{ clients: Array<{
now: number; now: number;
hostname: string; hostname: string;
@ -82,11 +82,11 @@ export interface NodeInfoResponse {
[pid: string]: number; [pid: string]: number;
}; };
}; };
} };
export const getNodeInfo = () => get<NodeInfoResponse>("/api/node_info", {}); export const getNodeInfo = () => get<NodeInfoResponse>("/api/node_info", {});
export interface RayletInfoResponse { export type RayletInfoResponse = {
nodes: { nodes: {
[ip: string]: { [ip: string]: {
extraInfo?: string; extraInfo?: string;
@ -130,33 +130,33 @@ export interface RayletInfoResponse {
invalidStateType?: "infeasibleActor" | "pendingActor"; invalidStateType?: "infeasibleActor" | "pendingActor";
}; };
}; };
} };
export const getRayletInfo = () => export const getRayletInfo = () =>
get<RayletInfoResponse>("/api/raylet_info", {}); get<RayletInfoResponse>("/api/raylet_info", {});
export interface ErrorsResponse { export type ErrorsResponse = {
[pid: string]: Array<{ [pid: string]: Array<{
message: string; message: string;
timestamp: number; timestamp: number;
type: string; type: string;
}>; }>;
} };
export const getErrors = (hostname: string, pid: number | null) => export const getErrors = (hostname: string, pid: number | null) =>
get<ErrorsResponse>("/api/errors", { get<ErrorsResponse>("/api/errors", {
hostname, hostname,
pid: pid === null ? "" : pid pid: pid === null ? "" : pid,
}); });
export interface LogsResponse { export type LogsResponse = {
[pid: string]: string[]; [pid: string]: string[];
} };
export const getLogs = (hostname: string, pid: number | null) => export const getLogs = (hostname: string, pid: number | null) =>
get<LogsResponse>("/api/logs", { get<LogsResponse>("/api/logs", {
hostname, hostname,
pid: pid === null ? "" : pid pid: pid === null ? "" : pid,
}); });
export type LaunchProfilingResponse = string; export type LaunchProfilingResponse = string;
@ -164,12 +164,12 @@ export type LaunchProfilingResponse = string;
export const launchProfiling = ( export const launchProfiling = (
nodeId: string, nodeId: string,
pid: number, pid: number,
duration: number duration: number,
) => ) =>
get<LaunchProfilingResponse>("/api/launch_profiling", { get<LaunchProfilingResponse>("/api/launch_profiling", {
node_id: nodeId, node_id: nodeId,
pid: pid, pid: pid,
duration: duration duration: duration,
}); });
export type CheckProfilingStatusResponse = export type CheckProfilingStatusResponse =
@ -179,26 +179,26 @@ export type CheckProfilingStatusResponse =
export const checkProfilingStatus = (profilingId: string) => export const checkProfilingStatus = (profilingId: string) =>
get<CheckProfilingStatusResponse>("/api/check_profiling_status", { get<CheckProfilingStatusResponse>("/api/check_profiling_status", {
profiling_id: profilingId profiling_id: profilingId,
}); });
export const getProfilingResultURL = (profilingId: string) => export const getProfilingResultURL = (profilingId: string) =>
`${base}/speedscope/index.html#profileURL=${encodeURIComponent( `${base}/speedscope/index.html#profileURL=${encodeURIComponent(
`${base}/api/get_profiling_info?profiling_id=${profilingId}` `${base}/api/get_profiling_info?profiling_id=${profilingId}`,
)}`; )}`;
export const launchKillActor = ( export const launchKillActor = (
actorId: string, actorId: string,
actorIpAddress: string, actorIpAddress: string,
actorPort: number actorPort: number,
) => ) =>
get<string>("/api/kill_actor", { get<string>("/api/kill_actor", {
actor_id: actorId, actor_id: actorId,
ip_address: actorIpAddress, ip_address: actorIpAddress,
port: actorPort port: actorPort,
}); });
export interface TuneTrial { export type TuneTrial = {
date: string; date: string;
episodes_total: string; episodes_total: string;
experiment_id: string; experiment_id: string;
@ -221,17 +221,17 @@ export interface TuneTrial {
job_id: string; job_id: string;
params: { [key: string]: string | number }; params: { [key: string]: string | number };
metrics: { [key: string]: string | number }; metrics: { [key: string]: string | number };
} };
export interface TuneJobResponse { export type TuneJobResponse = {
trial_records: { [key: string]: TuneTrial }; trial_records: { [key: string]: TuneTrial };
} };
export const getTuneInfo = () => get<TuneJobResponse>("/api/tune_info", {}); export const getTuneInfo = () => get<TuneJobResponse>("/api/tune_info", {});
export interface TuneAvailabilityResponse { export type TuneAvailabilityResponse = {
available: boolean; available: boolean;
} };
export const getTuneAvailability = () => export const getTuneAvailability = () =>
get<TuneAvailabilityResponse>("/api/tune_availability", {}); get<TuneAvailabilityResponse>("/api/tune_availability", {});

View file

@ -1,22 +1,25 @@
import Dialog from "@material-ui/core/Dialog"; import {
import IconButton from "@material-ui/core/IconButton"; createStyles,
import { Theme } from "@material-ui/core/styles/createMuiTheme"; Dialog,
import createStyles from "@material-ui/core/styles/createStyles"; IconButton,
import withStyles, { WithStyles } from "@material-ui/core/styles/withStyles"; Theme,
import Typography from "@material-ui/core/Typography"; Typography,
WithStyles,
withStyles,
} from "@material-ui/core";
import CloseIcon from "@material-ui/icons/Close"; import CloseIcon from "@material-ui/icons/Close";
import React from "react"; import React from "react";
const styles = (theme: Theme) => const styles = (theme: Theme) =>
createStyles({ createStyles({
paper: { paper: {
padding: theme.spacing(3) padding: theme.spacing(3),
}, },
closeButton: { closeButton: {
position: "absolute", position: "absolute",
right: theme.spacing(1.5), right: theme.spacing(1.5),
top: theme.spacing(1.5), top: theme.spacing(1.5),
zIndex: 1 zIndex: 1,
}, },
title: { title: {
borderBottomColor: theme.palette.divider, borderBottomColor: theme.palette.divider,
@ -25,14 +28,14 @@ const styles = (theme: Theme) =>
fontSize: "1.5rem", fontSize: "1.5rem",
lineHeight: 1, lineHeight: 1,
marginBottom: theme.spacing(3), marginBottom: theme.spacing(3),
paddingBottom: theme.spacing(3) paddingBottom: theme.spacing(3),
} },
}); });
interface Props { type Props = {
handleClose: () => void; handleClose: () => void;
title: string; title: string;
} };
class DialogWithTitle extends React.Component< class DialogWithTitle extends React.Component<
Props & WithStyles<typeof styles> Props & WithStyles<typeof styles>

View file

@ -1,25 +1,28 @@
import { Theme } from "@material-ui/core/styles/createMuiTheme"; import {
import createStyles from "@material-ui/core/styles/createStyles"; createStyles,
import withStyles, { WithStyles } from "@material-ui/core/styles/withStyles"; Table,
import Table from "@material-ui/core/Table"; TableBody,
import TableBody from "@material-ui/core/TableBody"; TableCell,
import TableCell from "@material-ui/core/TableCell"; TableRow,
import TableRow from "@material-ui/core/TableRow"; Theme,
withStyles,
WithStyles,
} from "@material-ui/core";
import classNames from "classnames"; import classNames from "classnames";
import React from "react"; import React from "react";
const styles = (theme: Theme) => const styles = (theme: Theme) =>
createStyles({ createStyles({
root: { root: {
overflowX: "auto" overflowX: "auto",
}, },
cell: { cell: {
borderWidth: 0, borderWidth: 0,
fontFamily: "SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace", fontFamily: "SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace",
padding: 0, padding: 0,
"&:last-child": { "&:last-child": {
paddingRight: 0 paddingRight: 0,
} },
}, },
lineNumber: { lineNumber: {
color: theme.palette.text.secondary, color: theme.palette.text.secondary,
@ -30,18 +33,18 @@ const styles = (theme: Theme) =>
// Use a ::before pseudo-element for the line number so that it won't // Use a ::before pseudo-element for the line number so that it won't
// interact with user selections or searching. // interact with user selections or searching.
"&::before": { "&::before": {
content: "attr(data-line-number)" content: "attr(data-line-number)",
} },
}, },
line: { line: {
textAlign: "left", textAlign: "left",
whiteSpace: "pre-wrap" whiteSpace: "pre-wrap",
} },
}); });
interface Props { type Props = {
lines: string[]; lines: string[];
} };
class NumberedLines extends React.Component<Props & WithStyles<typeof styles>> { class NumberedLines extends React.Component<Props & WithStyles<typeof styles>> {
render() { render() {

View file

@ -1,6 +1,4 @@
import { Theme } from "@material-ui/core/styles/createMuiTheme"; import { createStyles, Theme, withStyles, WithStyles } from "@material-ui/core";
import createStyles from "@material-ui/core/styles/createStyles";
import withStyles, { WithStyles } from "@material-ui/core/styles/withStyles";
import React, { HTMLAttributes } from "react"; import React, { HTMLAttributes } from "react";
const styles = (theme: Theme) => const styles = (theme: Theme) =>
@ -9,9 +7,9 @@ const styles = (theme: Theme) =>
color: theme.palette.primary.main, color: theme.palette.primary.main,
"&:hover": { "&:hover": {
cursor: "pointer", cursor: "pointer",
textDecoration: "underline" textDecoration: "underline",
} },
} },
}); });
class SpanButton extends React.Component< class SpanButton extends React.Component<

View file

@ -1,16 +1,14 @@
import { Theme } from "@material-ui/core/styles/createMuiTheme"; import { createStyles, Theme, withStyles, WithStyles } from "@material-ui/core";
import createStyles from "@material-ui/core/styles/createStyles";
import withStyles, { WithStyles } from "@material-ui/core/styles/withStyles";
import React from "react"; import React from "react";
const blend = ( const blend = (
[r1, g1, b1]: number[], [r1, g1, b1]: number[],
[r2, g2, b2]: number[], [r2, g2, b2]: number[],
ratio: number ratio: number,
) => [ ) => [
r1 * (1 - ratio) + r2 * ratio, r1 * (1 - ratio) + r2 * ratio,
g1 * (1 - ratio) + g2 * ratio, g1 * (1 - ratio) + g2 * ratio,
b1 * (1 - ratio) + b2 * ratio b1 * (1 - ratio) + b2 * ratio,
]; ];
const styles = (theme: Theme) => const styles = (theme: Theme) =>
@ -18,18 +16,18 @@ const styles = (theme: Theme) =>
root: { root: {
borderColor: theme.palette.divider, borderColor: theme.palette.divider,
borderStyle: "solid", borderStyle: "solid",
borderWidth: 1 borderWidth: 1,
}, },
inner: { inner: {
paddingLeft: theme.spacing(1), paddingLeft: theme.spacing(1),
paddingRight: theme.spacing(1) paddingRight: theme.spacing(1),
} },
}); });
interface Props { type Props = {
percent: number; percent: number;
text: string; text: string;
} };
class UsageBar extends React.Component<Props & WithStyles<typeof styles>> { class UsageBar extends React.Component<Props & WithStyles<typeof styles>> {
render() { render() {

View file

@ -1,6 +1,6 @@
export const formatByteAmount = ( export const formatByteAmount = (
amount: number, amount: number,
unit: "mebibyte" | "gibibyte" unit: "mebibyte" | "gibibyte",
) => ) =>
`${( `${(
amount / (unit === "mebibyte" ? Math.pow(1024, 2) : Math.pow(1024, 3)) amount / (unit === "mebibyte" ? Math.pow(1024, 2) : Math.pow(1024, 3))
@ -9,7 +9,7 @@ export const formatByteAmount = (
export const formatUsage = ( export const formatUsage = (
used: number, used: number,
total: number, total: number,
unit: "mebibyte" | "gibibyte" unit: "mebibyte" | "gibibyte",
) => { ) => {
const usedFormatted = formatByteAmount(used, unit); const usedFormatted = formatByteAmount(used, unit);
const totalFormatted = formatByteAmount(total, unit); const totalFormatted = formatByteAmount(total, unit);
@ -27,6 +27,6 @@ export const formatDuration = (durationInSeconds: number) => {
durationDays ? `${durationDays}d` : "", durationDays ? `${durationDays}d` : "",
`${pad(durationHours)}h`, `${pad(durationHours)}h`,
`${pad(durationMinutes)}m`, `${pad(durationMinutes)}m`,
`${pad(durationSeconds)}s` `${pad(durationSeconds)}s`,
].join(" "); ].join(" ");
}; };

View file

@ -1,9 +1,12 @@
import { Theme } from "@material-ui/core/styles/createMuiTheme"; import {
import createStyles from "@material-ui/core/styles/createStyles"; createStyles,
import withStyles, { WithStyles } from "@material-ui/core/styles/withStyles"; Tab,
import Tab from "@material-ui/core/Tab"; Tabs,
import Tabs from "@material-ui/core/Tabs"; Theme,
import Typography from "@material-ui/core/Typography"; Typography,
WithStyles,
withStyles,
} from "@material-ui/core";
import React from "react"; import React from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { getNodeInfo, getRayletInfo, getTuneAvailability } from "../../api"; import { getNodeInfo, getRayletInfo, getTuneAvailability } from "../../api";
@ -21,19 +24,19 @@ const styles = (theme: Theme) =>
backgroundColor: theme.palette.background.paper, backgroundColor: theme.palette.background.paper,
padding: theme.spacing(2), padding: theme.spacing(2),
"& > :not(:first-child)": { "& > :not(:first-child)": {
marginTop: theme.spacing(4) marginTop: theme.spacing(4),
} },
}, },
tabs: { tabs: {
borderBottomColor: theme.palette.divider, borderBottomColor: theme.palette.divider,
borderBottomStyle: "solid", borderBottomStyle: "solid",
borderBottomWidth: 1 borderBottomWidth: 1,
} },
}); });
const mapStateToProps = (state: StoreState) => ({ const mapStateToProps = (state: StoreState) => ({
tab: state.dashboard.tab, tab: state.dashboard.tab,
tuneAvailability: state.dashboard.tuneAvailability tuneAvailability: state.dashboard.tuneAvailability,
}); });
const mapDispatchToProps = dashboardActions; const mapDispatchToProps = dashboardActions;
@ -50,7 +53,7 @@ class Dashboard extends React.Component<
const [nodeInfo, rayletInfo, tuneAvailability] = await Promise.all([ const [nodeInfo, rayletInfo, tuneAvailability] = await Promise.all([
getNodeInfo(), getNodeInfo(),
getRayletInfo(), getRayletInfo(),
getTuneAvailability() getTuneAvailability(),
]); ]);
this.props.setNodeAndRayletInfo({ nodeInfo, rayletInfo }); this.props.setNodeAndRayletInfo({ nodeInfo, rayletInfo });
this.props.setTuneAvailability({ tuneAvailability }); this.props.setTuneAvailability({ tuneAvailability });
@ -80,7 +83,7 @@ class Dashboard extends React.Component<
{ label: "Machine view", component: NodeInfo }, { label: "Machine view", component: NodeInfo },
{ label: "Logical view", component: LogicalView }, { label: "Logical view", component: LogicalView },
{ label: "Ray config", component: RayConfig }, { label: "Ray config", component: RayConfig },
{ label: "Tune", component: Tune } { label: "Tune", component: Tune },
]; ];
// if Tune information is not available, remove Tune tab from the dashboard // if Tune information is not available, remove Tune tab from the dashboard
@ -112,5 +115,5 @@ class Dashboard extends React.Component<
export default connect( export default connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps,
)(withStyles(styles)(Dashboard)); )(withStyles(styles)(Dashboard));

View file

@ -1,7 +1,10 @@
import { Theme } from "@material-ui/core/styles/createMuiTheme"; import {
import createStyles from "@material-ui/core/styles/createStyles"; createStyles,
import withStyles, { WithStyles } from "@material-ui/core/styles/withStyles"; Theme,
import Typography from "@material-ui/core/Typography"; Typography,
WithStyles,
withStyles,
} from "@material-ui/core";
import React from "react"; import React from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { StoreState } from "../../store"; import { StoreState } from "../../store";
@ -9,23 +12,23 @@ import { StoreState } from "../../store";
const styles = (theme: Theme) => const styles = (theme: Theme) =>
createStyles({ createStyles({
root: { root: {
marginTop: theme.spacing(2) marginTop: theme.spacing(2),
}, },
lastUpdated: { lastUpdated: {
color: theme.palette.text.secondary, color: theme.palette.text.secondary,
fontSize: "0.8125rem", fontSize: "0.8125rem",
textAlign: "center" textAlign: "center",
}, },
error: { error: {
color: theme.palette.error.main, color: theme.palette.error.main,
fontSize: "0.8125rem", fontSize: "0.8125rem",
textAlign: "center" textAlign: "center",
} },
}); });
const mapStateToProps = (state: StoreState) => ({ const mapStateToProps = (state: StoreState) => ({
lastUpdatedAt: state.dashboard.lastUpdatedAt, lastUpdatedAt: state.dashboard.lastUpdatedAt,
error: state.dashboard.error error: state.dashboard.error,
}); });
class LastUpdated extends React.Component< class LastUpdated extends React.Component<

View file

@ -1,9 +1,11 @@
import Collapse from "@material-ui/core/Collapse"; import {
import orange from "@material-ui/core/colors/orange"; Collapse,
import { Theme } from "@material-ui/core/styles/createMuiTheme"; createStyles,
import createStyles from "@material-ui/core/styles/createStyles"; Theme,
import withStyles, { WithStyles } from "@material-ui/core/styles/withStyles"; Typography,
import Typography from "@material-ui/core/Typography"; withStyles,
WithStyles,
} from "@material-ui/core";
import React from "react"; import React from "react";
import { import {
checkProfilingStatus, checkProfilingStatus,
@ -11,7 +13,7 @@ import {
getProfilingResultURL, getProfilingResultURL,
launchKillActor, launchKillActor,
launchProfiling, launchProfiling,
RayletInfoResponse RayletInfoResponse,
} from "../../../api"; } from "../../../api";
import Actors from "./Actors"; import Actors from "./Actors";
@ -22,47 +24,47 @@ const styles = (theme: Theme) =>
borderStyle: "solid", borderStyle: "solid",
borderWidth: 1, borderWidth: 1,
marginTop: theme.spacing(2), marginTop: theme.spacing(2),
padding: theme.spacing(2) padding: theme.spacing(2),
}, },
title: { title: {
color: theme.palette.text.secondary, color: theme.palette.text.secondary,
fontSize: "0.75rem" fontSize: "0.75rem",
}, },
action: { action: {
color: theme.palette.primary.main, color: theme.palette.primary.main,
textDecoration: "none", textDecoration: "none",
"&:hover": { "&:hover": {
cursor: "pointer" cursor: "pointer",
} },
}, },
invalidStateTypeInfeasible: { invalidStateTypeInfeasible: {
color: theme.palette.error.main color: theme.palette.error.main,
}, },
invalidStateTypePendingActor: { invalidStateTypePendingActor: {
color: orange[500] color: theme.palette.secondary.main,
}, },
information: { information: {
fontSize: "0.875rem" fontSize: "0.875rem",
}, },
datum: { datum: {
"&:not(:first-child)": { "&:not(:first-child)": {
marginLeft: theme.spacing(2) marginLeft: theme.spacing(2),
} },
}, },
webuiDisplay: { webuiDisplay: {
fontSize: "0.875rem" fontSize: "0.875rem",
}, },
inlineHTML: { inlineHTML: {
fontSize: "0.875rem", fontSize: "0.875rem",
display: "inline" display: "inline",
} },
}); });
interface Props { type Props = {
actor: RayletInfoResponse["actors"][keyof RayletInfoResponse["actors"]]; actor: RayletInfoResponse["actors"][keyof RayletInfoResponse["actors"]];
} };
interface State { type State = {
expanded: boolean; expanded: boolean;
profiling: { profiling: {
[profilingId: string]: { [profilingId: string]: {
@ -70,12 +72,12 @@ interface State {
latestResponse: CheckProfilingStatusResponse | null; latestResponse: CheckProfilingStatusResponse | null;
}; };
}; };
} };
class Actor extends React.Component<Props & WithStyles<typeof styles>, State> { class Actor extends React.Component<Props & WithStyles<typeof styles>, State> {
state: State = { state: State = {
expanded: true, expanded: true,
profiling: {} profiling: {},
}; };
setExpanded = (expanded: boolean) => () => { setExpanded = (expanded: boolean) => () => {
@ -88,24 +90,24 @@ class Actor extends React.Component<Props & WithStyles<typeof styles>, State> {
const profilingId = await launchProfiling( const profilingId = await launchProfiling(
actor.nodeId, actor.nodeId,
actor.pid, actor.pid,
duration duration,
); );
this.setState(state => ({ this.setState((state) => ({
profiling: { profiling: {
...state.profiling, ...state.profiling,
[profilingId]: { startTime: Date.now(), latestResponse: null } [profilingId]: { startTime: Date.now(), latestResponse: null },
} },
})); }));
const checkProfilingStatusLoop = async () => { const checkProfilingStatusLoop = async () => {
const response = await checkProfilingStatus(profilingId); const response = await checkProfilingStatus(profilingId);
this.setState(state => ({ this.setState((state) => ({
profiling: { profiling: {
...state.profiling, ...state.profiling,
[profilingId]: { [profilingId]: {
...state.profiling[profilingId], ...state.profiling[profilingId],
latestResponse: response latestResponse: response,
} },
} },
})); }));
if (response.status === "pending") { if (response.status === "pending") {
setTimeout(checkProfilingStatusLoop, 1000); setTimeout(checkProfilingStatusLoop, 1000);
@ -131,11 +133,11 @@ class Actor extends React.Component<Props & WithStyles<typeof styles>, State> {
? [ ? [
{ {
label: "ActorTitle", label: "ActorTitle",
value: actor.actorTitle value: actor.actorTitle,
}, },
{ {
label: "State", label: "State",
value: actor.state.toLocaleString() value: actor.state.toLocaleString(),
}, },
{ {
label: "Resources", label: "Resources",
@ -144,28 +146,28 @@ class Actor extends React.Component<Props & WithStyles<typeof styles>, State> {
Object.entries(actor.usedResources) Object.entries(actor.usedResources)
.sort((a, b) => a[0].localeCompare(b[0])) .sort((a, b) => a[0].localeCompare(b[0]))
.map(([key, value]) => `${value.toLocaleString()} ${key}`) .map(([key, value]) => `${value.toLocaleString()} ${key}`)
.join(", ") .join(", "),
}, },
{ {
label: "Pending", label: "Pending",
value: actor.taskQueueLength.toLocaleString() value: actor.taskQueueLength.toLocaleString(),
}, },
{ {
label: "Executed", label: "Executed",
value: actor.numExecutedTasks.toLocaleString() value: actor.numExecutedTasks.toLocaleString(),
}, },
{ {
label: "NumObjectIdsInScope", label: "NumObjectIdsInScope",
value: actor.numObjectIdsInScope.toLocaleString() value: actor.numObjectIdsInScope.toLocaleString(),
}, },
{ {
label: "NumLocalObjects", label: "NumLocalObjects",
value: actor.numLocalObjects.toLocaleString() value: actor.numLocalObjects.toLocaleString(),
}, },
{ {
label: "UsedLocalObjectMemory", label: "UsedLocalObjectMemory",
value: actor.usedObjectStoreMemory.toLocaleString() value: actor.usedObjectStoreMemory.toLocaleString(),
} },
// { // {
// label: "Task", // label: "Task",
// value: actor.currentTaskFuncDesc.join(".") // value: actor.currentTaskFuncDesc.join(".")
@ -174,7 +176,7 @@ class Actor extends React.Component<Props & WithStyles<typeof styles>, State> {
: [ : [
{ {
label: "ID", label: "ID",
value: actor.actorId value: actor.actorId,
}, },
{ {
label: "Required resources", label: "Required resources",
@ -183,8 +185,8 @@ class Actor extends React.Component<Props & WithStyles<typeof styles>, State> {
Object.entries(actor.requiredResources) Object.entries(actor.requiredResources)
.sort((a, b) => a[0].localeCompare(b[0])) .sort((a, b) => a[0].localeCompare(b[0]))
.map(([key, value]) => `${value.toLocaleString()} ${key}`) .map(([key, value]) => `${value.toLocaleString()} ${key}`)
.join(", ") .join(", "),
} },
]; ];
// Construct the custom message from the actor. // Construct the custom message from the actor.
@ -242,7 +244,7 @@ class Actor extends React.Component<Props & WithStyles<typeof styles>, State> {
</React.Fragment> </React.Fragment>
)}{" "} )}{" "}
(Profile for (Profile for
{[10, 30, 60].map(duration => ( {[10, 30, 60].map((duration) => (
<React.Fragment> <React.Fragment>
{" "} {" "}
<span <span
@ -268,7 +270,7 @@ class Actor extends React.Component<Props & WithStyles<typeof styles>, State> {
( (
{latestResponse.status === "pending" ? ( {latestResponse.status === "pending" ? (
`Profiling for ${Math.round( `Profiling for ${Math.round(
(Date.now() - startTime) / 1000 (Date.now() - startTime) / 1000,
)}s...` )}s...`
) : latestResponse.status === "finished" ? ( ) : latestResponse.status === "finished" ? (
<a <a
@ -281,12 +283,10 @@ class Actor extends React.Component<Props & WithStyles<typeof styles>, State> {
</a> </a>
) : latestResponse.status === "error" ? ( ) : latestResponse.status === "error" ? (
`Profiling error: ${latestResponse.error.trim()}` `Profiling error: ${latestResponse.error.trim()}`
) : ( ) : undefined}
undefined
)}
){" "} ){" "}
</React.Fragment> </React.Fragment>
) ),
)} )}
</React.Fragment> </React.Fragment>
) : actor.invalidStateType === "infeasibleActor" ? ( ) : actor.invalidStateType === "infeasibleActor" ? (
@ -310,7 +310,7 @@ class Actor extends React.Component<Props & WithStyles<typeof styles>, State> {
{label}: {value} {label}: {value}
</span>{" "} </span>{" "}
</React.Fragment> </React.Fragment>
) ),
)} )}
</Typography> </Typography>
{actor.state !== -1 && ( {actor.state !== -1 && (

View file

@ -1,15 +1,13 @@
import { Theme } from "@material-ui/core/styles/createMuiTheme"; import { createStyles, Theme, withStyles, WithStyles } from "@material-ui/core";
import createStyles from "@material-ui/core/styles/createStyles";
import withStyles, { WithStyles } from "@material-ui/core/styles/withStyles";
import React from "react"; import React from "react";
import { RayletInfoResponse } from "../../../api"; import { RayletInfoResponse } from "../../../api";
import Actor from "./Actor"; import Actor from "./Actor";
const styles = (theme: Theme) => createStyles({}); const styles = (theme: Theme) => createStyles({});
interface Props { type Props = {
actors: RayletInfoResponse["actors"]; actors: RayletInfoResponse["actors"];
} };
class Actors extends React.Component<Props & WithStyles<typeof styles>> { class Actors extends React.Component<Props & WithStyles<typeof styles>> {
render() { render() {

View file

@ -1,7 +1,10 @@
import { Theme } from "@material-ui/core/styles/createMuiTheme"; import {
import createStyles from "@material-ui/core/styles/createStyles"; createStyles,
import withStyles, { WithStyles } from "@material-ui/core/styles/withStyles"; Theme,
import Typography from "@material-ui/core/Typography"; Typography,
WithStyles,
withStyles,
} from "@material-ui/core";
import WarningRoundedIcon from "@material-ui/icons/WarningRounded"; import WarningRoundedIcon from "@material-ui/icons/WarningRounded";
import React from "react"; import React from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
@ -12,16 +15,16 @@ const styles = (theme: Theme) =>
createStyles({ createStyles({
warning: { warning: {
fontSize: "0.8125rem", fontSize: "0.8125rem",
marginBottom: theme.spacing(2) marginBottom: theme.spacing(2),
}, },
warningIcon: { warningIcon: {
fontSize: "1.25em", fontSize: "1.25em",
verticalAlign: "text-bottom" verticalAlign: "text-bottom",
} },
}); });
const mapStateToProps = (state: StoreState) => ({ const mapStateToProps = (state: StoreState) => ({
rayletInfo: state.dashboard.rayletInfo rayletInfo: state.dashboard.rayletInfo,
}); });
class LogicalView extends React.Component< class LogicalView extends React.Component<

View file

@ -1,12 +1,15 @@
import { Theme } from "@material-ui/core/styles/createMuiTheme"; import {
import createStyles from "@material-ui/core/styles/createStyles"; createStyles,
import withStyles, { WithStyles } from "@material-ui/core/styles/withStyles"; Table,
import Table from "@material-ui/core/Table"; TableBody,
import TableBody from "@material-ui/core/TableBody"; TableCell,
import TableCell from "@material-ui/core/TableCell"; TableHead,
import TableHead from "@material-ui/core/TableHead"; TableRow,
import TableRow from "@material-ui/core/TableRow"; Theme,
import Typography from "@material-ui/core/Typography"; Typography,
withStyles,
WithStyles,
} from "@material-ui/core";
import React from "react"; import React from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { StoreState } from "../../../store"; import { StoreState } from "../../../store";
@ -18,33 +21,33 @@ import TotalRow from "./TotalRow";
const styles = (theme: Theme) => const styles = (theme: Theme) =>
createStyles({ createStyles({
table: { table: {
marginTop: theme.spacing(1) marginTop: theme.spacing(1),
}, },
cell: { cell: {
padding: theme.spacing(1), padding: theme.spacing(1),
textAlign: "center", textAlign: "center",
"&:last-child": { "&:last-child": {
paddingRight: theme.spacing(1) paddingRight: theme.spacing(1),
} },
} },
}); });
const mapStateToProps = (state: StoreState) => ({ const mapStateToProps = (state: StoreState) => ({
nodeInfo: state.dashboard.nodeInfo, nodeInfo: state.dashboard.nodeInfo,
rayletInfo: state.dashboard.rayletInfo rayletInfo: state.dashboard.rayletInfo,
}); });
interface State { type State = {
logDialog: { hostname: string; pid: number | null } | null; logDialog: { hostname: string; pid: number | null } | null;
errorDialog: { hostname: string; pid: number | null } | null; errorDialog: { hostname: string; pid: number | null } | null;
} };
class NodeInfo extends React.Component< class NodeInfo extends React.Component<
WithStyles<typeof styles> & ReturnType<typeof mapStateToProps> WithStyles<typeof styles> & ReturnType<typeof mapStateToProps>
> { > {
state: State = { state: State = {
logDialog: null, logDialog: null,
errorDialog: null errorDialog: null,
}; };
setLogDialog = (hostname: string, pid: number | null) => { setLogDialog = (hostname: string, pid: number | null) => {
@ -135,7 +138,7 @@ class NodeInfo extends React.Component<
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
{nodeInfo.clients.map(client => ( {nodeInfo.clients.map((client) => (
<NodeRowGroup <NodeRowGroup
key={client.ip} key={client.ip}
node={client} node={client}

View file

@ -1,8 +1,11 @@
import { Theme } from "@material-ui/core/styles/createMuiTheme"; import {
import createStyles from "@material-ui/core/styles/createStyles"; createStyles,
import withStyles, { WithStyles } from "@material-ui/core/styles/withStyles"; TableCell,
import TableCell from "@material-ui/core/TableCell"; TableRow,
import TableRow from "@material-ui/core/TableRow"; Theme,
withStyles,
WithStyles,
} from "@material-ui/core";
import AddIcon from "@material-ui/icons/Add"; import AddIcon from "@material-ui/icons/Add";
import RemoveIcon from "@material-ui/icons/Remove"; import RemoveIcon from "@material-ui/icons/Remove";
import classNames from "classnames"; import classNames from "classnames";
@ -25,27 +28,27 @@ const styles = (theme: Theme) =>
padding: theme.spacing(1), padding: theme.spacing(1),
textAlign: "center", textAlign: "center",
"&:last-child": { "&:last-child": {
paddingRight: theme.spacing(1) paddingRight: theme.spacing(1),
} },
}, },
expandCollapseCell: { expandCollapseCell: {
cursor: "pointer" cursor: "pointer",
}, },
expandCollapseIcon: { expandCollapseIcon: {
color: theme.palette.text.secondary, color: theme.palette.text.secondary,
fontSize: "1.5em", fontSize: "1.5em",
verticalAlign: "middle" verticalAlign: "middle",
}, },
extraInfo: { extraInfo: {
fontFamily: "SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace", fontFamily: "SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace",
whiteSpace: "pre" whiteSpace: "pre",
} },
}); });
type ArrayType<T> = T extends Array<infer U> ? U : never; type ArrayType<T> = T extends Array<infer U> ? U : never;
type Node = ArrayType<NodeInfoResponse["clients"]>; type Node = ArrayType<NodeInfoResponse["clients"]>;
interface Props { type Props = {
node: Node; node: Node;
raylet: RayletInfoResponse["nodes"][keyof RayletInfoResponse["nodes"]] | null; raylet: RayletInfoResponse["nodes"][keyof RayletInfoResponse["nodes"]] | null;
logCounts: { logCounts: {
@ -59,23 +62,23 @@ interface Props {
setLogDialog: (hostname: string, pid: number | null) => void; setLogDialog: (hostname: string, pid: number | null) => void;
setErrorDialog: (hostname: string, pid: number | null) => void; setErrorDialog: (hostname: string, pid: number | null) => void;
initialExpanded: boolean; initialExpanded: boolean;
} };
interface State { type State = {
expanded: boolean; expanded: boolean;
} };
class NodeRowGroup extends React.Component< class NodeRowGroup extends React.Component<
Props & WithStyles<typeof styles>, Props & WithStyles<typeof styles>,
State State
> { > {
state: State = { state: State = {
expanded: this.props.initialExpanded expanded: this.props.initialExpanded,
}; };
toggleExpand = () => { toggleExpand = () => {
this.setState(state => ({ this.setState((state) => ({
expanded: !state.expanded expanded: !state.expanded,
})); }));
}; };
@ -87,7 +90,7 @@ class NodeRowGroup extends React.Component<
logCounts, logCounts,
errorCounts, errorCounts,
setLogDialog, setLogDialog,
setErrorDialog setErrorDialog,
} = this.props; } = this.props;
const { expanded } = this.state; const { expanded } = this.state;
@ -102,12 +105,12 @@ class NodeRowGroup extends React.Component<
{ NodeFeature: NodeReceived, WorkerFeature: WorkerReceived }, { NodeFeature: NodeReceived, WorkerFeature: WorkerReceived },
{ {
NodeFeature: makeNodeLogs(logCounts, setLogDialog), NodeFeature: makeNodeLogs(logCounts, setLogDialog),
WorkerFeature: makeWorkerLogs(logCounts, setLogDialog) WorkerFeature: makeWorkerLogs(logCounts, setLogDialog),
}, },
{ {
NodeFeature: makeNodeErrors(errorCounts, setErrorDialog), NodeFeature: makeNodeErrors(errorCounts, setErrorDialog),
WorkerFeature: makeWorkerErrors(errorCounts, setErrorDialog) WorkerFeature: makeWorkerErrors(errorCounts, setErrorDialog),
} },
]; ];
return ( return (

View file

@ -1,8 +1,11 @@
import { Theme } from "@material-ui/core/styles/createMuiTheme"; import {
import createStyles from "@material-ui/core/styles/createStyles"; createStyles,
import withStyles, { WithStyles } from "@material-ui/core/styles/withStyles"; TableCell,
import TableCell from "@material-ui/core/TableCell"; TableRow,
import TableRow from "@material-ui/core/TableRow"; Theme,
WithStyles,
withStyles,
} from "@material-ui/core";
import LayersIcon from "@material-ui/icons/Layers"; import LayersIcon from "@material-ui/icons/Layers";
import React from "react"; import React from "react";
import { NodeInfoResponse } from "../../../api"; import { NodeInfoResponse } from "../../../api";
@ -26,17 +29,17 @@ const styles = (theme: Theme) =>
padding: theme.spacing(1), padding: theme.spacing(1),
textAlign: "center", textAlign: "center",
"&:last-child": { "&:last-child": {
paddingRight: theme.spacing(1) paddingRight: theme.spacing(1),
} },
}, },
totalIcon: { totalIcon: {
color: theme.palette.text.secondary, color: theme.palette.text.secondary,
fontSize: "1.5em", fontSize: "1.5em",
verticalAlign: "middle" verticalAlign: "middle",
} },
}); });
interface Props { type Props = {
nodes: NodeInfoResponse["clients"]; nodes: NodeInfoResponse["clients"];
logCounts: { logCounts: {
[ip: string]: { [ip: string]: {
@ -50,7 +53,7 @@ interface Props {
total: number; total: number;
}; };
}; };
} };
class TotalRow extends React.Component<Props & WithStyles<typeof styles>> { class TotalRow extends React.Component<Props & WithStyles<typeof styles>> {
render() { render() {
@ -66,7 +69,7 @@ class TotalRow extends React.Component<Props & WithStyles<typeof styles>> {
{ ClusterFeature: ClusterSent }, { ClusterFeature: ClusterSent },
{ ClusterFeature: ClusterReceived }, { ClusterFeature: ClusterReceived },
{ ClusterFeature: makeClusterLogs(logCounts) }, { ClusterFeature: makeClusterLogs(logCounts) },
{ ClusterFeature: makeClusterErrors(errorCounts) } { ClusterFeature: makeClusterErrors(errorCounts) },
]; ];
return ( return (

View file

@ -1,8 +1,11 @@
import { fade } from "@material-ui/core/styles/colorManipulator"; import {
import { Theme } from "@material-ui/core/styles/createMuiTheme"; createStyles,
import createStyles from "@material-ui/core/styles/createStyles"; fade,
import withStyles, { WithStyles } from "@material-ui/core/styles/withStyles"; Theme,
import Typography from "@material-ui/core/Typography"; Typography,
withStyles,
WithStyles,
} from "@material-ui/core";
import React from "react"; import React from "react";
import { ErrorsResponse, getErrors } from "../../../../../api"; import { ErrorsResponse, getErrors } from "../../../../../api";
import DialogWithTitle from "../../../../../common/DialogWithTitle"; import DialogWithTitle from "../../../../../common/DialogWithTitle";
@ -13,7 +16,7 @@ const styles = (theme: Theme) =>
header: { header: {
lineHeight: 1, lineHeight: 1,
marginBottom: theme.spacing(3), marginBottom: theme.spacing(3),
marginTop: theme.spacing(3) marginTop: theme.spacing(3),
}, },
error: { error: {
backgroundColor: fade(theme.palette.error.main, 0.04), backgroundColor: fade(theme.palette.error.main, 0.04),
@ -21,29 +24,29 @@ const styles = (theme: Theme) =>
borderLeftStyle: "solid", borderLeftStyle: "solid",
borderLeftWidth: 2, borderLeftWidth: 2,
marginTop: theme.spacing(3), marginTop: theme.spacing(3),
padding: theme.spacing(2) padding: theme.spacing(2),
}, },
timestamp: { timestamp: {
color: theme.palette.text.secondary, color: theme.palette.text.secondary,
marginBottom: theme.spacing(1) marginBottom: theme.spacing(1),
} },
}); });
interface Props { type Props = {
clearErrorDialog: () => void; clearErrorDialog: () => void;
hostname: string; hostname: string;
pid: number | null; pid: number | null;
} };
interface State { type State = {
result: ErrorsResponse | null; result: ErrorsResponse | null;
error: string | null; error: string | null;
} };
class Errors extends React.Component<Props & WithStyles<typeof styles>, State> { class Errors extends React.Component<Props & WithStyles<typeof styles>, State> {
state: State = { state: State = {
result: null, result: null,
error: null error: null,
}; };
async componentDidMount() { async componentDidMount() {

View file

@ -1,8 +1,11 @@
import { fade } from "@material-ui/core/styles/colorManipulator"; import {
import { Theme } from "@material-ui/core/styles/createMuiTheme"; createStyles,
import createStyles from "@material-ui/core/styles/createStyles"; fade,
import withStyles, { WithStyles } from "@material-ui/core/styles/withStyles"; Theme,
import Typography from "@material-ui/core/Typography"; Typography,
WithStyles,
withStyles,
} from "@material-ui/core";
import React from "react"; import React from "react";
import { getLogs, LogsResponse } from "../../../../../api"; import { getLogs, LogsResponse } from "../../../../../api";
import DialogWithTitle from "../../../../../common/DialogWithTitle"; import DialogWithTitle from "../../../../../common/DialogWithTitle";
@ -13,32 +16,32 @@ const styles = (theme: Theme) =>
header: { header: {
lineHeight: 1, lineHeight: 1,
marginBottom: theme.spacing(3), marginBottom: theme.spacing(3),
marginTop: theme.spacing(3) marginTop: theme.spacing(3),
}, },
log: { log: {
backgroundColor: fade(theme.palette.primary.main, 0.04), backgroundColor: fade(theme.palette.primary.main, 0.04),
borderLeftColor: theme.palette.primary.main, borderLeftColor: theme.palette.primary.main,
borderLeftStyle: "solid", borderLeftStyle: "solid",
borderLeftWidth: 2, borderLeftWidth: 2,
padding: theme.spacing(2) padding: theme.spacing(2),
} },
}); });
interface Props { type Props = {
clearLogDialog: () => void; clearLogDialog: () => void;
hostname: string; hostname: string;
pid: number | null; pid: number | null;
} };
interface State { type State = {
result: LogsResponse | null; result: LogsResponse | null;
error: string | null; error: string | null;
} };
class Logs extends React.Component<Props & WithStyles<typeof styles>, State> { class Logs extends React.Component<Props & WithStyles<typeof styles>, State> {
state: State = { state: State = {
result: null, result: null,
error: null error: null,
}; };
async componentDidMount() { async componentDidMount() {

View file

@ -3,14 +3,14 @@ import UsageBar from "../../../../common/UsageBar";
import { import {
ClusterFeatureComponent, ClusterFeatureComponent,
NodeFeatureComponent, NodeFeatureComponent,
WorkerFeatureComponent WorkerFeatureComponent,
} from "./types"; } from "./types";
const getWeightedAverage = ( const getWeightedAverage = (
input: { input: {
weight: number; weight: number;
value: number; value: number;
}[] }[],
) => { ) => {
if (input.length === 0) { if (input.length === 0) {
return 0; return 0;
@ -27,7 +27,7 @@ const getWeightedAverage = (
export const ClusterCPU: ClusterFeatureComponent = ({ nodes }) => { export const ClusterCPU: ClusterFeatureComponent = ({ nodes }) => {
const cpuWeightedAverage = getWeightedAverage( const cpuWeightedAverage = getWeightedAverage(
nodes.map(node => ({ weight: node.cpus[0], value: node.cpu })) nodes.map((node) => ({ weight: node.cpus[0], value: node.cpu })),
); );
return ( return (
<div style={{ minWidth: 60 }}> <div style={{ minWidth: 60 }}>

View file

@ -1,11 +1,11 @@
import Typography from "@material-ui/core/Typography"; import { Typography } from "@material-ui/core";
import React from "react"; import React from "react";
import { formatUsage } from "../../../../common/formatUtils"; import { formatUsage } from "../../../../common/formatUtils";
import UsageBar from "../../../../common/UsageBar"; import UsageBar from "../../../../common/UsageBar";
import { import {
ClusterFeatureComponent, ClusterFeatureComponent,
NodeFeatureComponent, NodeFeatureComponent,
WorkerFeatureComponent WorkerFeatureComponent,
} from "./types"; } from "./types";
export const ClusterDisk: ClusterFeatureComponent = ({ nodes }) => { export const ClusterDisk: ClusterFeatureComponent = ({ nodes }) => {

View file

@ -1,10 +1,10 @@
import Typography from "@material-ui/core/Typography"; import { Typography } from "@material-ui/core";
import React from "react"; import React from "react";
import SpanButton from "../../../../common/SpanButton"; import SpanButton from "../../../../common/SpanButton";
import { import {
ClusterFeatureComponent, ClusterFeatureComponent,
NodeFeatureComponent, NodeFeatureComponent,
WorkerFeatureComponent WorkerFeatureComponent,
} from "./types"; } from "./types";
export const makeClusterErrors = (errorCounts: { export const makeClusterErrors = (errorCounts: {
@ -38,7 +38,7 @@ export const makeNodeErrors = (
perWorker: { [pid: string]: number }; perWorker: { [pid: string]: number };
total: number; total: number;
}, },
setErrorDialog: (hostname: string, pid: number | null) => void setErrorDialog: (hostname: string, pid: number | null) => void,
): NodeFeatureComponent => ({ node }) => ): NodeFeatureComponent => ({ node }) =>
errorCounts.total === 0 ? ( errorCounts.total === 0 ? (
<Typography color="textSecondary" component="span" variant="inherit"> <Typography color="textSecondary" component="span" variant="inherit">
@ -55,7 +55,7 @@ export const makeWorkerErrors = (
perWorker: { [pid: string]: number }; perWorker: { [pid: string]: number };
total: number; total: number;
}, },
setErrorDialog: (hostname: string, pid: number | null) => void setErrorDialog: (hostname: string, pid: number | null) => void,
): WorkerFeatureComponent => ({ node, worker }) => ): WorkerFeatureComponent => ({ node, worker }) =>
errorCounts.perWorker[worker.pid] === 0 ? ( errorCounts.perWorker[worker.pid] === 0 ? (
<Typography color="textSecondary" component="span" variant="inherit"> <Typography color="textSecondary" component="span" variant="inherit">

View file

@ -2,7 +2,7 @@ import React from "react";
import { import {
ClusterFeatureComponent, ClusterFeatureComponent,
NodeFeatureComponent, NodeFeatureComponent,
WorkerFeatureComponent WorkerFeatureComponent,
} from "./types"; } from "./types";
export const ClusterHost: ClusterFeatureComponent = ({ nodes }) => ( export const ClusterHost: ClusterFeatureComponent = ({ nodes }) => (

View file

@ -1,10 +1,10 @@
import Typography from "@material-ui/core/Typography"; import { Typography } from "@material-ui/core";
import React from "react"; import React from "react";
import SpanButton from "../../../../common/SpanButton"; import SpanButton from "../../../../common/SpanButton";
import { import {
ClusterFeatureComponent, ClusterFeatureComponent,
NodeFeatureComponent, NodeFeatureComponent,
WorkerFeatureComponent WorkerFeatureComponent,
} from "./types"; } from "./types";
export const makeClusterLogs = (logCounts: { export const makeClusterLogs = (logCounts: {
@ -37,7 +37,7 @@ export const makeNodeLogs = (
perWorker: { [pid: string]: number }; perWorker: { [pid: string]: number };
total: number; total: number;
}, },
setLogDialog: (hostname: string, pid: number | null) => void setLogDialog: (hostname: string, pid: number | null) => void,
): NodeFeatureComponent => ({ node }) => ): NodeFeatureComponent => ({ node }) =>
logCounts.total === 0 ? ( logCounts.total === 0 ? (
<Typography color="textSecondary" component="span" variant="inherit"> <Typography color="textSecondary" component="span" variant="inherit">
@ -55,7 +55,7 @@ export const makeWorkerLogs = (
perWorker: { [pid: string]: number }; perWorker: { [pid: string]: number };
total: number; total: number;
}, },
setLogDialog: (hostname: string, pid: number | null) => void setLogDialog: (hostname: string, pid: number | null) => void,
): WorkerFeatureComponent => ({ node, worker }) => ): WorkerFeatureComponent => ({ node, worker }) =>
logCounts.perWorker[worker.pid] === 0 ? ( logCounts.perWorker[worker.pid] === 0 ? (
<Typography color="textSecondary" component="span" variant="inherit"> <Typography color="textSecondary" component="span" variant="inherit">

View file

@ -4,7 +4,7 @@ import UsageBar from "../../../../common/UsageBar";
import { import {
ClusterFeatureComponent, ClusterFeatureComponent,
NodeFeatureComponent, NodeFeatureComponent,
WorkerFeatureComponent WorkerFeatureComponent,
} from "./types"; } from "./types";
export const ClusterRAM: ClusterFeatureComponent = ({ nodes }) => { export const ClusterRAM: ClusterFeatureComponent = ({ nodes }) => {

View file

@ -1,10 +1,10 @@
import Typography from "@material-ui/core/Typography"; import { Typography } from "@material-ui/core";
import React from "react"; import React from "react";
import { formatByteAmount } from "../../../../common/formatUtils"; import { formatByteAmount } from "../../../../common/formatUtils";
import { import {
ClusterFeatureComponent, ClusterFeatureComponent,
NodeFeatureComponent, NodeFeatureComponent,
WorkerFeatureComponent WorkerFeatureComponent,
} from "./types"; } from "./types";
export const ClusterReceived: ClusterFeatureComponent = ({ nodes }) => { export const ClusterReceived: ClusterFeatureComponent = ({ nodes }) => {

View file

@ -1,10 +1,10 @@
import Typography from "@material-ui/core/Typography"; import { Typography } from "@material-ui/core";
import React from "react"; import React from "react";
import { formatByteAmount } from "../../../../common/formatUtils"; import { formatByteAmount } from "../../../../common/formatUtils";
import { import {
ClusterFeatureComponent, ClusterFeatureComponent,
NodeFeatureComponent, NodeFeatureComponent,
WorkerFeatureComponent WorkerFeatureComponent,
} from "./types"; } from "./types";
export const ClusterSent: ClusterFeatureComponent = ({ nodes }) => { export const ClusterSent: ClusterFeatureComponent = ({ nodes }) => {

View file

@ -1,10 +1,10 @@
import Typography from "@material-ui/core/Typography"; import { Typography } from "@material-ui/core";
import React from "react"; import React from "react";
import { formatDuration } from "../../../../common/formatUtils"; import { formatDuration } from "../../../../common/formatUtils";
import { import {
ClusterFeatureComponent, ClusterFeatureComponent,
NodeFeatureComponent, NodeFeatureComponent,
WorkerFeatureComponent WorkerFeatureComponent,
} from "./types"; } from "./types";
const getUptime = (bootTime: number) => Date.now() / 1000 - bootTime; const getUptime = (bootTime: number) => Date.now() / 1000 - bootTime;

View file

@ -2,7 +2,7 @@ import React from "react";
import { import {
ClusterFeatureComponent, ClusterFeatureComponent,
NodeFeatureComponent, NodeFeatureComponent,
WorkerFeatureComponent WorkerFeatureComponent,
} from "./types"; } from "./types";
export const ClusterWorkers: ClusterFeatureComponent = ({ nodes }) => { export const ClusterWorkers: ClusterFeatureComponent = ({ nodes }) => {

View file

@ -10,11 +10,11 @@ type NodeFeatureData = { node: Node };
type WorkerFeatureData = { node: Node; worker: Worker }; type WorkerFeatureData = { node: Node; worker: Worker };
export type ClusterFeatureComponent = ( export type ClusterFeatureComponent = (
data: ClusterFeatureData data: ClusterFeatureData,
) => React.ReactElement; ) => React.ReactElement;
export type NodeFeatureComponent = ( export type NodeFeatureComponent = (
data: NodeFeatureData data: NodeFeatureData,
) => React.ReactElement; ) => React.ReactElement;
export type WorkerFeatureComponent = ( export type WorkerFeatureComponent = (
data: WorkerFeatureData data: WorkerFeatureData,
) => React.ReactElement; ) => React.ReactElement;

View file

@ -1,12 +1,15 @@
import { Theme } from "@material-ui/core/styles/createMuiTheme"; import {
import createStyles from "@material-ui/core/styles/createStyles"; createStyles,
import withStyles, { WithStyles } from "@material-ui/core/styles/withStyles"; Table,
import Table from "@material-ui/core/Table"; TableBody,
import TableBody from "@material-ui/core/TableBody"; TableCell,
import TableCell from "@material-ui/core/TableCell"; TableHead,
import TableHead from "@material-ui/core/TableHead"; TableRow,
import TableRow from "@material-ui/core/TableRow"; Theme,
import Typography from "@material-ui/core/Typography"; Typography,
withStyles,
WithStyles,
} from "@material-ui/core";
import classNames from "classnames"; import classNames from "classnames";
import React from "react"; import React from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
@ -18,7 +21,7 @@ const styles = (theme: Theme) =>
createStyles({ createStyles({
table: { table: {
marginTop: theme.spacing(1), marginTop: theme.spacing(1),
width: "auto" width: "auto",
}, },
cell: { cell: {
paddingTop: theme.spacing(1), paddingTop: theme.spacing(1),
@ -27,16 +30,16 @@ const styles = (theme: Theme) =>
paddingRight: theme.spacing(3), paddingRight: theme.spacing(3),
textAlign: "center", textAlign: "center",
"&:last-child": { "&:last-child": {
paddingRight: theme.spacing(3) paddingRight: theme.spacing(3),
} },
}, },
key: { key: {
color: theme.palette.text.secondary color: theme.palette.text.secondary,
} },
}); });
const mapStateToProps = (state: StoreState) => ({ const mapStateToProps = (state: StoreState) => ({
rayConfig: state.dashboard.rayConfig rayConfig: state.dashboard.rayConfig,
}); });
const mapDispatchToProps = dashboardActions; const mapDispatchToProps = dashboardActions;
@ -74,34 +77,34 @@ class RayConfig extends React.Component<
const formattedRayConfig = [ const formattedRayConfig = [
{ {
key: "Autoscaling mode", key: "Autoscaling mode",
value: rayConfig.autoscaling_mode value: rayConfig.autoscaling_mode,
}, },
{ {
key: "Head node type", key: "Head node type",
value: rayConfig.head_type value: rayConfig.head_type,
}, },
{ {
key: "Worker node type", key: "Worker node type",
value: rayConfig.worker_type value: rayConfig.worker_type,
}, },
{ {
key: "Min worker nodes", key: "Min worker nodes",
value: rayConfig.min_workers value: rayConfig.min_workers,
}, },
{ {
key: "Initial worker nodes", key: "Initial worker nodes",
value: rayConfig.initial_workers value: rayConfig.initial_workers,
}, },
{ {
key: "Max worker nodes", key: "Max worker nodes",
value: rayConfig.max_workers value: rayConfig.max_workers,
}, },
{ {
key: "Idle timeout", key: "Idle timeout",
value: `${rayConfig.idle_timeout_minutes} ${ value: `${rayConfig.idle_timeout_minutes} ${
rayConfig.idle_timeout_minutes === 1 ? "minute" : "minutes" rayConfig.idle_timeout_minutes === 1 ? "minute" : "minutes"
}` }`,
} },
]; ];
return ( return (
@ -132,5 +135,5 @@ class RayConfig extends React.Component<
export default connect( export default connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps,
)(withStyles(styles)(RayConfig)); )(withStyles(styles)(RayConfig));

View file

@ -3,13 +3,13 @@ import {
NodeInfoResponse, NodeInfoResponse,
RayConfigResponse, RayConfigResponse,
RayletInfoResponse, RayletInfoResponse,
TuneAvailabilityResponse,
TuneJobResponse, TuneJobResponse,
TuneAvailabilityResponse
} from "../../api"; } from "../../api";
const name = "dashboard"; const name = "dashboard";
interface State { type State = {
tab: number; tab: number;
rayConfig: RayConfigResponse | null; rayConfig: RayConfigResponse | null;
nodeInfo: NodeInfoResponse | null; nodeInfo: NodeInfoResponse | null;
@ -18,7 +18,7 @@ interface State {
tuneAvailability: boolean; tuneAvailability: boolean;
lastUpdatedAt: number | null; lastUpdatedAt: number | null;
error: string | null; error: string | null;
} };
const initialState: State = { const initialState: State = {
tab: 0, tab: 0,
@ -28,7 +28,7 @@ const initialState: State = {
tuneInfo: null, tuneInfo: null,
tuneAvailability: false, tuneAvailability: false,
lastUpdatedAt: null, lastUpdatedAt: null,
error: null error: null,
}; };
const slice = createSlice({ const slice = createSlice({
@ -46,7 +46,7 @@ const slice = createSlice({
action: PayloadAction<{ action: PayloadAction<{
nodeInfo: NodeInfoResponse; nodeInfo: NodeInfoResponse;
rayletInfo: RayletInfoResponse; rayletInfo: RayletInfoResponse;
}> }>,
) => { ) => {
state.nodeInfo = action.payload.nodeInfo; state.nodeInfo = action.payload.nodeInfo;
state.rayletInfo = action.payload.rayletInfo; state.rayletInfo = action.payload.rayletInfo;
@ -60,7 +60,7 @@ const slice = createSlice({
state, state,
action: PayloadAction<{ action: PayloadAction<{
tuneAvailability: TuneAvailabilityResponse; tuneAvailability: TuneAvailabilityResponse;
}> }>,
) => { ) => {
const tuneAvailability = const tuneAvailability =
action.payload.tuneAvailability === null action.payload.tuneAvailability === null
@ -71,8 +71,8 @@ const slice = createSlice({
}, },
setError: (state, action: PayloadAction<string | null>) => { setError: (state, action: PayloadAction<string | null>) => {
state.error = action.payload; state.error = action.payload;
} },
} },
}); });
export const dashboardActions = slice.actions; export const dashboardActions = slice.actions;

View file

@ -1,46 +1,49 @@
import { Theme } from "@material-ui/core/styles/createMuiTheme"; import {
import createStyles from "@material-ui/core/styles/createStyles"; createStyles,
import withStyles, { WithStyles } from "@material-ui/core/styles/withStyles"; Tab,
Tabs,
Theme,
Typography,
WithStyles,
withStyles,
} from "@material-ui/core";
import WarningRoundedIcon from "@material-ui/icons/WarningRounded";
import React from "react"; import React from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { getTuneInfo } from "../../../api"; import { getTuneInfo } from "../../../api";
import { StoreState } from "../../../store"; import { StoreState } from "../../../store";
import { dashboardActions } from "../state"; import { dashboardActions } from "../state";
import Typography from "@material-ui/core/Typography";
import WarningRoundedIcon from "@material-ui/icons/WarningRounded";
import Tab from "@material-ui/core/Tab";
import Tabs from "@material-ui/core/Tabs";
import TuneTable from "./TuneTable"; import TuneTable from "./TuneTable";
import TuneTensorBoard from "./TuneTensorBoard"; import TuneTensorBoard from "./TuneTensorBoard";
const styles = (theme: Theme) => const styles = (theme: Theme) =>
createStyles({ createStyles({
root: { root: {
backgroundColor: theme.palette.background.paper backgroundColor: theme.palette.background.paper,
}, },
tabs: { tabs: {
borderBottomColor: theme.palette.divider, borderBottomColor: theme.palette.divider,
borderBottomStyle: "solid", borderBottomStyle: "solid",
borderBottomWidth: 1 borderBottomWidth: 1,
}, },
warning: { warning: {
fontSize: "0.8125rem" fontSize: "0.8125rem",
}, },
warningIcon: { warningIcon: {
fontSize: "1.25em", fontSize: "1.25em",
verticalAlign: "text-bottom" verticalAlign: "text-bottom",
} },
}); });
const mapStateToProps = (state: StoreState) => ({ const mapStateToProps = (state: StoreState) => ({
tuneInfo: state.dashboard.tuneInfo tuneInfo: state.dashboard.tuneInfo,
}); });
const mapDispatchToProps = dashboardActions; const mapDispatchToProps = dashboardActions;
interface State { type State = {
tabIndex: number; tabIndex: number;
} };
class Tune extends React.Component< class Tune extends React.Component<
WithStyles<typeof styles> & WithStyles<typeof styles> &
@ -51,7 +54,7 @@ class Tune extends React.Component<
timeout: number = 0; timeout: number = 0;
state: State = { state: State = {
tabIndex: 0 tabIndex: 0,
}; };
refreshTuneInfo = async () => { refreshTuneInfo = async () => {
@ -75,7 +78,7 @@ class Tune extends React.Component<
handleTabChange = (event: React.ChangeEvent<{}>, value: number) => { handleTabChange = (event: React.ChangeEvent<{}>, value: number) => {
this.setState({ this.setState({
tabIndex: value tabIndex: value,
}); });
}; };
@ -86,7 +89,7 @@ class Tune extends React.Component<
const tabs = [ const tabs = [
{ label: "Table", component: TuneTable }, { label: "Table", component: TuneTable },
{ label: "TensorBoard", component: TuneTensorBoard } { label: "TensorBoard", component: TuneTensorBoard },
]; ];
const SelectedComponent = tabs[tabIndex].component; const SelectedComponent = tabs[tabIndex].component;
@ -115,5 +118,5 @@ class Tune extends React.Component<
export default connect( export default connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps,
)(withStyles(styles)(Tune)); )(withStyles(styles)(Tune));

View file

@ -1,47 +1,50 @@
import { Theme } from "@material-ui/core/styles/createMuiTheme"; import {
import createStyles from "@material-ui/core/styles/createStyles"; createStyles,
import withStyles, { WithStyles } from "@material-ui/core/styles/withStyles"; Table,
TableBody,
TableCell,
TableHead,
TableRow,
TableSortLabel,
Theme,
withStyles,
WithStyles,
} from "@material-ui/core";
import React from "react"; import React from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { TuneTrial } from "../../../api";
import { StoreState } from "../../../store"; import { StoreState } from "../../../store";
import { dashboardActions } from "../state"; import { dashboardActions } from "../state";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import TableSortLabel from "@material-ui/core/TableSortLabel";
import { TuneTrial } from "../../../api";
const styles = (theme: Theme) => const styles = (theme: Theme) =>
createStyles({ createStyles({
root: { root: {
padding: theme.spacing(2), padding: theme.spacing(2),
"& > :not(:first-child)": { "& > :not(:first-child)": {
marginTop: theme.spacing(2) marginTop: theme.spacing(2),
} },
}, },
table: { table: {
marginTop: theme.spacing(1) marginTop: theme.spacing(1),
}, },
cell: { cell: {
padding: theme.spacing(1), padding: theme.spacing(1),
textAlign: "right", textAlign: "right",
"&:last-child": { "&:last-child": {
paddingRight: theme.spacing(1) paddingRight: theme.spacing(1),
} },
} },
}); });
const mapStateToProps = (state: StoreState) => ({ const mapStateToProps = (state: StoreState) => ({
tuneInfo: state.dashboard.tuneInfo tuneInfo: state.dashboard.tuneInfo,
}); });
interface State { type State = {
metricParamColumn: string; metricParamColumn: string;
ascending: boolean; ascending: boolean;
sortedColumn: keyof TuneTrial | undefined; sortedColumn: keyof TuneTrial | undefined;
} };
const mapDispatchToProps = dashboardActions; const mapDispatchToProps = dashboardActions;
@ -56,7 +59,7 @@ class TuneTable extends React.Component<
state: State = { state: State = {
sortedColumn: undefined, sortedColumn: undefined,
ascending: true, ascending: true,
metricParamColumn: "" metricParamColumn: "",
}; };
onColumnClick = (column: keyof TuneTrial, metricParamColumn?: string) => { onColumnClick = (column: keyof TuneTrial, metricParamColumn?: string) => {
@ -68,12 +71,12 @@ class TuneTable extends React.Component<
} }
this.setState({ this.setState({
sortedColumn: column, sortedColumn: column,
ascending: ascending ascending: ascending,
}); });
if (metricParamColumn) { if (metricParamColumn) {
this.setState({ this.setState({
metricParamColumn: metricParamColumn metricParamColumn: metricParamColumn,
}); });
} }
}; };
@ -82,14 +85,11 @@ class TuneTable extends React.Component<
* Replaces all underscores with spaces and capitalizes all words * Replaces all underscores with spaces and capitalizes all words
* in str * in str
*/ */
humanize = (str: string) => { humanize = (str: string) =>
var i, str
frags = str.split("_"); .split("_")
for (i = 0; i < frags.length; i++) { .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
frags[i] = frags[i].charAt(0).toUpperCase() + frags[i].slice(1); .join(" ");
}
return frags.join(" ");
};
sortedCell = (name: keyof TuneTrial, chosenMetricParam?: string) => { sortedCell = (name: keyof TuneTrial, chosenMetricParam?: string) => {
const { tuneInfo, classes } = this.props; const { tuneInfo, classes } = this.props;
@ -154,11 +154,11 @@ class TuneTable extends React.Component<
if (sortedColumn) { if (sortedColumn) {
if (ascending) { if (ascending) {
trialDetails.sort((a, b) => trialDetails.sort((a, b) =>
getAttribute(a) > getAttribute(b) ? 1 : -1 getAttribute(a) > getAttribute(b) ? 1 : -1,
); );
} else if (!ascending) { } else if (!ascending) {
trialDetails.sort((a, b) => trialDetails.sort((a, b) =>
getAttribute(a) < getAttribute(b) ? 1 : -1 getAttribute(a) < getAttribute(b) ? 1 : -1,
); );
} }
} }
@ -178,10 +178,10 @@ class TuneTable extends React.Component<
const firstTrial = Object.keys(tuneInfo["trial_records"])[0]; const firstTrial = Object.keys(tuneInfo["trial_records"])[0];
const paramsDict = tuneInfo["trial_records"][firstTrial]["params"]; const paramsDict = tuneInfo["trial_records"][firstTrial]["params"];
const paramNames = Object.keys(paramsDict).filter(k => k !== "args"); const paramNames = Object.keys(paramsDict).filter((k) => k !== "args");
const metricNames = Object.keys( const metricNames = Object.keys(
tuneInfo["trial_records"][firstTrial]["metrics"] tuneInfo["trial_records"][firstTrial]["metrics"],
); );
const trialDetails = this.sortedTrialRecords(); const trialDetails = this.sortedTrialRecords();
@ -194,9 +194,9 @@ class TuneTable extends React.Component<
{this.sortedCell("trial_id")} {this.sortedCell("trial_id")}
{this.sortedCell("job_id")} {this.sortedCell("job_id")}
{this.sortedCell("start_time")} {this.sortedCell("start_time")}
{paramNames.map(value => this.sortedCell("params", value))} {paramNames.map((value) => this.sortedCell("params", value))}
{this.sortedCell("status")} {this.sortedCell("status")}
{metricNames.map(value => this.sortedCell("metrics", value))} {metricNames.map((value) => this.sortedCell("metrics", value))}
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
@ -212,7 +212,7 @@ class TuneTable extends React.Component<
<TableCell className={classes.cell}> <TableCell className={classes.cell}>
{trial["start_time"]} {trial["start_time"]}
</TableCell> </TableCell>
{paramNames.map(value => ( {paramNames.map((value) => (
<TableCell className={classes.cell} key={value}> <TableCell className={classes.cell} key={value}>
{trial["params"][value]} {trial["params"][value]}
</TableCell> </TableCell>
@ -221,7 +221,7 @@ class TuneTable extends React.Component<
{trial["status"]} {trial["status"]}
</TableCell> </TableCell>
{trial["metrics"] && {trial["metrics"] &&
metricNames.map(value => ( metricNames.map((value) => (
<TableCell className={classes.cell} key={value}> <TableCell className={classes.cell} key={value}>
{trial["metrics"][value]} {trial["metrics"][value]}
</TableCell> </TableCell>
@ -237,5 +237,5 @@ class TuneTable extends React.Component<
export default connect( export default connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps,
)(withStyles(styles)(TuneTable)); )(withStyles(styles)(TuneTable));

View file

@ -1,11 +1,14 @@
import { Theme } from "@material-ui/core/styles/createMuiTheme"; import {
import createStyles from "@material-ui/core/styles/createStyles"; createStyles,
import withStyles, { WithStyles } from "@material-ui/core/styles/withStyles"; Theme,
Typography,
WithStyles,
withStyles,
} from "@material-ui/core";
import React from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { StoreState } from "../../../store"; import { StoreState } from "../../../store";
import { dashboardActions } from "../state"; import { dashboardActions } from "../state";
import React from "react";
import Typography from "@material-ui/core/Typography";
const styles = (theme: Theme) => const styles = (theme: Theme) =>
createStyles({ createStyles({
@ -13,21 +16,21 @@ const styles = (theme: Theme) =>
backgroundColor: theme.palette.background.paper, backgroundColor: theme.palette.background.paper,
padding: theme.spacing(2), padding: theme.spacing(2),
"& > :not(:first-child)": { "& > :not(:first-child)": {
marginTop: theme.spacing(4) marginTop: theme.spacing(4),
} },
}, },
board: { board: {
width: "100%", width: "100%",
height: "1000px", height: "1000px",
border: "none" border: "none",
}, },
warning: { warning: {
fontSize: "0.8125rem" fontSize: "0.8125rem",
} },
}); });
const mapStateToProps = (state: StoreState) => ({ const mapStateToProps = (state: StoreState) => ({
error: state.dashboard.error error: state.dashboard.error,
}); });
const mapDispatchToProps = dashboardActions; const mapDispatchToProps = dashboardActions;
@ -60,5 +63,5 @@ class TuneTensorBoard extends React.Component<
export default connect( export default connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps,
)(withStyles(styles)(TuneTensorBoard)); )(withStyles(styles)(TuneTensorBoard));

View file

@ -3,9 +3,9 @@ import { dashboardReducer } from "./pages/dashboard/state";
export const store = configureStore({ export const store = configureStore({
reducer: { reducer: {
dashboard: dashboardReducer dashboard: dashboardReducer,
}, },
devTools: process.env.NODE_ENV === "development" devTools: process.env.NODE_ENV === "development",
}); });
export type StoreState = ReturnType<typeof store.getState>; export type StoreState = ReturnType<typeof store.getState>;