1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-16 22:50:10 +03:00
This commit is contained in:
Sergio Betanzos 2021-07-01 11:30:29 +02:00
parent ffceed0cef
commit e25b2ad18b
No known key found for this signature in database
GPG Key ID: E3E704F097737136
13 changed files with 242 additions and 15 deletions

View File

@ -16,11 +16,12 @@ import {
ServerConnection as NetworksIcon,
NetworkAlt as NetworkIcon,
Combine as NetworkTemplateIcon,
KeyframesCouple as NetworkTemplateIcon,
CloudSync as InfrastructureIcon,
Server as ClusterIcon,
HardDrive as HostIcon,
MinusPinAlt as ZoneIcon,
Home as SystemIcon,
User as UserIcon,
@ -53,7 +54,7 @@ const VNetworkTemplates = loadable(() => import('client/containers/VNetworkTempl
const Clusters = loadable(() => import('client/containers/Clusters'), { ssr: false })
const Hosts = loadable(() => import('client/containers/Hosts'), { ssr: false })
// const Zones = loadable(() => import('client/containers/Zones'), { ssr: false })
const Zones = loadable(() => import('client/containers/Zones'), { ssr: false })
const Users = loadable(() => import('client/containers/Users'), { ssr: false })
const Groups = loadable(() => import('client/containers/Groups'), { ssr: false })
@ -106,6 +107,9 @@ export const PATH = {
},
HOSTS: {
LIST: '/hosts'
},
ZONES: {
LIST: '/zones'
}
},
SYSTEM: {
@ -229,6 +233,13 @@ export const ENDPOINTS = [
sidebar: true,
icon: HostIcon,
Component: Hosts
},
{
label: 'Zones',
path: PATH.INFRASTRUCTURE.ZONES.LIST,
sidebar: true,
icon: ZoneIcon,
Component: Zones
}
]
},

View File

@ -0,0 +1,26 @@
import CategoryFilter from 'client/components/Tables/Enhanced/Utils/CategoryFilter'
import * as ZoneModel from 'client/models/Zone'
export default [
{ Header: 'ID', accessor: 'ID', sortType: 'number' },
{ Header: 'Name', accessor: 'NAME' },
{
Header: 'State',
id: 'STATE',
accessor: row => ZoneModel.getState(row)?.name,
disableFilters: false,
Filter: ({ column }) => CategoryFilter({
column,
multiple: true,
title: 'State'
}),
filter: 'includesValue'
},
{
Header: 'ENDPOINT',
id: 'ENDPOINT',
accessor: row => row?.TEMPLATE?.ENDPOINT,
disableSortBy: true
}
]

View File

@ -0,0 +1,36 @@
import React, { useEffect } from 'react'
import { useFetch } from 'client/hooks'
import { useZone, useZoneApi } from 'client/features/One'
import { SkeletonTable, EnhancedTable } from 'client/components/Tables'
import ZoneColumns from 'client/components/Tables/Zones/columns'
import ZoneRow from 'client/components/Tables/Zones/row'
const ZonesTable = () => {
const columns = React.useMemo(() => ZoneColumns, [])
const zones = useZone()
const { getZones } = useZoneApi()
const { status, fetchRequest, loading, reloading, STATUS } = useFetch(getZones)
const { INIT, PENDING } = STATUS
useEffect(() => { fetchRequest() }, [])
if (zones?.length === 0 && [INIT, PENDING].includes(status)) {
return <SkeletonTable />
}
return (
<EnhancedTable
columns={columns}
data={zones}
isLoading={loading || reloading}
getRowId={row => String(row.ID)}
RowComponent={ZoneRow}
/>
)
}
export default ZonesTable

View File

@ -0,0 +1,50 @@
import * as React from 'react'
import PropTypes from 'prop-types'
import { ShieldCheck } from 'iconoir-react'
import { Typography } from '@material-ui/core'
import { StatusCircle } from 'client/components/Status'
import { rowStyles } from 'client/components/Tables/styles'
import * as ZoneModel from 'client/models/Zone'
const Row = ({ original, value, ...props }) => {
const classes = rowStyles()
const { ID, NAME, ENDPOINT } = value
const { color: stateColor, name: stateName } = ZoneModel.getState(original)
return (
<div {...props}>
<div>
<StatusCircle color={stateColor} tooltip={stateName} />
</div>
<div className={classes.main}>
<div className={classes.title}>
<Typography className={classes.titleText} component='span'>
{NAME}
</Typography>
</div>
<div className={classes.caption}>
<span>
{`#${ID}`}
</span>
<span title={`Endpoint: ${ENDPOINT}`}>
<ShieldCheck size={16} />
<span>{` ${ENDPOINT}`}</span>
</span>
</div>
</div>
</div>
)
}
Row.propTypes = {
original: PropTypes.object,
value: PropTypes.object,
isSelected: PropTypes.bool,
handleClick: PropTypes.func
}
export default Row

View File

@ -13,6 +13,7 @@ import VmsTable from 'client/components/Tables/Vms'
import VmTemplatesTable from 'client/components/Tables/VmTemplates'
import VNetworksTable from 'client/components/Tables/VNetworks'
import VNetworkTemplatesTable from 'client/components/Tables/VNetworkTemplates'
import ZoneTable from 'client/components/Tables/Zones'
export {
SkeletonTable,
@ -30,5 +31,6 @@ export {
VmsTable,
VmTemplatesTable,
VNetworksTable,
VNetworkTemplatesTable
VNetworkTemplatesTable,
ZoneTable
}

View File

@ -35,6 +35,7 @@ export const DISK_SNAPSHOT_REVERT_POWEROFF = 'DISK_SNAPSHOT_REVERT_POWEROFF'
export const DISK_SNAPSHOT_REVERT_SUSPENDED = 'DISK_SNAPSHOT_REVERT_SUSPENDED'
export const DISK_SNAPSHOT_SUSPENDED = 'DISK_SNAPSHOT_SUSPENDED'
export const DONE = 'DONE'
export const ENABLED = 'ENABLED'
export const EPILOG = 'EPILOG'
export const EPILOG_FAILURE = 'EPILOG_FAILURE'
export const EPILOG_STOP = 'EPILOG_STOP'

View File

@ -0,0 +1,22 @@
import * as React from 'react'
import { Container, Box } from '@material-ui/core'
import * as Tables from 'client/components/Tables'
function Zones () {
return (
<Box
height={1}
py={2}
overflow='auto'
display='flex'
flexDirection='column'
component={Container}
>
<Tables.ZoneTable />
</Box>
)
}
export default Zones

View File

@ -20,3 +20,4 @@ export * from 'client/features/One/vm/hooks'
export * from 'client/features/One/vmTemplate/hooks'
export * from 'client/features/One/vnetwork/hooks'
export * from 'client/features/One/vnetworkTemplate/hooks'
export * from 'client/features/One/zone/hooks'

View File

@ -0,0 +1,14 @@
import { createAction } from 'client/features/One/utils'
import { zoneService } from 'client/features/One/zone/services'
import { RESOURCES } from 'client/features/One/slice'
export const getZone = createAction(
'zone/detail',
zoneService.getZone
)
export const getZones = createAction(
'zone/pool',
zoneService.getZones,
response => ({ [RESOURCES.zone]: response })
)

View File

@ -0,0 +1,24 @@
import { useCallback } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { unwrapResult } from '@reduxjs/toolkit'
import * as actions from 'client/features/One/zone/actions'
import { RESOURCES } from 'client/features/One/slice'
export const useZone = () => (
useSelector(state => state.one[RESOURCES.zone])
)
export const useZoneApi = () => {
const dispatch = useDispatch()
const unwrapDispatch = useCallback(
action => dispatch(action).then(unwrapResult)
, [dispatch]
)
return {
getZone: id => unwrapDispatch(actions.getZone({ id })),
getZones: () => unwrapDispatch(actions.getZones())
}
}

View File

@ -0,0 +1,25 @@
import { Actions, Commands } from 'server/utils/constants/commands/zone'
import { httpCodes } from 'server/utils/constants'
import { requestParams, RestClient } from 'client/utils'
import { poolRequest } from 'client/features/One/utils'
export const zoneService = ({
getZone: ({ filter, id }) => {
const name = Actions.ZONE_INFO
const { url, options } = requestParams(
{ filter, id },
{ name, ...Commands[name] }
)
return RestClient.get(url, options).then(res => {
if (!res?.id || res?.id !== httpCodes.ok.id) throw res
return res?.data?.ZONE ?? {}
})
},
getZones: data => {
const name = Actions.ZONE_POOL_INFO
const command = { name, ...Commands[name] }
return poolRequest(data, command, 'ZONE')
}
})

View File

@ -0,0 +1,15 @@
import * as STATES from 'client/constants/states'
import COLOR from 'client/constants/color'
const ZONE_STATES = [
{ // 0
name: STATES.ENABLED,
color: COLOR.success.main
},
{ // 1
name: STATES.DISABLED,
color: COLOR.debug.main
}
]
export const getState = ({ STATE = 0 } = {}) => ZONE_STATES[+STATE]

View File

@ -16,15 +16,15 @@
const {
from: { resource, postBody, query },
httpMethod: { GET, POST, PUT, DELETE }
} = require('../defaults');
} = require('../defaults')
const ZONE_ALLOCATE = 'zone.allocate';
const ZONE_DELETE = 'zone.delete';
const ZONE_UPDATE = 'zone.update';
const ZONE_RENAME = 'zone.rename';
const ZONE_INFO = 'zone.info';
const ZONE_RAFTSTATUS = 'zone.raftstatus';
const ZONEPOOL_INFO = 'zonepool.info';
const ZONE_ALLOCATE = 'zone.allocate'
const ZONE_DELETE = 'zone.delete'
const ZONE_UPDATE = 'zone.update'
const ZONE_RENAME = 'zone.rename'
const ZONE_INFO = 'zone.info'
const ZONE_RAFTSTATUS = 'zone.raftstatus'
const ZONE_POOL_INFO = 'zonepool.info'
const Actions = {
ZONE_ALLOCATE,
@ -33,8 +33,8 @@ const Actions = {
ZONE_RENAME,
ZONE_INFO,
ZONE_RAFTSTATUS,
ZONEPOOL_INFO
};
ZONE_POOL_INFO
}
module.exports = {
Actions,
@ -110,10 +110,10 @@ module.exports = {
httpMethod: GET,
params: {}
},
[ZONEPOOL_INFO]: {
[ZONE_POOL_INFO]: {
// inspected
httpMethod: GET,
params: {}
}
}
};
}