feat: added shutdown function to the machine loader

feat: created shutdown route and call it from gql server (called from
admin UI button)

feat: added an extra message property to the ConfirmDialog

refactor: simplified the MachineDetailsCard component

feat: added an extra information message to the Shutdown machine action
This commit is contained in:
Liordino Neto 2020-10-30 12:08:29 -03:00 committed by Josh Harvey
parent f10b49f31c
commit 3a5bbbca1f
4 changed files with 59 additions and 43 deletions

View file

@ -111,6 +111,10 @@ function reboot (rec) {
return axios.post(`http://localhost:3030/reboot?device_id=${rec.deviceId}`) return axios.post(`http://localhost:3030/reboot?device_id=${rec.deviceId}`)
} }
function shutdown (rec) {
return axios.post(`http://localhost:3030/shutdown?device_id=${rec.deviceId}`)
}
function restartServices (rec) { function restartServices (rec) {
return axios.post(`http://localhost:3030/restartServices?device_id=${rec.deviceId}`) return axios.post(`http://localhost:3030/restartServices?device_id=${rec.deviceId}`)
} }
@ -122,6 +126,7 @@ function setMachine (rec) {
case 'resetCashOutBills': return resetCashOutBills(rec) case 'resetCashOutBills': return resetCashOutBills(rec)
case 'unpair': return unpair(rec) case 'unpair': return unpair(rec)
case 'reboot': return reboot(rec) case 'reboot': return reboot(rec)
case 'shutdown': return shutdown(rec)
case 'restartServices': return restartServices(rec) case 'restartServices': return restartServices(rec)
default: throw new Error('No such action: ' + rec.action) default: throw new Error('No such action: ' + rec.action)
} }

View file

