diff --git a/src/fireedge/src/client/apps/sunstone/routes.js b/src/fireedge/src/client/apps/sunstone/routes.js index febe5cb553..d521ae7693 100644 --- a/src/fireedge/src/client/apps/sunstone/routes.js +++ b/src/fireedge/src/client/apps/sunstone/routes.js @@ -4,6 +4,7 @@ import { Cell4x4 as InstancesIcons, ModernTv as VmsIcons, + Shuffle as VRoutersIcons, Archive as TemplatesIcon, GoogleDocs as TemplateIcon, @@ -35,7 +36,7 @@ const Dashboard = loadable(() => import('client/containers/Dashboard/Sunstone'), const Settings = loadable(() => import('client/containers/Settings'), { ssr: false }) const VirtualMachines = loadable(() => import('client/containers/VirtualMachines'), { ssr: false }) -// const VirtualRouters = loadable(() => import('client/containers/VirtualRouters'), { ssr: false }) +const VirtualRouters = loadable(() => import('client/containers/VirtualRouters'), { ssr: false }) const VmTemplates = loadable(() => import('client/containers/VmTemplates'), { ssr: false }) // const VrTemplates = loadable(() => import('client/containers/VrTemplates'), { ssr: false }) @@ -66,6 +67,9 @@ export const PATH = { INSTANCE: { VMS: { LIST: '/vms' + }, + VROUTERS: { + LIST: '/virtual-routers' } }, TEMPLATE: { @@ -142,6 +146,13 @@ export const ENDPOINTS = [ sidebar: true, icon: VmsIcons, Component: VirtualMachines + }, + { + label: 'Virtual Routers', + path: PATH.INSTANCE.VROUTERS.LIST, + sidebar: true, + icon: VRoutersIcons, + Component: VirtualRouters } ] }, diff --git a/src/fireedge/src/client/components/Tables/Enhanced/Utils/CategoryFilter.js b/src/fireedge/src/client/components/Tables/Enhanced/Utils/CategoryFilter.js index d0b02cb105..6138e165c8 100644 --- a/src/fireedge/src/client/components/Tables/Enhanced/Utils/CategoryFilter.js +++ b/src/fireedge/src/client/components/Tables/Enhanced/Utils/CategoryFilter.js @@ -60,7 +60,7 @@ const CategoryFilter = ({ title, column, accessorOption, multiple }) => { > {Tr(title)} {isFiltered && ( - + )} diff --git a/src/fireedge/src/client/components/Tables/VRouters/columns.js b/src/fireedge/src/client/components/Tables/VRouters/columns.js new file mode 100644 index 0000000000..153af7314b --- /dev/null +++ b/src/fireedge/src/client/components/Tables/VRouters/columns.js @@ -0,0 +1,19 @@ +const getTotalOfResources = resources => [resources?.ID ?? []].flat().length || 0 + +export default [ + { Header: 'ID', accessor: 'ID', sortType: 'number' }, + { Header: 'Name', accessor: 'NAME' }, + { Header: 'Owner', accessor: 'UNAME' }, + { Header: 'Group', accessor: 'GNAME' }, + { + Header: 'Total VMs', + id: 'VMS', + accessor: row => getTotalOfResources(row?.VMS), + sortType: 'number' + }, + { + Header: 'Group', + id: 'TEMPLATE_ID', + accessor: row => row?.TEMPLATE?.TEMPLATE_ID + } +] diff --git a/src/fireedge/src/client/components/Tables/VRouters/index.js b/src/fireedge/src/client/components/Tables/VRouters/index.js new file mode 100644 index 0000000000..f7215495d3 --- /dev/null +++ b/src/fireedge/src/client/components/Tables/VRouters/index.js @@ -0,0 +1,36 @@ +import React, { useEffect } from 'react' + +import { useFetch } from 'client/hooks' +import { useVRouter, useVRouterApi } from 'client/features/One' + +import { SkeletonTable, EnhancedTable } from 'client/components/Tables' +import VRouterColumns from 'client/components/Tables/VRouters/columns' +import VRouterRow from 'client/components/Tables/VRouters/row' + +const VRoutersTable = () => { + const columns = React.useMemo(() => VRouterColumns, []) + + const vRouters = useVRouter() + const { getVRouters } = useVRouterApi() + + const { status, fetchRequest, loading, reloading, STATUS } = useFetch(getVRouters) + const { INIT, PENDING } = STATUS + + useEffect(() => { fetchRequest() }, []) + + if (vRouters?.length === 0 && [INIT, PENDING].includes(status)) { + return + } + + return ( + String(row.ID)} + RowComponent={VRouterRow} + /> + ) +} + +export default VRoutersTable diff --git a/src/fireedge/src/client/components/Tables/VRouters/row.js b/src/fireedge/src/client/components/Tables/VRouters/row.js new file mode 100644 index 0000000000..2dd3242fc7 --- /dev/null +++ b/src/fireedge/src/client/components/Tables/VRouters/row.js @@ -0,0 +1,54 @@ +import * as React from 'react' +import PropTypes from 'prop-types' + +import { User, Group, EmptyPage, ModernTv } from 'iconoir-react' +import { Typography } from '@material-ui/core' + +import { rowStyles } from 'client/components/Tables/styles' + +const Row = ({ original, value, ...props }) => { + const classes = rowStyles() + const { ID, NAME, UNAME, GNAME, VMS, TEMPLATE_ID } = value + + return ( +
+
+
+ + {NAME} + +
+
+ + {`#${ID}`} + + + + {` ${UNAME}`} + + + + {` ${GNAME}`} + + + + {` ${TEMPLATE_ID}`} + + + + {` ${VMS}`} + +
+
+
+ ) +} + +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/VmTemplates/columns.js b/src/fireedge/src/client/components/Tables/VmTemplates/columns.js index 62bc55ff96..d9bb7eda25 100644 --- a/src/fireedge/src/client/components/Tables/VmTemplates/columns.js +++ b/src/fireedge/src/client/components/Tables/VmTemplates/columns.js @@ -1,8 +1,23 @@ +import CategoryFilter from 'client/components/Tables/Enhanced/Utils/CategoryFilter' +import * as Helper from 'client/models/Helper' + export default [ { Header: 'ID', accessor: 'ID', sortType: 'number' }, { Header: 'Name', accessor: 'NAME' }, { Header: 'Owner', accessor: 'UNAME' }, { Header: 'Group', accessor: 'GNAME' }, { Header: 'Start Time', accessor: 'REGTIME' }, - { Header: 'Locked', accessor: 'LOCK' } + { Header: 'Locked', accessor: 'LOCK' }, + { + Header: 'Virtual Router', + id: 'VROUTER', + accessor: row => + Helper.stringToBoolean(row?.TEMPLATE?.VROUTER) && 'VROUTER', + disableFilters: false, + Filter: ({ column }) => CategoryFilter({ + column, + title: 'Virtual Router' + }), + filter: 'exact' + } ] diff --git a/src/fireedge/src/client/components/Tables/VmTemplates/row.js b/src/fireedge/src/client/components/Tables/VmTemplates/row.js index 4188079589..dbcc6aa545 100644 --- a/src/fireedge/src/client/components/Tables/VmTemplates/row.js +++ b/src/fireedge/src/client/components/Tables/VmTemplates/row.js @@ -4,13 +4,14 @@ import PropTypes from 'prop-types' import { User, Group, Lock } from 'iconoir-react' import { Typography } from '@material-ui/core' +import { StatusChip } from 'client/components/Status' import { rowStyles } from 'client/components/Tables/styles' import * as Helper from 'client/models/Helper' const Row = ({ original, value, ...props }) => { const classes = rowStyles() - const { ID, NAME, UNAME, GNAME, REGTIME, LOCK } = value + const { ID, NAME, UNAME, GNAME, REGTIME, LOCK, VROUTER } = value const time = Helper.timeFromMilliseconds(+REGTIME) const timeAgo = `registered ${time.toRelative()}` @@ -24,6 +25,7 @@ const Row = ({ original, value, ...props }) => { {LOCK && } + {VROUTER && }
diff --git a/src/fireedge/src/client/components/Tables/index.js b/src/fireedge/src/client/components/Tables/index.js index 296e8281de..a53495b5d2 100644 --- a/src/fireedge/src/client/components/Tables/index.js +++ b/src/fireedge/src/client/components/Tables/index.js @@ -13,7 +13,8 @@ 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' +import VRoutersTable from 'client/components/Tables/VRouters' +import ZonesTable from 'client/components/Tables/Zones' export { SkeletonTable, @@ -32,5 +33,6 @@ export { VmTemplatesTable, VNetworksTable, VNetworkTemplatesTable, - ZoneTable + VRoutersTable, + ZonesTable } diff --git a/src/fireedge/src/client/containers/VirtualRouters/index.js b/src/fireedge/src/client/containers/VirtualRouters/index.js new file mode 100644 index 0000000000..9d9c28b9c6 --- /dev/null +++ b/src/fireedge/src/client/containers/VirtualRouters/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 VirtualRouters () { + return ( + + + + ) +} + +export default VirtualRouters diff --git a/src/fireedge/src/client/containers/Zones/index.js b/src/fireedge/src/client/containers/Zones/index.js index e81bc1da42..14808310e1 100644 --- a/src/fireedge/src/client/containers/Zones/index.js +++ b/src/fireedge/src/client/containers/Zones/index.js @@ -14,7 +14,7 @@ function Zones () { flexDirection='column' component={Container} > - + ) } diff --git a/src/fireedge/src/client/features/One/hooks.js b/src/fireedge/src/client/features/One/hooks.js index c21cfc1ba1..510960a328 100644 --- a/src/fireedge/src/client/features/One/hooks.js +++ b/src/fireedge/src/client/features/One/hooks.js @@ -20,4 +20,5 @@ 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/vrouter/hooks' export * from 'client/features/One/zone/hooks' diff --git a/src/fireedge/src/client/features/One/slice.js b/src/fireedge/src/client/features/One/slice.js index e911c9adb2..01f02474ce 100644 --- a/src/fireedge/src/client/features/One/slice.js +++ b/src/fireedge/src/client/features/One/slice.js @@ -27,6 +27,7 @@ const RESOURCES = { vmgroup: 'vmGroups', vn: 'vNetworks', vntemplate: 'vNetworksTemplates', + vrouter: 'vRouters', zone: 'zones', document: { 100: 'applications', @@ -58,6 +59,7 @@ const initial = { [RESOURCES.vmgroup]: [], [RESOURCES.vn]: [], [RESOURCES.vntemplate]: [], + [RESOURCES.vrouter]: [], [RESOURCES.zone]: [], [RESOURCES.document[100]]: [], [RESOURCES.document[101]]: [], diff --git a/src/fireedge/src/client/features/One/vrouter/actions.js b/src/fireedge/src/client/features/One/vrouter/actions.js new file mode 100644 index 0000000000..b625b20d64 --- /dev/null +++ b/src/fireedge/src/client/features/One/vrouter/actions.js @@ -0,0 +1,14 @@ +import { createAction } from 'client/features/One/utils' +import { vRouterService } from 'client/features/One/vrouter/services' +import { RESOURCES } from 'client/features/One/slice' + +export const getVRouter = createAction( + 'vrouter/detail', + vRouterService.getVRouter +) + +export const getVRouters = createAction( + 'vrouter/pool', + vRouterService.getVRouters, + response => ({ [RESOURCES.vrouter]: response }) +) diff --git a/src/fireedge/src/client/features/One/vrouter/hooks.js b/src/fireedge/src/client/features/One/vrouter/hooks.js new file mode 100644 index 0000000000..88cfaf13ff --- /dev/null +++ b/src/fireedge/src/client/features/One/vrouter/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/vrouter/actions' +import { RESOURCES } from 'client/features/One/slice' + +export const useVRouter = () => ( + useSelector(state => state.one[RESOURCES.vrouter]) +) + +export const useVRouterApi = () => { + const dispatch = useDispatch() + + const unwrapDispatch = useCallback( + action => dispatch(action).then(unwrapResult) + , [dispatch] + ) + + return { + getVRouter: id => unwrapDispatch(actions.getVRouter({ id })), + getVRouters: () => unwrapDispatch(actions.getVRouters()) + } +} diff --git a/src/fireedge/src/client/features/One/vrouter/services.js b/src/fireedge/src/client/features/One/vrouter/services.js new file mode 100644 index 0000000000..ea6935e6b7 --- /dev/null +++ b/src/fireedge/src/client/features/One/vrouter/services.js @@ -0,0 +1,25 @@ +import { Actions, Commands } from 'server/utils/constants/commands/vrouter' +import { httpCodes } from 'server/utils/constants' +import { requestParams, RestClient } from 'client/utils' +import { poolRequest } from 'client/features/One/utils' + +export const vRouterService = ({ + getVRouter: ({ filter, id }) => { + const name = Actions.VROUTER_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?.VROUTER ?? {} + }) + }, + getVRouters: data => { + const name = Actions.VROUTER_POOL_INFO + const command = { name, ...Commands[name] } + return poolRequest(data, command, 'VROUTER') + } +}) diff --git a/src/fireedge/src/client/models/Helper.js b/src/fireedge/src/client/models/Helper.js index cb098eb806..aa026d82a7 100644 --- a/src/fireedge/src/client/models/Helper.js +++ b/src/fireedge/src/client/models/Helper.js @@ -2,6 +2,9 @@ import { DateTime } from 'luxon' export const booleanToString = bool => bool ? 'Yes' : 'No' +export const stringToBoolean = str => + String(str).toLowerCase() === 'yes' || +str === 1 + export const timeToString = time => +time ? new Date(+time * 1000).toLocaleString() : '-' diff --git a/src/fireedge/src/server/utils/constants/commands/vrouter.js b/src/fireedge/src/server/utils/constants/commands/vrouter.js index d12f9b2185..77e72778ac 100644 --- a/src/fireedge/src/server/utils/constants/commands/vrouter.js +++ b/src/fireedge/src/server/utils/constants/commands/vrouter.js @@ -16,21 +16,21 @@ const { from: { resource, postBody, query }, httpMethod: { GET, POST, PUT, DELETE } -} = require('../defaults'); +} = require('../defaults') -const VROUTER_ALLOCATE = 'vrouter.allocate'; -const VROUTER_DELETE = 'vrouter.delete'; -const VROUTER_INSTANTIATE = 'vrouter.instantiate'; -const VROUTER_NIC_ATTACH = 'vrouter.attachnic'; -const VROUTER_NIC_DETACH = 'vrouter.detachnic'; -const VROUTER_UPDATE = 'vrouter.update'; -const VROUTER_CHMOD = 'vrouter.chmod'; -const VROUTER_CHOWN = 'vrouter.chown'; -const VROUTER_RENAME = 'vrouter.rename'; -const VROUTER_INFO = 'vrouter.info'; -const VROUTER_LOCK = 'vrouter.lock'; -const VROUTER_UNLOCK = 'vrouter.unlock'; -const VROUTER_POOL_INFO = 'vrouterpool.info'; +const VROUTER_ALLOCATE = 'vrouter.allocate' +const VROUTER_DELETE = 'vrouter.delete' +const VROUTER_INSTANTIATE = 'vrouter.instantiate' +const VROUTER_NIC_ATTACH = 'vrouter.attachnic' +const VROUTER_NIC_DETACH = 'vrouter.detachnic' +const VROUTER_UPDATE = 'vrouter.update' +const VROUTER_CHMOD = 'vrouter.chmod' +const VROUTER_CHOWN = 'vrouter.chown' +const VROUTER_RENAME = 'vrouter.rename' +const VROUTER_INFO = 'vrouter.info' +const VROUTER_LOCK = 'vrouter.lock' +const VROUTER_UNLOCK = 'vrouter.unlock' +const VROUTER_POOL_INFO = 'vrouterpool.info' const Actions = { VROUTER_ALLOCATE, @@ -46,7 +46,7 @@ const Actions = { VROUTER_LOCK, VROUTER_UNLOCK, VROUTER_POOL_INFO -}; +} module.exports = { Actions, @@ -286,4 +286,4 @@ module.exports = { } } } -}; +}