fix: add machine actions to 'Dashboard > Machine Details'
This commit is contained in:
parent
e11d7548e3
commit
bf5ee5feb4
6 changed files with 389 additions and 392 deletions
|
|
@ -87,9 +87,54 @@ function getMachineName (machineId) {
|
|||
.then(it => it.name)
|
||||
}
|
||||
|
||||
function getMachine (machineId) {
|
||||
function getMachine (machineId, config) {
|
||||
const fullyFunctionalStatus = { label: 'Fully functional', type: 'success' }
|
||||
const unresponsiveStatus = { label: 'Unresponsive', type: 'error' }
|
||||
const stuckStatus = { label: 'Stuck', type: 'error' }
|
||||
|
||||
const sql = 'SELECT * FROM devices WHERE device_id=$1'
|
||||
return db.oneOrNone(sql, [machineId]).then(res => _.mapKeys(_.camelCase)(res))
|
||||
const queryMachine = db.oneOrNone(sql, [machineId]).then(r => ({
|
||||
deviceId: r.device_id,
|
||||
cashbox: r.cashbox,
|
||||
cassette1: r.cassette1,
|
||||
cassette2: r.cassette2,
|
||||
version: r.version,
|
||||
model: r.model,
|
||||
pairedAt: new Date(r.created),
|
||||
lastPing: new Date(r.last_online),
|
||||
name: r.name,
|
||||
paired: r.paired
|
||||
}))
|
||||
|
||||
return Promise.all([queryMachine, dbm.machineEvents(), config])
|
||||
.then(([machine, events, config]) => {
|
||||
const pings = checkPings([machine])
|
||||
|
||||
const getStatus = (ping, stuck) => {
|
||||
if (ping && ping.age) return unresponsiveStatus
|
||||
|
||||
if (stuck && stuck.age) return stuckStatus
|
||||
|
||||
return fullyFunctionalStatus
|
||||
}
|
||||
|
||||
const addName = r => {
|
||||
const cashOutConfig = configManager.getCashOut(r.deviceId, config)
|
||||
|
||||
const cashOut = !!cashOutConfig.active
|
||||
|
||||
const statuses = [
|
||||
getStatus(
|
||||
_.first(pings[r.deviceId]),
|
||||
_.first(checkStuckScreen(events, r.name))
|
||||
)
|
||||
]
|
||||
|
||||
return _.assign(r, { cashOut, statuses })
|
||||
}
|
||||
|
||||
return addName(machine)
|
||||
})
|
||||
}
|
||||
|
||||
function renameMachine (rec) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,221 @@
|
|||
import { useMutation, useLazyQuery } from '@apollo/react-hooks'
|
||||
import { makeStyles } from '@material-ui/core/styles'
|
||||
import gql from 'graphql-tag'
|
||||
// import moment from 'moment'
|
||||
import React, { memo, useState } from 'react'
|
||||
|
||||
import { ConfirmDialog } from 'src/components/ConfirmDialog'
|
||||
import ActionButton from 'src/components/buttons/ActionButton'
|
||||
// // import { Status } from 'src/components/Status'
|
||||
import { ReactComponent as EditReversedIcon } from 'src/styling/icons/button/edit/white.svg'
|
||||
import { ReactComponent as EditIcon } from 'src/styling/icons/button/edit/zodiac.svg'
|
||||
import { ReactComponent as RebootReversedIcon } from 'src/styling/icons/button/reboot/white.svg'
|
||||
import { ReactComponent as RebootIcon } from 'src/styling/icons/button/reboot/zodiac.svg'
|
||||
import { ReactComponent as ShutdownReversedIcon } from 'src/styling/icons/button/shut down/white.svg'
|
||||
import { ReactComponent as ShutdownIcon } from 'src/styling/icons/button/shut down/zodiac.svg'
|
||||
import { ReactComponent as UnpairReversedIcon } from 'src/styling/icons/button/unpair/white.svg'
|
||||
import { ReactComponent as UnpairIcon } from 'src/styling/icons/button/unpair/zodiac.svg'
|
||||
|
||||
import { machineActionsStyles } from './MachineActions.styles'
|
||||
|
||||
const useStyles = makeStyles(machineActionsStyles)
|
||||
|
||||
const MACHINE_ACTION = gql`
|
||||
mutation MachineAction(
|
||||
$deviceId: ID!
|
||||
$action: MachineAction!
|
||||
$newName: String
|
||||
) {
|
||||
machineAction(deviceId: $deviceId, action: $action, newName: $newName) {
|
||||
deviceId
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const MACHINE = gql`
|
||||
query getMachine($deviceId: ID!) {
|
||||
machine(deviceId: $deviceId) {
|
||||
latestEvent {
|
||||
note
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const isStaticState = machineState => {
|
||||
if (!machineState) {
|
||||
return true
|
||||
}
|
||||
const staticStates = [
|
||||
'chooseCoin',
|
||||
'idle',
|
||||
'pendingIdle',
|
||||
'dualIdle',
|
||||
'networkDown',
|
||||
'unpaired',
|
||||
'maintenance',
|
||||
'virgin',
|
||||
'wifiList'
|
||||
]
|
||||
return staticStates.includes(machineState)
|
||||
}
|
||||
|
||||
const getState = machineEventsLazy =>
|
||||
JSON.parse(machineEventsLazy.machine.latestEvent?.note ?? '{"state": null}')
|
||||
.state
|
||||
|
||||
const Label = ({ children }) => {
|
||||
const classes = useStyles()
|
||||
|
||||
return <div className={classes.label}>{children}</div>
|
||||
}
|
||||
|
||||
const MachineActions = memo(({ machine, onActionSuccess }) => {
|
||||
const [action, setAction] = useState({ command: null })
|
||||
const [errorMessage, setErrorMessage] = useState(null)
|
||||
const classes = useStyles()
|
||||
|
||||
const warningMessage = (
|
||||
<span className={classes.warning}>
|
||||
A user may be in the middle of a transaction and they could lose their
|
||||
funds if you continue.
|
||||
</span>
|
||||
)
|
||||
|
||||
const [fetchMachineEvents, { loading: loadingEvents }] = useLazyQuery(
|
||||
MACHINE,
|
||||
{
|
||||
variables: {
|
||||
deviceId: machine.deviceId
|
||||
},
|
||||
onCompleted: machineEventsLazy => {
|
||||
const message = !isStaticState(getState(machineEventsLazy))
|
||||
? warningMessage
|
||||
: null
|
||||
setAction(action => ({ ...action, message }))
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const [machineAction, { loading }] = useMutation(MACHINE_ACTION, {
|
||||
onError: ({ message }) => {
|
||||
const errorMessage = message ?? 'An error ocurred'
|
||||
setErrorMessage(errorMessage)
|
||||
},
|
||||
onCompleted: () => {
|
||||
onActionSuccess && onActionSuccess()
|
||||
setAction({ command: null })
|
||||
}
|
||||
})
|
||||
|
||||
const confirmDialogOpen = Boolean(action.command)
|
||||
const disabled = !!(action?.command === 'restartServices' && loadingEvents)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Label>Actions</Label>
|
||||
<div className={classes.stack}>
|
||||
<ActionButton
|
||||
color="primary"
|
||||
className={classes.mr}
|
||||
Icon={EditIcon}
|
||||
InverseIcon={EditReversedIcon}
|
||||
disabled={loading}
|
||||
onClick={() =>
|
||||
setAction({
|
||||
command: 'rename',
|
||||
display: 'Rename',
|
||||
confirmationMessage: 'Write the new name for this machine'
|
||||
})
|
||||
}>
|
||||
Rename
|
||||
</ActionButton>
|
||||
<ActionButton
|
||||
color="primary"
|
||||
className={classes.mr}
|
||||
Icon={UnpairIcon}
|
||||
InverseIcon={UnpairReversedIcon}
|
||||
disabled={loading}
|
||||
onClick={() =>
|
||||
setAction({
|
||||
command: 'unpair',
|
||||
display: 'Unpair'
|
||||
})
|
||||
}>
|
||||
Unpair
|
||||
</ActionButton>
|
||||
<ActionButton
|
||||
color="primary"
|
||||
className={classes.mr}
|
||||
Icon={RebootIcon}
|
||||
InverseIcon={RebootReversedIcon}
|
||||
disabled={loading}
|
||||
onClick={() =>
|
||||
setAction({
|
||||
command: 'reboot',
|
||||
display: 'Reboot'
|
||||
})
|
||||
}>
|
||||
Reboot
|
||||
</ActionButton>
|
||||
<ActionButton
|
||||
color="primary"
|
||||
className={classes.mr}
|
||||
Icon={ShutdownIcon}
|
||||
InverseIcon={ShutdownReversedIcon}
|
||||
disabled={loading}
|
||||
onClick={() =>
|
||||
setAction({
|
||||
command: 'shutdown',
|
||||
display: 'Shutdown',
|
||||
message:
|
||||
'In order to bring it back online, the machine will need to be visited and its power reset.'
|
||||
})
|
||||
}>
|
||||
Shutdown
|
||||
</ActionButton>
|
||||
<ActionButton
|
||||
color="primary"
|
||||
className={classes.inlineChip}
|
||||
Icon={RebootIcon}
|
||||
InverseIcon={RebootReversedIcon}
|
||||
disabled={loading}
|
||||
onClick={() => {
|
||||
fetchMachineEvents()
|
||||
setAction({
|
||||
command: 'restartServices',
|
||||
display: 'Restart services for'
|
||||
})
|
||||
}}>
|
||||
Restart Services
|
||||
</ActionButton>
|
||||
</div>
|
||||
<ConfirmDialog
|
||||
disabled={disabled}
|
||||
open={confirmDialogOpen}
|
||||
title={`${action?.display} this machine?`}
|
||||
errorMessage={errorMessage}
|
||||
toBeConfirmed={machine.name}
|
||||
message={action?.message}
|
||||
confirmationMessage={action?.confirmationMessage}
|
||||
saveButtonAlwaysEnabled={action?.command === 'rename'}
|
||||
onConfirmed={value => {
|
||||
setErrorMessage(null)
|
||||
machineAction({
|
||||
variables: {
|
||||
deviceId: machine.deviceId,
|
||||
action: `${action?.command}`,
|
||||
...(action?.command === 'rename' && { newName: value })
|
||||
}
|
||||
})
|
||||
}}
|
||||
onDissmised={() => {
|
||||
setAction({ command: null })
|
||||
setErrorMessage(null)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
export default MachineActions
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
import { fade } from '@material-ui/core/styles/colorManipulator'
|
||||
|
||||
import typographyStyles from 'src/components/typography/styles'
|
||||
import {
|
||||
offColor,
|
||||
spacer,
|
||||
comet,
|
||||
primaryColor,
|
||||
fontSize4,
|
||||
errorColor
|
||||
} from 'src/styling/variables'
|
||||
|
||||
const { label1 } = typographyStyles
|
||||
|
||||
const machineActionsStyles = {
|
||||
colDivider: {
|
||||
width: 1,
|
||||
margin: [[spacer * 2, spacer * 4]],
|
||||
backgroundColor: comet,
|
||||
border: 'none'
|
||||
},
|
||||
label: {
|
||||
extend: label1,
|
||||
color: offColor,
|
||||
marginBottom: 4
|
||||
},
|
||||
inlineChip: {
|
||||
marginInlineEnd: '0.25em'
|
||||
},
|
||||
stack: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'start'
|
||||
},
|
||||
wrapper: {
|
||||
display: 'flex',
|
||||
// marginTop: 24,
|
||||
// marginBottom: 32,
|
||||
marginTop: 12,
|
||||
marginBottom: 16,
|
||||
fontSize: fontSize4
|
||||
},
|
||||
row: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row'
|
||||
// marginBottom: 36
|
||||
},
|
||||
list: {
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
listStyle: 'none'
|
||||
},
|
||||
item: {
|
||||
height: spacer * 3,
|
||||
marginBottom: spacer * 1.5
|
||||
},
|
||||
link: {
|
||||
color: primaryColor,
|
||||
textDecoration: 'none'
|
||||
},
|
||||
divider: {
|
||||
margin: '0 1rem'
|
||||
},
|
||||
mr: {
|
||||
marginRight: spacer,
|
||||
marginBottom: spacer
|
||||
},
|
||||
separator: {
|
||||
width: 1,
|
||||
height: 170,
|
||||
zIndex: 1,
|
||||
marginRight: 60,
|
||||
marginLeft: 'auto',
|
||||
background: fade(comet, 0.5)
|
||||
},
|
||||
warning: {
|
||||
color: errorColor
|
||||
}
|
||||
}
|
||||
|
||||
export { machineActionsStyles }
|
||||
|
|
@ -1,35 +1,14 @@
|
|||
import { useMutation } from '@apollo/react-hooks'
|
||||
import { makeStyles } from '@material-ui/core/styles'
|
||||
import gql from 'graphql-tag'
|
||||
import moment from 'moment'
|
||||
import React, { useState } from 'react'
|
||||
import React from 'react'
|
||||
|
||||
import { ConfirmDialog } from 'src/components/ConfirmDialog'
|
||||
import { Status } from 'src/components/Status'
|
||||
import ActionButton from 'src/components/buttons/ActionButton'
|
||||
import MachineActions from 'src/components/machineActions/MachineActions'
|
||||
import { H3, Label3, P } from 'src/components/typography'
|
||||
import { ReactComponent as RebootReversedIcon } from 'src/styling/icons/button/reboot/white.svg'
|
||||
import { ReactComponent as RebootIcon } from 'src/styling/icons/button/reboot/zodiac.svg'
|
||||
import { ReactComponent as ShutdownReversedIcon } from 'src/styling/icons/button/shut down/white.svg'
|
||||
import { ReactComponent as ShutdownIcon } from 'src/styling/icons/button/shut down/zodiac.svg'
|
||||
import { ReactComponent as UnpairReversedIcon } from 'src/styling/icons/button/unpair/white.svg'
|
||||
import { ReactComponent as UnpairIcon } from 'src/styling/icons/button/unpair/zodiac.svg'
|
||||
|
||||
import styles from '../Machines.styles'
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
const MACHINE_ACTION = gql`
|
||||
mutation MachineAction(
|
||||
$deviceId: ID!
|
||||
$action: MachineAction!
|
||||
$newName: String
|
||||
) {
|
||||
machineAction(deviceId: $deviceId, action: $action, newName: $newName) {
|
||||
deviceId
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const makeLastPing = lastPing => {
|
||||
if (!lastPing) return null
|
||||
const now = moment()
|
||||
|
|
@ -50,25 +29,8 @@ const makeLastPing = lastPing => {
|
|||
}
|
||||
|
||||
const Overview = ({ data, onActionSuccess }) => {
|
||||
const [action, setAction] = useState('')
|
||||
const [confirmActionDialogOpen, setConfirmActionDialogOpen] = useState(false)
|
||||
const [errorMessage, setErrorMessage] = useState(null)
|
||||
const classes = useStyles()
|
||||
|
||||
const [machineAction] = useMutation(MACHINE_ACTION, {
|
||||
onError: ({ message }) => {
|
||||
const errorMessage = message ?? 'An error ocurred'
|
||||
setErrorMessage(errorMessage)
|
||||
},
|
||||
onCompleted: () => {
|
||||
onActionSuccess && onActionSuccess()
|
||||
setConfirmActionDialogOpen(false)
|
||||
}
|
||||
})
|
||||
|
||||
const confirmActionDialog = action =>
|
||||
setAction(action) || setConfirmActionDialogOpen(true)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={classes.row}>
|
||||
|
|
@ -90,57 +52,11 @@ const Overview = ({ data, onActionSuccess }) => {
|
|||
</div>
|
||||
<div className={classes.row}>
|
||||
<div className={classes.rowItem}>
|
||||
{' '}
|
||||
<Label3 className={classes.label3}>Actions</Label3>
|
||||
{data.name && (
|
||||
<div className={classes.actionButtonsContainer}>
|
||||
<ActionButton
|
||||
color="primary"
|
||||
className={classes.actionButton}
|
||||
Icon={UnpairIcon}
|
||||
InverseIcon={UnpairReversedIcon}
|
||||
onClick={() => confirmActionDialog('Unpair')}>
|
||||
Unpair
|
||||
</ActionButton>
|
||||
<ActionButton
|
||||
color="primary"
|
||||
className={classes.actionButton}
|
||||
Icon={RebootIcon}
|
||||
InverseIcon={RebootReversedIcon}
|
||||
onClick={() => confirmActionDialog('Reboot')}>
|
||||
Reboot
|
||||
</ActionButton>
|
||||
<ActionButton
|
||||
className={classes.actionButton}
|
||||
color="primary"
|
||||
Icon={ShutdownIcon}
|
||||
InverseIcon={ShutdownReversedIcon}
|
||||
onClick={() => confirmActionDialog('Shutdown')}>
|
||||
Shutdown
|
||||
</ActionButton>
|
||||
</div>
|
||||
)}
|
||||
<MachineActions
|
||||
machine={data}
|
||||
onActionSuccess={onActionSuccess}></MachineActions>
|
||||
</div>
|
||||
</div>
|
||||
<ConfirmDialog
|
||||
open={confirmActionDialogOpen}
|
||||
title={`${action} this machine?`}
|
||||
errorMessage={errorMessage}
|
||||
toBeConfirmed={data.name}
|
||||
onConfirmed={() => {
|
||||
setErrorMessage(null)
|
||||
machineAction({
|
||||
variables: {
|
||||
deviceId: data.deviceId,
|
||||
action: `${action}`.toLowerCase()
|
||||
}
|
||||
})
|
||||
}}
|
||||
onDissmised={() => {
|
||||
setConfirmActionDialogOpen(false)
|
||||
setErrorMessage(null)
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@ import { makeStyles } from '@material-ui/core/styles'
|
|||
import NavigateNextIcon from '@material-ui/icons/NavigateNext'
|
||||
import classnames from 'classnames'
|
||||
import gql from 'graphql-tag'
|
||||
import * as R from 'ramda'
|
||||
import React from 'react'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { Link, useLocation } from 'react-router-dom'
|
||||
|
||||
import { TL1, TL2, Label3 } from 'src/components/typography'
|
||||
|
|
@ -19,11 +18,9 @@ import Transactions from './MachineComponents/Transactions'
|
|||
import styles from './Machines.styles'
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
const getMachineInfo = R.compose(R.find, R.propEq('name'))
|
||||
|
||||
const GET_INFO = gql`
|
||||
query getInfo {
|
||||
machines {
|
||||
query getMachine($deviceId: ID!) {
|
||||
machine(deviceId: $deviceId) {
|
||||
name
|
||||
deviceId
|
||||
paired
|
||||
|
|
@ -38,24 +35,34 @@ const GET_INFO = gql`
|
|||
label
|
||||
type
|
||||
}
|
||||
latestEvent {
|
||||
note
|
||||
}
|
||||
}
|
||||
config
|
||||
}
|
||||
`
|
||||
|
||||
const getMachines = R.path(['machines'])
|
||||
const getMachineID = path => path.slice(path.lastIndexOf('/') + 1)
|
||||
|
||||
const Machines = () => {
|
||||
const { data, refetch } = useQuery(GET_INFO)
|
||||
const location = useLocation()
|
||||
const [machine, setMachine] = useState({})
|
||||
const [config, setConfig] = useState({})
|
||||
const { data, refetch } = useQuery(GET_INFO, {
|
||||
variables: {
|
||||
deviceId: getMachineID(location.pathname)
|
||||
},
|
||||
onCompleted: () => {
|
||||
setMachine(data.machine)
|
||||
setConfig(data.config)
|
||||
}
|
||||
})
|
||||
const classes = useStyles()
|
||||
|
||||
const selectedMachine =
|
||||
R.path(['state', 'selectedMachine'])(location) ??
|
||||
R.path(['machines', 0, 'name'])(data) ??
|
||||
''
|
||||
const machines = getMachines(data) ?? []
|
||||
const machineInfo = getMachineInfo(selectedMachine)(machines) ?? {}
|
||||
useEffect(() => {
|
||||
if (data) setMachine(data.machine)
|
||||
}, [data])
|
||||
|
||||
return (
|
||||
<Grid container className={classes.grid}>
|
||||
|
|
@ -69,10 +76,10 @@ const Machines = () => {
|
|||
</Label3>
|
||||
</Link>
|
||||
<TL2 noMargin className={classes.subtitle}>
|
||||
{selectedMachine}
|
||||
{machine.name}
|
||||
</TL2>
|
||||
</Breadcrumbs>
|
||||
<Overview data={machineInfo} onActionSuccess={refetch} />
|
||||
<Overview data={machine} onActionSuccess={refetch} />
|
||||
</div>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
|
|
@ -90,26 +97,23 @@ const Machines = () => {
|
|||
<div
|
||||
className={classnames(classes.detailItem, classes.detailsMargin)}>
|
||||
<TL1 className={classes.subtitle}>{'Details'}</TL1>
|
||||
<Details data={machineInfo} />
|
||||
<Details data={machine} />
|
||||
</div>
|
||||
<div className={classes.detailItem}>
|
||||
<TL1 className={classes.subtitle}>{'Cash cassettes'}</TL1>
|
||||
<Cassettes
|
||||
refetchData={refetch}
|
||||
machine={machineInfo}
|
||||
config={data?.config ?? false}
|
||||
machine={machine}
|
||||
config={config ?? false}
|
||||
/>
|
||||
</div>
|
||||
<div className={classes.transactionsItem}>
|
||||
<TL1 className={classes.subtitle}>{'Latest transactions'}</TL1>
|
||||
<Transactions id={machineInfo?.deviceId ?? null} />
|
||||
<Transactions id={machine?.deviceId ?? null} />
|
||||
</div>
|
||||
<div className={classes.detailItem}>
|
||||
<TL1 className={classes.subtitle}>{'Commissions'}</TL1>
|
||||
<Commissions
|
||||
name={'commissions'}
|
||||
id={machineInfo?.deviceId ?? null}
|
||||
/>
|
||||
<Commissions name={'commissions'} id={machine?.deviceId ?? null} />
|
||||
</div>
|
||||
</div>
|
||||
</Grid>
|
||||
|
|
|
|||
|
|
@ -1,47 +1,15 @@
|
|||
import { useMutation, useLazyQuery } from '@apollo/react-hooks'
|
||||
import { Grid /*, Divider */ } from '@material-ui/core'
|
||||
import { makeStyles } from '@material-ui/core/styles'
|
||||
import gql from 'graphql-tag'
|
||||
import moment from 'moment'
|
||||
import React, { useState } from 'react'
|
||||
import React from 'react'
|
||||
|
||||
import MachineActions from 'src/components/machineActions/MachineActions'
|
||||
|
||||
import { ConfirmDialog } from 'src/components/ConfirmDialog'
|
||||
// import { Status } from 'src/components/Status'
|
||||
import ActionButton from 'src/components/buttons/ActionButton'
|
||||
import { ReactComponent as EditReversedIcon } from 'src/styling/icons/button/edit/white.svg'
|
||||
import { ReactComponent as EditIcon } from 'src/styling/icons/button/edit/zodiac.svg'
|
||||
// import { ReactComponent as LinkIcon } from 'src/styling/icons/button/link/zodiac.svg'
|
||||
import { ReactComponent as RebootReversedIcon } from 'src/styling/icons/button/reboot/white.svg'
|
||||
import { ReactComponent as RebootIcon } from 'src/styling/icons/button/reboot/zodiac.svg'
|
||||
import { ReactComponent as ShutdownReversedIcon } from 'src/styling/icons/button/shut down/white.svg'
|
||||
import { ReactComponent as ShutdownIcon } from 'src/styling/icons/button/shut down/zodiac.svg'
|
||||
import { ReactComponent as UnpairReversedIcon } from 'src/styling/icons/button/unpair/white.svg'
|
||||
import { ReactComponent as UnpairIcon } from 'src/styling/icons/button/unpair/zodiac.svg'
|
||||
|
||||
import { labelStyles, machineDetailsStyles } from './MachineDetailsCard.styles'
|
||||
|
||||
const MACHINE_ACTION = gql`
|
||||
mutation MachineAction(
|
||||
$deviceId: ID!
|
||||
$action: MachineAction!
|
||||
$newName: String
|
||||
) {
|
||||
machineAction(deviceId: $deviceId, action: $action, newName: $newName) {
|
||||
deviceId
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const MACHINE = gql`
|
||||
query getMachine($deviceId: ID!) {
|
||||
machine(deviceId: $deviceId) {
|
||||
latestEvent {
|
||||
note
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
// const supportArtices = [
|
||||
// {
|
||||
// // Default article for non-maped statuses
|
||||
|
|
@ -53,24 +21,6 @@ const MACHINE = gql`
|
|||
// // TODO add Stuck and Fully Functional statuses articles for the new-admins
|
||||
// ]
|
||||
|
||||
const isStaticState = machineState => {
|
||||
if (!machineState) {
|
||||
return true
|
||||
}
|
||||
const staticStates = [
|
||||
'chooseCoin',
|
||||
'idle',
|
||||
'pendingIdle',
|
||||
'dualIdle',
|
||||
'networkDown',
|
||||
'unpaired',
|
||||
'maintenance',
|
||||
'virgin',
|
||||
'wifiList'
|
||||
]
|
||||
return staticStates.includes(machineState)
|
||||
}
|
||||
|
||||
// const article = ({ code: status }) =>
|
||||
// supportArtices.find(({ code: article }) => article === status)
|
||||
|
||||
|
|
@ -96,51 +46,9 @@ const Item = ({ children, ...props }) => (
|
|||
</Grid>
|
||||
)
|
||||
|
||||
const getState = machineEventsLazy =>
|
||||
JSON.parse(machineEventsLazy.machine.latestEvent?.note ?? '{"state": null}')
|
||||
.state
|
||||
|
||||
const MachineDetailsRow = ({ it: machine, onActionSuccess }) => {
|
||||
const [action, setAction] = useState({ command: null })
|
||||
const [errorMessage, setErrorMessage] = useState(null)
|
||||
const classes = useMDStyles()
|
||||
|
||||
const warningMessage = (
|
||||
<span className={classes.warning}>
|
||||
A user may be in the middle of a transaction and they could lose their
|
||||
funds if you continue.
|
||||
</span>
|
||||
)
|
||||
|
||||
const [fetchMachineEvents, { loading: loadingEvents }] = useLazyQuery(
|
||||
MACHINE,
|
||||
{
|
||||
variables: {
|
||||
deviceId: machine.deviceId
|
||||
},
|
||||
onCompleted: machineEventsLazy => {
|
||||
const message = !isStaticState(getState(machineEventsLazy))
|
||||
? warningMessage
|
||||
: null
|
||||
setAction(action => ({ ...action, message }))
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const [machineAction, { loading }] = useMutation(MACHINE_ACTION, {
|
||||
onError: ({ message }) => {
|
||||
const errorMessage = message ?? 'An error ocurred'
|
||||
setErrorMessage(errorMessage)
|
||||
},
|
||||
onCompleted: () => {
|
||||
onActionSuccess && onActionSuccess()
|
||||
setAction({ command: null })
|
||||
}
|
||||
})
|
||||
|
||||
const confirmDialogOpen = Boolean(action.command)
|
||||
const disabled = !!(action?.command === 'restartServices' && loadingEvents)
|
||||
|
||||
return (
|
||||
<Container className={classes.wrapper}>
|
||||
{/* <Item xs={5}>
|
||||
|
|
@ -180,30 +88,6 @@ const MachineDetailsRow = ({ it: machine, onActionSuccess }) => {
|
|||
flexItem
|
||||
className={classes.separator}
|
||||
/> */}
|
||||
<ConfirmDialog
|
||||
disabled={disabled}
|
||||
open={confirmDialogOpen}
|
||||
title={`${action?.display} this machine?`}
|
||||
errorMessage={errorMessage}
|
||||
toBeConfirmed={machine.name}
|
||||
message={action?.message}
|
||||
confirmationMessage={action?.confirmationMessage}
|
||||
saveButtonAlwaysEnabled={action?.command === 'rename'}
|
||||
onConfirmed={value => {
|
||||
setErrorMessage(null)
|
||||
machineAction({
|
||||
variables: {
|
||||
deviceId: machine.deviceId,
|
||||
action: `${action?.command}`,
|
||||
...(action?.command === 'rename' && { newName: value })
|
||||
}
|
||||
})
|
||||
}}
|
||||
onDissmised={() => {
|
||||
setAction({ command: null })
|
||||
setErrorMessage(null)
|
||||
}}
|
||||
/>
|
||||
<Item xs>
|
||||
<Container className={classes.row}>
|
||||
<Item xs={2}>
|
||||
|
|
@ -217,166 +101,11 @@ const MachineDetailsRow = ({ it: machine, onActionSuccess }) => {
|
|||
</span>
|
||||
</Item>
|
||||
<Item xs={6}>
|
||||
<Label>Actions</Label>
|
||||
<div className={classes.stack}>
|
||||
<ActionButton
|
||||
className={classes.mr}
|
||||
disabled={loading}
|
||||
color="primary"
|
||||
Icon={EditIcon}
|
||||
InverseIcon={EditReversedIcon}
|
||||
onClick={() =>
|
||||
setAction({
|
||||
command: 'rename',
|
||||
display: 'Rename',
|
||||
confirmationMessage: 'Write the new name for this machine'
|
||||
})
|
||||
}>
|
||||
Rename
|
||||
</ActionButton>
|
||||
<ActionButton
|
||||
color="primary"
|
||||
className={classes.mr}
|
||||
Icon={UnpairIcon}
|
||||
InverseIcon={UnpairReversedIcon}
|
||||
disabled={loading}
|
||||
onClick={() =>
|
||||
setAction({
|
||||
command: 'unpair',
|
||||
display: 'Unpair'
|
||||
})
|
||||
}>
|
||||
Unpair
|
||||
</ActionButton>
|
||||
<ActionButton
|
||||
color="primary"
|
||||
className={classes.mr}
|
||||
Icon={RebootIcon}
|
||||
InverseIcon={RebootReversedIcon}
|
||||
disabled={loading}
|
||||
onClick={() =>
|
||||
setAction({
|
||||
command: 'reboot',
|
||||
display: 'Reboot'
|
||||
})
|
||||
}>
|
||||
Reboot
|
||||
</ActionButton>
|
||||
<ActionButton
|
||||
className={classes.mr}
|
||||
disabled={loading}
|
||||
color="primary"
|
||||
Icon={ShutdownIcon}
|
||||
InverseIcon={ShutdownReversedIcon}
|
||||
onClick={() =>
|
||||
setAction({
|
||||
command: 'shutdown',
|
||||
display: 'Shutdown',
|
||||
message:
|
||||
'In order to bring it back online, the machine will need to be visited and its power reset.'
|
||||
})
|
||||
}>
|
||||
Shutdown
|
||||
</ActionButton>
|
||||
<ActionButton
|
||||
color="primary"
|
||||
className={classes.inlineChip}
|
||||
Icon={RebootIcon}
|
||||
InverseIcon={RebootReversedIcon}
|
||||
disabled={loading}
|
||||
onClick={() => {
|
||||
fetchMachineEvents()
|
||||
setAction({
|
||||
command: 'restartServices',
|
||||
display: 'Restart services for'
|
||||
})
|
||||
}}>
|
||||
Restart Services
|
||||
</ActionButton>
|
||||
</div>
|
||||
<MachineActions
|
||||
machine={machine}
|
||||
onActionSuccess={onActionSuccess}></MachineActions>
|
||||
</Item>
|
||||
</Container>
|
||||
{/* <Container>
|
||||
<Item>
|
||||
<Label>Actions</Label>
|
||||
<div className={classes.stack}>
|
||||
<ActionButton
|
||||
className={classes.mr}
|
||||
disabled={loading}
|
||||
color="primary"
|
||||
Icon={EditIcon}
|
||||
InverseIcon={EditReversedIcon}
|
||||
onClick={() =>
|
||||
setAction({
|
||||
command: 'rename',
|
||||
display: 'Rename',
|
||||
confirmationMessage: 'Write the new name for this machine'
|
||||
})
|
||||
}>
|
||||
Rename
|
||||
</ActionButton>
|
||||
<ActionButton
|
||||
color="primary"
|
||||
className={classes.mr}
|
||||
Icon={UnpairIcon}
|
||||
InverseIcon={UnpairReversedIcon}
|
||||
disabled={loading}
|
||||
onClick={() =>
|
||||
setAction({
|
||||
command: 'unpair',
|
||||
display: 'Unpair'
|
||||
})
|
||||
}>
|
||||
Unpair
|
||||
</ActionButton>
|
||||
<ActionButton
|
||||
color="primary"
|
||||
className={classes.mr}
|
||||
Icon={RebootIcon}
|
||||
InverseIcon={RebootReversedIcon}
|
||||
disabled={loading}
|
||||
onClick={() =>
|
||||
setAction({
|
||||
command: 'reboot',
|
||||
display: 'Reboot'
|
||||
})
|
||||
}>
|
||||
Reboot
|
||||
</ActionButton>
|
||||
<ActionButton
|
||||
className={classes.mr}
|
||||
disabled={loading}
|
||||
color="primary"
|
||||
Icon={ShutdownIcon}
|
||||
InverseIcon={ShutdownReversedIcon}
|
||||
onClick={() =>
|
||||
setAction({
|
||||
command: 'shutdown',
|
||||
display: 'Shutdown',
|
||||
message:
|
||||
'In order to bring it back online, the machine will need to be visited and its power reset.'
|
||||
})
|
||||
}>
|
||||
Shutdown
|
||||
</ActionButton>
|
||||
<ActionButton
|
||||
color="primary"
|
||||
className={classes.inlineChip}
|
||||
Icon={RebootIcon}
|
||||
InverseIcon={RebootReversedIcon}
|
||||
disabled={loading}
|
||||
onClick={() => {
|
||||
fetchMachineEvents()
|
||||
setAction({
|
||||
command: 'restartServices',
|
||||
display: 'Restart services for'
|
||||
})
|
||||
}}>
|
||||
Restart Services
|
||||
</ActionButton>
|
||||
</div>
|
||||
</Item>
|
||||
</Container> */}
|
||||
</Item>
|
||||
</Container>
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue