mirror of
https://github.com/OpenNebula/one.git
synced 2024-12-23 17:33:56 +03:00
parent
5e09101b92
commit
8b03aae0fa
@ -44,7 +44,10 @@ const DatastoreCard = memo(
|
||||
/>
|
||||
)
|
||||
},
|
||||
(prev, next) => prev.isSelected === next.isSelected
|
||||
(prev, next) => (
|
||||
prev.isSelected === next.isSelected &&
|
||||
prev.value?.STATE === next.value?.STATE
|
||||
)
|
||||
)
|
||||
|
||||
DatastoreCard.propTypes = {
|
||||
|
@ -26,7 +26,7 @@ const HostCard = memo(
|
||||
stylesProps={{ minHeight: 160 }}
|
||||
cardProps={{ className: classes.card, elevation: 2 }}
|
||||
icon={
|
||||
<StatusBadge stateColor={state.color}>
|
||||
<StatusBadge title={state?.name} stateColor={state.color}>
|
||||
<HostIcon />
|
||||
</StatusBadge>
|
||||
}
|
||||
@ -46,7 +46,10 @@ const HostCard = memo(
|
||||
/>
|
||||
)
|
||||
},
|
||||
(prev, next) => prev.isSelected === next.isSelected
|
||||
(prev, next) => (
|
||||
prev.isSelected === next.isSelected &&
|
||||
prev.value?.STATE === next.value?.STATE
|
||||
)
|
||||
)
|
||||
|
||||
HostCard.propTypes = {
|
||||
|
@ -49,7 +49,7 @@ const ProvisionCard = memo(
|
||||
isProvider ? (
|
||||
<ProviderIcon />
|
||||
) : (
|
||||
<StatusBadge stateColor={stateInfo?.color}>
|
||||
<StatusBadge title={stateInfo?.name} stateColor={stateInfo?.color}>
|
||||
<ProvisionIcon />
|
||||
</StatusBadge>
|
||||
)
|
||||
@ -62,7 +62,12 @@ const ProvisionCard = memo(
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}, (prev, next) => prev.isSelected === next.isSelected
|
||||
}, (prev, next) => (
|
||||
prev.isSelected === next.isSelected &&
|
||||
!prev.isProvider &&
|
||||
!next.isProvider &&
|
||||
prev.value?.BODY?.state === next.value?.BODY?.state
|
||||
)
|
||||
)
|
||||
|
||||
ProvisionCard.propTypes = {
|
||||
|
@ -96,7 +96,7 @@ ansiHTML.setColors = function (colors) {
|
||||
|
||||
var _finalColors = {}
|
||||
for (var key in _defColors) {
|
||||
var hex = colors.hasOwnProperty(key) ? colors[key] : null
|
||||
var hex = Object.prototype.hasOwnProperty.call(colors, key) ? colors[key] : null
|
||||
if (!hex) {
|
||||
_finalColors[key] = _defColors[key]
|
||||
continue
|
||||
|
@ -4,6 +4,7 @@ import clsx from 'clsx'
|
||||
|
||||
import { makeStyles } from '@material-ui/core'
|
||||
import ChevronRightIcon from '@material-ui/icons/ChevronRight'
|
||||
import ExpandMoreIcon from '@material-ui/icons/ExpandMore'
|
||||
|
||||
import { DEBUG_LEVEL } from 'client/constants'
|
||||
import AnsiHtml from 'client/components/DebugLog/ansiHtml'
|
||||
@ -16,7 +17,7 @@ const useStyles = makeStyles(theme => ({
|
||||
alignItems: 'center',
|
||||
marginBottom: '0.3em',
|
||||
padding: '0.5em 0',
|
||||
cursor: ({ isCollapsed }) => isCollapsed ? 'pointer' : 'default',
|
||||
cursor: ({ isMoreThanMaxChars }) => isMoreThanMaxChars ? 'pointer' : 'default',
|
||||
fontFamily: 'monospace',
|
||||
'&:hover': {
|
||||
background: '#333537'
|
||||
@ -43,29 +44,35 @@ const useStyles = makeStyles(theme => ({
|
||||
// --------------------------------------------
|
||||
|
||||
const Message = memo(({ timestamp, severity, message }) => {
|
||||
const [isCollapsed, setCollapse] = useState(() => message?.length >= MAX_CHARS)
|
||||
const classes = useStyles({ isCollapsed })
|
||||
const sanitize = AnsiHtml(message)
|
||||
const isMoreThanMaxChars = message?.length >= MAX_CHARS
|
||||
const [isCollapsed, setCollapse] = useState(() => isMoreThanMaxChars)
|
||||
const classes = useStyles({ isMoreThanMaxChars })
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(classes.root, classes[severity])}
|
||||
onClick={() => setCollapse(false)}
|
||||
onClick={() => setCollapse(prev => !prev)}
|
||||
>
|
||||
<div className={classes.arrow}>
|
||||
{isCollapsed && <ChevronRightIcon fontSize='small' />}
|
||||
{isMoreThanMaxChars && (isCollapsed ? (
|
||||
<ChevronRightIcon fontSize='small' />
|
||||
) : (
|
||||
<ExpandMoreIcon fontSize='small' />
|
||||
))}
|
||||
</div>
|
||||
<div className={classes.time}>{timestamp}</div>
|
||||
<div className={classes.message}>
|
||||
{isCollapsed ? `${sanitize.slice(0, MAX_CHARS)}...` : sanitize}
|
||||
</div>
|
||||
{(isCollapsed && isMoreThanMaxChars) ? (
|
||||
<div className={classes.message}>{`${message?.slice(0, MAX_CHARS)}…`}</div>
|
||||
) : (
|
||||
<div className={classes.message} dangerouslySetInnerHTML={{ __html: AnsiHtml(message) }} />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
Message.propTypes = {
|
||||
timestamp: PropTypes.string,
|
||||
severity: PropTypes.oneOf([Object.keys(DEBUG_LEVEL)]),
|
||||
severity: PropTypes.oneOf(Object.keys(DEBUG_LEVEL)),
|
||||
message: PropTypes.string
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ const useStyles = makeStyles(theme => ({
|
||||
}
|
||||
}))
|
||||
|
||||
const StatusBadge = memo(({ stateColor, children }) => {
|
||||
const StatusBadge = memo(({ stateColor, children, ...props }) => {
|
||||
const classes = useStyles({ stateColor })
|
||||
|
||||
return (
|
||||
@ -41,6 +41,7 @@ const StatusBadge = memo(({ stateColor, children }) => {
|
||||
classes={{ badge: classes.badge }}
|
||||
overlap="circle"
|
||||
variant="dot"
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</Badge>
|
||||
|
@ -2,6 +2,7 @@ import React, { useState, useEffect, createElement } from 'react'
|
||||
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import { Container, Box } from '@material-ui/core'
|
||||
import EditIcon from '@material-ui/icons/Settings'
|
||||
import DeleteIcon from '@material-ui/icons/Delete'
|
||||
|
||||
import { PATH } from 'client/router/provision'
|
||||
@ -18,7 +19,13 @@ function Provisions () {
|
||||
const history = useHistory()
|
||||
const [showDialog, setShowDialog] = useState(false)
|
||||
|
||||
const { provisions, getProvisions, getProvision, deleteProvision } = useProvision()
|
||||
const {
|
||||
provisions,
|
||||
getProvisions,
|
||||
getProvision,
|
||||
configureProvision,
|
||||
deleteProvision
|
||||
} = useProvision()
|
||||
|
||||
const { error, fetchRequest, loading, reloading } = useFetch(getProvisions)
|
||||
const { result, handleChange } = useSearch({
|
||||
@ -56,19 +63,26 @@ function Provisions () {
|
||||
subheader: `#${ID}`,
|
||||
content: DialogInfo
|
||||
}),
|
||||
actions: [{
|
||||
handleClick: () => setShowDialog({
|
||||
id: ID,
|
||||
title: `DELETE provision - #${ID} - ${NAME}`,
|
||||
handleAccept: () => {
|
||||
deleteProvision({ id: ID })
|
||||
setShowDialog(false)
|
||||
},
|
||||
content: DialogInfo
|
||||
}),
|
||||
icon: <DeleteIcon color='error' />,
|
||||
cy: `provision-delete-${ID}`
|
||||
}]
|
||||
actions: [
|
||||
{
|
||||
handleClick: () => configureProvision({ id: ID }),
|
||||
icon: <EditIcon />,
|
||||
cy: `provision-configure-${ID}`
|
||||
},
|
||||
{
|
||||
handleClick: () => setShowDialog({
|
||||
id: ID,
|
||||
title: `DELETE provision - #${ID} - ${NAME}`,
|
||||
handleAccept: () => {
|
||||
deleteProvision({ id: ID })
|
||||
setShowDialog(false)
|
||||
},
|
||||
content: DialogInfo
|
||||
}),
|
||||
icon: <DeleteIcon color='error' />,
|
||||
cy: `provision-delete-${ID}`
|
||||
}
|
||||
]
|
||||
})}
|
||||
breakpoints={{ xs: 12, sm: 6, md: 4 }}
|
||||
/>
|
||||
|
@ -142,6 +142,18 @@ export default function useProvision () {
|
||||
[dispatch]
|
||||
)
|
||||
|
||||
const configureProvision = useCallback(
|
||||
({ id }) =>
|
||||
serviceProvision
|
||||
.configureProvision({ id })
|
||||
.then(doc => {
|
||||
dispatch(enqueueSuccess(`Provision configuring - ID: ${id}`))
|
||||
return doc
|
||||
})
|
||||
.catch(err => dispatch(enqueueError(err ?? 'Error CONFIGURE provision')))
|
||||
, [dispatch]
|
||||
)
|
||||
|
||||
const deleteProvision = useCallback(
|
||||
({ id }) =>
|
||||
serviceProvision
|
||||
@ -227,6 +239,7 @@ export default function useProvision () {
|
||||
getProvision,
|
||||
getProvisions,
|
||||
createProvision,
|
||||
configureProvision,
|
||||
deleteProvision,
|
||||
getProvisionLog,
|
||||
|
||||
|
@ -62,6 +62,19 @@ export const createProvision = ({ data = {} }) =>
|
||||
return res?.data ?? {}
|
||||
})
|
||||
|
||||
export const configureProvision = ({ id }) =>
|
||||
requestData(`/api/${PROVISION}/configure/${id}`, {
|
||||
method: PUT,
|
||||
error: err => err?.message
|
||||
}).then(res => {
|
||||
if (!res?.id || res?.id !== httpCodes.ok.id) {
|
||||
if (res?.id === httpCodes.accepted.id) return res
|
||||
throw res
|
||||
}
|
||||
|
||||
return res?.data ?? {}
|
||||
})
|
||||
|
||||
export const deleteProvision = ({ id }) =>
|
||||
requestData(`/api/${PROVISION}/delete/${id}`, {
|
||||
method: DELETE,
|
||||
|
@ -105,13 +105,6 @@ const routes = {
|
||||
resource: { from: fromData.postBody, front: true }
|
||||
}
|
||||
},
|
||||
configure: {
|
||||
action: configureProvision,
|
||||
params: {
|
||||
resource: { from: fromData.resource, name: 'method' }
|
||||
},
|
||||
websocket: true
|
||||
},
|
||||
host: {
|
||||
poweroff: {
|
||||
action: hostCommand,
|
||||
@ -210,6 +203,13 @@ const routes = {
|
||||
}
|
||||
},
|
||||
[PUT]: {
|
||||
configure: {
|
||||
action: configureProvision,
|
||||
params: {
|
||||
id: { from: fromData.resource, name: 'id' }
|
||||
},
|
||||
websocket: true
|
||||
},
|
||||
host: {
|
||||
action: configureHost,
|
||||
params: {
|
||||
|
Loading…
Reference in New Issue
Block a user