From e25b2ad18b90f94bce2e9c19d32df08894e75d0f Mon Sep 17 00:00:00 2001 From: Sergio Betanzos Date: Thu, 1 Jul 2021 11:30:29 +0200 Subject: [PATCH] F OpenNebula/one#5422: Add zones table --- .../src/client/apps/sunstone/routes.js | 15 +++++- .../client/components/Tables/Zones/columns.js | 26 ++++++++++ .../client/components/Tables/Zones/index.js | 36 +++++++++++++ .../src/client/components/Tables/Zones/row.js | 50 +++++++++++++++++++ .../src/client/components/Tables/index.js | 4 +- src/fireedge/src/client/constants/states.js | 1 + .../src/client/containers/Zones/index.js | 22 ++++++++ src/fireedge/src/client/features/One/hooks.js | 1 + .../src/client/features/One/zone/actions.js | 14 ++++++ .../src/client/features/One/zone/hooks.js | 24 +++++++++ .../src/client/features/One/zone/services.js | 25 ++++++++++ src/fireedge/src/client/models/Zone.js | 15 ++++++ .../server/utils/constants/commands/zone.js | 24 ++++----- 13 files changed, 242 insertions(+), 15 deletions(-) create mode 100644 src/fireedge/src/client/components/Tables/Zones/columns.js create mode 100644 src/fireedge/src/client/components/Tables/Zones/index.js create mode 100644 src/fireedge/src/client/components/Tables/Zones/row.js create mode 100644 src/fireedge/src/client/containers/Zones/index.js create mode 100644 src/fireedge/src/client/features/One/zone/actions.js create mode 100644 src/fireedge/src/client/features/One/zone/hooks.js create mode 100644 src/fireedge/src/client/features/One/zone/services.js create mode 100644 src/fireedge/src/client/models/Zone.js diff --git a/src/fireedge/src/client/apps/sunstone/routes.js b/src/fireedge/src/client/apps/sunstone/routes.js index 88a6cb4213..febe5cb553 100644 --- a/src/fireedge/src/client/apps/sunstone/routes.js +++ b/src/fireedge/src/client/apps/sunstone/routes.js @@ -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 } ] }, diff --git a/src/fireedge/src/client/components/Tables/Zones/columns.js b/src/fireedge/src/client/components/Tables/Zones/columns.js new file mode 100644 index 0000000000..3198a5a8da --- /dev/null +++ b/src/fireedge/src/client/components/Tables/Zones/columns.js @@ -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 + } + +] diff --git a/src/fireedge/src/client/components/Tables/Zones/index.js b/src/fireedge/src/client/components/Tables/Zones/index.js new file mode 100644 index 0000000000..4188a18305 --- /dev/null +++ b/src/fireedge/src/client/components/Tables/Zones/index.js @@ -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 + } + + return ( + String(row.ID)} + RowComponent={ZoneRow} + /> + ) +} + +export default ZonesTable diff --git a/src/fireedge/src/client/components/Tables/Zones/row.js b/src/fireedge/src/client/components/Tables/Zones/row.js new file mode 100644 index 0000000000..29bb23e518 --- /dev/null +++ b/src/fireedge/src/client/components/Tables/Zones/row.js @@ -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 ( +
+
+ +
+
+
+ + {NAME} + +
+
+ + {`#${ID}`} + + + + {` ${ENDPOINT}`} + +
+
+
+ ) +} + +Row.propTypes = { + original: PropTypes.object, + value: PropTypes.object, + isSelected: PropTypes.bool, + handleClick: PropTypes.func +} + +export default Row diff --git a/src/fireedge/src/client/components/Tables/index.js b/src/fireedge/src/client/components/Tables/index.js index c782cdad13..296e8281de 100644 --- a/src/fireedge/src/client/components/Tables/index.js +++ b/src/fireedge/src/client/components/Tables/index.js @@ -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 } diff --git a/src/fireedge/src/client/constants/states.js b/src/fireedge/src/client/constants/states.js index 4e184b48ba..da89eb1071 100644 --- a/src/fireedge/src/client/constants/states.js +++ b/src/fireedge/src/client/constants/states.js @@ -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' diff --git a/src/fireedge/src/client/containers/Zones/index.js b/src/fireedge/src/client/containers/Zones/index.js new file mode 100644 index 0000000000..e81bc1da42 --- /dev/null +++ b/src/fireedge/src/client/containers/Zones/index.js @@ -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 ( + + + + ) +} + +export default Zones diff --git a/src/fireedge/src/client/features/One/hooks.js b/src/fireedge/src/client/features/One/hooks.js index 8a27a22e3c..c21cfc1ba1 100644 --- a/src/fireedge/src/client/features/One/hooks.js +++ b/src/fireedge/src/client/features/One/hooks.js @@ -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' diff --git a/src/fireedge/src/client/features/One/zone/actions.js b/src/fireedge/src/client/features/One/zone/actions.js new file mode 100644 index 0000000000..21040b13fb --- /dev/null +++ b/src/fireedge/src/client/features/One/zone/actions.js @@ -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 }) +) diff --git a/src/fireedge/src/client/features/One/zone/hooks.js b/src/fireedge/src/client/features/One/zone/hooks.js new file mode 100644 index 0000000000..3f4927aadb --- /dev/null +++ b/src/fireedge/src/client/features/One/zone/hooks.js @@ -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()) + } +} diff --git a/src/fireedge/src/client/features/One/zone/services.js b/src/fireedge/src/client/features/One/zone/services.js new file mode 100644 index 0000000000..0d4c548e21 --- /dev/null +++ b/src/fireedge/src/client/features/One/zone/services.js @@ -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') + } +}) diff --git a/src/fireedge/src/client/models/Zone.js b/src/fireedge/src/client/models/Zone.js new file mode 100644 index 0000000000..ece6e0edf5 --- /dev/null +++ b/src/fireedge/src/client/models/Zone.js @@ -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] diff --git a/src/fireedge/src/server/utils/constants/commands/zone.js b/src/fireedge/src/server/utils/constants/commands/zone.js index e20df263d9..451bca8d7e 100644 --- a/src/fireedge/src/server/utils/constants/commands/zone.js +++ b/src/fireedge/src/server/utils/constants/commands/zone.js @@ -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: {} } } -}; +}