From 4afac0039cd8fcbe4a1cdff2bccdaf48663f4aa7 Mon Sep 17 00:00:00 2001 From: Jorge Miguel Lobo Escalona Date: Thu, 19 Sep 2024 12:50:38 +0200 Subject: [PATCH] F OpenNebula/One#6718: Add DataTable rows as lists functionality --- .../client/components/Tables/ACLs/index.js | 79 +++++++--- .../src/client/components/Tables/ACLs/row.js | 10 +- .../client/components/Tables/AllImages/row.js | 19 +-- .../components/Tables/BackupJobs/index.js | 99 +++++++++++- .../components/Tables/BackupJobs/row.js | 3 +- .../client/components/Tables/Backups/index.js | 33 +++- .../client/components/Tables/Backups/row.js | 41 ++--- .../components/Tables/Clusters/index.js | 38 ++++- .../client/components/Tables/Clusters/row.js | 5 +- .../components/Tables/Datastores/index.js | 60 ++++++- .../components/Tables/Datastores/row.js | 32 ++-- .../components/Tables/Enhanced/WrapperRow.js | 95 +++++++++++ .../components/Tables/Enhanced/index.js | 147 +++++++++++------- .../components/Tables/Enhanced/styles.js | 3 + .../client/components/Tables/Files/index.js | 35 ++++- .../client/components/Tables/Groups/index.js | 85 +++++++++- .../client/components/Tables/Hosts/index.js | 73 ++++++++- .../src/client/components/Tables/Hosts/row.js | 5 +- .../client/components/Tables/Images/index.js | 36 ++++- .../client/components/Tables/Images/row.js | 3 +- .../components/Tables/Increments/row.js | 9 +- .../Tables/MarketplaceApps/index.js | 52 ++++++- .../components/Tables/MarketplaceApps/row.js | 7 +- .../components/Tables/Marketplaces/index.js | 62 +++++++- .../components/Tables/Marketplaces/row.js | 7 +- .../components/Tables/SecurityGroups/index.js | 22 ++- .../components/Tables/SecurityGroups/row.js | 9 +- .../components/Tables/ServiceTemplates/row.js | 7 +- .../client/components/Tables/Services/row.js | 7 +- .../client/components/Tables/Support/index.js | 21 ++- .../client/components/Tables/Support/row.js | 5 +- .../client/components/Tables/Users/index.js | 85 +++++++++- .../src/client/components/Tables/Users/row.js | 3 +- .../Tables/VNetworkTemplates/index.js | 22 ++- .../Tables/VNetworkTemplates/row.js | 5 +- .../components/Tables/VNetworks/index.js | 65 +++++++- .../client/components/Tables/VNetworks/row.js | 11 +- .../Tables/VRouterTemplates/index.js | 19 ++- .../components/Tables/VRouterTemplates/row.js | 7 +- .../components/Tables/VRouters/index.js | 22 ++- .../client/components/Tables/VRouters/row.js | 5 +- .../Tables/VirtualDataCenters/index.js | 87 ++++++++++- .../Tables/VirtualDataCenters/row.js | 7 +- .../client/components/Tables/VmDisks/row.js | 5 +- .../components/Tables/VmGroups/index.js | 20 ++- .../client/components/Tables/VmGroups/row.js | 3 +- .../components/Tables/VmTemplates/index.js | 26 +++- .../components/Tables/VmTemplates/row.js | 7 +- .../src/client/components/Tables/Vms/index.js | 79 +++++++++- .../src/client/components/Tables/Vms/row.js | 3 +- .../src/client/components/Tables/Wilds/row.js | 5 +- .../client/components/Tables/Zombies/row.js | 5 +- .../client/components/Tables/Zones/index.js | 20 ++- .../src/client/components/Tables/Zones/row.js | 7 +- .../src/client/constants/translates.js | 6 + .../Settings/ConfigurationUI/schema.js | 17 ++ .../src/client/containers/Settings/index.js | 2 +- 57 files changed, 1348 insertions(+), 304 deletions(-) create mode 100644 src/fireedge/src/client/components/Tables/Enhanced/WrapperRow.js diff --git a/src/fireedge/src/client/components/Tables/ACLs/index.js b/src/fireedge/src/client/components/Tables/ACLs/index.js index a764b65096..7ec620f1c9 100644 --- a/src/fireedge/src/client/components/Tables/ACLs/index.js +++ b/src/fireedge/src/client/components/Tables/ACLs/index.js @@ -13,14 +13,15 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { useMemo, Component, useState } from 'react' -import { useViews } from 'client/features/Auth' -import { useGetAclsExtendedQuery } from 'client/features/OneApi/acl' - -import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' import ACLColumns from 'client/components/Tables/ACLs/columns' import ACLRow from 'client/components/Tables/ACLs/row' -import { RESOURCE_NAMES, ACL_TABLE_VIEWS } from 'client/constants' +import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' +import { ACL_TABLE_VIEWS, RESOURCE_NAMES, T } from 'client/constants' +import { useViews } from 'client/features/Auth' +import { useGetAclsExtendedQuery } from 'client/features/OneApi/acl' +import { sentenceCase } from 'client/utils' +import { Component, useMemo, useState } from 'react' const DEFAULT_DATA_CY = 'acls' @@ -72,23 +73,55 @@ const ACLsTable = (props) => { }, } - return ( - data && ( - String(row.ID)} - RowComponent={useMemo(() => ACLRow(viewType), [viewType])} - singleSelect={singleSelect} - tableViews={tableViews} - {...rest} - /> - ) - ) + const listHeader = [ + { header: T.ID, id: 'id', accessor: 'ID' }, + { + header: T.AppliesTo, + id: 'applies', + accessor: ({ USER }) => + USER?.type ? sentenceCase(`${USER?.type} ${USER?.name ?? ''}`) : '', + }, + { + header: T.AffectedResources, + id: 'affected-resources', + accessor: ({ RESOURCE }) => + Array.isArray(RESOURCE?.resources) + ? sentenceCase(RESOURCE.resources.join(', ')) + : '', + }, + { + header: T.AllowedOperations, + id: 'allowed-operations', + accessor: ({ RIGHTS }) => sentenceCase(RIGHTS?.string || ''), + }, + { + header: T.Zone, + id: 'zone', + accessor: ({ ZONE }) => ZONE?.name || T.All, + }, + ] + const CardStyle = useMemo(() => ACLRow(viewType), [viewType]) + const { component, header } = WrapperRow(CardStyle) + + const EnhancedTableProps = { + columns, + data, + rootProps, + searchProps, + refetch, + isLoading: isFetching, + getRowId: (row) => String(row.ID), + singleSelect, + RowComponent: component, + headerList: header && listHeader, + ...rest, + } + !header && (EnhancedTableProps.tableViews = tableViews) + + return data && } +ACLsTable.propTypes = { ...EnhancedTable.propTypes } +ACLsTable.displayName = 'ACLsTable' + export default ACLsTable diff --git a/src/fireedge/src/client/components/Tables/ACLs/row.js b/src/fireedge/src/client/components/Tables/ACLs/row.js index b524ea825c..041ad18f86 100644 --- a/src/fireedge/src/client/components/Tables/ACLs/row.js +++ b/src/fireedge/src/client/components/Tables/ACLs/row.js @@ -13,20 +13,20 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import PropTypes from 'prop-types' import { + ACLCardCLI, ACLCardIcons, ACLCardNames, - ACLCardCLI, + ACLCardReadableRule, ACLCardResources, ACLCardRule, - ACLCardReadableRule, } from 'client/components/Cards' import { ACL_TABLE_VIEWS } from 'client/constants' +/* eslint-disable jsdoc/require-jsdoc */ +import PropTypes from 'prop-types' const Row = (viewType) => { - const aclRow = ({ original, value, ...props }) => { + const aclRow = ({ original, value, headerList, ...props }) => { // Check what view show in the table cards if (viewType === ACL_TABLE_VIEWS.NAMES.type) { return diff --git a/src/fireedge/src/client/components/Tables/AllImages/row.js b/src/fireedge/src/client/components/Tables/AllImages/row.js index 6e32ccc9d3..c662640bac 100644 --- a/src/fireedge/src/client/components/Tables/AllImages/row.js +++ b/src/fireedge/src/client/components/Tables/AllImages/row.js @@ -16,26 +16,26 @@ /* eslint-disable jsdoc/require-jsdoc */ import PropTypes from 'prop-types' +import { Typography } from '@mui/material' import { - Lock, - User, - Group, Db as DatastoreIcon, + Archive as DiskTypeIcon, + Group, + Lock, ModernTv, Pin as PersistentIcon, - Archive as DiskTypeIcon, + User, } from 'iconoir-react' -import { Typography } from '@mui/material' -import Timer from 'client/components/Timer' -import { StatusCircle, StatusChip } from 'client/components/Status' +import { StatusChip, StatusCircle } from 'client/components/Status' import { rowStyles } from 'client/components/Tables/styles' +import Timer from 'client/components/Timer' import { T } from 'client/constants' -import * as ImageModel from 'client/models/Image' import * as Helper from 'client/models/Helper' +import * as ImageModel from 'client/models/Image' -const Row = ({ original, value, ...props }) => { +const Row = ({ original, value, headerList, ...props }) => { const classes = rowStyles() const { ID, @@ -126,6 +126,7 @@ Row.propTypes = { value: PropTypes.object, isSelected: PropTypes.bool, handleClick: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } export default Row diff --git a/src/fireedge/src/client/components/Tables/BackupJobs/index.js b/src/fireedge/src/client/components/Tables/BackupJobs/index.js index 13c1d8acbc..c64d3fa84f 100644 --- a/src/fireedge/src/client/components/Tables/BackupJobs/index.js +++ b/src/fireedge/src/client/components/Tables/BackupJobs/index.js @@ -13,18 +13,25 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { ReactElement, useMemo } from 'react' - -import { useViews } from 'client/features/Auth' -import { useGetBackupJobsQuery } from 'client/features/OneApi/backupjobs' - +import { StatusCircle } from 'client/components/Status' import BackupJobsColumns from 'client/components/Tables/BackupJobs/columns' import BackupJobsRow from 'client/components/Tables/BackupJobs/row' import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' -import { RESOURCE_NAMES } from 'client/constants' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' +import Timer from 'client/components/Timer' +import { RESOURCE_NAMES, T } from 'client/constants' +import COLOR from 'client/constants/color' +import { useViews } from 'client/features/Auth' +import { useGetBackupJobsQuery } from 'client/features/OneApi/backupjobs' +import { timeFromMilliseconds } from 'client/models/Helper' +import { ReactElement, useMemo } from 'react' const DEFAULT_DATA_CY = 'backupjobs' +const haveValues = function (object) { + return Object.values(object).length > 0 +} + /** * @param {object} props - Props * @returns {ReactElement} Backup Jobs table @@ -46,6 +53,83 @@ const BackupJobsTable = (props) => { [view] ) + const listHeader = [ + { + header: '', + id: 'status-icon', + accessor: ({ + OUTDATED_VMS, + BACKING_UP_VMS, + ERROR_VMS, + LAST_BACKUP_TIME, + }) => { + const status = useMemo(() => { + const completed = { + color: COLOR.success.main, + tooltip: T.Completed, + } + const noStarted = { + color: COLOR.warning.main, + tooltip: T.NotStartedYet, + } + + const error = { + color: COLOR.error.main, + tooltip: T.Error, + } + + const onGoing = { + color: COLOR.info.main, + tooltip: T.OnGoing, + } + + if (haveValues(ERROR_VMS)) { + return error + } + + if (!haveValues(OUTDATED_VMS) && !haveValues(BACKING_UP_VMS)) { + return LAST_BACKUP_TIME === '0' ? noStarted : completed + } + + if (haveValues(OUTDATED_VMS)) { + return completed + } + + if (haveValues(BACKING_UP_VMS)) { + return onGoing + } + }, [OUTDATED_VMS, BACKING_UP_VMS, ERROR_VMS, LAST_BACKUP_TIME]) + + return + }, + }, + { header: T.ID, id: 'id', accessor: 'ID' }, + { header: T.Name, id: 'name', accessor: 'NAME' }, + { header: T.Owner, id: 'owner', accessor: 'UNAME' }, + { header: T.Group, id: 'group', accessor: 'GNAME' }, + { header: T.Priority, id: 'priority', accessor: 'PRIORITY' }, + { + header: T.LastBackupTimeInfo, + id: 'last-time', + accessor: ({ LAST_BACKUP_TIME }) => { + const LastBackupTime = +LAST_BACKUP_TIME + if (LastBackupTime > 0) { + const timer = timeFromMilliseconds(LastBackupTime) + + return ( + + + + ) + } else { + return '' + } + }, + }, + ] + + const { component, header } = WrapperRow(BackupJobsRow) + return ( { refetch={refetch} isLoading={isFetching} getRowId={(row) => String(row.ID)} - RowComponent={BackupJobsRow} + RowComponent={component} + headerList={header && listHeader} {...rest} /> ) diff --git a/src/fireedge/src/client/components/Tables/BackupJobs/row.js b/src/fireedge/src/client/components/Tables/BackupJobs/row.js index b890a84fc4..a542e1d7da 100644 --- a/src/fireedge/src/client/components/Tables/BackupJobs/row.js +++ b/src/fireedge/src/client/components/Tables/BackupJobs/row.js @@ -23,7 +23,7 @@ import backupjobApi, { import { jsonToXml } from 'client/models/Helper' const Row = memo( - ({ original, value, onClickLabel, ...props }) => { + ({ original, value, onClickLabel, headerList, ...props }) => { const [update] = useUpdateBackupJobMutation() const state = backupjobApi.endpoints.getBackupJobs.useQueryState( @@ -67,6 +67,7 @@ Row.propTypes = { className: PropTypes.string, onClick: PropTypes.func, onClickLabel: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } Row.displayName = 'VirtualDataCenterRow' diff --git a/src/fireedge/src/client/components/Tables/Backups/index.js b/src/fireedge/src/client/components/Tables/Backups/index.js index d909ff29c7..9b085a3b4a 100644 --- a/src/fireedge/src/client/components/Tables/Backups/index.js +++ b/src/fireedge/src/client/components/Tables/Backups/index.js @@ -13,15 +13,17 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { useMemo, ReactElement } from 'react' - +import { StatusCircle } from 'client/components/Status' import { useViews } from 'client/features/Auth' import { useGetBackupsQuery } from 'client/features/OneApi/image' +import { ReactElement, useMemo } from 'react' -import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' import backupColumns from 'client/components/Tables/Backups/columns' import BackupRow from 'client/components/Tables/Backups/row' -import { RESOURCE_NAMES } from 'client/constants' +import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' +import { RESOURCE_NAMES, T } from 'client/constants' +import { getState, getType } from 'client/models/Image' const DEFAULT_DATA_CY = 'backups' @@ -87,6 +89,26 @@ const BackupsTable = (props) => { const isFetchingAll = () => isFetchingVm ? !!(isFetchingVm && isFetching) : isFetching + const listHeader = [ + { + header: '', + id: 'status-icon', + accessor: (template) => { + const { color: stateColor, name: stateName } = getState(template) + + return + }, + }, + { header: T.ID, id: 'id', accessor: 'ID' }, + { header: T.Name, id: 'name', accessor: 'NAME' }, + { header: T.Owner, id: 'owner', accessor: 'UNAME' }, + { header: T.Group, id: 'group', accessor: 'GNAME' }, + { header: T.Datastore, id: 'datastore', accessor: 'DATASTORE' }, + { header: T.Type, id: 'type', accessor: (template) => getType(template) }, + ] + + const { component, header } = WrapperRow(BackupRow) + return ( { refetch={refetchAll} isLoading={isFetchingAll()} getRowId={(row) => String(row.ID)} - RowComponent={BackupRow} + RowComponent={component} + headerList={header && listHeader} {...rest} /> ) diff --git a/src/fireedge/src/client/components/Tables/Backups/row.js b/src/fireedge/src/client/components/Tables/Backups/row.js index 5adbd5e877..f7ea261c7c 100644 --- a/src/fireedge/src/client/components/Tables/Backups/row.js +++ b/src/fireedge/src/client/components/Tables/Backups/row.js @@ -13,39 +13,39 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ +import { useAuth } from 'client/features/Auth' +import imageApi, { useUpdateImageMutation } from 'client/features/OneApi/image' /* eslint-disable jsdoc/require-jsdoc */ import PropTypes from 'prop-types' -import { useAuth } from 'client/features/Auth' -import { useMemo, useCallback } from 'react' -import imageApi, { useUpdateImageMutation } from 'client/features/OneApi/image' +import { useCallback, useMemo } from 'react' -import { - Lock, - User, - Group, - Db as DatastoreIcon, - ModernTv, - Pin as PersistentIcon, - Archive as DiskTypeIcon, -} from 'iconoir-react' import { Typography } from '@mui/material' import MultipleTags from 'client/components/MultipleTags' import { - jsonToXml, - getUniqueLabels, getColorFromString, + getUniqueLabels, + jsonToXml, } from 'client/models/Helper' +import { + Db as DatastoreIcon, + Archive as DiskTypeIcon, + Group, + Lock, + ModernTv, + Pin as PersistentIcon, + User, +} from 'iconoir-react' -import Timer from 'client/components/Timer' -import { StatusCircle, StatusChip } from 'client/components/Status' -import { rowStyles } from 'client/components/Tables/styles' -import { T } from 'client/constants' import { Tr } from 'client/components/HOC' +import { StatusChip, StatusCircle } from 'client/components/Status' +import { rowStyles } from 'client/components/Tables/styles' +import Timer from 'client/components/Timer' +import { T } from 'client/constants' -import * as ImageModel from 'client/models/Image' import * as Helper from 'client/models/Helper' +import * as ImageModel from 'client/models/Image' -const Row = ({ original, value, onClickLabel, ...props }) => { +const Row = ({ original, value, onClickLabel, headerList, ...props }) => { const [update] = useUpdateImageMutation() const { labels: userLabels } = useAuth() @@ -187,6 +187,7 @@ Row.propTypes = { isSelected: PropTypes.bool, handleClick: PropTypes.func, onClickLabel: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } export default Row diff --git a/src/fireedge/src/client/components/Tables/Clusters/index.js b/src/fireedge/src/client/components/Tables/Clusters/index.js index 229de30211..7638e6bdc6 100644 --- a/src/fireedge/src/client/components/Tables/Clusters/index.js +++ b/src/fireedge/src/client/components/Tables/Clusters/index.js @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { useMemo, ReactElement } from 'react' +import { ReactElement, useMemo } from 'react' -import { useViews } from 'client/features/Auth' -import { useGetClustersQuery } from 'client/features/OneApi/cluster' - -import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' import ClusterColumns from 'client/components/Tables/Clusters/columns' import ClusterRow from 'client/components/Tables/Clusters/row' -import { RESOURCE_NAMES } from 'client/constants' +import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' +import { RESOURCE_NAMES, T } from 'client/constants' +import { useViews } from 'client/features/Auth' +import { useGetClustersQuery } from 'client/features/OneApi/cluster' const DEFAULT_DATA_CY = 'clusters' @@ -74,6 +74,29 @@ const ClustersTable = (props) => { [view] ) + const listHeader = [ + { header: T.ID, id: 'id', accessor: 'ID' }, + { header: T.Name, id: 'name', accessor: 'NAME' }, + { + header: T.Hosts, + id: 'hosts', + accessor: ({ HOSTS }) => (Array.isArray(HOSTS.ID) ? HOSTS.ID.length : 1), + }, + { + header: T.Vnets, + id: 'vnets', + accessor: ({ VNETS }) => (Array.isArray(VNETS.ID) ? VNETS.ID.length : 1), + }, + { + header: T.Datastore, + id: 'datastores', + accessor: ({ DATASTORES }) => + Array.isArray(DATASTORES.ID) ? DATASTORES.ID.length : 1, + }, + ] + + const { component, header } = WrapperRow(ClusterRow) + return ( { refetch={refetch} isLoading={isFetching} getRowId={(row) => String(row.ID)} - RowComponent={ClusterRow} + RowComponent={component} + headerList={header && listHeader} {...rest} /> ) diff --git a/src/fireedge/src/client/components/Tables/Clusters/row.js b/src/fireedge/src/client/components/Tables/Clusters/row.js index f255f79b62..7078c8769d 100644 --- a/src/fireedge/src/client/components/Tables/Clusters/row.js +++ b/src/fireedge/src/client/components/Tables/Clusters/row.js @@ -16,15 +16,15 @@ /* eslint-disable jsdoc/require-jsdoc */ import PropTypes from 'prop-types' -import { HardDrive, NetworkAlt, Folder, Cloud } from 'iconoir-react' import { Typography } from '@mui/material' +import { Cloud, Folder, HardDrive, NetworkAlt } from 'iconoir-react' import { rowStyles } from 'client/components/Tables/styles' import { Tr } from 'client/components/HOC' import { T } from 'client/constants' -const Row = ({ original, value, ...props }) => { +const Row = ({ original, value, headerList, ...props }) => { const classes = rowStyles() const { ID, NAME, HOSTS, DATASTORES, VNETS, PROVIDER_NAME } = value @@ -76,6 +76,7 @@ Row.propTypes = { value: PropTypes.object, isSelected: PropTypes.bool, handleClick: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } export default Row diff --git a/src/fireedge/src/client/components/Tables/Datastores/index.js b/src/fireedge/src/client/components/Tables/Datastores/index.js index 95a7bad684..9180108743 100644 --- a/src/fireedge/src/client/components/Tables/Datastores/index.js +++ b/src/fireedge/src/client/components/Tables/Datastores/index.js @@ -18,6 +18,7 @@ import { ReactElement, useCallback, useEffect, useMemo, useState } from 'react' import { useViews } from 'client/features/Auth' import { useGetDatastoresQuery } from 'client/features/OneApi/datastore' +import { LinearProgressWithLabel, StatusCircle } from 'client/components/Status' import DatastoreColumns from 'client/components/Tables/Datastores/columns' import DatastoreRow from 'client/components/Tables/Datastores/row' import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' @@ -25,7 +26,9 @@ import { areArraysEqual, sortStateTables, } from 'client/components/Tables/Enhanced/Utils/DataTableUtils' -import { RESOURCE_NAMES } from 'client/constants' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' +import { DS_THRESHOLD, RESOURCE_NAMES, T } from 'client/constants' +import { getCapacityInfo, getState, getType } from 'client/models/Datastore' import { useFormContext } from 'react-hook-form' const DEFAULT_DATA_CY = 'datastores' @@ -135,6 +138,58 @@ const DatastoresTable = (props) => { } }) + const listHeader = [ + { + header: T.Status, + id: 'status', + accessor: (template) => { + const { color: stateColor, name: stateName } = getState(template) + + return + }, + }, + { header: T.ID, id: 'id', accessor: 'ID' }, + { header: T.Name, id: 'name', accessor: 'NAME' }, + { header: T.Owner, id: 'owner', accessor: 'UNAME' }, + { header: T.Group, id: 'group', accessor: 'GNAME' }, + { + header: T.Capacity, + id: 'capacity', + accessor: (template) => { + const capacity = useMemo(() => getCapacityInfo(template), [template]) + const { percentOfUsed, percentLabel } = capacity + + return ( + + ) + }, + }, + { + header: T.Cluster, + id: 'cluster', + accessor: ({ CLUSTERS }) => { + const clusters = useMemo( + () => [CLUSTERS?.ID ?? []].flat(), + [CLUSTERS?.ID] + ) + + return clusters.length && clusters[0] + }, + }, + { + header: T.Type, + id: 'type', + accessor: (template) => getType(template), + }, + ] + const { component, header } = WrapperRow(DatastoreRow) + return ( { refetch={refetch} isLoading={isFetching} getRowId={(row) => String(row.ID)} - RowComponent={DatastoreRow} dataDepend={values} + RowComponent={component} + headerList={header && listHeader} {...rest} /> ) diff --git a/src/fireedge/src/client/components/Tables/Datastores/row.js b/src/fireedge/src/client/components/Tables/Datastores/row.js index 753ab49c9f..b350277d41 100644 --- a/src/fireedge/src/client/components/Tables/Datastores/row.js +++ b/src/fireedge/src/client/components/Tables/Datastores/row.js @@ -13,27 +13,34 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo, useCallback, useMemo } from 'react' +import { jsonToXml } from 'client/models/Helper' import PropTypes from 'prop-types' +import { memo, useCallback, useMemo } from 'react' -import { - useGetDatastoresQuery, +import { DatastoreCard } from 'client/components/Cards' +import api, { useUpdateDatastoreMutation, } from 'client/features/OneApi/datastore' -import { DatastoreCard } from 'client/components/Cards' -import { jsonToXml } from 'client/models/Helper' const Row = memo( - ({ original, onClickLabel, ...props }) => { - const { data: datastores } = useGetDatastoresQuery(undefined) - const selectedDatastore = datastores?.find( - (datastore) => +datastore.ID === +original.ID - ) + ({ original, value, onClickLabel, zone, headerList, ...props }) => { const [update] = useUpdateDatastoreMutation() + const { + data: datastores, + error, + isLoading, + } = api.endpoints.getDatastores.useQueryState({ zone }) + + const selectedDatastore = useMemo( + () => + datastores?.find((datastore) => +datastore.ID === +original.ID) ?? + original, + [datastores, original] + ) const memoDs = useMemo( () => selectedDatastore ?? original, - [datastores, original] + [selectedDatastore, original, update, isLoading, error, datastores] ) const handleDeleteLabel = useCallback( @@ -62,7 +69,10 @@ const Row = memo( Row.propTypes = { original: PropTypes.object, + value: PropTypes.object, onClickLabel: PropTypes.func, + zone: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } Row.displayName = 'DatastoreRow' diff --git a/src/fireedge/src/client/components/Tables/Enhanced/WrapperRow.js b/src/fireedge/src/client/components/Tables/Enhanced/WrapperRow.js new file mode 100644 index 0000000000..3b4162b40a --- /dev/null +++ b/src/fireedge/src/client/components/Tables/Enhanced/WrapperRow.js @@ -0,0 +1,95 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2024, OpenNebula Project, OpenNebula Systems * + * * + * Licensed under the Apache License, Version 2.0 (the "License"); you may * + * not use this file except in compliance with the License. You may obtain * + * a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, software * + * distributed under the License is distributed on an "AS IS" BASIS, * + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * + * See the License for the specific language governing permissions and * + * limitations under the License. * + * ------------------------------------------------------------------------- */ +import { TableCell, TableRow } from '@mui/material' +import makeStyles from '@mui/styles/makeStyles' +import { SERVER_CONFIG } from 'client/constants' +import { useAuth } from 'client/features/Auth' +import get from 'lodash.get' +import PropTypes from 'prop-types' +import { ReactElement, memo } from 'react' + +const listStyles = makeStyles(({ palette }) => ({ + row: { + '&.selected': { + boxShadow: `inset 0px -0.5px 0px 2px ${palette.secondary.main}`, + }, + }, +})) + +/** + * @param {object} props - Props + * @returns {ReactElement} Generic Row + */ +const RowStyle = memo( + ({ + original, + value, + onClickLabel, + globalErrors, + headerList = [], + className, + ...props + }) => { + const styles = listStyles() + + return ( + + {headerList.map(({ id, accessor }) => { + switch (typeof accessor) { + case 'string': + return {get(original, accessor)} + case 'function': + return {accessor(original)} + default: + return '' + } + })} + + ) + }, + (prev, next) => prev.className === next.className +) + +RowStyle.propTypes = { + original: PropTypes.object, + value: PropTypes.object, + onClickLabel: PropTypes.func, + globalErrors: PropTypes.array, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), + className: PropTypes.string, +} + +RowStyle.displayName = 'RowStyle' + +/** + * @param {ReactElement} RowCardComponent - Standard row component (Card). + * @returns {ReactElement} Generic Row + */ +const WrapperRow = (RowCardComponent) => { + const { settings: { FIREEDGE: fireedge = {} } = {} } = useAuth() + const { ROW_STYLE } = fireedge + const { rowStyle } = SERVER_CONFIG + + const data = ROW_STYLE || rowStyle + const header = data === 'list' + + return { + component: header ? RowStyle : RowCardComponent, + header, + } +} + +export default WrapperRow diff --git a/src/fireedge/src/client/components/Tables/Enhanced/index.js b/src/fireedge/src/client/components/Tables/Enhanced/index.js index 7cab185b82..7bc04a3218 100644 --- a/src/fireedge/src/client/components/Tables/Enhanced/index.js +++ b/src/fireedge/src/client/components/Tables/Enhanced/index.js @@ -17,7 +17,17 @@ import PropTypes from 'prop-types' import { useEffect, useMemo, useState } from 'react' -import { Alert, Box, Chip, Grid } from '@mui/material' +import { + Alert, + Box, + Chip, + Grid, + Table, + TableBody, + TableCell, + TableHead, + TableRow, +} from '@mui/material' import clsx from 'clsx' import InfoEmpty from 'iconoir-react/dist/InfoEmpty' import RemoveIcon from 'iconoir-react/dist/RemoveSquare' @@ -83,6 +93,7 @@ const EnhancedTable = ({ readOnly = false, tableViews, zoneId, + headerList, }) => { const styles = EnhancedTableStyles({ readOnly: readOnly, @@ -301,6 +312,84 @@ const EnhancedTable = ({ ) } + const DataListPerPage = ({ page: internalPage = [] }) => { + if (!internalPage.length) { + return '' + } + + const valuesPerPages = internalPage.map((row) => { + prepareRow(row) + + /** @type {UseRowSelectRowProps} */ + const { getRowProps, original, values, toggleRowSelected, isSelected } = + row + const { key, ...rowProps } = getRowProps() + + return ( + { + const currentFilter = + state.filters + ?.filter(({ id }) => id === LABEL_COLUMN_ID) + ?.map(({ value }) => value) + ?.flat() || [] + + const nextFilter = [...new Set([...currentFilter, label])] + setFilter(LABEL_COLUMN_ID, nextFilter) + }, + })} + onClick={(e) => { + typeof onRowClick === 'function' && onRowClick(original) + + if (!disableRowSelect && !readOnly) { + if ( + singleSelect || + (!singleSelect && !(e.ctrlKey || e.metaKey)) + ) { + toggleAllRowsSelected?.(false) + } + toggleRowSelected?.(!isSelected) + } + }} + /> + ) + }) + + return headerList ? ( + + + + {headerList.map(({ header = '', id = '' }) => ( + + {header} + + ))} + + + {valuesPerPages} +
+ ) : ( + <>{valuesPerPages} + ) + } + + DataListPerPage.propTypes = { + page: PropTypes.any, + } + + DataListPerPage.displayName = 'DataListPerPage' + return ( -
+
{!!messages.length && } {/* NO DATA MESSAGE */} {!isLoading && @@ -390,58 +479,7 @@ const EnhancedTable = ({ ))} {/* DATALIST PER PAGE */} - {page.map((row) => { - prepareRow(row) - - /** @type {UseRowSelectRowProps} */ - const { - getRowProps, - original, - values, - toggleRowSelected, - isSelected, - } = row - const { key, ...rowProps } = getRowProps() - - return ( - { - const currentFilter = - state.filters - ?.filter(({ id }) => id === LABEL_COLUMN_ID) - ?.map(({ value }) => value) - ?.flat() || [] - - const nextFilter = [...new Set([...currentFilter, label])] - setFilter(LABEL_COLUMN_ID, nextFilter) - }, - })} - onClick={(e) => { - typeof onRowClick === 'function' && onRowClick(original) - - if (!disableRowSelect && !readOnly) { - if ( - singleSelect || - (!singleSelect && !(e.ctrlKey || e.metaKey)) - ) { - toggleAllRowsSelected?.(false) - } - toggleRowSelected?.(!isSelected) - } - }} - /> - ) - })} +
) @@ -490,6 +528,7 @@ EnhancedTable.propTypes = { readOnly: PropTypes.bool, tableViews: PropTypes.object, zoneId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } export * from 'client/components/Tables/Enhanced/Utils' diff --git a/src/fireedge/src/client/components/Tables/Enhanced/styles.js b/src/fireedge/src/client/components/Tables/Enhanced/styles.js index 949e7f3f63..d44ed2e4c9 100644 --- a/src/fireedge/src/client/components/Tables/Enhanced/styles.js +++ b/src/fireedge/src/client/components/Tables/Enhanced/styles.js @@ -132,4 +132,7 @@ export default makeStyles(({ palette, typography, breakpoints }) => ({ gap: '0.8em', padding: '1em', }, + cellHeaders: { + fontWeight: 'bold', + }, })) diff --git a/src/fireedge/src/client/components/Tables/Files/index.js b/src/fireedge/src/client/components/Tables/Files/index.js index 301f265f5c..36b89b83b6 100644 --- a/src/fireedge/src/client/components/Tables/Files/index.js +++ b/src/fireedge/src/client/components/Tables/Files/index.js @@ -13,15 +13,17 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { useMemo, ReactElement } from 'react' - -import { useViews } from 'client/features/Auth' -import { useGetFilesQuery } from 'client/features/OneApi/image' +import { ReactElement, useMemo } from 'react' +import { StatusCircle } from 'client/components/Status' import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' import ImageColumns from 'client/components/Tables/Images/columns' import ImageRow from 'client/components/Tables/Images/row' -import { RESOURCE_NAMES } from 'client/constants' +import { RESOURCE_NAMES, T } from 'client/constants' +import { useViews } from 'client/features/Auth' +import { useGetFilesQuery } from 'client/features/OneApi/image' +import { getState, getType } from 'client/models/Image' const DEFAULT_DATA_CY = 'images' @@ -61,6 +63,26 @@ const FilesTable = (props) => { [view] ) + const listHeader = [ + { + header: '', + id: 'status-icon', + accessor: (vm) => { + const { color: stateColor, name: stateName } = getState(vm) + + return + }, + }, + { header: T.ID, id: 'id', accessor: 'ID' }, + { header: T.Name, id: 'name', accessor: 'NAME' }, + { header: T.Owner, id: 'owner', accessor: 'UNAME' }, + { header: T.Group, id: 'group', accessor: 'GNAME' }, + { header: T.Datastore, id: 'datastore', accessor: 'DATASTORE' }, + { header: T.Type, id: 'type', accessor: (template) => getType(template) }, + ] + + const { component, header } = WrapperRow(ImageRow) + return ( { refetch={refetch} isLoading={isFetching} getRowId={(row) => String(row.ID)} - RowComponent={ImageRow} + RowComponent={component} + headerList={header && listHeader} {...rest} /> ) diff --git a/src/fireedge/src/client/components/Tables/Groups/index.js b/src/fireedge/src/client/components/Tables/Groups/index.js index 8b56785594..8f8c1b2dc8 100644 --- a/src/fireedge/src/client/components/Tables/Groups/index.js +++ b/src/fireedge/src/client/components/Tables/Groups/index.js @@ -13,13 +13,16 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { useMemo, Component } from 'react' -import { useViews } from 'client/features/Auth' -import { useGetGroupsQuery } from 'client/features/OneApi/group' +import { LinearProgressWithTooltip } from 'client/components/Status' import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' import GroupColumns from 'client/components/Tables/Groups/columns' import GroupRow from 'client/components/Tables/Groups/row' -import { RESOURCE_NAMES } from 'client/constants' +import { RESOURCE_NAMES, T } from 'client/constants' +import { useViews } from 'client/features/Auth' +import { useGetGroupsQuery } from 'client/features/OneApi/group' +import { getQuotaUsage } from 'client/models/Group' +import { Component, useMemo } from 'react' const DEFAULT_DATA_CY = 'groups' @@ -58,6 +61,74 @@ const GroupsTable = (props) => { [view] ) + const listHeader = [ + { header: T.ID, id: 'id', accessor: 'ID' }, + { header: T.Name, id: 'name', accessor: 'NAME' }, + { + header: T.Users, + id: 'users', + accessor: ({ USERS }) => (Array.isArray(USERS?.ID) ? USERS.ID.length : 0), + }, + { + header: T.VMs, + id: 'vms', + accessor: ({ VM_QUOTA }) => { + const vmQuotaUsage = useMemo( + () => getQuotaUsage('VM', VM_QUOTA), + [VM_QUOTA] + ) + + return ( + + ) + }, + }, + { + header: T.Datastores, + id: 'datastores', + accessor: ({ DATASTORE_QUOTA }) => { + const datastoreQuotaUsage = useMemo( + () => getQuotaUsage('DATASTORE', DATASTORE_QUOTA), + [DATASTORE_QUOTA] + ) + + return ( + + ) + }, + }, + { + header: T.Networks, + id: 'networks', + accessor: ({ NETWORK_QUOTA }) => { + const networkQuotaUsage = useMemo( + () => getQuotaUsage('NETWORK', NETWORK_QUOTA), + [NETWORK_QUOTA] + ) + + return ( + + ) + }, + }, + ] + const { component, header } = WrapperRow(GroupRow) + return ( { refetch={refetch} isLoading={isFetching} getRowId={(row) => String(row.ID)} - RowComponent={GroupRow} singleSelect={singleSelect} + RowComponent={component} + headerList={header && listHeader} {...rest} /> ) } +GroupsTable.propTypes = { ...EnhancedTable.propTypes } +GroupsTable.displayName = 'GroupsTable' + export default GroupsTable diff --git a/src/fireedge/src/client/components/Tables/Hosts/index.js b/src/fireedge/src/client/components/Tables/Hosts/index.js index 82af6df6a5..9f36e44d7c 100644 --- a/src/fireedge/src/client/components/Tables/Hosts/index.js +++ b/src/fireedge/src/client/components/Tables/Hosts/index.js @@ -15,17 +15,20 @@ * ------------------------------------------------------------------------- */ import { ReactElement, useCallback, useEffect, useMemo, useState } from 'react' -import { useViews } from 'client/features/Auth' -import { useGetHostsQuery } from 'client/features/OneApi/host' - +import { Tr } from 'client/components/HOC' +import { LinearProgressWithLabel, StatusCircle } from 'client/components/Status' import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' import { areArraysEqual, sortStateTables, } from 'client/components/Tables/Enhanced/Utils/DataTableUtils' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' import HostColumns from 'client/components/Tables/Hosts/columns' import HostRow from 'client/components/Tables/Hosts/row' -import { RESOURCE_NAMES } from 'client/constants' +import { HOST_THRESHOLD, RESOURCE_NAMES, T } from 'client/constants' +import { useViews } from 'client/features/Auth' +import { useGetHostsQuery } from 'client/features/OneApi/host' +import { getAllocatedInfo, getState } from 'client/models/Host' import { useFormContext } from 'react-hook-form' const DEFAULT_DATA_CY = 'hosts' @@ -136,6 +139,65 @@ const HostsTable = (props) => { }) useEffect(() => refetch(), []) + const listHeader = [ + { + header: '', + id: 'status-icon', + accessor: (host) => { + const { color: stateColor, name: stateName } = getState(host) + + return + }, + }, + { header: T.ID, id: 'id', accessor: 'ID' }, + { header: T.Name, id: 'name', accessor: 'NAME' }, + { header: T.Cluster, id: 'cluster', accessor: 'CLUSTER' }, + { + header: T.Rvms, + id: 'rvms', + accessor: ({ HOST_SHARE }) => HOST_SHARE?.RUNNING_VMS || 0, + }, + { + header: T.AllocatedCpu, + id: 'cpu', + accessor: (host) => { + const { percentCpuUsed, percentCpuLabel, colorCpu } = + getAllocatedInfo(host) + + return ( + + ) + }, + }, + { + header: T.AllocatedMemory, + id: 'memory', + accessor: (host) => { + const { percentMemUsed, percentMemLabel, colorMem } = + getAllocatedInfo(host) + + return ( + + ) + }, + }, + ] + const { component, header } = WrapperRow(HostRow) + return ( { refetch={refetch} isLoading={isFetching} getRowId={(row) => String(row.ID)} - RowComponent={HostRow} dataDepend={values} zoneId={zoneId} + RowComponent={component} + headerList={header && listHeader} {...rest} /> ) diff --git a/src/fireedge/src/client/components/Tables/Hosts/row.js b/src/fireedge/src/client/components/Tables/Hosts/row.js index 09ebe25aca..2280964208 100644 --- a/src/fireedge/src/client/components/Tables/Hosts/row.js +++ b/src/fireedge/src/client/components/Tables/Hosts/row.js @@ -20,14 +20,14 @@ import PropTypes from 'prop-types' import { memo, useCallback, useMemo } from 'react' const Row = memo( - ({ original, value, onClickLabel, zone, ...props }) => { + ({ original, value, onClickLabel, zone, headerList, ...props }) => { const [update] = useUpdateHostMutation() const { data: hosts, error, isLoading, - } = hostApi.endpoints.getHosts.useQuery({ zone }) + } = hostApi.endpoints.getHosts.useQueryState({ zone }) const host = useMemo( () => hosts?.find((h) => +h.ID === +original.ID) ?? original, @@ -71,6 +71,7 @@ Row.propTypes = { handleClick: PropTypes.func, onClickLabel: PropTypes.func, zone: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } Row.displayName = 'HostRow' diff --git a/src/fireedge/src/client/components/Tables/Images/index.js b/src/fireedge/src/client/components/Tables/Images/index.js index 4529b73d70..f42cb0815d 100644 --- a/src/fireedge/src/client/components/Tables/Images/index.js +++ b/src/fireedge/src/client/components/Tables/Images/index.js @@ -13,15 +13,17 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { useMemo, ReactElement } from 'react' - -import { useViews } from 'client/features/Auth' -import { useGetImagesQuery } from 'client/features/OneApi/image' +import { ReactElement, useMemo } from 'react' +import { StatusCircle } from 'client/components/Status' import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' import ImageColumns from 'client/components/Tables/Images/columns' import ImageRow from 'client/components/Tables/Images/row' -import { RESOURCE_NAMES } from 'client/constants' +import { RESOURCE_NAMES, T } from 'client/constants' +import { useViews } from 'client/features/Auth' +import { useGetImagesQuery } from 'client/features/OneApi/image' +import { getState, getType } from 'client/models/Image' const DEFAULT_DATA_CY = 'images' @@ -46,6 +48,27 @@ const ImagesTable = (props) => { [view] ) + const listHeader = [ + { + header: '', + id: 'status-icon', + accessor: (vm) => { + const { color: stateColor, name: stateName } = getState(vm) + + return + }, + }, + { header: T.ID, id: 'id', accessor: 'ID' }, + { header: T.Name, id: 'name', accessor: 'NAME' }, + { header: T.Owner, id: 'owner', accessor: 'UNAME' }, + { header: T.Group, id: 'group', accessor: 'GNAME' }, + { header: T.Datastore, id: 'datastore', accessor: 'DATASTORE' }, + { header: T.Type, id: 'type', accessor: (template) => getType(template) }, + { header: T.VMs, id: 'vms', accessor: 'RUNNING_VMS' }, + ] + + const { component, header } = WrapperRow(ImageRow) + return ( { refetch={refetch} isLoading={isFetching} getRowId={(row) => String(row.ID)} - RowComponent={ImageRow} + RowComponent={component} + headerList={header && listHeader} {...rest} /> ) diff --git a/src/fireedge/src/client/components/Tables/Images/row.js b/src/fireedge/src/client/components/Tables/Images/row.js index 6c30f31a76..95a6387b07 100644 --- a/src/fireedge/src/client/components/Tables/Images/row.js +++ b/src/fireedge/src/client/components/Tables/Images/row.js @@ -45,7 +45,7 @@ import { prettyBytes } from 'client/utils' import * as Helper from 'client/models/Helper' import * as ImageModel from 'client/models/Image' -const Row = ({ original, value, onClickLabel, ...props }) => { +const Row = ({ original, value, onClickLabel, headerList, ...props }) => { const [update] = useUpdateImageMutation() const { labels: userLabels } = useAuth() @@ -167,6 +167,7 @@ Row.propTypes = { isSelected: PropTypes.bool, handleClick: PropTypes.func, onClickLabel: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } export default Row diff --git a/src/fireedge/src/client/components/Tables/Increments/row.js b/src/fireedge/src/client/components/Tables/Increments/row.js index abbb967408..9b390032b8 100644 --- a/src/fireedge/src/client/components/Tables/Increments/row.js +++ b/src/fireedge/src/client/components/Tables/Increments/row.js @@ -16,22 +16,22 @@ /* eslint-disable jsdoc/require-jsdoc */ import PropTypes from 'prop-types' +import { Typography } from '@mui/material' import { - HardDrive as SizeIcon, RefreshCircular as FullIcon, Refresh as IncrementIcon, + HardDrive as SizeIcon, } from 'iconoir-react' -import { Typography } from '@mui/material' -import Timer from 'client/components/Timer' import { StatusChip } from 'client/components/Status' import { rowStyles } from 'client/components/Tables/styles' +import Timer from 'client/components/Timer' import { T } from 'client/constants' import { prettyBytes } from 'client/utils' import * as Helper from 'client/models/Helper' -const Row = ({ original, value, ...props }) => { +const Row = ({ original, value, headerList, ...props }) => { const classes = rowStyles() const { ID, TYPE, DATE, SIZE, SOURCE } = value @@ -78,6 +78,7 @@ Row.propTypes = { value: PropTypes.object, isSelected: PropTypes.bool, handleClick: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } export default Row diff --git a/src/fireedge/src/client/components/Tables/MarketplaceApps/index.js b/src/fireedge/src/client/components/Tables/MarketplaceApps/index.js index e11e6d8715..aa3fcca496 100644 --- a/src/fireedge/src/client/components/Tables/MarketplaceApps/index.js +++ b/src/fireedge/src/client/components/Tables/MarketplaceApps/index.js @@ -13,15 +13,17 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { useMemo, ReactElement } from 'react' - -import { useViews } from 'client/features/Auth' -import { useGetMarketplaceAppsQuery } from 'client/features/OneApi/marketplaceApp' - +import { StatusCircle } from 'client/components/Status' import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' import MarketplaceAppColumns from 'client/components/Tables/MarketplaceApps/columns' import MarketplaceAppRow from 'client/components/Tables/MarketplaceApps/row' -import { RESOURCE_NAMES } from 'client/constants' +import { RESOURCE_NAMES, T } from 'client/constants' +import { useViews } from 'client/features/Auth' +import { useGetMarketplaceAppsQuery } from 'client/features/OneApi/marketplaceApp' +import { getState, getType } from 'client/models/MarketplaceApp' +import { prettyBytes } from 'client/utils' +import { ReactElement, useMemo } from 'react' const DEFAULT_DATA_CY = 'apps' @@ -56,6 +58,41 @@ const MarketplaceAppsTable = (props) => { [view] ) + const listHeader = [ + { + header: '', + id: 'status-icon', + accessor: (vm) => { + const { color: stateColor, name: stateName } = getState(vm) + + return + }, + }, + { header: T.ID, id: 'id', accessor: 'ID' }, + { header: T.Name, id: 'name', accessor: 'NAME' }, + { header: T.Owner, id: 'owner', accessor: 'UNAME' }, + { header: T.Group, id: 'group', accessor: 'GNAME' }, + { + header: T.Size, + id: 'Size', + accessor: ({ SIZE }) => prettyBytes(+SIZE, 'MB'), + }, + { + header: T.Type, + id: 'type', + accessor: (template) => + useMemo(() => getType(template), [template?.TYPE]), + }, + { + header: T.Marketplace, + id: 'marketplace', + accessor: 'MARKETPLACE', + }, + { header: T.Zone, id: 'zone', accessor: 'ZONE_ID' }, + ] + + const { component, header } = WrapperRow(MarketplaceAppRow) + return ( { refetch={refetch} isLoading={isFetching} getRowId={(row) => String(row.ID)} - RowComponent={MarketplaceAppRow} + RowComponent={component} + headerList={header && listHeader} {...rest} /> ) diff --git a/src/fireedge/src/client/components/Tables/MarketplaceApps/row.js b/src/fireedge/src/client/components/Tables/MarketplaceApps/row.js index a78b0cee08..46776219e6 100644 --- a/src/fireedge/src/client/components/Tables/MarketplaceApps/row.js +++ b/src/fireedge/src/client/components/Tables/MarketplaceApps/row.js @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo, useMemo, useCallback } from 'react' import PropTypes from 'prop-types' +import { memo, useCallback, useMemo } from 'react' +import { MarketplaceAppCard } from 'client/components/Cards' import api, { useUpdateAppMutation, } from 'client/features/OneApi/marketplaceApp' -import { MarketplaceAppCard } from 'client/components/Cards' import { jsonToXml } from 'client/models/Helper' const Row = memo( - ({ original, value, onClickLabel, ...props }) => { + ({ original, value, onClickLabel, headerList, ...props }) => { const [update] = useUpdateAppMutation() const state = api.endpoints.getMarketplaceApps.useQueryState(undefined, { @@ -64,6 +64,7 @@ Row.propTypes = { className: PropTypes.string, onClick: PropTypes.func, onClickLabel: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } Row.displayName = 'MarketplaceAppRow' diff --git a/src/fireedge/src/client/components/Tables/Marketplaces/index.js b/src/fireedge/src/client/components/Tables/Marketplaces/index.js index 76836ab886..ff7fd11132 100644 --- a/src/fireedge/src/client/components/Tables/Marketplaces/index.js +++ b/src/fireedge/src/client/components/Tables/Marketplaces/index.js @@ -13,16 +13,19 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { useMemo, ReactElement } from 'react' import PropTypes from 'prop-types' +import { ReactElement, useMemo } from 'react' -import { useViews } from 'client/features/Auth' -import { useGetMarketplacesQuery } from 'client/features/OneApi/marketplace' - +import { Tr } from 'client/components/HOC' +import { LinearProgressWithLabel, StatusCircle } from 'client/components/Status' import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' import MarketplaceColumns from 'client/components/Tables/Marketplaces/columns' import MarketplaceRow from 'client/components/Tables/Marketplaces/row' -import { RESOURCE_NAMES } from 'client/constants' +import { MARKET_THRESHOLD, RESOURCE_NAMES, T } from 'client/constants' +import { useViews } from 'client/features/Auth' +import { useGetMarketplacesQuery } from 'client/features/OneApi/marketplace' +import { getCapacityInfo, getState } from 'client/models/Datastore' const DEFAULT_DATA_CY = 'marketplaces' @@ -53,6 +56,52 @@ const MarketplacesTable = ({ filter, ...props }) => { [view] ) + const listHeader = [ + { + header: '', + id: 'status-icon', + accessor: (vm) => { + const { color: stateColor, name: stateName } = getState(vm) + + return + }, + }, + { header: T.ID, id: 'id', accessor: 'ID' }, + { header: T.Name, id: 'name', accessor: 'NAME' }, + { header: T.Owner, id: 'owner', accessor: 'UNAME' }, + { header: T.Group, id: 'group', accessor: 'GNAME' }, + { + header: T.Capacity, + id: 'capacity', + accessor: (template) => { + const capacity = useMemo(() => getCapacityInfo(template), [template]) + const { percentOfUsed, percentLabel } = capacity + + return ( + + ) + }, + }, + { + header: T.Apps, + id: 'apps', + accessor: ({ MARKETPLACEAPPS }) => + useMemo( + () => [MARKETPLACEAPPS?.ID ?? []].flat().length || 0, + [MARKETPLACEAPPS?.ID] + ), + }, + { header: T.Zone, id: 'zone', accessor: 'ZONE_ID' }, + ] + + const { component, header } = WrapperRow(MarketplaceRow) + return ( { refetch={refetch} isLoading={isFetching} getRowId={(row) => String(row.ID)} - RowComponent={MarketplaceRow} + RowComponent={component} + headerList={header && listHeader} {...rest} /> ) diff --git a/src/fireedge/src/client/components/Tables/Marketplaces/row.js b/src/fireedge/src/client/components/Tables/Marketplaces/row.js index 521c03ac8b..a26d8268f8 100644 --- a/src/fireedge/src/client/components/Tables/Marketplaces/row.js +++ b/src/fireedge/src/client/components/Tables/Marketplaces/row.js @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo, useMemo } from 'react' import PropTypes from 'prop-types' +import { memo, useMemo } from 'react' -import marketplaceApi from 'client/features/OneApi/marketplace' import { MarketplaceCard } from 'client/components/Cards' +import marketplaceApi from 'client/features/OneApi/marketplace' const Row = memo( - ({ original, value, ...props }) => { + ({ original, value, headerList, ...props }) => { const state = marketplaceApi.endpoints.getMarketplaces.useQueryState( undefined, { @@ -42,6 +42,7 @@ Row.propTypes = { isSelected: PropTypes.bool, className: PropTypes.string, handleClick: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } Row.displayName = 'MarketplaceRow' diff --git a/src/fireedge/src/client/components/Tables/SecurityGroups/index.js b/src/fireedge/src/client/components/Tables/SecurityGroups/index.js index cacb52da77..12f476dea3 100644 --- a/src/fireedge/src/client/components/Tables/SecurityGroups/index.js +++ b/src/fireedge/src/client/components/Tables/SecurityGroups/index.js @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { useMemo, ReactElement } from 'react' - -import { useViews } from 'client/features/Auth' -import { useGetSecGroupsQuery } from 'client/features/OneApi/securityGroup' +import { ReactElement, useMemo } from 'react' import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' import SecurityGroupColumns from 'client/components/Tables/SecurityGroups/columns' import SecurityGroupsRow from 'client/components/Tables/SecurityGroups/row' -import { RESOURCE_NAMES } from 'client/constants' +import { RESOURCE_NAMES, T } from 'client/constants' +import { useViews } from 'client/features/Auth' +import { useGetSecGroupsQuery } from 'client/features/OneApi/securityGroup' const DEFAULT_DATA_CY = 'secgroup' @@ -51,6 +51,15 @@ const SecurityGroupsTable = (props) => { [view] ) + const listHeader = [ + { header: T.ID, id: 'id', accessor: 'ID' }, + { header: T.Name, id: 'name', accessor: 'NAME' }, + { header: T.Owner, id: 'owner', accessor: 'UNAME' }, + { header: T.Group, id: 'group', accessor: 'GNAME' }, + ] + + const { component, header } = WrapperRow(SecurityGroupsRow) + return ( { refetch={refetch} isLoading={isFetching} getRowId={(row) => String(row.ID)} - RowComponent={SecurityGroupsRow} + RowComponent={component} + headerList={header && listHeader} {...rest} /> ) diff --git a/src/fireedge/src/client/components/Tables/SecurityGroups/row.js b/src/fireedge/src/client/components/Tables/SecurityGroups/row.js index 84c4508456..ceb207d1ee 100644 --- a/src/fireedge/src/client/components/Tables/SecurityGroups/row.js +++ b/src/fireedge/src/client/components/Tables/SecurityGroups/row.js @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo, useMemo, useCallback } from 'react' -import PropTypes from 'prop-types' +import { SecurityGroupCard } from 'client/components/Cards' import secGroupApi, { useUpdateSecGroupMutation, } from 'client/features/OneApi/securityGroup' -import { SecurityGroupCard } from 'client/components/Cards' import { jsonToXml } from 'client/models/Helper' +import PropTypes from 'prop-types' +import { memo, useCallback, useMemo } from 'react' const Row = memo( - ({ original, value, onClickLabel, ...props }) => { + ({ original, value, onClickLabel, headerList, ...props }) => { const [update] = useUpdateSecGroupMutation() const { @@ -74,6 +74,7 @@ Row.propTypes = { isSelected: PropTypes.bool, handleClick: PropTypes.func, onClickLabel: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } Row.displayName = 'SecurityGroupRow' diff --git a/src/fireedge/src/client/components/Tables/ServiceTemplates/row.js b/src/fireedge/src/client/components/Tables/ServiceTemplates/row.js index ee6a9a0e66..4c3320e648 100644 --- a/src/fireedge/src/client/components/Tables/ServiceTemplates/row.js +++ b/src/fireedge/src/client/components/Tables/ServiceTemplates/row.js @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo, useMemo, useCallback } from 'react' import PropTypes from 'prop-types' +import { memo, useCallback, useMemo } from 'react' +import { ServiceTemplateCard } from 'client/components/Cards' import serviceTemplateApi, { useUpdateServiceTemplateMutation, } from 'client/features/OneApi/serviceTemplate' -import { ServiceTemplateCard } from 'client/components/Cards' const Row = memo( - ({ original, value, ...props }) => { + ({ original, value, headerList, ...props }) => { const [update] = useUpdateServiceTemplateMutation() const state = @@ -63,6 +63,7 @@ Row.propTypes = { isSelected: PropTypes.bool, className: PropTypes.string, handleClick: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } Row.displayName = 'ServiceTemplateRow' diff --git a/src/fireedge/src/client/components/Tables/Services/row.js b/src/fireedge/src/client/components/Tables/Services/row.js index f9fcd2e81d..d82cc87a29 100644 --- a/src/fireedge/src/client/components/Tables/Services/row.js +++ b/src/fireedge/src/client/components/Tables/Services/row.js @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo, useMemo } from 'react' import PropTypes from 'prop-types' +import { memo, useMemo } from 'react' -import serviceApi from 'client/features/OneApi/service' import { ServiceCard } from 'client/components/Cards' +import serviceApi from 'client/features/OneApi/service' const Row = memo( - ({ original, value, ...props }) => { + ({ original, value, headerList, ...props }) => { const state = serviceApi.endpoints.getServices.useQueryState(undefined, { selectFromResult: ({ data = [] }) => data.find((service) => +service.ID === +original.ID), @@ -39,6 +39,7 @@ Row.propTypes = { isSelected: PropTypes.bool, className: PropTypes.string, handleClick: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } Row.displayName = 'ServiceRow' diff --git a/src/fireedge/src/client/components/Tables/Support/index.js b/src/fireedge/src/client/components/Tables/Support/index.js index 7e43257a19..3c9b683e14 100644 --- a/src/fireedge/src/client/components/Tables/Support/index.js +++ b/src/fireedge/src/client/components/Tables/Support/index.js @@ -13,15 +13,14 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { useMemo, ReactElement } from 'react' - -import { useViews } from 'client/features/Auth' -import { useGetTicketsQuery } from 'client/features/OneApi/support' - import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' import SupportColumns from 'client/components/Tables/Support/columns' import SupportRow from 'client/components/Tables/Support/row' -import { RESOURCE_NAMES } from 'client/constants' +import { RESOURCE_NAMES, T } from 'client/constants' +import { useViews } from 'client/features/Auth' +import { useGetTicketsQuery } from 'client/features/OneApi/support' +import { ReactElement, useMemo } from 'react' const DEFAULT_DATA_CY = 'support' @@ -62,6 +61,13 @@ const SupportTable = (props) => { [view] ) + const listHeader = [ + { header: T.ID, id: 'id', accessor: 'id' }, + { header: T.Subject, id: 'subject', accessor: 'subject' }, + { header: T.Status, id: 'status', accessor: 'status' }, + ] + const { component, header } = WrapperRow(SupportRow) + return ( { refetch={refetch} isLoading={isFetching} getRowId={(row) => String(row.id)} - RowComponent={SupportRow} initialState={initialState} + RowComponent={component} + headerList={header && listHeader} {...rest} /> ) diff --git a/src/fireedge/src/client/components/Tables/Support/row.js b/src/fireedge/src/client/components/Tables/Support/row.js index 0bd6e93cb8..db55127a33 100644 --- a/src/fireedge/src/client/components/Tables/Support/row.js +++ b/src/fireedge/src/client/components/Tables/Support/row.js @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo } from 'react' import PropTypes from 'prop-types' +import { memo } from 'react' import { SupportCard } from 'client/components/Cards' const Row = memo( - ({ original, value, ...props }) => ( + ({ original, value, headerList, ...props }) => ( ), (prev, next) => prev.className === next.className @@ -31,6 +31,7 @@ Row.propTypes = { isSelected: PropTypes.bool, className: PropTypes.string, onClick: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } Row.displayName = 'SupportRow' diff --git a/src/fireedge/src/client/components/Tables/Users/index.js b/src/fireedge/src/client/components/Tables/Users/index.js index dd1c8948c8..6d1e9242e6 100644 --- a/src/fireedge/src/client/components/Tables/Users/index.js +++ b/src/fireedge/src/client/components/Tables/Users/index.js @@ -13,15 +13,17 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { useMemo, ReactElement } from 'react' - -import { useViews } from 'client/features/Auth' -import { useGetUsersQuery } from 'client/features/OneApi/user' +import { ReactElement, useMemo } from 'react' +import { LinearProgressWithTooltip } from 'client/components/Status' import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' import UserColumns from 'client/components/Tables/Users/columns' import UserRow from 'client/components/Tables/Users/row' -import { RESOURCE_NAMES } from 'client/constants' +import { RESOURCE_NAMES, T } from 'client/constants' +import { useViews } from 'client/features/Auth' +import { useGetUsersQuery } from 'client/features/OneApi/user' +import { getQuotaUsage } from 'client/models/User' const DEFAULT_DATA_CY = 'users' @@ -52,6 +54,76 @@ const UsersTable = (props) => { [view] ) + const listHeader = [ + { header: T.ID, id: 'id', accessor: 'ID' }, + { header: T.Name, id: 'name', accessor: 'NAME' }, + { header: T.Group, id: 'group', accessor: 'GNAME' }, + { + header: T.Enabled, + id: 'enabled', + accessor: ({ ENABLED }) => (+ENABLED ? T.Yes : T.No), + }, + { header: T.AuthDriver, id: 'auth-driver', accessor: 'AUTH_DRIVER' }, + { + header: T.VMs, + id: 'vms', + accessor: ({ VM_QUOTA }) => { + const vmQuotaUsage = useMemo( + () => getQuotaUsage('VM', VM_QUOTA), + [VM_QUOTA] + ) + + return ( + + ) + }, + }, + { + header: T.Datastores, + id: 'datastores', + accessor: ({ DATASTORE_QUOTA }) => { + const datastoreQuotaUsage = useMemo( + () => getQuotaUsage('DATASTORE', DATASTORE_QUOTA), + [DATASTORE_QUOTA] + ) + + return ( + + ) + }, + }, + { + header: T.Networks, + id: 'networks', + accessor: ({ NETWORK_QUOTA }) => { + const networkQuotaUsage = useMemo( + () => getQuotaUsage('NETWORK', NETWORK_QUOTA), + [NETWORK_QUOTA] + ) + + return ( + + ) + }, + }, + ] + const { component, header } = WrapperRow(UserRow) + return ( { refetch={refetch} isLoading={isFetching} getRowId={(row) => String(row.ID)} - RowComponent={UserRow} + RowComponent={component} + headerList={header && listHeader} {...rest} /> ) diff --git a/src/fireedge/src/client/components/Tables/Users/row.js b/src/fireedge/src/client/components/Tables/Users/row.js index b743efd185..8fa10525ed 100644 --- a/src/fireedge/src/client/components/Tables/Users/row.js +++ b/src/fireedge/src/client/components/Tables/Users/row.js @@ -18,7 +18,7 @@ import PropTypes from 'prop-types' import { UserCard } from 'client/components/Cards' -const Row = ({ original, value, ...props }) => ( +const Row = ({ original, value, headerList, ...props }) => ( ) @@ -27,6 +27,7 @@ Row.propTypes = { value: PropTypes.object, isSelected: PropTypes.bool, handleClick: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } export default Row diff --git a/src/fireedge/src/client/components/Tables/VNetworkTemplates/index.js b/src/fireedge/src/client/components/Tables/VNetworkTemplates/index.js index 10962361e8..85c0969766 100644 --- a/src/fireedge/src/client/components/Tables/VNetworkTemplates/index.js +++ b/src/fireedge/src/client/components/Tables/VNetworkTemplates/index.js @@ -14,15 +14,15 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ -import { useMemo, ReactElement } from 'react' - -import { useViews } from 'client/features/Auth' -import { useGetVNTemplatesQuery } from 'client/features/OneApi/networkTemplate' +import { ReactElement, useMemo } from 'react' import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' import VNetworkTemplateColumns from 'client/components/Tables/VNetworkTemplates/columns' import VNetworkTemplateRow from 'client/components/Tables/VNetworkTemplates/row' -import { RESOURCE_NAMES } from 'client/constants' +import { RESOURCE_NAMES, T } from 'client/constants' +import { useViews } from 'client/features/Auth' +import { useGetVNTemplatesQuery } from 'client/features/OneApi/networkTemplate' const DEFAULT_DATA_CY = 'vnet-templates' @@ -47,6 +47,15 @@ const VNetworkTemplatesTable = (props) => { [view] ) + const listHeader = [ + { header: T.ID, id: 'id', accessor: 'ID' }, + { header: T.Name, id: 'name', accessor: 'NAME' }, + { header: T.Owner, id: 'owner', accessor: 'UNAME' }, + { header: T.Group, id: 'group', accessor: 'GNAME' }, + ] + + const { component, header } = WrapperRow(VNetworkTemplateRow) + return ( { refetch={refetch} isLoading={isFetching} getRowId={(row) => String(row.ID)} - RowComponent={VNetworkTemplateRow} + RowComponent={component} + headerList={header && listHeader} {...rest} /> ) diff --git a/src/fireedge/src/client/components/Tables/VNetworkTemplates/row.js b/src/fireedge/src/client/components/Tables/VNetworkTemplates/row.js index 874fe3ee5b..ea37609c72 100644 --- a/src/fireedge/src/client/components/Tables/VNetworkTemplates/row.js +++ b/src/fireedge/src/client/components/Tables/VNetworkTemplates/row.js @@ -19,13 +19,13 @@ import PropTypes from 'prop-types' import { Typography } from '@mui/material' import { Cloud, Group, Lock, User } from 'iconoir-react' -import { rowStyles } from 'client/components/Tables/styles' import { Tr } from 'client/components/HOC' +import { rowStyles } from 'client/components/Tables/styles' import { T } from 'client/constants' import * as Helper from 'client/models/Helper' -const Row = ({ original, value, ...props }) => { +const Row = ({ original, value, headerList, ...props }) => { const classes = rowStyles() const { ID, NAME, UNAME, GNAME, LOCK, REGTIME, PROVISION_ID } = value @@ -68,6 +68,7 @@ Row.propTypes = { value: PropTypes.object, isSelected: PropTypes.bool, handleClick: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } export default Row diff --git a/src/fireedge/src/client/components/Tables/VNetworks/index.js b/src/fireedge/src/client/components/Tables/VNetworks/index.js index cb41d7e43c..8ce4436652 100644 --- a/src/fireedge/src/client/components/Tables/VNetworks/index.js +++ b/src/fireedge/src/client/components/Tables/VNetworks/index.js @@ -13,19 +13,21 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { ReactElement, useCallback, useEffect, useMemo, useState } from 'react' - -import { useViews } from 'client/features/Auth' -import { useGetVNetworksQuery } from 'client/features/OneApi/network' - +import { Tr } from 'client/components/HOC' +import { LinearProgressWithLabel, StatusCircle } from 'client/components/Status' import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' import { areArraysEqual, sortStateTables, } from 'client/components/Tables/Enhanced/Utils/DataTableUtils' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' import VNetworkColumns from 'client/components/Tables/VNetworks/columns' import VNetworkRow from 'client/components/Tables/VNetworks/row' -import { RESOURCE_NAMES } from 'client/constants' +import { RESOURCE_NAMES, T, VNET_THRESHOLD } from 'client/constants' +import { useViews } from 'client/features/Auth' +import { useGetVNetworksQuery } from 'client/features/OneApi/network' +import { getLeasesInfo, getState } from 'client/models/VirtualNetwork' +import { ReactElement, useCallback, useEffect, useMemo, useState } from 'react' import { useFormContext } from 'react-hook-form' const DEFAULT_DATA_CY = 'vnets' @@ -137,6 +139,54 @@ const VNetworksTable = (props) => { }) useEffect(() => refetch(), []) + const listHeader = [ + { + header: '', + id: 'status-icon', + accessor: (template) => { + const { color: stateColor, name: stateName } = getState(template) + + return + }, + }, + { header: T.ID, id: 'id', accessor: 'ID' }, + { header: T.Name, id: 'name', accessor: 'NAME' }, + { header: T.Owner, id: 'owner', accessor: 'UNAME' }, + { header: T.Group, id: 'group', accessor: 'GNAME' }, + { + header: T.Clusters, + id: 'clusters', + accessor: ({ CLUSTERS }) => { + const clusters = useMemo( + () => [CLUSTERS?.ID ?? []].flat(), + [CLUSTERS?.ID] + ) + + return clusters.length && clusters[0] + }, + }, + { + header: T.Leases, + id: 'leases', + accessor: (template) => { + const leasesInfo = useMemo(() => getLeasesInfo(template), [template]) + const { percentOfUsed, percentLabel } = leasesInfo + + return ( + + ) + }, + }, + ] + + const { component, header } = WrapperRow(VNetworkRow) + return ( { refetch={refetch} isLoading={isFetching} getRowId={(row) => String(row.ID)} - RowComponent={VNetworkRow} dataDepend={values} + RowComponent={component} + headerList={header && listHeader} {...rest} /> ) diff --git a/src/fireedge/src/client/components/Tables/VNetworks/row.js b/src/fireedge/src/client/components/Tables/VNetworks/row.js index 06a1d5b2ab..565c6b8714 100644 --- a/src/fireedge/src/client/components/Tables/VNetworks/row.js +++ b/src/fireedge/src/client/components/Tables/VNetworks/row.js @@ -13,21 +13,21 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo, useMemo, useCallback } from 'react' -import PropTypes from 'prop-types' import { jsonToXml } from 'client/models/Helper' +import PropTypes from 'prop-types' +import { memo, useCallback, useMemo } from 'react' -import api, { useUpdateVNetMutation } from 'client/features/OneApi/network' import { NetworkCard } from 'client/components/Cards' +import api, { useUpdateVNetMutation } from 'client/features/OneApi/network' const Row = memo( - ({ original, value, onClickLabel, ...props }) => { + ({ original, value, onClickLabel, headerList, ...props }) => { const [update] = useUpdateVNetMutation() const { data: vnetworks, error, isLoading, - } = api.endpoints.getVNetworks.useQuery(undefined) + } = api.endpoints.getVNetworks.useQueryState(undefined) const vnetwork = useMemo( () => vnetworks?.find((vnet) => +vnet.ID === +original.ID) ?? original, @@ -69,6 +69,7 @@ Row.propTypes = { className: PropTypes.string, onClick: PropTypes.func, onClickLabel: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } Row.displayName = 'VirtualNetworkRow' diff --git a/src/fireedge/src/client/components/Tables/VRouterTemplates/index.js b/src/fireedge/src/client/components/Tables/VRouterTemplates/index.js index 043c6d27fa..b15ae45bd9 100644 --- a/src/fireedge/src/client/components/Tables/VRouterTemplates/index.js +++ b/src/fireedge/src/client/components/Tables/VRouterTemplates/index.js @@ -29,6 +29,7 @@ import { BoxIso as DownloadIcon } from 'iconoir-react' import { Tr, Translate } from 'client/components/HOC' import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' import VRouterTemplateColumns from 'client/components/Tables/VRouterTemplates/columns' import VRouterTemplateRow from 'client/components/Tables/VRouterTemplates/row' import { useStyles } from 'client/components/Tabs/EmptyTab/styles' @@ -37,6 +38,7 @@ import { useExportAppMutation, useLazyGetMarketplaceAppsQuery, } from 'client/features/OneApi/marketplaceApp' +import { timeToString } from 'client/models/Helper' import InfoEmpty from 'iconoir-react/dist/InfoEmpty' import { debounce } from 'lodash' @@ -262,6 +264,20 @@ const VRouterTemplatesTable = (props) => { ) + const listHeader = [ + { header: T.ID, id: 'id', accessor: 'ID' }, + { header: T.Name, id: 'name', accessor: 'NAME' }, + { header: T.Owner, id: 'owner', accessor: 'UNAME' }, + { header: T.Group, id: 'group', accessor: 'GNAME' }, + { + header: T.RegistrationTime, + id: 'registration-time', + accessor: (template) => timeToString(template.REGTIME), + }, + ] + + const { component, header } = WrapperRow(VRouterTemplateRow) + return ( { refetch={refetch} isLoading={loading} getRowId={(row) => String(row.ID)} - RowComponent={VRouterTemplateRow} noDataCustomRenderer={} + RowComponent={component} + headerList={header && listHeader} {...rest} /> ) diff --git a/src/fireedge/src/client/components/Tables/VRouterTemplates/row.js b/src/fireedge/src/client/components/Tables/VRouterTemplates/row.js index 0eb6b72757..b4b86b938c 100644 --- a/src/fireedge/src/client/components/Tables/VRouterTemplates/row.js +++ b/src/fireedge/src/client/components/Tables/VRouterTemplates/row.js @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo, useMemo, useCallback } from 'react' import PropTypes from 'prop-types' +import { memo, useCallback, useMemo } from 'react' +import { VmTemplateCard as VRouterTemplateCard } from 'client/components/Cards' import vrouterTemplatesApi, { useUpdateTemplateMutation, } from 'client/features/OneApi/vmTemplate' -import { VmTemplateCard as VRouterTemplateCard } from 'client/components/Cards' import { jsonToXml } from 'client/models/Helper' const Row = memo( - ({ original, value, onClickLabel, ...props }) => { + ({ original, value, onClickLabel, headerList, ...props }) => { const [update] = useUpdateTemplateMutation() const state = @@ -68,6 +68,7 @@ Row.propTypes = { className: PropTypes.string, onClick: PropTypes.func, onClickLabel: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } Row.displayName = 'VRouterTemplateRow' diff --git a/src/fireedge/src/client/components/Tables/VRouters/index.js b/src/fireedge/src/client/components/Tables/VRouters/index.js index d012c0c395..e0e60a5851 100644 --- a/src/fireedge/src/client/components/Tables/VRouters/index.js +++ b/src/fireedge/src/client/components/Tables/VRouters/index.js @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { useMemo, ReactElement } from 'react' - -import { useViews } from 'client/features/Auth' -import { useGetVRoutersQuery } from 'client/features/OneApi/vrouter' +import { ReactElement, useMemo } from 'react' import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' import VRouterColumns from 'client/components/Tables/VRouters/columns' import VRouterRow from 'client/components/Tables/VRouters/row' -import { RESOURCE_NAMES } from 'client/constants' +import { RESOURCE_NAMES, T } from 'client/constants' +import { useViews } from 'client/features/Auth' +import { useGetVRoutersQuery } from 'client/features/OneApi/vrouter' const DEFAULT_DATA_CY = 'vrouters' @@ -51,6 +51,15 @@ const VRoutersTable = (props) => { [view] ) + const listHeader = [ + { header: T.ID, id: 'id', accessor: 'ID' }, + { header: T.Name, id: 'name', accessor: 'NAME' }, + { header: T.Owner, id: 'owner', accessor: 'UNAME' }, + { header: T.Group, id: 'group', accessor: 'GNAME' }, + ] + + const { component, header } = WrapperRow(VRouterRow) + return ( { refetch={refetch} isLoading={isFetching} getRowId={(row) => String(row.ID)} - RowComponent={VRouterRow} + RowComponent={component} + headerList={header && listHeader} {...rest} /> ) diff --git a/src/fireedge/src/client/components/Tables/VRouters/row.js b/src/fireedge/src/client/components/Tables/VRouters/row.js index 910dbd94af..d400959185 100644 --- a/src/fireedge/src/client/components/Tables/VRouters/row.js +++ b/src/fireedge/src/client/components/Tables/VRouters/row.js @@ -16,15 +16,15 @@ /* eslint-disable jsdoc/require-jsdoc */ import PropTypes from 'prop-types' -import { User, Group, EmptyPage, ModernTv } from 'iconoir-react' import { Typography } from '@mui/material' +import { EmptyPage, Group, ModernTv, User } from 'iconoir-react' import { rowStyles } from 'client/components/Tables/styles' import { Tr } from 'client/components/HOC' import { T } from 'client/constants' -const Row = ({ original, value, ...props }) => { +const Row = ({ original, value, headerList, ...props }) => { const classes = rowStyles() const { ID, NAME, UNAME, GNAME, VMS, TEMPLATE_ID } = value @@ -65,6 +65,7 @@ Row.propTypes = { value: PropTypes.object, isSelected: PropTypes.bool, handleClick: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } export default Row diff --git a/src/fireedge/src/client/components/Tables/VirtualDataCenters/index.js b/src/fireedge/src/client/components/Tables/VirtualDataCenters/index.js index 9ef73cfc70..e3aea79be1 100644 --- a/src/fireedge/src/client/components/Tables/VirtualDataCenters/index.js +++ b/src/fireedge/src/client/components/Tables/VirtualDataCenters/index.js @@ -13,18 +13,21 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { useMemo, ReactElement } from 'react' +import { ReactElement, useMemo } from 'react' +import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' +import VDCColumns from 'client/components/Tables/VirtualDataCenters/columns' +import VDCRow from 'client/components/Tables/VirtualDataCenters/row' +import { ALL_SELECTED, RESOURCE_NAMES, T } from 'client/constants' import { useViews } from 'client/features/Auth' import { useGetVDCsQuery } from 'client/features/OneApi/vdc' -import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' -import VDCColumns from 'client/components/Tables/VirtualDataCenters/columns' -import VDCRow from 'client/components/Tables/VirtualDataCenters/row' -import { RESOURCE_NAMES } from 'client/constants' - const DEFAULT_DATA_CY = 'vdcs' +const isAllSelected = (resourceArray) => + resourceArray.length === 1 && resourceArray[0] === ALL_SELECTED + /** * @param {object} props - Props * @returns {ReactElement} VM Templates table @@ -46,6 +49,75 @@ const VDCsTable = (props) => { [view] ) + const listHeader = [ + { header: T.ID, id: 'id', accessor: 'ID' }, + { header: T.Name, id: 'name', accessor: 'NAME' }, + { + header: T.Groups, + id: 'group', + accessor: ({ GROUPS }) => + useMemo(() => { + const { ID: groupsIds = [] } = GROUPS + const groupsArray = Array.isArray(groupsIds) ? groupsIds : [groupsIds] + + return groupsArray.length + }, [GROUPS.ID]), + }, + { + header: T.Clusters, + id: 'clusters', + accessor: ({ CLUSTERS }) => + useMemo(() => { + const { CLUSTER: clustersInfo = [] } = CLUSTERS + const clustersArray = ( + Array.isArray(clustersInfo) ? clustersInfo : [clustersInfo] + ).map((cluster) => cluster.CLUSTER_ID) + + return isAllSelected(clustersArray) ? T.All : clustersArray.length + }, [CLUSTERS.CLUSTER]), + }, + { + header: T.Hosts, + id: 'hosts', + accessor: ({ HOSTS }) => + useMemo(() => { + const { HOST: hostsInfo = [] } = HOSTS + const hostsArray = ( + Array.isArray(hostsInfo) ? hostsInfo : [hostsInfo] + ).map((host) => host.HOST_ID) + + return isAllSelected(hostsArray) ? T.All : hostsArray.length + }, [HOSTS.HOST]), + }, + { + header: T.Vnets, + id: 'vnets', + accessor: ({ VNETS }) => + useMemo(() => { + const { VNET: vnetsInfo = [] } = VNETS + const vnetsArray = ( + Array.isArray(vnetsInfo) ? vnetsInfo : [vnetsInfo] + ).map((vnet) => vnet.VNET_ID) + + return isAllSelected(vnetsArray) ? T.All : vnetsArray.length + }, [VNETS.VNET]), + }, + { + header: T.Datastores, + id: 'datastores', + accessor: ({ DATASTORES }) => + useMemo(() => { + const { DATASTORE: datastoresInfo = [] } = DATASTORES + const datastoresArray = ( + Array.isArray(datastoresInfo) ? datastoresInfo : [datastoresInfo] + ).map((ds) => ds.DATASTORE_ID) + + return isAllSelected(datastoresArray) ? T.All : datastoresArray.length + }, [DATASTORES.DATASTORE]), + }, + ] + const { component, header } = WrapperRow(VDCRow) + return ( { refetch={refetch} isLoading={isFetching} getRowId={(row) => String(row.ID)} - RowComponent={VDCRow} + RowComponent={component} + headerList={header && listHeader} {...rest} /> ) diff --git a/src/fireedge/src/client/components/Tables/VirtualDataCenters/row.js b/src/fireedge/src/client/components/Tables/VirtualDataCenters/row.js index 27b2082cac..2884213df5 100644 --- a/src/fireedge/src/client/components/Tables/VirtualDataCenters/row.js +++ b/src/fireedge/src/client/components/Tables/VirtualDataCenters/row.js @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo, useMemo, useCallback } from 'react' import PropTypes from 'prop-types' +import { memo, useCallback, useMemo } from 'react' -import vdcApi, { useUpdateVDCMutation } from 'client/features/OneApi/vdc' import { VirtualDataCenterCard } from 'client/components/Cards' +import vdcApi, { useUpdateVDCMutation } from 'client/features/OneApi/vdc' import { jsonToXml } from 'client/models/Helper' const Row = memo( - ({ original, value, onClickLabel, ...props }) => { + ({ original, value, onClickLabel, headerList, ...props }) => { const [update] = useUpdateVDCMutation() const state = vdcApi.endpoints.getVDCs.useQueryState(undefined, { @@ -62,6 +62,7 @@ Row.propTypes = { className: PropTypes.string, onClick: PropTypes.func, onClickLabel: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } Row.displayName = 'VirtualDataCenterRow' diff --git a/src/fireedge/src/client/components/Tables/VmDisks/row.js b/src/fireedge/src/client/components/Tables/VmDisks/row.js index 437116b2e0..3fd155099e 100644 --- a/src/fireedge/src/client/components/Tables/VmDisks/row.js +++ b/src/fireedge/src/client/components/Tables/VmDisks/row.js @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo, useMemo } from 'react' import PropTypes from 'prop-types' +import { memo, useMemo } from 'react' import { DiskCard } from 'client/components/Cards' const Row = memo( - ({ original, value, ...props }) => { + ({ original, value, headerList, ...props }) => { const memoDisk = useMemo(() => original, [original]) return @@ -33,6 +33,7 @@ Row.propTypes = { isSelected: PropTypes.bool, className: PropTypes.string, handleClick: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } Row.displayName = 'VmDiskRow' diff --git a/src/fireedge/src/client/components/Tables/VmGroups/index.js b/src/fireedge/src/client/components/Tables/VmGroups/index.js index 5cf07b72d8..3f4b78777d 100644 --- a/src/fireedge/src/client/components/Tables/VmGroups/index.js +++ b/src/fireedge/src/client/components/Tables/VmGroups/index.js @@ -15,13 +15,13 @@ * ------------------------------------------------------------------------- */ import { ReactElement, useEffect, useMemo } from 'react' -import { useViews } from 'client/features/Auth' -import { useGetVMGroupsQuery } from 'client/features/OneApi/vmGroup' - import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' import VmGroupColumns from 'client/components/Tables/VmGroups/columns' import VmGroupRow from 'client/components/Tables/VmGroups/row' -import { RESOURCE_NAMES } from 'client/constants' +import { RESOURCE_NAMES, T } from 'client/constants' +import { useViews } from 'client/features/Auth' +import { useGetVMGroupsQuery } from 'client/features/OneApi/vmGroup' const DEFAULT_DATA_CY = 'vmgroups' @@ -48,6 +48,15 @@ const VmGroupsTable = (props) => { useEffect(() => refetch(), []) + const listHeader = [ + { header: T.ID, id: 'id', accessor: 'ID' }, + { header: T.Name, id: 'name', accessor: 'NAME' }, + { header: T.Owner, id: 'owner', accessor: 'UNAME' }, + { header: T.Group, id: 'group', accessor: 'GNAME' }, + ] + + const { component, header } = WrapperRow(VmGroupRow) + return ( { refetch={refetch} isLoading={isFetching} getRowId={(row) => String(row.ID)} - RowComponent={VmGroupRow} + RowComponent={component} + headerList={header && listHeader} {...rest} /> ) diff --git a/src/fireedge/src/client/components/Tables/VmGroups/row.js b/src/fireedge/src/client/components/Tables/VmGroups/row.js index 1c7fc479ac..b533cadf84 100644 --- a/src/fireedge/src/client/components/Tables/VmGroups/row.js +++ b/src/fireedge/src/client/components/Tables/VmGroups/row.js @@ -18,7 +18,7 @@ import PropTypes from 'prop-types' import { VmGroupCard } from 'client/components/Cards' -const Row = ({ original, value, ...props }) => ( +const Row = ({ original, value, headerList, ...props }) => ( ) @@ -27,6 +27,7 @@ Row.propTypes = { value: PropTypes.object, isSelected: PropTypes.bool, handleClick: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } export default Row diff --git a/src/fireedge/src/client/components/Tables/VmTemplates/index.js b/src/fireedge/src/client/components/Tables/VmTemplates/index.js index fc62d9ce24..c7391d27f5 100644 --- a/src/fireedge/src/client/components/Tables/VmTemplates/index.js +++ b/src/fireedge/src/client/components/Tables/VmTemplates/index.js @@ -15,13 +15,14 @@ * ------------------------------------------------------------------------- */ import { ReactElement, useEffect, useMemo } from 'react' -import { useViews } from 'client/features/Auth' -import { useGetTemplatesQuery } from 'client/features/OneApi/vmTemplate' - import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' import VmTemplateColumns from 'client/components/Tables/VmTemplates/columns' import VmTemplateRow from 'client/components/Tables/VmTemplates/row' -import { RESOURCE_NAMES } from 'client/constants' +import { RESOURCE_NAMES, T } from 'client/constants' +import { useViews } from 'client/features/Auth' +import { useGetTemplatesQuery } from 'client/features/OneApi/vmTemplate' +import { timeToString } from 'client/models/Helper' const DEFAULT_DATA_CY = 'vm-templates' @@ -47,6 +48,20 @@ const VmTemplatesTable = (props) => { ) useEffect(() => refetch(), []) + const listHeader = [ + { header: T.ID, id: 'id', accessor: 'ID' }, + { header: T.Name, id: 'name', accessor: 'NAME' }, + { header: T.Owner, id: 'owner', accessor: 'UNAME' }, + { header: T.Group, id: 'group', accessor: 'GNAME' }, + { + header: T.RegistrationTime, + id: 'registration-time', + accessor: (vm) => timeToString(vm.REGTIME), + }, + ] + + const { component, header } = WrapperRow(VmTemplateRow) + return ( { refetch={refetch} isLoading={isFetching} getRowId={(row) => String(row.ID)} - RowComponent={VmTemplateRow} + RowComponent={component} + headerList={header && listHeader} {...rest} /> ) diff --git a/src/fireedge/src/client/components/Tables/VmTemplates/row.js b/src/fireedge/src/client/components/Tables/VmTemplates/row.js index 4bf9cf52dd..f354585a5f 100644 --- a/src/fireedge/src/client/components/Tables/VmTemplates/row.js +++ b/src/fireedge/src/client/components/Tables/VmTemplates/row.js @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo, useMemo, useCallback } from 'react' import PropTypes from 'prop-types' +import { memo, useCallback, useMemo } from 'react' +import { VmTemplateCard } from 'client/components/Cards' import vmTemplateApi, { useUpdateTemplateMutation, } from 'client/features/OneApi/vmTemplate' -import { VmTemplateCard } from 'client/components/Cards' import { jsonToXml } from 'client/models/Helper' const Row = memo( - ({ original, value, onClickLabel, ...props }) => { + ({ original, value, onClickLabel, headerList, ...props }) => { const [update] = useUpdateTemplateMutation() const state = vmTemplateApi.endpoints.getTemplates.useQueryState( @@ -67,6 +67,7 @@ Row.propTypes = { className: PropTypes.string, onClick: PropTypes.func, onClickLabel: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } Row.displayName = 'VmTemplateRow' diff --git a/src/fireedge/src/client/components/Tables/Vms/index.js b/src/fireedge/src/client/components/Tables/Vms/index.js index 77e24c0182..efa6140b2c 100644 --- a/src/fireedge/src/client/components/Tables/Vms/index.js +++ b/src/fireedge/src/client/components/Tables/Vms/index.js @@ -15,21 +15,29 @@ * ------------------------------------------------------------------------- */ import { ReactElement, useMemo } from 'react' -import { useViews } from 'client/features/Auth' -import { useGetVmsQuery } from 'client/features/OneApi/vm' - +import { ConsoleButton } from 'client/components/Buttons' +import { StatusCircle } from 'client/components/Status' import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' import VmColumns from 'client/components/Tables/Vms/columns' import VmRow from 'client/components/Tables/Vms/row' import { RESOURCE_NAMES, STATES, + T, + VM_ACTIONS, VM_EXTENDED_POOL, VM_STATES, } from 'client/constants' - +import { useViews } from 'client/features/Auth' +import { useGeneral } from 'client/features/General' +import { useGetVmsQuery } from 'client/features/OneApi/vm' +import { getIps, getLastHistory, getState } from 'client/models/VirtualMachine' const DEFAULT_DATA_CY = 'vms' +const { VNC, RDP, SSH, VMRC } = VM_ACTIONS +const CONNECTION_TYPES = [VNC, RDP, SSH, VMRC] + /** * @param {object} props - Props * @returns {ReactElement} Virtual Machines table @@ -121,6 +129,66 @@ const VmsTable = (props) => { [view] ) + const { zone, defaultZone } = useGeneral() + const listHeader = [ + { + header: '', + id: 'status-icon', + accessor: (vm) => { + const { + color: stateColor, + name: stateName, + displayName: stateDisplayName, + } = getState(vm) + + return ( + + ) + }, + }, + { header: T.ID, id: 'id', accessor: 'ID' }, + { header: T.Name, id: 'name', accessor: 'NAME' }, + { header: T.Owner, id: 'owner', accessor: 'UNAME' }, + { header: T.Group, id: 'group', accessor: 'GNAME' }, + { + header: T.State, + id: 'state', + accessor: (vm) => getState(vm)?.name, + }, + { + header: T.Hostname, + id: 'hostname', + accessor: (vm) => getLastHistory(vm)?.HOSTNAME, + }, + { + header: T.IP, + id: 'ips', + accessor: (vm) => getIps(vm).join(), + }, + ] + + zone === defaultZone && + listHeader.push({ + header: '', + id: 'consoles', + accessor: (vm) => ( + <> + {CONNECTION_TYPES.map((connectionType) => ( + + ))} + + ), + }) + + const { component, header } = WrapperRow(VmRow) + return ( { refetch={refetch} isLoading={isFetching} getRowId={(row) => String(row.ID)} - RowComponent={VmRow} initialState={initialState} + RowComponent={component} + headerList={header && listHeader} {...rest} /> ) diff --git a/src/fireedge/src/client/components/Tables/Vms/row.js b/src/fireedge/src/client/components/Tables/Vms/row.js index 81d644b885..318013fbbe 100644 --- a/src/fireedge/src/client/components/Tables/Vms/row.js +++ b/src/fireedge/src/client/components/Tables/Vms/row.js @@ -27,7 +27,7 @@ const { VNC, RDP, SSH, VMRC } = VM_ACTIONS const CONNECTION_TYPES = [VNC, RDP, SSH, VMRC] const Row = memo( - ({ original, value, onClickLabel, globalErrors, ...props }) => { + ({ original, value, onClickLabel, globalErrors, headerList, ...props }) => { // This is for not showing VNC coneections when the user use other zone. const { zone, defaultZone } = useGeneral() @@ -88,6 +88,7 @@ Row.propTypes = { onClick: PropTypes.func, onClickLabel: PropTypes.func, globalErrors: PropTypes.array, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } Row.displayName = 'VirtualMachineRow' diff --git a/src/fireedge/src/client/components/Tables/Wilds/row.js b/src/fireedge/src/client/components/Tables/Wilds/row.js index f36bacc66e..d2041a5457 100644 --- a/src/fireedge/src/client/components/Tables/Wilds/row.js +++ b/src/fireedge/src/client/components/Tables/Wilds/row.js @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo, ReactElement } from 'react' import PropTypes from 'prop-types' +import { memo, ReactElement } from 'react' import { Typography } from '@mui/material' @@ -28,7 +28,7 @@ import { Row as RowType } from 'react-table' * @param {Function} props.handleClick - Action by click * @returns {ReactElement} - Table row */ -const Row = memo(({ original, ...props }) => { +const Row = memo(({ original, headerList, ...props }) => { const classes = rowStyles() const { DEPLOY_ID, VM_NAME } = original @@ -52,6 +52,7 @@ Row.propTypes = { original: PropTypes.object, isSelected: PropTypes.bool, handleClick: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } Row.displayName = 'WildsRow' diff --git a/src/fireedge/src/client/components/Tables/Zombies/row.js b/src/fireedge/src/client/components/Tables/Zombies/row.js index fad71672ee..8b142f7bf7 100644 --- a/src/fireedge/src/client/components/Tables/Zombies/row.js +++ b/src/fireedge/src/client/components/Tables/Zombies/row.js @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo, ReactElement } from 'react' import PropTypes from 'prop-types' +import { memo, ReactElement } from 'react' import { Typography } from '@mui/material' @@ -28,7 +28,7 @@ import { Row as RowType } from 'react-table' * @param {Function} props.handleClick - Action by click * @returns {ReactElement} - Table row */ -const Row = memo(({ original, ...props }) => { +const Row = memo(({ original, headerList, ...props }) => { const classes = rowStyles() const { DEPLOY_ID, VM_NAME } = original @@ -49,6 +49,7 @@ Row.propTypes = { original: PropTypes.object, isSelected: PropTypes.bool, handleClick: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } Row.displayName = 'ZombiesRow' diff --git a/src/fireedge/src/client/components/Tables/Zones/index.js b/src/fireedge/src/client/components/Tables/Zones/index.js index e0363e1999..eb812a07f0 100644 --- a/src/fireedge/src/client/components/Tables/Zones/index.js +++ b/src/fireedge/src/client/components/Tables/Zones/index.js @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { useMemo, ReactElement } from 'react' - -import { useViews } from 'client/features/Auth' -import { useGetZonesQuery } from 'client/features/OneApi/zone' +import { ReactElement, useMemo } from 'react' import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' +import WrapperRow from 'client/components/Tables/Enhanced/WrapperRow' import ZoneColumns from 'client/components/Tables/Zones/columns' import ZoneRow from 'client/components/Tables/Zones/row' -import { RESOURCE_NAMES } from 'client/constants' +import { RESOURCE_NAMES, T } from 'client/constants' +import { useViews } from 'client/features/Auth' +import { useGetZonesQuery } from 'client/features/OneApi/zone' const DEFAULT_DATA_CY = 'zones' @@ -46,6 +46,13 @@ const ZonesTable = (props) => { [view] ) + const listHeader = [ + { header: T.ID, id: 'id', accessor: 'ID' }, + { header: T.Name, id: 'name', accessor: 'NAME' }, + { header: T.Endpoint, id: 'endpoint', accessor: 'TEMPLATE.ENDPOINT' }, + ] + const { component, header } = WrapperRow(ZoneRow) + return ( { refetch={refetch} isLoading={isFetching} getRowId={(row) => String(row.ID)} - RowComponent={ZoneRow} + RowComponent={component} + headerList={header && listHeader} {...rest} /> ) diff --git a/src/fireedge/src/client/components/Tables/Zones/row.js b/src/fireedge/src/client/components/Tables/Zones/row.js index b9bab07016..0058c4ae70 100644 --- a/src/fireedge/src/client/components/Tables/Zones/row.js +++ b/src/fireedge/src/client/components/Tables/Zones/row.js @@ -17,15 +17,15 @@ import PropTypes from 'prop-types' import { Typography } from '@mui/material' -import { HomeShield } from 'iconoir-react' import { Tr } from 'client/components/HOC' -import { T } from 'client/constants' import { StatusCircle } from 'client/components/Status' import { rowStyles } from 'client/components/Tables/styles' +import { T } from 'client/constants' +import { HomeShield } from 'iconoir-react' import * as ZoneModel from 'client/models/Zone' -const Row = ({ original, value, ...props }) => { +const Row = ({ original, value, headerList, ...props }) => { const classes = rowStyles() const { ID, NAME, ENDPOINT } = value @@ -57,6 +57,7 @@ Row.propTypes = { value: PropTypes.object, isSelected: PropTypes.bool, handleClick: PropTypes.func, + headerList: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]), } export default Row diff --git a/src/fireedge/src/client/constants/translates.js b/src/fireedge/src/client/constants/translates.js index 746e7818bb..482786f3c3 100644 --- a/src/fireedge/src/client/constants/translates.js +++ b/src/fireedge/src/client/constants/translates.js @@ -427,6 +427,9 @@ module.exports = { /* sections - settings */ Settings: 'Settings', + AppliesTo: 'Applies To', + AllowedOperations: 'Allowed operations', + AffectedResources: 'Affected resources', Schema: 'Schema', Dark: 'Dark', Light: 'Light', @@ -591,6 +594,7 @@ module.exports = { Zone: 'Zone', Zones: 'Zones', Vnet: 'Vnet', + Vnets: 'Vnets', 'cluster.form.create.general.help.title': 'Cluster', 'cluster.form.create.general.help.paragraph.1.1': 'Clusters group together hosts, datastores and virtual networks that are configured to work together. A cluster is used to:', @@ -929,6 +933,7 @@ module.exports = { Reconnect: 'Reconnect', FullScreen: 'Full screen', FullScreenInfo: 'Full screen information in datatables', + RowStyle: 'DataTables Row Style', Screenshot: 'Screenshot', LastConnection: 'Last connection', PartOf: 'Part of', @@ -1485,6 +1490,7 @@ module.exports = { AutomaticDeletion: 'Automatic deletion', Role: 'Role', Roles: 'Roles', + Card: 'Card', Cardinality: 'Cardinality', Parents: 'Parents', ParentRoles: 'Parent roles', diff --git a/src/fireedge/src/client/containers/Settings/ConfigurationUI/schema.js b/src/fireedge/src/client/containers/Settings/ConfigurationUI/schema.js index e3292158aa..e48aca8ab0 100644 --- a/src/fireedge/src/client/containers/Settings/ConfigurationUI/schema.js +++ b/src/fireedge/src/client/containers/Settings/ConfigurationUI/schema.js @@ -119,6 +119,22 @@ const FULL_SCREEN_INFO_FIELD = { grid: { md: 12 }, } +const ROW_STYLE_FIELD = { + name: 'ROW_STYLE', + label: T.RowStyle, + type: INPUT_TYPES.AUTOCOMPLETE, + optionsOnly: true, + values: [ + { text: T.Card, value: 'card' }, + { text: T.List, value: 'list' }, + ], + validation: string() + .trim() + .required() + .default(() => 'card'), + grid: { md: 12 }, +} + /** * @param {object} props - Props * @param {object} props.views - views. @@ -131,6 +147,7 @@ export const FIELDS = (props) => [ LANG_FIELD, VIEW_FIELD(props), ZONE_ENDPOINT_FIELD(props), + ROW_STYLE_FIELD, DISABLE_ANIMATIONS_FIELD, FULL_SCREEN_INFO_FIELD, ] diff --git a/src/fireedge/src/client/containers/Settings/index.js b/src/fireedge/src/client/containers/Settings/index.js index aff3bd81e4..d5d7859095 100644 --- a/src/fireedge/src/client/containers/Settings/index.js +++ b/src/fireedge/src/client/containers/Settings/index.js @@ -43,7 +43,7 @@ const Settings = () => {