mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-21 14:50:08 +03:00
parent
cd023c29e6
commit
1bda1e37af
@ -16,7 +16,7 @@
|
||||
import { JSXElementConstructor } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { TableProps } from 'react-table'
|
||||
import { TableProps, Row } from 'react-table'
|
||||
import { styled, Chip, Alert, Button, alertClasses } from '@mui/material'
|
||||
|
||||
import { Translate } from 'client/components/HOC'
|
||||
@ -39,10 +39,15 @@ const MessageStyled = styled(Alert)({
|
||||
*
|
||||
* @param {object} props - Props
|
||||
* @param {boolean} props.withAlert - If `true`, the list of selected rows will be an alert
|
||||
* @param {function(Row)} [props.gotoRowPage] - Function to navigate to a page of the row
|
||||
* @param {TableProps} props.useTableProps - Table props
|
||||
* @returns {JSXElementConstructor} Component JSX
|
||||
*/
|
||||
const GlobalSelectedRows = ({ withAlert = false, useTableProps }) => {
|
||||
const GlobalSelectedRows = ({
|
||||
withAlert = false,
|
||||
useTableProps,
|
||||
gotoRowPage,
|
||||
}) => {
|
||||
const {
|
||||
preFilteredRows,
|
||||
toggleAllRowsSelected,
|
||||
@ -78,11 +83,12 @@ const GlobalSelectedRows = ({ withAlert = false, useTableProps }) => {
|
||||
</MessageStyled>
|
||||
) : (
|
||||
<div>
|
||||
{selectedRows?.map(({ original, id, toggleRowSelected }) => (
|
||||
{selectedRows?.map((row) => (
|
||||
<Chip
|
||||
key={id}
|
||||
label={original?.NAME ?? id}
|
||||
onDelete={() => toggleRowSelected(false)}
|
||||
key={row.id}
|
||||
label={row.original?.NAME ?? row.id}
|
||||
onDelete={() => row.toggleRowSelected(false)}
|
||||
{...(gotoRowPage && { onClick: () => gotoRowPage(row) })}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@ -92,6 +98,7 @@ const GlobalSelectedRows = ({ withAlert = false, useTableProps }) => {
|
||||
GlobalSelectedRows.propTypes = {
|
||||
withAlert: PropTypes.bool,
|
||||
useTableProps: PropTypes.object.isRequired,
|
||||
gotoRowPage: PropTypes.func,
|
||||
}
|
||||
|
||||
GlobalSelectedRows.displayName = ' GlobalSelectedRows'
|
||||
|
@ -104,11 +104,9 @@ const EnhancedTable = ({
|
||||
autoResetSelectedRow: false,
|
||||
autoResetSelectedRows: false,
|
||||
autoResetSortBy: false,
|
||||
autoResetPage: false,
|
||||
// -------------------------------------
|
||||
initialState: {
|
||||
pageSize,
|
||||
...initialState,
|
||||
},
|
||||
initialState: { pageSize, ...initialState },
|
||||
},
|
||||
useGlobalFilter,
|
||||
useFilters,
|
||||
@ -126,13 +124,24 @@ const EnhancedTable = ({
|
||||
page,
|
||||
gotoPage,
|
||||
pageCount,
|
||||
state: { pageIndex, selectedRowIds },
|
||||
state: { pageIndex, selectedRowIds, ...state },
|
||||
} = useTableProps
|
||||
|
||||
const gotoRowPage = async (row) => {
|
||||
const pageIdx = Math.floor(row.index / state.pageSize)
|
||||
|
||||
await gotoPage(pageIdx)
|
||||
|
||||
// scroll to the row in the table view (if it's visible)
|
||||
document
|
||||
?.querySelector(`.selected[role='row'][data-cy$='-${row.id}']`)
|
||||
?.scrollIntoView({ behavior: 'smooth', block: 'center' })
|
||||
}
|
||||
|
||||
useMountedLayoutEffect(() => {
|
||||
const selectedRows = preFilteredRows.filter(
|
||||
(row) => !!selectedRowIds[row.id]
|
||||
)
|
||||
const selectedRows = preFilteredRows
|
||||
.filter((row) => !!selectedRowIds[row.id])
|
||||
.map((row) => ({ ...row, gotoPage: () => gotoRowPage(row) }))
|
||||
|
||||
onSelectedRowsChange?.(selectedRows)
|
||||
}, [selectedRowIds])
|
||||
@ -189,7 +198,10 @@ const EnhancedTable = ({
|
||||
{/* SELECTED ROWS */}
|
||||
{displaySelectedRows && (
|
||||
<div>
|
||||
<GlobalSelectedRows useTableProps={useTableProps} />
|
||||
<GlobalSelectedRows
|
||||
useTableProps={useTableProps}
|
||||
gotoRowPage={gotoRowPage}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -85,6 +85,7 @@ module.exports = {
|
||||
Info: 'Info',
|
||||
Instantiate: 'Instantiate',
|
||||
InstantiateVmTemplate: 'Instantiate VM Template',
|
||||
LocateOnTable: 'Locate on table',
|
||||
Lock: 'Lock',
|
||||
Migrate: 'Migrate',
|
||||
MigrateLive: 'Migrate live',
|
||||
|
@ -15,13 +15,16 @@
|
||||
* ------------------------------------------------------------------------- */
|
||||
import { ReactElement, useState, memo } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Typography, Box, Stack, Chip } from '@mui/material'
|
||||
import { BookmarkEmpty } from 'iconoir-react'
|
||||
import { Typography, Box, Stack, Chip, IconButton } from '@mui/material'
|
||||
import { Row } from 'react-table'
|
||||
|
||||
import { ClustersTable } from 'client/components/Tables'
|
||||
import ClusterTabs from 'client/components/Tabs/Cluster'
|
||||
import SplitPane from 'client/components/SplitPane'
|
||||
import MultipleTags from 'client/components/MultipleTags'
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import { T, Cluster } from 'client/constants'
|
||||
|
||||
/**
|
||||
* Displays a list of Clusters with a split pane between the list and selected row(s).
|
||||
@ -47,7 +50,10 @@ function Clusters() {
|
||||
{moreThanOneSelected ? (
|
||||
<GroupedTags tags={selectedRows} />
|
||||
) : (
|
||||
<InfoTabs cluster={selectedRows[0]?.original} />
|
||||
<InfoTabs
|
||||
cluster={selectedRows[0]?.original}
|
||||
gotoPage={selectedRows[0]?.gotoPage}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
@ -60,19 +66,31 @@ function Clusters() {
|
||||
/**
|
||||
* Displays details of a Cluster.
|
||||
*
|
||||
* @param {object} cluster - Cluster to display
|
||||
* @param {Cluster} cluster - Cluster to display
|
||||
* @param {Function} [gotoPage] - Function to navigate to a page of a Cluster
|
||||
* @returns {ReactElement} Cluster details
|
||||
*/
|
||||
const InfoTabs = memo(({ cluster }) => (
|
||||
const InfoTabs = memo(({ cluster, gotoPage }) => (
|
||||
<Stack overflow="auto">
|
||||
<Typography color="text.primary" noWrap mb={1}>
|
||||
{`#${cluster.ID} | ${cluster.NAME}`}
|
||||
</Typography>
|
||||
<Stack direction="row" alignItems="center" gap={1} mb={1}>
|
||||
<Typography color="text.primary" noWrap>
|
||||
{`#${cluster.ID} | ${cluster.NAME}`}
|
||||
</Typography>
|
||||
{gotoPage && (
|
||||
<IconButton title={Tr(T.LocateOnTable)} onClick={gotoPage}>
|
||||
<BookmarkEmpty />
|
||||
</IconButton>
|
||||
)}
|
||||
</Stack>
|
||||
<ClusterTabs id={cluster.ID} />
|
||||
</Stack>
|
||||
))
|
||||
|
||||
InfoTabs.propTypes = { cluster: PropTypes.object.isRequired }
|
||||
InfoTabs.propTypes = {
|
||||
cluster: PropTypes.object.isRequired,
|
||||
gotoPage: PropTypes.func,
|
||||
}
|
||||
|
||||
InfoTabs.displayName = 'InfoTabs'
|
||||
|
||||
/**
|
||||
@ -82,13 +100,14 @@ InfoTabs.displayName = 'InfoTabs'
|
||||
* @returns {ReactElement} List of tags
|
||||
*/
|
||||
const GroupedTags = memo(({ tags = [] }) => (
|
||||
<Stack direction="row" flexWrap="wrap" gap={1}>
|
||||
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
|
||||
<MultipleTags
|
||||
limitTags={10}
|
||||
tags={tags?.map(({ original, id, toggleRowSelected }) => (
|
||||
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
|
||||
<Chip
|
||||
key={id}
|
||||
label={original?.NAME ?? id}
|
||||
onClick={gotoPage}
|
||||
onDelete={() => toggleRowSelected(false)}
|
||||
/>
|
||||
))}
|
||||
|
@ -15,13 +15,16 @@
|
||||
* ------------------------------------------------------------------------- */
|
||||
import { ReactElement, useState, memo } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Typography, Box, Stack, Chip } from '@mui/material'
|
||||
import { BookmarkEmpty } from 'iconoir-react'
|
||||
import { Typography, Box, Stack, Chip, IconButton } from '@mui/material'
|
||||
import { Row } from 'react-table'
|
||||
|
||||
import { DatastoresTable } from 'client/components/Tables'
|
||||
import DatastoreTabs from 'client/components/Tabs/Datastore'
|
||||
import SplitPane from 'client/components/SplitPane'
|
||||
import MultipleTags from 'client/components/MultipleTags'
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import { T, Datastore } from 'client/constants'
|
||||
|
||||
/**
|
||||
* Displays a list of Datastores with a split pane between the list and selected row(s).
|
||||
@ -47,7 +50,10 @@ function Datastores() {
|
||||
{moreThanOneSelected ? (
|
||||
<GroupedTags tags={selectedRows} />
|
||||
) : (
|
||||
<InfoTabs datastore={selectedRows[0]?.original} />
|
||||
<InfoTabs
|
||||
datastore={selectedRows[0]?.original}
|
||||
gotoPage={selectedRows[0]?.gotoPage}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
@ -60,19 +66,31 @@ function Datastores() {
|
||||
/**
|
||||
* Displays details of a Datastore.
|
||||
*
|
||||
* @param {object} datastore - Datastore to display
|
||||
* @param {Datastore} datastore - Datastore to display
|
||||
* @param {Function} [gotoPage] - Function to navigate to a page of a Datastore
|
||||
* @returns {ReactElement} Datastore details
|
||||
*/
|
||||
const InfoTabs = memo(({ datastore }) => (
|
||||
const InfoTabs = memo(({ datastore, gotoPage }) => (
|
||||
<Stack overflow="auto">
|
||||
<Typography color="text.primary" noWrap mb={1}>
|
||||
{`#${datastore.ID} | ${datastore.NAME}`}
|
||||
</Typography>
|
||||
<Stack direction="row" alignItems="center" gap={1} mb={1}>
|
||||
<Typography color="text.primary" noWrap>
|
||||
{`#${datastore.ID} | ${datastore.NAME}`}
|
||||
</Typography>
|
||||
{gotoPage && (
|
||||
<IconButton title={Tr(T.LocateOnTable)} onClick={gotoPage}>
|
||||
<BookmarkEmpty />
|
||||
</IconButton>
|
||||
)}
|
||||
</Stack>
|
||||
<DatastoreTabs id={datastore.ID} />
|
||||
</Stack>
|
||||
))
|
||||
|
||||
InfoTabs.propTypes = { datastore: PropTypes.object.isRequired }
|
||||
InfoTabs.propTypes = {
|
||||
datastore: PropTypes.object.isRequired,
|
||||
gotoPage: PropTypes.func,
|
||||
}
|
||||
|
||||
InfoTabs.displayName = 'InfoTabs'
|
||||
|
||||
/**
|
||||
@ -82,13 +100,14 @@ InfoTabs.displayName = 'InfoTabs'
|
||||
* @returns {ReactElement} List of tags
|
||||
*/
|
||||
const GroupedTags = memo(({ tags = [] }) => (
|
||||
<Stack direction="row" flexWrap="wrap" gap={1}>
|
||||
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
|
||||
<MultipleTags
|
||||
limitTags={10}
|
||||
tags={tags?.map(({ original, id, toggleRowSelected }) => (
|
||||
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
|
||||
<Chip
|
||||
key={id}
|
||||
label={original?.NAME ?? id}
|
||||
onClick={gotoPage}
|
||||
onDelete={() => toggleRowSelected(false)}
|
||||
/>
|
||||
))}
|
||||
|
@ -15,13 +15,16 @@
|
||||
* ------------------------------------------------------------------------- */
|
||||
import { ReactElement, useState, memo } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Typography, Box, Stack, Chip } from '@mui/material'
|
||||
import { BookmarkEmpty } from 'iconoir-react'
|
||||
import { Typography, Box, Stack, Chip, IconButton } from '@mui/material'
|
||||
import { Row } from 'react-table'
|
||||
|
||||
import { GroupsTable } from 'client/components/Tables'
|
||||
import GroupTabs from 'client/components/Tabs/Group'
|
||||
import SplitPane from 'client/components/SplitPane'
|
||||
import MultipleTags from 'client/components/MultipleTags'
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import { T, Group } from 'client/constants'
|
||||
|
||||
/**
|
||||
* Displays a list of Groups with a split pane between the list and selected row(s).
|
||||
@ -47,7 +50,10 @@ function Groups() {
|
||||
{moreThanOneSelected ? (
|
||||
<GroupedTags tags={selectedRows} />
|
||||
) : (
|
||||
<InfoTabs group={selectedRows[0]?.original} />
|
||||
<InfoTabs
|
||||
group={selectedRows[0]?.original}
|
||||
gotoPage={selectedRows[0]?.gotoPage}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
@ -60,19 +66,31 @@ function Groups() {
|
||||
/**
|
||||
* Displays details of a Group.
|
||||
*
|
||||
* @param {object} group - Group to display
|
||||
* @param {Group} group - Group to display
|
||||
* @param {Function} [gotoPage] - Function to navigate to a page of a Group
|
||||
* @returns {ReactElement} Group details
|
||||
*/
|
||||
const InfoTabs = memo(({ group }) => (
|
||||
const InfoTabs = memo(({ group, gotoPage }) => (
|
||||
<Stack overflow="auto">
|
||||
<Typography color="text.primary" noWrap mb={1}>
|
||||
{`#${group.ID} | ${group.NAME}`}
|
||||
</Typography>
|
||||
<Stack direction="row" alignItems="center" gap={1} mb={1}>
|
||||
<Typography color="text.primary" noWrap>
|
||||
{`#${group.ID} | ${group.NAME}`}
|
||||
</Typography>
|
||||
{gotoPage && (
|
||||
<IconButton title={Tr(T.LocateOnTable)} onClick={gotoPage}>
|
||||
<BookmarkEmpty />
|
||||
</IconButton>
|
||||
)}
|
||||
</Stack>
|
||||
<GroupTabs id={group.ID} />
|
||||
</Stack>
|
||||
))
|
||||
|
||||
InfoTabs.propTypes = { group: PropTypes.object.isRequired }
|
||||
InfoTabs.propTypes = {
|
||||
group: PropTypes.object.isRequired,
|
||||
gotoPage: PropTypes.func,
|
||||
}
|
||||
|
||||
InfoTabs.displayName = 'InfoTabs'
|
||||
|
||||
/**
|
||||
@ -82,13 +100,14 @@ InfoTabs.displayName = 'InfoTabs'
|
||||
* @returns {ReactElement} List of tags
|
||||
*/
|
||||
const GroupedTags = memo(({ tags = [] }) => (
|
||||
<Stack direction="row" flexWrap="wrap" gap={1}>
|
||||
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
|
||||
<MultipleTags
|
||||
limitTags={10}
|
||||
tags={tags?.map(({ original, id, toggleRowSelected }) => (
|
||||
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
|
||||
<Chip
|
||||
key={id}
|
||||
label={original?.NAME ?? id}
|
||||
onClick={gotoPage}
|
||||
onDelete={() => toggleRowSelected(false)}
|
||||
/>
|
||||
))}
|
||||
|
@ -15,7 +15,8 @@
|
||||
* ------------------------------------------------------------------------- */
|
||||
import { ReactElement, useState, memo } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Typography, Box, Stack, Chip } from '@mui/material'
|
||||
import { BookmarkEmpty } from 'iconoir-react'
|
||||
import { Typography, Box, Stack, Chip, IconButton } from '@mui/material'
|
||||
import { Row } from 'react-table'
|
||||
|
||||
import { HostsTable } from 'client/components/Tables'
|
||||
@ -23,6 +24,8 @@ import HostTabs from 'client/components/Tabs/Host'
|
||||
import HostActions from 'client/components/Tables/Hosts/actions'
|
||||
import SplitPane from 'client/components/SplitPane'
|
||||
import MultipleTags from 'client/components/MultipleTags'
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import { T, Host } from 'client/constants'
|
||||
|
||||
/**
|
||||
* Displays a list of Hosts with a split pane between the list and selected row(s).
|
||||
@ -52,7 +55,10 @@ function Hosts() {
|
||||
{moreThanOneSelected ? (
|
||||
<GroupedTags tags={selectedRows} />
|
||||
) : (
|
||||
<InfoTabs host={selectedRows[0]?.original} />
|
||||
<InfoTabs
|
||||
host={selectedRows[0]?.original}
|
||||
gotoPage={selectedRows[0]?.gotoPage}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
@ -65,19 +71,31 @@ function Hosts() {
|
||||
/**
|
||||
* Displays details of a Host.
|
||||
*
|
||||
* @param {object} host - Host to display
|
||||
* @param {Host} host - Host to display
|
||||
* @param {Function} [gotoPage] - Function to navigate to a page of a Host
|
||||
* @returns {ReactElement} Host details
|
||||
*/
|
||||
const InfoTabs = memo(({ host }) => (
|
||||
const InfoTabs = memo(({ host, gotoPage }) => (
|
||||
<Stack overflow="auto">
|
||||
<Typography color="text.primary" noWrap mb={1}>
|
||||
{`#${host.ID} | ${host.NAME}`}
|
||||
</Typography>
|
||||
<Stack direction="row" alignItems="center" gap={1} mb={1}>
|
||||
<Typography color="text.primary" noWrap>
|
||||
{`#${host.ID} | ${host.NAME}`}
|
||||
</Typography>
|
||||
{gotoPage && (
|
||||
<IconButton title={Tr(T.LocateOnTable)} onClick={gotoPage}>
|
||||
<BookmarkEmpty />
|
||||
</IconButton>
|
||||
)}
|
||||
</Stack>
|
||||
<HostTabs id={host.ID} />
|
||||
</Stack>
|
||||
))
|
||||
|
||||
InfoTabs.propTypes = { host: PropTypes.object.isRequired }
|
||||
InfoTabs.propTypes = {
|
||||
host: PropTypes.object.isRequired,
|
||||
gotoPage: PropTypes.func,
|
||||
}
|
||||
|
||||
InfoTabs.displayName = 'InfoTabs'
|
||||
|
||||
/**
|
||||
@ -87,13 +105,14 @@ InfoTabs.displayName = 'InfoTabs'
|
||||
* @returns {ReactElement} List of tags
|
||||
*/
|
||||
const GroupedTags = memo(({ tags = [] }) => (
|
||||
<Stack direction="row" flexWrap="wrap" gap={1}>
|
||||
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
|
||||
<MultipleTags
|
||||
limitTags={10}
|
||||
tags={tags?.map(({ original, id, toggleRowSelected }) => (
|
||||
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
|
||||
<Chip
|
||||
key={id}
|
||||
label={original?.NAME ?? id}
|
||||
onClick={gotoPage}
|
||||
onDelete={() => toggleRowSelected(false)}
|
||||
/>
|
||||
))}
|
||||
|
@ -15,13 +15,16 @@
|
||||
* ------------------------------------------------------------------------- */
|
||||
import { ReactElement, useState, memo } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Typography, Box, Stack, Chip } from '@mui/material'
|
||||
import { BookmarkEmpty } from 'iconoir-react'
|
||||
import { Typography, Box, Stack, Chip, IconButton } from '@mui/material'
|
||||
import { Row } from 'react-table'
|
||||
|
||||
import { ImagesTable } from 'client/components/Tables'
|
||||
import ImageTabs from 'client/components/Tabs/Image'
|
||||
import SplitPane from 'client/components/SplitPane'
|
||||
import MultipleTags from 'client/components/MultipleTags'
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import { T, Image } from 'client/constants'
|
||||
|
||||
/**
|
||||
* Displays a list of Images with a split pane between the list and selected row(s).
|
||||
@ -47,7 +50,10 @@ function Images() {
|
||||
{moreThanOneSelected ? (
|
||||
<GroupedTags tags={selectedRows} />
|
||||
) : (
|
||||
<InfoTabs image={selectedRows[0]?.original} />
|
||||
<InfoTabs
|
||||
image={selectedRows[0]?.original}
|
||||
gotoPage={selectedRows[0]?.gotoPage}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
@ -60,19 +66,31 @@ function Images() {
|
||||
/**
|
||||
* Displays details of an Image.
|
||||
*
|
||||
* @param {object} image - Image to display
|
||||
* @param {Image} image - Image to display
|
||||
* @param {Function} [gotoPage] - Function to navigate to a page of an Image
|
||||
* @returns {ReactElement} Image details
|
||||
*/
|
||||
const InfoTabs = memo(({ image }) => (
|
||||
const InfoTabs = memo(({ image, gotoPage }) => (
|
||||
<Stack overflow="auto">
|
||||
<Typography color="text.primary" noWrap mb={1}>
|
||||
{`#${image.ID} | ${image.NAME}`}
|
||||
</Typography>
|
||||
<Stack direction="row" alignItems="center" gap={1} mb={1}>
|
||||
<Typography color="text.primary" noWrap>
|
||||
{`#${image.ID} | ${image.NAME}`}
|
||||
</Typography>
|
||||
{gotoPage && (
|
||||
<IconButton title={Tr(T.LocateOnTable)} onClick={gotoPage}>
|
||||
<BookmarkEmpty />
|
||||
</IconButton>
|
||||
)}
|
||||
</Stack>
|
||||
<ImageTabs id={image.ID} />
|
||||
</Stack>
|
||||
))
|
||||
|
||||
InfoTabs.propTypes = { image: PropTypes.object.isRequired }
|
||||
InfoTabs.propTypes = {
|
||||
image: PropTypes.object.isRequired,
|
||||
gotoPage: PropTypes.func,
|
||||
}
|
||||
|
||||
InfoTabs.displayName = 'InfoTabs'
|
||||
|
||||
/**
|
||||
@ -82,13 +100,14 @@ InfoTabs.displayName = 'InfoTabs'
|
||||
* @returns {ReactElement} List of tags
|
||||
*/
|
||||
const GroupedTags = memo(({ tags = [] }) => (
|
||||
<Stack direction="row" flexWrap="wrap" gap={1}>
|
||||
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
|
||||
<MultipleTags
|
||||
limitTags={10}
|
||||
tags={tags?.map(({ original, id, toggleRowSelected }) => (
|
||||
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
|
||||
<Chip
|
||||
key={id}
|
||||
label={original?.NAME ?? id}
|
||||
onClick={gotoPage}
|
||||
onDelete={() => toggleRowSelected(false)}
|
||||
/>
|
||||
))}
|
||||
|
@ -15,7 +15,8 @@
|
||||
* ------------------------------------------------------------------------- */
|
||||
import { ReactElement, useState, memo } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Typography, Box, Stack, Chip } from '@mui/material'
|
||||
import { BookmarkEmpty } from 'iconoir-react'
|
||||
import { Typography, Box, Stack, Chip, IconButton } from '@mui/material'
|
||||
import { Row } from 'react-table'
|
||||
|
||||
import { MarketplaceAppsTable } from 'client/components/Tables'
|
||||
@ -23,6 +24,8 @@ import MarketplaceAppActions from 'client/components/Tables/MarketplaceApps/acti
|
||||
import MarketplaceAppsTabs from 'client/components/Tabs/MarketplaceApp'
|
||||
import SplitPane from 'client/components/SplitPane'
|
||||
import MultipleTags from 'client/components/MultipleTags'
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import { T, MarketplaceApp } from 'client/constants'
|
||||
|
||||
/**
|
||||
* Displays a list of Marketplace Apps with a split pane between the list and selected row(s).
|
||||
@ -52,7 +55,10 @@ function MarketplaceApps() {
|
||||
{moreThanOneSelected ? (
|
||||
<GroupedTags tags={selectedRows} />
|
||||
) : (
|
||||
<InfoTabs app={selectedRows[0]?.original} />
|
||||
<InfoTabs
|
||||
app={selectedRows[0]?.original}
|
||||
gotoPage={selectedRows[0]?.gotoPage}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
@ -65,19 +71,31 @@ function MarketplaceApps() {
|
||||
/**
|
||||
* Displays details of a Marketplace App.
|
||||
*
|
||||
* @param {object} app - Marketplace App to display
|
||||
* @param {MarketplaceApp} app - Marketplace App to display
|
||||
* @param {Function} [gotoPage] - Function to navigate to a page of a Marketplace App
|
||||
* @returns {ReactElement} Marketplace App details
|
||||
*/
|
||||
const InfoTabs = memo(({ app }) => (
|
||||
const InfoTabs = memo(({ app, gotoPage }) => (
|
||||
<Stack overflow="auto">
|
||||
<Typography color="text.primary" noWrap mb={1}>
|
||||
{`#${app.ID} | ${app.NAME}`}
|
||||
</Typography>
|
||||
<Stack direction="row" alignItems="center" gap={1} mb={1}>
|
||||
<Typography color="text.primary" noWrap>
|
||||
{`#${app.ID} | ${app.NAME}`}
|
||||
</Typography>
|
||||
{gotoPage && (
|
||||
<IconButton title={Tr(T.LocateOnTable)} onClick={gotoPage}>
|
||||
<BookmarkEmpty />
|
||||
</IconButton>
|
||||
)}
|
||||
</Stack>
|
||||
<MarketplaceAppsTabs id={app.ID} />
|
||||
</Stack>
|
||||
))
|
||||
|
||||
InfoTabs.propTypes = { app: PropTypes.object.isRequired }
|
||||
InfoTabs.propTypes = {
|
||||
app: PropTypes.object.isRequired,
|
||||
gotoPage: PropTypes.func,
|
||||
}
|
||||
|
||||
InfoTabs.displayName = 'InfoTabs'
|
||||
|
||||
/**
|
||||
@ -87,13 +105,14 @@ InfoTabs.displayName = 'InfoTabs'
|
||||
* @returns {ReactElement} List of tags
|
||||
*/
|
||||
const GroupedTags = memo(({ tags = [] }) => (
|
||||
<Stack direction="row" flexWrap="wrap" gap={1}>
|
||||
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
|
||||
<MultipleTags
|
||||
limitTags={10}
|
||||
tags={tags?.map(({ original, id, toggleRowSelected }) => (
|
||||
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
|
||||
<Chip
|
||||
key={id}
|
||||
label={original?.NAME ?? id}
|
||||
onClick={gotoPage}
|
||||
onDelete={() => toggleRowSelected(false)}
|
||||
/>
|
||||
))}
|
||||
|
@ -15,13 +15,16 @@
|
||||
* ------------------------------------------------------------------------- */
|
||||
import { ReactElement, useState, memo } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Typography, Box, Stack, Chip } from '@mui/material'
|
||||
import { BookmarkEmpty } from 'iconoir-react'
|
||||
import { Typography, Box, Stack, Chip, IconButton } from '@mui/material'
|
||||
import { Row } from 'react-table'
|
||||
|
||||
import { MarketplacesTable } from 'client/components/Tables'
|
||||
import MarketplaceTabs from 'client/components/Tabs/Marketplace'
|
||||
import SplitPane from 'client/components/SplitPane'
|
||||
import MultipleTags from 'client/components/MultipleTags'
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import { T, Marketplace } from 'client/constants'
|
||||
|
||||
/**
|
||||
* Displays a list of Marketplaces with a split pane between the list and selected row(s).
|
||||
@ -47,7 +50,10 @@ function Marketplaces() {
|
||||
{moreThanOneSelected ? (
|
||||
<GroupedTags tags={selectedRows} />
|
||||
) : (
|
||||
<InfoTabs market={selectedRows[0]?.original} />
|
||||
<InfoTabs
|
||||
market={selectedRows[0]?.original}
|
||||
gotoPage={selectedRows[0]?.gotoPage}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
@ -60,19 +66,31 @@ function Marketplaces() {
|
||||
/**
|
||||
* Displays details of a Marketplace.
|
||||
*
|
||||
* @param {object} market - Marketplace to display
|
||||
* @param {Marketplace} market - Marketplace to display
|
||||
* @param {Function} [gotoPage] - Function to navigate to a page of a Marketplace
|
||||
* @returns {ReactElement} Marketplace details
|
||||
*/
|
||||
const InfoTabs = memo(({ market }) => (
|
||||
const InfoTabs = memo(({ market, gotoPage }) => (
|
||||
<Stack overflow="auto">
|
||||
<Typography color="text.primary" noWrap mb={1}>
|
||||
{`#${market.ID} | ${market.NAME}`}
|
||||
</Typography>
|
||||
<Stack direction="row" alignItems="center" gap={1} mb={1}>
|
||||
<Typography color="text.primary" noWrap>
|
||||
{`#${market.ID} | ${market.NAME}`}
|
||||
</Typography>
|
||||
{gotoPage && (
|
||||
<IconButton title={Tr(T.LocateOnTable)} onClick={gotoPage}>
|
||||
<BookmarkEmpty />
|
||||
</IconButton>
|
||||
)}
|
||||
</Stack>
|
||||
<MarketplaceTabs id={market.ID} />
|
||||
</Stack>
|
||||
))
|
||||
|
||||
InfoTabs.propTypes = { market: PropTypes.object.isRequired }
|
||||
InfoTabs.propTypes = {
|
||||
market: PropTypes.object.isRequired,
|
||||
gotoPage: PropTypes.func,
|
||||
}
|
||||
|
||||
InfoTabs.displayName = 'InfoTabs'
|
||||
|
||||
/**
|
||||
@ -82,13 +100,14 @@ InfoTabs.displayName = 'InfoTabs'
|
||||
* @returns {ReactElement} List of tags
|
||||
*/
|
||||
const GroupedTags = memo(({ tags = [] }) => (
|
||||
<Stack direction="row" flexWrap="wrap" gap={1}>
|
||||
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
|
||||
<MultipleTags
|
||||
limitTags={10}
|
||||
tags={tags?.map(({ original, id, toggleRowSelected }) => (
|
||||
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
|
||||
<Chip
|
||||
key={id}
|
||||
label={original?.NAME ?? id}
|
||||
onClick={gotoPage}
|
||||
onDelete={() => toggleRowSelected(false)}
|
||||
/>
|
||||
))}
|
||||
|
@ -15,13 +15,16 @@
|
||||
* ------------------------------------------------------------------------- */
|
||||
import { ReactElement, useState, memo } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Typography, Box, Stack, Chip } from '@mui/material'
|
||||
import { BookmarkEmpty } from 'iconoir-react'
|
||||
import { Typography, Box, Stack, Chip, IconButton } from '@mui/material'
|
||||
import { Row } from 'react-table'
|
||||
|
||||
import { UsersTable } from 'client/components/Tables'
|
||||
import UserTabs from 'client/components/Tabs/User'
|
||||
import SplitPane from 'client/components/SplitPane'
|
||||
import MultipleTags from 'client/components/MultipleTags'
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import { T, User } from 'client/constants'
|
||||
|
||||
/**
|
||||
* Displays a list of Users with a split pane between the list and selected row(s).
|
||||
@ -47,7 +50,10 @@ function Users() {
|
||||
{moreThanOneSelected ? (
|
||||
<GroupedTags tags={selectedRows} />
|
||||
) : (
|
||||
<InfoTabs user={selectedRows[0]?.original} />
|
||||
<InfoTabs
|
||||
user={selectedRows[0]?.original}
|
||||
gotoPage={selectedRows[0]?.gotoPage}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
@ -60,19 +66,31 @@ function Users() {
|
||||
/**
|
||||
* Displays details of an User.
|
||||
*
|
||||
* @param {object} user - User to display
|
||||
* @param {User} user - User to display
|
||||
* @param {Function} [gotoPage] - Function to navigate to a page of an User
|
||||
* @returns {ReactElement} User details
|
||||
*/
|
||||
const InfoTabs = memo(({ user }) => (
|
||||
const InfoTabs = memo(({ user, gotoPage }) => (
|
||||
<Stack overflow="auto">
|
||||
<Typography color="text.primary" noWrap mb={1}>
|
||||
{`#${user.ID} | ${user.NAME}`}
|
||||
</Typography>
|
||||
<Stack direction="row" alignItems="center" gap={1} mb={1}>
|
||||
<Typography color="text.primary" noWrap>
|
||||
{`#${user.ID} | ${user.NAME}`}
|
||||
</Typography>
|
||||
{gotoPage && (
|
||||
<IconButton title={Tr(T.LocateOnTable)} onClick={gotoPage}>
|
||||
<BookmarkEmpty />
|
||||
</IconButton>
|
||||
)}
|
||||
</Stack>
|
||||
<UserTabs id={user.ID} />
|
||||
</Stack>
|
||||
))
|
||||
|
||||
InfoTabs.propTypes = { user: PropTypes.object.isRequired }
|
||||
InfoTabs.propTypes = {
|
||||
user: PropTypes.object.isRequired,
|
||||
gotoPage: PropTypes.func,
|
||||
}
|
||||
|
||||
InfoTabs.displayName = 'InfoTabs'
|
||||
|
||||
/**
|
||||
@ -82,13 +100,14 @@ InfoTabs.displayName = 'InfoTabs'
|
||||
* @returns {ReactElement} List of tags
|
||||
*/
|
||||
const GroupedTags = memo(({ tags = [] }) => (
|
||||
<Stack direction="row" flexWrap="wrap" gap={1}>
|
||||
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
|
||||
<MultipleTags
|
||||
limitTags={10}
|
||||
tags={tags?.map(({ original, id, toggleRowSelected }) => (
|
||||
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
|
||||
<Chip
|
||||
key={id}
|
||||
label={original?.NAME ?? id}
|
||||
onClick={gotoPage}
|
||||
onDelete={() => toggleRowSelected(false)}
|
||||
/>
|
||||
))}
|
||||
|
@ -15,13 +15,16 @@
|
||||
* ------------------------------------------------------------------------- */
|
||||
import { ReactElement, useState, memo } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Typography, Box, Stack, Chip } from '@mui/material'
|
||||
import { BookmarkEmpty } from 'iconoir-react'
|
||||
import { Typography, Box, Stack, Chip, IconButton } from '@mui/material'
|
||||
import { Row } from 'react-table'
|
||||
|
||||
import { VNetworkTemplatesTable } from 'client/components/Tables'
|
||||
import VNetworkTemplateTabs from 'client/components/Tabs/VNetworkTemplate'
|
||||
import SplitPane from 'client/components/SplitPane'
|
||||
import MultipleTags from 'client/components/MultipleTags'
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import { T, VNetworkTemplate } from 'client/constants'
|
||||
|
||||
/**
|
||||
* Displays a list of VNet Templates with a split pane between the list and selected row(s).
|
||||
@ -47,7 +50,10 @@ function VNetworkTemplates() {
|
||||
{moreThanOneSelected ? (
|
||||
<GroupedTags tags={selectedRows} />
|
||||
) : (
|
||||
<InfoTabs vnTemplate={selectedRows[0]?.original} />
|
||||
<InfoTabs
|
||||
vnTemplate={selectedRows[0]?.original}
|
||||
gotoPage={selectedRows[0]?.gotoPage}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
@ -60,19 +66,31 @@ function VNetworkTemplates() {
|
||||
/**
|
||||
* Displays details of a VNet Template.
|
||||
*
|
||||
* @param {object} vnTemplate - VNet Template to display
|
||||
* @param {VNetworkTemplate} vnTemplate - VNet Template to display
|
||||
* @param {Function} [gotoPage] - Function to navigate to a page of a VNet Template
|
||||
* @returns {ReactElement} VNet Template details
|
||||
*/
|
||||
const InfoTabs = memo(({ vnTemplate }) => (
|
||||
const InfoTabs = memo(({ vnTemplate, gotoPage }) => (
|
||||
<Stack overflow="auto" data-cy="detail">
|
||||
<Typography color="text.primary" noWrap mb={1}>
|
||||
{`#${vnTemplate.ID} | ${vnTemplate.NAME}`}
|
||||
</Typography>
|
||||
<Stack direction="row" alignItems="center" gap={1} mb={1}>
|
||||
<Typography color="text.primary" noWrap>
|
||||
{`#${vnTemplate.ID} | ${vnTemplate.NAME}`}
|
||||
</Typography>
|
||||
{gotoPage && (
|
||||
<IconButton title={Tr(T.LocateOnTable)} onClick={gotoPage}>
|
||||
<BookmarkEmpty />
|
||||
</IconButton>
|
||||
)}
|
||||
</Stack>
|
||||
<VNetworkTemplateTabs id={vnTemplate.ID} />
|
||||
</Stack>
|
||||
))
|
||||
|
||||
InfoTabs.propTypes = { vnTemplate: PropTypes.object.isRequired }
|
||||
InfoTabs.propTypes = {
|
||||
vnTemplate: PropTypes.object.isRequired,
|
||||
gotoPage: PropTypes.func,
|
||||
}
|
||||
|
||||
InfoTabs.displayName = 'InfoTabs'
|
||||
|
||||
/**
|
||||
@ -82,13 +100,14 @@ InfoTabs.displayName = 'InfoTabs'
|
||||
* @returns {ReactElement} List of tags
|
||||
*/
|
||||
const GroupedTags = memo(({ tags = [] }) => (
|
||||
<Stack direction="row" flexWrap="wrap" gap={1}>
|
||||
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
|
||||
<MultipleTags
|
||||
limitTags={10}
|
||||
tags={tags?.map(({ original, id, toggleRowSelected }) => (
|
||||
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
|
||||
<Chip
|
||||
key={id}
|
||||
label={original?.NAME ?? id}
|
||||
onClick={gotoPage}
|
||||
onDelete={() => toggleRowSelected(false)}
|
||||
/>
|
||||
))}
|
||||
|
@ -15,7 +15,8 @@
|
||||
* ------------------------------------------------------------------------- */
|
||||
import { ReactElement, useState, memo } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Typography, Box, Stack, Chip } from '@mui/material'
|
||||
import { BookmarkEmpty } from 'iconoir-react'
|
||||
import { Typography, Box, Stack, Chip, IconButton } from '@mui/material'
|
||||
import { Row } from 'react-table'
|
||||
|
||||
import { VmsTable } from 'client/components/Tables'
|
||||
@ -23,6 +24,8 @@ import VmActions from 'client/components/Tables/Vms/actions'
|
||||
import VmTabs from 'client/components/Tabs/Vm'
|
||||
import SplitPane from 'client/components/SplitPane'
|
||||
import MultipleTags from 'client/components/MultipleTags'
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import { T, VM } from 'client/constants'
|
||||
|
||||
/**
|
||||
* Displays a list of VMs with a split pane between the list and selected row(s).
|
||||
@ -52,7 +55,10 @@ function VirtualMachines() {
|
||||
{moreThanOneSelected ? (
|
||||
<GroupedTags tags={selectedRows} />
|
||||
) : (
|
||||
<InfoTabs vm={selectedRows[0]?.original} />
|
||||
<InfoTabs
|
||||
vm={selectedRows[0]?.original}
|
||||
gotoPage={selectedRows[0]?.gotoPage}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
@ -65,19 +71,31 @@ function VirtualMachines() {
|
||||
/**
|
||||
* Displays details of a VM.
|
||||
*
|
||||
* @param {object} vm - VM to display
|
||||
* @param {VM} vm - VM to display
|
||||
* @param {Function} [gotoPage] - Function to navigate to a page of a VM
|
||||
* @returns {ReactElement} VM details
|
||||
*/
|
||||
const InfoTabs = memo(({ vm }) => (
|
||||
const InfoTabs = memo(({ vm, gotoPage }) => (
|
||||
<Stack overflow="auto">
|
||||
<Typography color="text.primary" noWrap mb={1}>
|
||||
{`#${vm.ID} | ${vm.NAME}`}
|
||||
</Typography>
|
||||
<Stack direction="row" alignItems="center" gap={1} mb={1}>
|
||||
<Typography color="text.primary" noWrap>
|
||||
{`#${vm.ID} | ${vm.NAME}`}
|
||||
</Typography>
|
||||
{gotoPage && (
|
||||
<IconButton title={Tr(T.LocateOnTable)} onClick={gotoPage}>
|
||||
<BookmarkEmpty />
|
||||
</IconButton>
|
||||
)}
|
||||
</Stack>
|
||||
<VmTabs id={vm.ID} />
|
||||
</Stack>
|
||||
))
|
||||
|
||||
InfoTabs.propTypes = { vm: PropTypes.object.isRequired }
|
||||
InfoTabs.propTypes = {
|
||||
vm: PropTypes.object.isRequired,
|
||||
gotoPage: PropTypes.func,
|
||||
}
|
||||
|
||||
InfoTabs.displayName = 'InfoTabs'
|
||||
|
||||
/**
|
||||
@ -87,13 +105,14 @@ InfoTabs.displayName = 'InfoTabs'
|
||||
* @returns {ReactElement} List of tags
|
||||
*/
|
||||
const GroupedTags = memo(({ tags = [] }) => (
|
||||
<Stack direction="row" flexWrap="wrap" gap={1}>
|
||||
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
|
||||
<MultipleTags
|
||||
limitTags={10}
|
||||
tags={tags?.map(({ original, id, toggleRowSelected }) => (
|
||||
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
|
||||
<Chip
|
||||
key={id}
|
||||
label={original?.NAME ?? id}
|
||||
onClick={gotoPage}
|
||||
onDelete={() => toggleRowSelected(false)}
|
||||
/>
|
||||
))}
|
||||
|
@ -15,13 +15,16 @@
|
||||
* ------------------------------------------------------------------------- */
|
||||
import { ReactElement, useState, memo } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Typography, Box, Stack, Chip } from '@mui/material'
|
||||
import { BookmarkEmpty } from 'iconoir-react'
|
||||
import { Typography, Box, Stack, Chip, IconButton } from '@mui/material'
|
||||
import { Row } from 'react-table'
|
||||
|
||||
import { VNetworksTable } from 'client/components/Tables'
|
||||
import VNetworkTabs from 'client/components/Tabs/VNetwork'
|
||||
import SplitPane from 'client/components/SplitPane'
|
||||
import MultipleTags from 'client/components/MultipleTags'
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import { T, VirtualNetwork } from 'client/constants'
|
||||
|
||||
/**
|
||||
* Displays a list of Virtual Networks with a split pane between the list and selected row(s).
|
||||
@ -47,7 +50,10 @@ function VirtualNetworks() {
|
||||
{moreThanOneSelected ? (
|
||||
<GroupedTags tags={selectedRows} />
|
||||
) : (
|
||||
<InfoTabs vnet={selectedRows[0]?.original} />
|
||||
<InfoTabs
|
||||
vnet={selectedRows[0]?.original}
|
||||
gotoPage={selectedRows[0]?.gotoPage}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
@ -60,19 +66,31 @@ function VirtualNetworks() {
|
||||
/**
|
||||
* Displays details of a Virtual Network.
|
||||
*
|
||||
* @param {object} vnet - Virtual Network to display
|
||||
* @param {VirtualNetwork} vnet - Virtual Network to display
|
||||
* @param {Function} [gotoPage] - Function to navigate to a page of a Virtual Network
|
||||
* @returns {ReactElement} Virtual Network details
|
||||
*/
|
||||
const InfoTabs = memo(({ vnet }) => (
|
||||
const InfoTabs = memo(({ vnet, gotoPage }) => (
|
||||
<Stack overflow="auto">
|
||||
<Typography color="text.primary" noWrap mb={1}>
|
||||
{`#${vnet.ID} | ${vnet.NAME}`}
|
||||
</Typography>
|
||||
<Stack direction="row" alignItems="center" gap={1} mb={1}>
|
||||
<Typography color="text.primary" noWrap>
|
||||
{`#${vnet.ID} | ${vnet.NAME}`}
|
||||
</Typography>
|
||||
{gotoPage && (
|
||||
<IconButton title={Tr(T.LocateOnTable)} onClick={gotoPage}>
|
||||
<BookmarkEmpty />
|
||||
</IconButton>
|
||||
)}
|
||||
</Stack>
|
||||
<VNetworkTabs id={vnet.ID} />
|
||||
</Stack>
|
||||
))
|
||||
|
||||
InfoTabs.propTypes = { vnet: PropTypes.object.isRequired }
|
||||
InfoTabs.propTypes = {
|
||||
vnet: PropTypes.object.isRequired,
|
||||
gotoPage: PropTypes.func,
|
||||
}
|
||||
|
||||
InfoTabs.displayName = 'InfoTabs'
|
||||
|
||||
/**
|
||||
@ -82,13 +100,14 @@ InfoTabs.displayName = 'InfoTabs'
|
||||
* @returns {ReactElement} List of tags
|
||||
*/
|
||||
const GroupedTags = memo(({ tags = [] }) => (
|
||||
<Stack direction="row" flexWrap="wrap" gap={1}>
|
||||
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
|
||||
<MultipleTags
|
||||
limitTags={10}
|
||||
tags={tags?.map(({ original, id, toggleRowSelected }) => (
|
||||
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
|
||||
<Chip
|
||||
key={id}
|
||||
label={original?.NAME ?? id}
|
||||
onClick={gotoPage}
|
||||
onDelete={() => toggleRowSelected(false)}
|
||||
/>
|
||||
))}
|
||||
|
@ -15,7 +15,8 @@
|
||||
* ------------------------------------------------------------------------- */
|
||||
import { ReactElement, useState, memo } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Typography, Box, Stack, Chip } from '@mui/material'
|
||||
import { BookmarkEmpty } from 'iconoir-react'
|
||||
import { Typography, Box, Stack, Chip, IconButton } from '@mui/material'
|
||||
import { Row } from 'react-table'
|
||||
|
||||
import { VmTemplatesTable } from 'client/components/Tables'
|
||||
@ -23,6 +24,8 @@ import VmTemplateActions from 'client/components/Tables/VmTemplates/actions'
|
||||
import VmTemplateTabs from 'client/components/Tabs/VmTemplate'
|
||||
import SplitPane from 'client/components/SplitPane'
|
||||
import MultipleTags from 'client/components/MultipleTags'
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import { T, VmTemplate } from 'client/constants'
|
||||
|
||||
/**
|
||||
* Displays a list of VM Templates with a split pane between the list and selected row(s).
|
||||
@ -52,7 +55,10 @@ function VmTemplates() {
|
||||
{moreThanOneSelected ? (
|
||||
<GroupedTags tags={selectedRows} />
|
||||
) : (
|
||||
<InfoTabs vmTemplate={selectedRows[0]?.original} />
|
||||
<InfoTabs
|
||||
vmTemplate={selectedRows[0]?.original}
|
||||
gotoPage={selectedRows[0]?.gotoPage}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
@ -65,19 +71,31 @@ function VmTemplates() {
|
||||
/**
|
||||
* Displays details of a VM Template.
|
||||
*
|
||||
* @param {object} vmTemplate - VM Template to display
|
||||
* @param {VmTemplate} vmTemplate - VM Template to display
|
||||
* @param {Function} [gotoPage] - Function to navigate to a page of a VM Template
|
||||
* @returns {ReactElement} VM Template details
|
||||
*/
|
||||
const InfoTabs = memo(({ vmTemplate }) => (
|
||||
const InfoTabs = memo(({ vmTemplate, gotoPage }) => (
|
||||
<Stack overflow="auto">
|
||||
<Typography color="text.primary" noWrap mb={1}>
|
||||
{`#${vmTemplate.ID} | ${vmTemplate.NAME}`}
|
||||
</Typography>
|
||||
<Stack direction="row" alignItems="center" gap={1} mb={1}>
|
||||
<Typography color="text.primary" noWrap>
|
||||
{`#${vmTemplate.ID} | ${vmTemplate.NAME}`}
|
||||
</Typography>
|
||||
{gotoPage && (
|
||||
<IconButton title={Tr(T.LocateOnTable)} onClick={gotoPage}>
|
||||
<BookmarkEmpty />
|
||||
</IconButton>
|
||||
)}
|
||||
</Stack>
|
||||
<VmTemplateTabs id={vmTemplate.ID} />
|
||||
</Stack>
|
||||
))
|
||||
|
||||
InfoTabs.propTypes = { vmTemplate: PropTypes.object.isRequired }
|
||||
InfoTabs.propTypes = {
|
||||
vmTemplate: PropTypes.object.isRequired,
|
||||
gotoPage: PropTypes.func,
|
||||
}
|
||||
|
||||
InfoTabs.displayName = 'InfoTabs'
|
||||
|
||||
/**
|
||||
@ -87,13 +105,14 @@ InfoTabs.displayName = 'InfoTabs'
|
||||
* @returns {ReactElement} List of tags
|
||||
*/
|
||||
const GroupedTags = memo(({ tags = [] }) => (
|
||||
<Stack direction="row" flexWrap="wrap" gap={1}>
|
||||
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
|
||||
<MultipleTags
|
||||
limitTags={10}
|
||||
tags={tags?.map(({ original, id, toggleRowSelected }) => (
|
||||
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
|
||||
<Chip
|
||||
key={id}
|
||||
label={original?.NAME ?? id}
|
||||
onClick={gotoPage}
|
||||
onDelete={() => toggleRowSelected(false)}
|
||||
/>
|
||||
))}
|
||||
|
@ -15,13 +15,16 @@
|
||||
* ------------------------------------------------------------------------- */
|
||||
import { ReactElement, useState, memo } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Typography, Box, Stack, Chip } from '@mui/material'
|
||||
import { BookmarkEmpty } from 'iconoir-react'
|
||||
import { Typography, Box, Stack, Chip, IconButton } from '@mui/material'
|
||||
import { Row } from 'react-table'
|
||||
|
||||
import { ZonesTable } from 'client/components/Tables'
|
||||
import ZoneTabs from 'client/components/Tabs/Zone'
|
||||
import SplitPane from 'client/components/SplitPane'
|
||||
import MultipleTags from 'client/components/MultipleTags'
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import { T, Zone } from 'client/constants'
|
||||
|
||||
/**
|
||||
* Displays a list of Zones with a split pane between the list and selected row(s).
|
||||
@ -47,7 +50,10 @@ function Zones() {
|
||||
{moreThanOneSelected ? (
|
||||
<GroupedTags tags={selectedRows} />
|
||||
) : (
|
||||
<InfoTabs zone={selectedRows[0]?.original} />
|
||||
<InfoTabs
|
||||
zone={selectedRows[0]?.original}
|
||||
gotoPage={selectedRows[0]?.gotoPage}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
@ -60,19 +66,31 @@ function Zones() {
|
||||
/**
|
||||
* Displays details of a Zone.
|
||||
*
|
||||
* @param {object} zone - Zone to display
|
||||
* @param {Zone} zone - Zone to display
|
||||
* @param {Function} [gotoPage] - Function to navigate to a page of a Zone
|
||||
* @returns {ReactElement} Zone details
|
||||
*/
|
||||
const InfoTabs = memo(({ zone }) => (
|
||||
const InfoTabs = memo(({ zone, gotoPage }) => (
|
||||
<Stack overflow="auto">
|
||||
<Typography color="text.primary" noWrap mb={1}>
|
||||
{`#${zone.ID} | ${zone.NAME}`}
|
||||
</Typography>
|
||||
<Stack direction="row" alignItems="center" gap={1} mb={1}>
|
||||
<Typography color="text.primary" noWrap>
|
||||
{`#${zone.ID} | ${zone.NAME}`}
|
||||
</Typography>
|
||||
{gotoPage && (
|
||||
<IconButton title={Tr(T.LocateOnTable)} onClick={gotoPage}>
|
||||
<BookmarkEmpty />
|
||||
</IconButton>
|
||||
)}
|
||||
</Stack>
|
||||
<ZoneTabs id={zone.ID} />
|
||||
</Stack>
|
||||
))
|
||||
|
||||
InfoTabs.propTypes = { zone: PropTypes.object.isRequired }
|
||||
InfoTabs.propTypes = {
|
||||
zone: PropTypes.object.isRequired,
|
||||
gotoPage: PropTypes.func,
|
||||
}
|
||||
|
||||
InfoTabs.displayName = 'InfoTabs'
|
||||
|
||||
/**
|
||||
@ -82,13 +100,14 @@ InfoTabs.displayName = 'InfoTabs'
|
||||
* @returns {ReactElement} List of tags
|
||||
*/
|
||||
const GroupedTags = memo(({ tags = [] }) => (
|
||||
<Stack direction="row" flexWrap="wrap" gap={1}>
|
||||
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
|
||||
<MultipleTags
|
||||
limitTags={10}
|
||||
tags={tags?.map(({ original, id, toggleRowSelected }) => (
|
||||
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
|
||||
<Chip
|
||||
key={id}
|
||||
label={original?.NAME ?? id}
|
||||
onClick={gotoPage}
|
||||
onDelete={() => toggleRowSelected(false)}
|
||||
/>
|
||||
))}
|
||||
|
Loading…
x
Reference in New Issue
Block a user