@ -38,6 +38,7 @@ const SETTINGS_CACHE_REFRESH = 60 * 60 * 1000
const pids = {} const pids = {}
const reboots = {} const reboots = {}
const shutdowns = {}
const restartServicesMap = {} const restartServicesMap = {}
const canGetLastSeenMap = {} const canGetLastSeenMap = {}
const canLogClockSkewMap = {} const canLogClockSkewMap = {}
@ -74,6 +75,7 @@ function poll (req, res, next) {
const cassettes = results.cassettes const cassettes = results.cassettes
const reboot = pid && reboots[deviceId] && reboots[deviceId] === pid const reboot = pid && reboots[deviceId] && reboots[deviceId] === pid
const shutdown = pid && shutdowns[deviceId] && shutdowns[deviceId] === pid
const restartServices = pid && restartServicesMap[deviceId] && restartServicesMap[deviceId] === pid const restartServices = pid && restartServicesMap[deviceId] && restartServicesMap[deviceId] === pid
const langs = localeConfig.languages const langs = localeConfig.languages
@ -95,6 +97,7 @@ function poll (req, res, next) {
twoWayMode: cashOutConfig.active, twoWayMode: cashOutConfig.active,
zeroConfLimit: cashOutConfig.zeroConfLimit, zeroConfLimit: cashOutConfig.zeroConfLimit,
reboot, reboot,
shutdown,
restartServices, restartServices,
hasLightning, hasLightning,
receipt, receipt,
@ -510,6 +513,18 @@ localApp.post('/reboot', (req, res) => {
res.sendStatus(200) res.sendStatus(200)
}) })
localApp.post('/shutdown', (req, res) => {
const deviceId = req.query.device_id
const pid = pids[deviceId] && pids[deviceId].pid
if (!deviceId || !pid) {
return res.sendStatus(400)
}
shutdowns[deviceId] = pid
res.sendStatus(200)
})
localApp.post('/restartServices', (req, res) => { localApp.post('/restartServices', (req, res) => {
const deviceId = req.query.device_id const deviceId = req.query.device_id
const pid = pids[deviceId] && pids[deviceId].pid const pid = pids[deviceId] && pids[deviceId].pid

View file

@ -8,7 +8,7 @@ import React, { memo, useState } from 'react'
import { Button, IconButton } from 'src/components/buttons' import { Button, IconButton } from 'src/components/buttons'
import { TextInput } from 'src/components/inputs' import { TextInput } from 'src/components/inputs'
import { H4 } from 'src/components/typography' import { H4, P } from 'src/components/typography'
import { ReactComponent as CloseIcon } from 'src/styling/icons/action/close/zodiac.svg' import { ReactComponent as CloseIcon } from 'src/styling/icons/action/close/zodiac.svg'
import { spacer } from 'src/styling/variables' import { spacer } from 'src/styling/variables'
@ -60,6 +60,7 @@ export const ConfirmDialog = memo(
open, open,
toBeConfirmed, toBeConfirmed,
saveButtonAlwaysEnabled = false, saveButtonAlwaysEnabled = false,
message,
confirmationMessage = `Write '${toBeConfirmed}' to confirm this action`, confirmationMessage = `Write '${toBeConfirmed}' to confirm this action`,
onConfirmed, onConfirmed,
onDissmised, onDissmised,
@ -98,6 +99,7 @@ export const ConfirmDialog = memo(
</DialogTitle> </DialogTitle>
)} )}
<DialogContent className={classes.dialogContent}> <DialogContent className={classes.dialogContent}>
{message && <P>{message}</P>}
<TextInput <TextInput
label={confirmationMessage} label={confirmationMessage}
name="confirm-input" name="confirm-input"

View file

@ -69,18 +69,10 @@ const Item = ({ children, ...props }) => (
) )
const MachineDetailsRow = ({ it: machine, onActionSuccess }) => { const MachineDetailsRow = ({ it: machine, onActionSuccess }) => {
const [action, setAction] = useState('') const [action, setAction] = useState(null)
const [renameActionDialogOpen, setRenameActionDialogOpen] = useState(false)
const [confirmActionDialogOpen, setConfirmActionDialogOpen] = useState(false)
const [errorMessage, setErrorMessage] = useState(null) const [errorMessage, setErrorMessage] = useState(null)
const classes = useMDStyles() const classes = useMDStyles()
const confirmActionDialog = action =>
setAction(action) || setConfirmActionDialogOpen(true)
const renameActionDialog = () =>
setAction('Rename') || setRenameActionDialogOpen(true)
const [machineAction, { loading }] = useMutation(MACHINE_ACTION, { const [machineAction, { loading }] = useMutation(MACHINE_ACTION, {
onError: ({ message }) => { onError: ({ message }) => {
const errorMessage = message ?? 'An error ocurred' const errorMessage = message ?? 'An error ocurred'
@ -88,11 +80,12 @@ const MachineDetailsRow = ({ it: machine, onActionSuccess }) => {
}, },
onCompleted: () => { onCompleted: () => {
onActionSuccess && onActionSuccess() onActionSuccess && onActionSuccess()
setConfirmActionDialogOpen(false) setAction(null)
setRenameActionDialogOpen(false)
} }
}) })
const confirmDialogOpen = Boolean(action)
return ( return (
<> <>
<Container className={classes.wrapper}> <Container className={classes.wrapper}>
@ -134,43 +127,25 @@ const MachineDetailsRow = ({ it: machine, onActionSuccess }) => {
className={classes.separator} className={classes.separator}
/> />
<ConfirmDialog <ConfirmDialog
open={renameActionDialogOpen} open={confirmDialogOpen}
title={`Rename this machine?`} title={`${action?.command} this machine?`}
initialValue={machine.name}
errorMessage={errorMessage} errorMessage={errorMessage}
confirmationMessage={`Write the new name for this machine`} toBeConfirmed={machine.name}
saveButtonAlwaysEnabled={true} message={action?.message}
confirmationMessage={action?.confirmationMessage}
saveButtonAlwaysEnabled={action?.command === 'Rename'}
onConfirmed={value => { onConfirmed={value => {
setErrorMessage(null) setErrorMessage(null)
machineAction({ machineAction({
variables: { variables: {
deviceId: machine.deviceId, deviceId: machine.deviceId,
action: `${action}`.toLowerCase(), action: `${action?.command}`.toLowerCase(),
newName: value ...(action?.command === 'Rename' && { newName: value })
} }
}) })
}} }}
onDissmised={() => { onDissmised={() => {
setRenameActionDialogOpen(false) setAction(null)
setErrorMessage(null)
}}
/>
<ConfirmDialog
open={confirmActionDialogOpen}
title={`${action} this machine?`}
errorMessage={errorMessage}
toBeConfirmed={machine.name}
onConfirmed={() => {
setErrorMessage(null)
machineAction({
variables: {
deviceId: machine.deviceId,
action: `${action}`.toLowerCase()
}
})
}}
onDissmised={() => {
setConfirmActionDialogOpen(false)
setErrorMessage(null) setErrorMessage(null)
}} }}
/> />
@ -197,7 +172,12 @@ const MachineDetailsRow = ({ it: machine, onActionSuccess }) => {
color="primary" color="primary"
Icon={EditIcon} Icon={EditIcon}
InverseIcon={EditReversedIcon} InverseIcon={EditReversedIcon}
onClick={() => renameActionDialog()}> onClick={() =>
setAction({
command: 'Rename',
confirmationMessage: 'Write the new name for this machine'
})
}>
Rename Rename
</ActionButton> </ActionButton>
<ActionButton <ActionButton
@ -206,7 +186,11 @@ const MachineDetailsRow = ({ it: machine, onActionSuccess }) => {
Icon={UnpairIcon} Icon={UnpairIcon}
InverseIcon={UnpairReversedIcon} InverseIcon={UnpairReversedIcon}
disabled={loading} disabled={loading}
onClick={() => confirmActionDialog('Unpair')}> onClick={() =>
setAction({
command: 'Unpair'
})
}>
Unpair Unpair
</ActionButton> </ActionButton>
<ActionButton <ActionButton
@ -215,7 +199,11 @@ const MachineDetailsRow = ({ it: machine, onActionSuccess }) => {
Icon={RebootIcon} Icon={RebootIcon}
InverseIcon={RebootReversedIcon} InverseIcon={RebootReversedIcon}
disabled={loading} disabled={loading}
onClick={() => confirmActionDialog('Reboot')}> onClick={() =>
setAction({
command: 'Reboot'
})
}>
Reboot Reboot
</ActionButton> </ActionButton>
<ActionButton <ActionButton
@ -224,7 +212,13 @@ const MachineDetailsRow = ({ it: machine, onActionSuccess }) => {
color="primary" color="primary"
Icon={ShutdownIcon} Icon={ShutdownIcon}
InverseIcon={ShutdownReversedIcon} InverseIcon={ShutdownReversedIcon}
onClick={() => confirmActionDialog('Shutdown')}> onClick={() =>
setAction({
command: 'Shutdown',
message:
'In order to bring it back online, the machine will need to be visited and its power reset.'
})
}>
Shutdown Shutdown
</ActionButton> </ActionButton>
</div> </div>