Shutdown and restart actions
parent
5536cddf1b
commit
8eb5f0caa0
|
@ -13,3 +13,8 @@ Log-ul va fi popup iar continutul lui poate fi ultima componenta de aici https:/
|
||||||
https://medium.com/@tacomanator/environments-with-create-react-app-7b645312c09d
|
https://medium.com/@tacomanator/environments-with-create-react-app-7b645312c09d
|
||||||
https://create-react-app.dev/docs/adding-custom-environment-variables/
|
https://create-react-app.dev/docs/adding-custom-environment-variables/
|
||||||
https://stackoverflow.com/questions/55690143/what-is-the-difference-between-env-local-and-env-development-local
|
https://stackoverflow.com/questions/55690143/what-is-the-difference-between-env-local-and-env-development-local
|
||||||
|
|
||||||
|
|
||||||
|
REACT v4:
|
||||||
|
https://v4.mui.com/getting-started/installation/
|
||||||
|
https://v4.mui.com/components/material-icons/
|
|
@ -36,7 +36,11 @@
|
||||||
"PoweredOn": "Powered on",
|
"PoweredOn": "Powered on",
|
||||||
"Actions": {
|
"Actions": {
|
||||||
"Wake": "Wake",
|
"Wake": "Wake",
|
||||||
"Ping": "Ping"
|
"Ping": "Ping",
|
||||||
|
"More": "More",
|
||||||
|
"Shutdown": "Shutdown",
|
||||||
|
"Restart": "Restart",
|
||||||
|
"Advanced": "Advanced"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,11 @@
|
||||||
"PoweredOn": "Pornit",
|
"PoweredOn": "Pornit",
|
||||||
"Actions": {
|
"Actions": {
|
||||||
"Wake": "Pornește",
|
"Wake": "Pornește",
|
||||||
"Ping": "Ping"
|
"Ping": "Ping",
|
||||||
|
"More": "Mai mult",
|
||||||
|
"Shutdown": "Oprește",
|
||||||
|
"Restart": "Repornește",
|
||||||
|
"Advanced": "Avansat"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,10 @@ const useApi = () => {
|
||||||
error(message);
|
error(message);
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultOptions = { onCompleted: () => {}, onError: handleError };
|
const defaultOptions = {
|
||||||
|
onCompleted: () => {},
|
||||||
|
onError: handleError
|
||||||
|
};
|
||||||
|
|
||||||
const call = async (request, options) => {
|
const call = async (request, options) => {
|
||||||
const internalOptions = { ...defaultOptions, ...options };
|
const internalOptions = { ...defaultOptions, ...options };
|
||||||
|
@ -63,7 +66,39 @@ const useApi = () => {
|
||||||
return promise;
|
return promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
return { readMachines, wakeMachine, pingMachine };
|
const shutdownMachine = (
|
||||||
|
machineId,
|
||||||
|
delay,
|
||||||
|
force,
|
||||||
|
options = defaultOptions
|
||||||
|
) => {
|
||||||
|
const promise = call(
|
||||||
|
() => post(`${powerActionsRoute}/shutdown`, { machineId, delay, force }),
|
||||||
|
options
|
||||||
|
);
|
||||||
|
return promise;
|
||||||
|
};
|
||||||
|
|
||||||
|
const restartMachine = (
|
||||||
|
machineId,
|
||||||
|
delay,
|
||||||
|
force,
|
||||||
|
options = defaultOptions
|
||||||
|
) => {
|
||||||
|
const promise = call(
|
||||||
|
() => post(`${powerActionsRoute}/restart`, { machineId, delay, force }),
|
||||||
|
options
|
||||||
|
);
|
||||||
|
return promise;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
readMachines,
|
||||||
|
wakeMachine,
|
||||||
|
pingMachine,
|
||||||
|
shutdownMachine,
|
||||||
|
restartMachine
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useApi;
|
export default useApi;
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import React from "react";
|
import React, { useMemo } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import {
|
import {
|
||||||
TableCell,
|
TableCell,
|
||||||
TableRow,
|
TableRow,
|
||||||
IconButton,
|
IconButton,
|
||||||
Collapse,
|
Collapse,
|
||||||
Tooltip
|
Tooltip,
|
||||||
|
Menu
|
||||||
} from "@material-ui/core";
|
} from "@material-ui/core";
|
||||||
import { KeyboardArrowDown, KeyboardArrowUp } from "@material-ui/icons";
|
import { KeyboardArrowDown, KeyboardArrowUp } from "@material-ui/icons";
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
|
@ -20,10 +21,46 @@ const useRowStyles = makeStyles({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const Machine = ({ machine, actions, logs, addLog }) => {
|
const ActionButton = React.forwardRef((props, _ref) => {
|
||||||
|
const { action, machine } = props;
|
||||||
|
return (
|
||||||
|
<Tooltip
|
||||||
|
id={`machine-item-${machine.machineId}-${action.code}-tooltip`}
|
||||||
|
title={action.tooltip}
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
<IconButton
|
||||||
|
id={`machine-item-${machine.machineId}-${action.code}`}
|
||||||
|
size={"small"}
|
||||||
|
onClick={action.system ? action.effect : action.effect(machine)}
|
||||||
|
>
|
||||||
|
<action.icon />
|
||||||
|
</IconButton>
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const Machine = ({
|
||||||
|
machine,
|
||||||
|
actions,
|
||||||
|
logs,
|
||||||
|
addLog,
|
||||||
|
secondaryActionsMenuProps
|
||||||
|
}) => {
|
||||||
const [open, setOpen] = React.useState(false);
|
const [open, setOpen] = React.useState(false);
|
||||||
const classes = useRowStyles();
|
const classes = useRowStyles();
|
||||||
|
|
||||||
|
const topActions = useMemo(
|
||||||
|
() => actions.filter(a => a.top === true),
|
||||||
|
[actions]
|
||||||
|
);
|
||||||
|
|
||||||
|
const secondaryActions = useMemo(
|
||||||
|
() => actions.filter(a => a.top === false),
|
||||||
|
[actions]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<TableRow className={classes.root}>
|
<TableRow className={classes.root}>
|
||||||
|
@ -44,22 +81,28 @@ const Machine = ({ machine, actions, logs, addLog }) => {
|
||||||
<TableCell>{machine.macAddress}</TableCell>
|
<TableCell>{machine.macAddress}</TableCell>
|
||||||
<TableCell align="right">
|
<TableCell align="right">
|
||||||
<WakeComponent machine={machine} addLog={addLog} />
|
<WakeComponent machine={machine} addLog={addLog} />
|
||||||
{actions.map(action => (
|
{topActions.map(action => (
|
||||||
<Tooltip
|
<ActionButton
|
||||||
title={action.tooltip}
|
key={`machine-item-${machine.machineId}-${action.code}`}
|
||||||
key={`machine-item-${machine.machineId}-${action.code}-tooltip`}
|
action={action}
|
||||||
>
|
machine={machine}
|
||||||
<span>
|
/>
|
||||||
<IconButton
|
|
||||||
id={`machine-item-${machine.machineId}-${action.code}`}
|
|
||||||
size={"small"}
|
|
||||||
onClick={action.effect(machine)}
|
|
||||||
>
|
|
||||||
<action.icon />
|
|
||||||
</IconButton>
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
))}
|
))}
|
||||||
|
<Menu
|
||||||
|
id="secondary-actions-menu"
|
||||||
|
anchorEl={secondaryActionsMenuProps.anchor}
|
||||||
|
keepMounted
|
||||||
|
open={Boolean(secondaryActionsMenuProps.anchor)}
|
||||||
|
onClose={secondaryActionsMenuProps.onCloseSecondaryActions}
|
||||||
|
>
|
||||||
|
{secondaryActions.map(action => (
|
||||||
|
<ActionButton
|
||||||
|
key={`machine-item-${machine.machineId}-${action.code}`}
|
||||||
|
action={action}
|
||||||
|
machine={machine}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Menu>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
|
@ -84,7 +127,8 @@ Machine.propTypes = {
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
actions: PropTypes.array.isRequired,
|
actions: PropTypes.array.isRequired,
|
||||||
logs: PropTypes.array.isRequired,
|
logs: PropTypes.array.isRequired,
|
||||||
addLog: PropTypes.func.isRequired
|
addLog: PropTypes.func.isRequired,
|
||||||
|
secondaryActionsMenuProps: PropTypes.object.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Machine;
|
export default Machine;
|
||||||
|
|
|
@ -2,12 +2,21 @@ import React, { useState, useCallback } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import Machine from "./Machine";
|
import Machine from "./Machine";
|
||||||
import { useToast } from "../../../hooks";
|
import { useToast } from "../../../hooks";
|
||||||
import { LastPage } from "@material-ui/icons";
|
import {
|
||||||
|
LastPage,
|
||||||
|
MoreHoriz,
|
||||||
|
RotateLeft,
|
||||||
|
Launch,
|
||||||
|
Stop
|
||||||
|
} from "@material-ui/icons";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import useApi from "../../../api";
|
import useApi from "../../../api";
|
||||||
|
|
||||||
const MachineContainer = ({ machine }) => {
|
const MachineContainer = ({ machine }) => {
|
||||||
const [logs, setLogs] = useState([]);
|
const [logs, setLogs] = useState([]);
|
||||||
|
const [secondaryActionsAnchor, setSecondaryActionsAnchor] =
|
||||||
|
React.useState(null);
|
||||||
|
|
||||||
const { success, error } = useToast();
|
const { success, error } = useToast();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
@ -20,20 +29,58 @@ const MachineContainer = ({ machine }) => {
|
||||||
[setLogs]
|
[setLogs]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const manageActionResponse = useCallback(
|
||||||
|
response => {
|
||||||
|
addLog(`Success: ${response.success}. Status: ${response.status}`);
|
||||||
|
if (response.success) {
|
||||||
|
success(response.status);
|
||||||
|
} else {
|
||||||
|
error(response.status);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[error, success, addLog]
|
||||||
|
);
|
||||||
|
|
||||||
const pingMachine = useCallback(
|
const pingMachine = useCallback(
|
||||||
machine => async () => {
|
machine => async () => {
|
||||||
await api.pingMachine(machine.machineId, {
|
await api.pingMachine(machine.machineId, {
|
||||||
onCompleted: result => {
|
onCompleted: manageActionResponse
|
||||||
addLog(`Success: ${result.success}. Status: ${result.status}`);
|
|
||||||
if (result.success) {
|
|
||||||
success(result.status);
|
|
||||||
} else {
|
|
||||||
error(result.status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[error, success, addLog, api]
|
[manageActionResponse, api]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleOpenSecondaryActions = event => {
|
||||||
|
setSecondaryActionsAnchor(event.currentTarget);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCloseSecondaryActions = () => {
|
||||||
|
setSecondaryActionsAnchor(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const secondaryActionsMenuProps = {
|
||||||
|
anchor: secondaryActionsAnchor,
|
||||||
|
onCloseSecondaryActions: handleCloseSecondaryActions
|
||||||
|
};
|
||||||
|
|
||||||
|
const shutdownMachine = useCallback(
|
||||||
|
machine => async () => {
|
||||||
|
await api.shutdownMachine(machine.machineId, 0, false, {
|
||||||
|
onCompleted: manageActionResponse
|
||||||
|
});
|
||||||
|
handleCloseSecondaryActions();
|
||||||
|
},
|
||||||
|
[manageActionResponse, api]
|
||||||
|
);
|
||||||
|
|
||||||
|
const restartMachine = useCallback(
|
||||||
|
machine => async () => {
|
||||||
|
await api.restartMachine(machine.machineId, 0, false, {
|
||||||
|
onCompleted: manageActionResponse
|
||||||
|
});
|
||||||
|
handleCloseSecondaryActions();
|
||||||
|
},
|
||||||
|
[manageActionResponse, api]
|
||||||
);
|
);
|
||||||
|
|
||||||
const actions = [
|
const actions = [
|
||||||
|
@ -41,12 +88,48 @@ const MachineContainer = ({ machine }) => {
|
||||||
code: "ping",
|
code: "ping",
|
||||||
effect: pingMachine,
|
effect: pingMachine,
|
||||||
icon: LastPage,
|
icon: LastPage,
|
||||||
tooltip: t("Machine.Actions.Ping")
|
tooltip: t("Machine.Actions.Ping"),
|
||||||
|
top: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: "more",
|
||||||
|
effect: handleOpenSecondaryActions,
|
||||||
|
icon: MoreHoriz,
|
||||||
|
tooltip: t("Machine.Actions.More"),
|
||||||
|
top: true,
|
||||||
|
system: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: "shutdown",
|
||||||
|
effect: shutdownMachine,
|
||||||
|
icon: Stop,
|
||||||
|
tooltip: t("Machine.Actions.Shutdown"),
|
||||||
|
top: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: "restart",
|
||||||
|
effect: restartMachine,
|
||||||
|
icon: RotateLeft,
|
||||||
|
tooltip: t("Machine.Actions.Restart"),
|
||||||
|
top: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: "advanced",
|
||||||
|
effect: () => {},
|
||||||
|
icon: Launch,
|
||||||
|
tooltip: t("Machine.Actions.Advanced"),
|
||||||
|
top: false
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Machine machine={machine} actions={actions} logs={logs} addLog={addLog} />
|
<Machine
|
||||||
|
machine={machine}
|
||||||
|
actions={actions}
|
||||||
|
logs={logs}
|
||||||
|
addLog={addLog}
|
||||||
|
secondaryActionsMenuProps={secondaryActionsMenuProps}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue