From 301da35182b9dc8091b20b083e7ba03302a88414 Mon Sep 17 00:00:00 2001 From: Sergio Betanzos Date: Tue, 22 Jun 2021 09:20:22 +0200 Subject: [PATCH] F OpenNebula/one#5422: Add images table --- .../components/Tables/Images/columns.js | 11 +++ .../client/components/Tables/Images/index.js | 33 ++++++++ .../client/components/Tables/Images/row.js | 77 +++++++++++++++++++ .../src/client/containers/Newstone/index.js | 71 ++++++----------- src/fireedge/src/client/models/Image.js | 71 +++++++++++++++++ 5 files changed, 214 insertions(+), 49 deletions(-) create mode 100644 src/fireedge/src/client/components/Tables/Images/columns.js create mode 100644 src/fireedge/src/client/components/Tables/Images/index.js create mode 100644 src/fireedge/src/client/components/Tables/Images/row.js create mode 100644 src/fireedge/src/client/models/Image.js diff --git a/src/fireedge/src/client/components/Tables/Images/columns.js b/src/fireedge/src/client/components/Tables/Images/columns.js new file mode 100644 index 0000000000..42d3a31988 --- /dev/null +++ b/src/fireedge/src/client/components/Tables/Images/columns.js @@ -0,0 +1,11 @@ +export default [ + { Header: '', accessor: 'ID' }, + { Header: '', accessor: 'NAME' }, + { Header: '', accessor: 'UNAME' }, + { Header: '', accessor: 'GNAME' }, + { Header: '', accessor: 'STATE' }, + { Header: '', accessor: 'TYPE' }, + { Header: '', accessor: 'DISK_TYPE' }, + { Header: '', accessor: 'DATASTORE_ID' }, + { Header: '', accessor: 'DATASTORE' } +] diff --git a/src/fireedge/src/client/components/Tables/Images/index.js b/src/fireedge/src/client/components/Tables/Images/index.js new file mode 100644 index 0000000000..5b1d13139c --- /dev/null +++ b/src/fireedge/src/client/components/Tables/Images/index.js @@ -0,0 +1,33 @@ +import React, { useEffect } from 'react' + +import { useAuth } from 'client/features/Auth' +import { useFetch } from 'client/hooks' +import { useImage, useImageApi } from 'client/features/One' + +import { EnhancedTable } from 'client/components/Tables' +import ImageColumns from 'client/components/Tables/Images/columns' +import ImageRow from 'client/components/Tables/Images/row' + +const ImagesTable = () => { + const columns = React.useMemo(() => ImageColumns, []) + + const images = useImage() + const { getImages } = useImageApi() + const { filterPool } = useAuth() + + const { fetchRequest, loading, reloading } = useFetch(getImages) + + useEffect(() => { fetchRequest() }, [filterPool]) + + return ( + String(row.ID)} + RowComponent={ImageRow} + /> + ) +} + +export default ImagesTable diff --git a/src/fireedge/src/client/components/Tables/Images/row.js b/src/fireedge/src/client/components/Tables/Images/row.js new file mode 100644 index 0000000000..c36a6154f0 --- /dev/null +++ b/src/fireedge/src/client/components/Tables/Images/row.js @@ -0,0 +1,77 @@ +import * as React from 'react' +import PropTypes from 'prop-types' + +import { Lock, User, Group, Folder, ModernTv } from 'iconoir-react' +import { Typography } from '@material-ui/core' + +import { StatusCircle, StatusChip } from 'client/components/Status' +import { rowStyles } from 'client/components/Tables/styles' + +import * as ImageModel from 'client/models/Image' +import * as Helper from 'client/models/Helper' + +const Row = ({ value, ...props }) => { + const classes = rowStyles() + const { ID, NAME, UNAME, GNAME, REGTIME, PERSISTENT, LOCK, DATASTORE, VMS, RUNNING_VMS } = value + + const state = ImageModel.getState(value) + const type = ImageModel.getType(value) + const diskType = ImageModel.getDiskType(value) + const isPersistent = PERSISTENT && 'PERSISTENT' + + const usedByVms = [VMS?.ID ?? []].flat().length || 0 + + const labels = [...new Set([isPersistent, type, diskType])].filter(Boolean) + + const time = Helper.timeFromMilliseconds(+REGTIME) + const timeAgo = `registered ${time.toRelative()}` + + return ( +
+
+ +
+
+ + {NAME} + {LOCK && } + + {labels.map(label => ( + + ))} + + +
+ + {`#${ID} ${timeAgo}`} + + + + {` ${UNAME}`} + + + + {` ${GNAME}`} + + + + {` ${DATASTORE}`} + + + + {` ${RUNNING_VMS} / ${usedByVms}`} + +
+
+
+
+ ) +} + +Row.propTypes = { + value: PropTypes.object, + isSelected: PropTypes.bool, + handleClick: PropTypes.func +} + +export default Row diff --git a/src/fireedge/src/client/containers/Newstone/index.js b/src/fireedge/src/client/containers/Newstone/index.js index 6de19fee55..054749f22b 100644 --- a/src/fireedge/src/client/containers/Newstone/index.js +++ b/src/fireedge/src/client/containers/Newstone/index.js @@ -3,71 +3,41 @@ import * as React from 'react' import { useParams, useHistory } from 'react-router' import { Redirect, Route, Switch, Link } from 'react-router-dom' -import { withStyles, Container, Tabs, Tab, Box } from '@material-ui/core' +import { Container, Tabs, Tab, Box } from '@material-ui/core' import { DatastoresTable, HostsTable, - VmsTable + VmsTable, + MarketplacesTable, + MarketplaceAppsTable, + ImagesTable } from 'client/components/Tables' + import { PATH } from 'client/router/dev' const TABS = { vms: PATH.NEWSTONE.replace(':resource', 'vms'), datastores: PATH.NEWSTONE.replace(':resource', 'datastores'), - hosts: PATH.NEWSTONE.replace(':resource', 'hosts') + hosts: PATH.NEWSTONE.replace(':resource', 'hosts'), + marketplaces: PATH.NEWSTONE.replace(':resource', 'marketplaces'), + apps: PATH.NEWSTONE.replace(':resource', 'apps'), + images: PATH.NEWSTONE.replace(':resource', 'images') } -const AntTabs = withStyles(theme => ({ - root: { - borderBottom: '1px solid #e8e8e8' - }, - indicator: { - backgroundColor: theme.palette.secondary.main - } -}))(Tabs) - -const AntTab = withStyles(theme => ({ - root: { - minWidth: 72, - fontWeight: theme.typography.fontWeightRegular, - marginRight: theme.spacing(4), - '&:hover': { - color: theme.palette.secondary.light, - opacity: 1 - }, - '&$selected': { - color: theme.palette.secondary.main, - fontWeight: theme.typography.fontWeightMedium - }, - '&:focus': { - color: theme.palette.secondary.light - } - }, - selected: {} -}))(props => ) - -const AntContainer = withStyles({ - root: { - height: '100%', - display: 'flex', - flexDirection: 'column', - paddingInline: 0 - } -})(Container) - const Newstone = () => { const history = useHistory() const { resource } = useParams() const renderTabs = React.useMemo(() => ( - {Object.keys(TABS).map(tabName => - { to={tabName} /> )} - + ), [resource]) return ( - + {Object.values(TABS).includes(history.location.pathname) && renderTabs} - - - + + + + + + } /> - + ) } diff --git a/src/fireedge/src/client/models/Image.js b/src/fireedge/src/client/models/Image.js new file mode 100644 index 0000000000..7ee8e316b2 --- /dev/null +++ b/src/fireedge/src/client/models/Image.js @@ -0,0 +1,71 @@ +import * as STATES from 'client/constants/states' +import COLOR from 'client/constants/color' + +const IMAGE_TYPES = [ + 'OS', + 'CD ROM', + 'DATABLOCK', + 'KERNEL', + 'RAMDISK', + 'CONTEXT' +] + +const IMAGE_STATES = [ + { // 0 + name: STATES.INIT, + color: COLOR.debug.main + }, + { // 1 + name: STATES.READY, + color: COLOR.success.main + }, + { // 2 + name: STATES.USED, + color: COLOR.success.main + }, + { // 3 + name: STATES.DISABLED, + color: COLOR.debug.light + }, + { // 4 + name: STATES.LOCKED, + color: COLOR.warning.main + }, + { // 5 + name: STATES.ERROR, + color: COLOR.error.main + }, + { // 6 + name: STATES.CLONE, + color: COLOR.info.light + }, + { // 7 + name: STATES.DELETE, + color: COLOR.error.main + }, + { // 8 + name: STATES.USED_PERS, + color: COLOR.error.light + }, + { // 9 + name: STATES.LOCKED_USED, + color: COLOR.warning.light + }, + { // 10 + name: STATES.LOCKED_USED_PERS, + color: COLOR.error.light + } +] + +const DISK_TYPES = [ + 'FILE', + 'CD ROM', + 'BLOCK', + 'RBD' +] + +export const getType = ({ TYPE } = {}) => IMAGE_TYPES[+TYPE] + +export const getDiskType = ({ DISK_TYPE } = {}) => DISK_TYPES[+DISK_TYPE] + +export const getState = ({ STATE } = {}) => IMAGE_STATES[+STATE]