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:
parent
f10b49f31c
commit
3a5bbbca1f
4 changed files with 59 additions and 43 deletions
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue