1
0
mirror of https://github.com/OpenNebula/one.git synced 2024-12-22 13:33:52 +03:00

F OpenNebula/one#6092: Add full screen info tab (#3087)

This commit is contained in:
Jorge Miguel Lobo Escalona 2024-06-03 11:00:09 +02:00 committed by GitHub
parent 168bd86983
commit 4f8e837fd9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 1956 additions and 1206 deletions

View File

@ -0,0 +1,45 @@
/* ------------------------------------------------------------------------- *
* Copyright 2002-2023, 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 { Grid, IconButton } from '@mui/material'
import NavArrowLeft from 'iconoir-react/dist/NavArrowLeft'
import { ReactElement, useCallback } from 'react'
import { useHistory } from 'react-router-dom'
/**
* Back Button.
*
* @returns {ReactElement} BackButton rendered
*/
const BackButton = () => {
const history = useHistory()
const handleBackClick = useCallback(() => {
history.goBack()
})
return (
<Grid container>
<Grid item>
<IconButton onClick={handleBackClick}>
<NavArrowLeft />
</IconButton>
</Grid>
</Grid>
)
}
export default BackButton

View File

@ -0,0 +1,200 @@
/* ------------------------------------------------------------------------- *
* Copyright 2002-2023, 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 { Box, Grid, IconButton, styled } from '@mui/material'
import { Tr } from 'client/components/HOC'
import SplitPane from 'client/components/SplitPane'
import { GlobalActions } from 'client/components/Tables/Enhanced/Utils'
import Pagination from 'client/components/Tables/Enhanced/pagination'
import EnhancedTableStyles from 'client/components/Tables/Enhanced/styles'
import { T } from 'client/constants'
import { useAuth } from 'client/features/Auth'
import NavArrowLeft from 'iconoir-react/dist/NavArrowLeft'
import OpenInWindow from 'iconoir-react/dist/OpenInWindow'
import OpenNewWindow from 'iconoir-react/dist/OpenNewWindow'
import PropTypes from 'prop-types'
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
const StyledWindowButtons = styled(Grid)(() => ({
'&': {
textAlign: 'right',
},
}))
const StyledRowButtons = styled(Grid)(() => ({
'&': {
marginBottom: '.5rem',
},
}))
const defaultPropsResize = 'auto 1fr auto 1fr'
const ResourcesBackButton = memo(
({
selectedRows = [],
table = () => undefined,
info = () => undefined,
simpleGroupsTags = () => undefined,
setSelectedRows = () => undefined,
actions = [],
...restProps
}) => {
const styles = EnhancedTableStyles({
readOnly: false,
})
const { settings: { FIREEDGE: fireedge = {} } = {} } = useAuth()
const { FULL_SCREEN_INFO } = fireedge
const [divided, setDivided] = useState(() => false)
const [propsResize, setPropsResize] = useState(() => defaultPropsResize)
const [pageIndex, setPageIndex] = useState(() => 0)
useEffect(() => {
divided
? setPropsResize('auto auto auto 1fr')
: setPropsResize(defaultPropsResize)
!divided && setPageIndex(0)
}, [divided])
useEffect(() => {
FULL_SCREEN_INFO === 'true' && setDivided(true)
}, [])
const countSelectedRows = selectedRows?.length
const moreThanOneSelected = countSelectedRows > 1
const hasSelectedRows = countSelectedRows > 0
const selectedRowsTable = useMemo(
() =>
selectedRows?.reduce((res, { id }) => ({ ...res, [id]: true }), {}) ||
[],
[selectedRows]
)
const handleUnselectRow = useCallback(
(id) => {
const newRows = selectedRows.filter((item) => item?.id !== id)
setSelectedRows(newRows)
},
[selectedRows]
)
const props = {
...restProps,
actions,
moreThanOneSelected,
selectedRows,
selectedRowsTable,
setSelectedRows,
handleElement: !divided,
gotoPage: !divided && selectedRows?.[0]?.gotoPage,
unselect: !divided && (() => selectedRows?.[0]?.toggleRowSelected(false)),
handleUnselectRow,
}
return (
<SplitPane gridTemplateRows={propsResize}>
{({ getGridProps, GutterComponent }) => (
<Box
height={1}
sx={{
paddingBottom: '3rem',
overflow: divided && hasSelectedRows ? 'visible' : 'hidden',
}}
{...(!divided && hasSelectedRows && getGridProps())}
>
<StyledRowButtons container>
<Grid item xs={8}>
{hasSelectedRows && divided && (
<IconButton
onClick={() => setSelectedRows([])}
title={Tr(T.Back)}
>
<NavArrowLeft />
</IconButton>
)}
</Grid>
<StyledWindowButtons item xs={4}>
{!divided && (
<IconButton
onClick={() => setDivided(true)}
title={Tr(T.DivideWindow)}
>
<OpenNewWindow />
</IconButton>
)}
{divided && (
<IconButton
onClick={() => setDivided(false)}
title={Tr(T.UnDivideWindow)}
>
<OpenInWindow />
</IconButton>
)}
</StyledWindowButtons>
</StyledRowButtons>
{divided ? !hasSelectedRows && table(props) : table(props)}
{!divided && <GutterComponent direction="row" track={2} />}
{hasSelectedRows && divided && (
<div className={styles.toolbar}>
<GlobalActions
className={styles.actions}
globalActions={actions}
selectedRows={selectedRows}
/>
{moreThanOneSelected && (
<Pagination
className={styles.pagination}
handleChangePage={(index) => setPageIndex(index)}
count={countSelectedRows}
showPageCount={true}
useTableProps={{
state: {
pageIndex,
pageSize: 1,
},
}}
/>
)}
</div>
)}
{moreThanOneSelected
? divided
? info({
...props,
selectedRows: [selectedRows[pageIndex]],
})
: simpleGroupsTags(props)
: hasSelectedRows && info(props)}
</Box>
)}
</SplitPane>
)
}
)
ResourcesBackButton.propTypes = {
selectedRows: PropTypes.array,
table: PropTypes.func,
info: PropTypes.func,
simpleGroupsTags: PropTypes.func,
setSelectedRows: PropTypes.func,
actions: PropTypes.array,
}
ResourcesBackButton.displayName = 'ResourcesBackButton'
export default ResourcesBackButton

View File

@ -75,14 +75,17 @@ const GlobalActions = ({
onClick={refetch}
/>
)}
{!singleSelect && !disableRowSelect && (
<Checkbox
{...getToggleAllPageRowsSelectedProps()}
title={Tr(T.ToggleAllSelectedCardsCurrentPage)}
indeterminate={getToggleAllRowsSelectedProps().indeterminate}
color="secondary"
/>
)}
{!singleSelect &&
!disableRowSelect &&
getToggleAllPageRowsSelectedProps &&
getToggleAllRowsSelectedProps && (
<Checkbox
{...getToggleAllPageRowsSelectedProps()}
title={Tr(T.ToggleAllSelectedCardsCurrentPage)}
indeterminate={getToggleAllRowsSelectedProps().indeterminate}
color="secondary"
/>
)}
{globalActions?.map((item, idx) => {
if ((singleSelect || disableRowSelect) && item.selected) return null

View File

@ -48,6 +48,9 @@ import EnhancedTableStyles from 'client/components/Tables/Enhanced/styles'
import { Translate } from 'client/components/HOC'
import { T } from 'client/constants'
import _ from 'lodash'
const RELOAD_STATE = 'RELOAD_STATE'
const EnhancedTable = ({
columns,
@ -103,7 +106,7 @@ const EnhancedTable = ({
)
const stateReducer = (newState, action, prevState) => {
switch (action.type) {
case 'RELOAD_STATE': {
case RELOAD_STATE: {
const updatedState = {
...prevState,
selectedRowIds: action.value,
@ -169,6 +172,7 @@ const EnhancedTable = ({
setGlobalFilter,
state,
toggleRowSelected: propsToggleRow,
dispatch,
} = useTableProps
const [stateData, setStateData] = useState(data)
@ -220,6 +224,15 @@ const EnhancedTable = ({
}))
}, [state.selectedRowIds, selectedRowStates])
useEffect(() => {
initialState?.selectedRowIds &&
!_.isEqual(state.selectedRowIds, initialState.selectedRowIds) &&
dispatch({
type: RELOAD_STATE,
value: initialState.selectedRowIds,
})
}, [initialState?.selectedRowIds])
useEffect(() => {
if (
dataDepend &&
@ -423,7 +436,6 @@ const EnhancedTable = ({
) {
toggleAllRowsSelected?.(false)
}
toggleRowSelected?.(!isSelected)
}
}}
@ -477,7 +489,7 @@ EnhancedTable.propTypes = {
dataDepend: PropTypes.oneOfType([PropTypes.array, PropTypes.string]),
readOnly: PropTypes.bool,
tableViews: PropTypes.object,
zoneId: PropTypes.string,
zoneId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
}
export * from 'client/components/Tables/Enhanced/Utils'

View File

@ -70,7 +70,7 @@ Row.propTypes = {
className: PropTypes.string,
handleClick: PropTypes.func,
onClickLabel: PropTypes.func,
zone: PropTypes.string,
zone: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
}
Row.displayName = 'HostRow'

View File

@ -17,6 +17,8 @@ module.exports = {
/* pagination / stepper */
Back: 'Back',
Previous: 'Previous',
DivideWindow: 'Divide Window',
UnDivideWindow: 'Undivide Window',
Next: 'Next',
Sort: 'Sort',
SortBy: 'Sort by',
@ -116,6 +118,7 @@ module.exports = {
DetachRestricted:
'You cannot delete this resource because it has restricted attributes on this template. Please, contact with your administrator.',
DetachSomething: 'Detach: %s',
Disable: 'Disable',
Dismiss: 'Dismiss',
DiskSnapshotCreate: 'Disk snapshot create',
@ -830,6 +833,7 @@ module.exports = {
CtrlAltDel: 'Ctrl-Alt-Del',
Reconnect: 'Reconnect',
FullScreen: 'Full screen',
FullScreenInfo: 'Full screen information in datatables',
Screenshot: 'Screenshot',
LastConnection: 'Last connection',
VmIsNotOnVCenter: '%s is not located on vCenter Host',

View File

@ -13,14 +13,16 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { ReactElement, useState, memo } from 'react'
import PropTypes from 'prop-types'
import { Box, Stack, Chip } from '@mui/material'
import { Row } from 'react-table'
import SplitPane from 'client/components/SplitPane'
/* eslint-disable react/prop-types */
import { Chip, Stack } from '@mui/material'
import MultipleTags from 'client/components/MultipleTags'
import ACLActions from 'client/components/Tables/ACLs/actions'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { ACLsTable } from 'client/components/Tables'
import ACLActions from 'client/components/Tables/ACLs/actions'
import { useGeneral } from 'client/features/General'
import PropTypes from 'prop-types'
import { ReactElement, useState } from 'react'
import { Row } from 'react-table'
/**
* Displays a list of Groups with a split pane between the list and selected row(s).
@ -28,30 +30,41 @@ import { ACLsTable } from 'client/components/Tables'
* @returns {ReactElement} Groups list and selected row(s)
*/
function ACLs() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const hasSelectedRows = selectedRows?.length > 0
const [selectedRows, setSelectedRows] = useState(() => [])
const { zone } = useGeneral()
const actions = ACLActions()
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<ACLsTable
onSelectedRowsChange={onSelectedRowsChange}
globalActions={actions}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
<GroupedTags tags={selectedRows} />
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
zone={zone}
actions={actions}
table={(props) => (
<ACLsTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
/>
)
}
@ -61,23 +74,34 @@ function ACLs() {
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
const GroupedTags = ({
tags = [],
handleElement = true,
onDelete = () => undefined,
}) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
return <Chip key={id} label={original?.NAME ?? id} {...clickElement} />
})}
/>
</Stack>
))
)
GroupedTags.propTypes = { tags: PropTypes.array }
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default ACLs

View File

@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { Box, Chip, Stack, Typography } from '@mui/material'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import { Cancel, Pin as GotoIcon, RefreshDouble } from 'iconoir-react'
import PropTypes from 'prop-types'
import { ReactElement, memo, useState } from 'react'
@ -22,12 +23,13 @@ import { Row } from 'react-table'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import SplitPane from 'client/components/SplitPane'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { BackupJobsTable } from 'client/components/Tables'
import BackupJobActions from 'client/components/Tables/BackupJobs/actions'
import BackupJobsTabs from 'client/components/Tabs/BackupJobs'
import { T } from 'client/constants'
import { useGeneral } from 'client/features/General'
import {
useLazyGetBackupJobQuery,
useUpdateBackupJobMutation,
@ -39,39 +41,46 @@ import {
* @returns {ReactElement} Backup Jobs list and selected row(s)
*/
function BackupJobs() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const [selectedRows, setSelectedRows] = useState(() => [])
const actions = BackupJobActions()
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
const { zone } = useGeneral()
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<BackupJobsTable
onSelectedRowsChange={onSelectedRowsChange}
globalActions={actions}
useUpdateMutation={useUpdateBackupJobMutation}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
template={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
useUpdateMutation={useUpdateBackupJobMutation}
zone={zone}
actions={actions}
table={(props) => (
<BackupJobsTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
useUpdateMutation={props.useUpdateMutation}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
template: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -85,8 +94,8 @@ function BackupJobs() {
*/
const InfoTabs = memo(({ template, gotoPage, unselect }) => {
const [getBackupJob, { data, isFetching }] = useLazyGetBackupJobQuery()
const id = data?.ID ?? template.ID
const name = data?.NAME ?? template.NAME
const id = data?.ID ?? template?.ID
const name = data?.NAME ?? template?.NAME
return (
<Stack overflow="auto">
@ -140,23 +149,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
const GroupedTags = ({
tags = [],
handleElement = true,
onDelete = () => undefined,
}) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
return <Chip key={id} label={original?.NAME ?? id} {...clickElement} />
})}
/>
</Stack>
))
)
GroupedTags.propTypes = { tags: PropTypes.array }
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default BackupJobs

View File

@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { Box, Chip, Stack, Typography } from '@mui/material'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import Cancel from 'iconoir-react/dist/Cancel'
import GotoIcon from 'iconoir-react/dist/Pin'
import RefreshDouble from 'iconoir-react/dist/RefreshDouble'
@ -24,11 +25,12 @@ import { Row } from 'react-table'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import SplitPane from 'client/components/SplitPane'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { BackupsTable } from 'client/components/Tables'
import BackupActions from 'client/components/Tables/Backups/actions'
import BackupTabs from 'client/components/Tabs/Backup'
import { Image, T } from 'client/constants'
import { useGeneral } from 'client/features/General'
import {
useLazyGetImageQuery,
useUpdateImageMutation,
@ -40,39 +42,46 @@ import {
* @returns {ReactElement} Backups list and selected row(s)
*/
function Backups() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const [selectedRows, setSelectedRows] = useState(() => [])
const actions = BackupActions(selectedRows)
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
const { zone } = useGeneral()
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<BackupsTable
onSelectedRowsChange={onSelectedRowsChange}
globalActions={actions}
useUpdateMutation={useUpdateImageMutation}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
image={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
useUpdateMutation={useUpdateImageMutation}
zone={zone}
actions={actions}
table={(props) => (
<BackupsTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
useUpdateMutation={props.useUpdateMutation}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
image: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -86,8 +95,8 @@ function Backups() {
*/
const InfoTabs = memo(({ image, gotoPage, unselect }) => {
const [getImage, { data: lazyData, isFetching }] = useLazyGetImageQuery()
const id = lazyData?.ID ?? image.ID
const name = lazyData?.NAME ?? image.NAME
const id = lazyData?.ID ?? image?.ID
const name = lazyData?.NAME ?? image?.NAME
return (
<Stack overflow="auto">
@ -119,7 +128,7 @@ const InfoTabs = memo(({ image, gotoPage, unselect }) => {
/>
)}
</Stack>
<BackupTabs id={image.ID} />
<BackupTabs id={id} />
</Stack>
)
})
@ -138,23 +147,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
const GroupedTags = ({
tags = [],
handleElement = true,
onDelete = () => undefined,
}) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
return <Chip key={id} label={original?.NAME ?? id} {...clickElement} />
})}
/>
</Stack>
))
)
GroupedTags.propTypes = { tags: PropTypes.array }
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default Backups

View File

@ -13,26 +13,28 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { ReactElement, useState, memo } from 'react'
import PropTypes from 'prop-types'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import Cancel from 'iconoir-react/dist/Cancel'
import GotoIcon from 'iconoir-react/dist/Pin'
import RefreshDouble from 'iconoir-react/dist/RefreshDouble'
import Cancel from 'iconoir-react/dist/Cancel'
import { Typography, Box, Stack, Chip } from '@mui/material'
import PropTypes from 'prop-types'
import { ReactElement, memo, useState } from 'react'
import { Row } from 'react-table'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { ClustersTable } from 'client/components/Tables'
import ClusterActions from 'client/components/Tables/Clusters/actions'
import ClusterTabs from 'client/components/Tabs/Cluster'
import { Cluster, T } from 'client/constants'
import { useGeneral } from 'client/features/General'
import {
useLazyGetClustersQuery,
useUpdateClusterMutation,
} from 'client/features/OneApi/cluster'
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 { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import { T, Cluster } from 'client/constants'
import ClusterActions from 'client/components/Tables/Clusters/actions'
/**
* Displays a list of Clusters with a split pane between the list and selected row(s).
@ -40,40 +42,47 @@ import ClusterActions from 'client/components/Tables/Clusters/actions'
* @returns {ReactElement} Clusters list and selected row(s)
*/
function Clusters() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
const [selectedRows, setSelectedRows] = useState(() => [])
const actions = ClusterActions()
const { zone } = useGeneral()
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<ClustersTable
onSelectedRowsChange={onSelectedRowsChange}
useUpdateMutation={useUpdateClusterMutation}
globalActions={actions}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
cluster={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
useUpdateMutation={useUpdateClusterMutation}
zone={zone}
actions={actions}
table={(props) => (
<ClustersTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
useUpdateMutation={props.useUpdateMutation}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
cluster: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -87,8 +96,8 @@ function Clusters() {
*/
const InfoTabs = memo(({ cluster, gotoPage, unselect }) => {
const [get, { data: lazyData, isFetching }] = useLazyGetClustersQuery()
const id = lazyData?.ID ?? cluster.ID
const name = lazyData?.NAME ?? cluster.NAME
const id = lazyData?.ID ?? cluster?.ID
const name = lazyData?.NAME ?? cluster?.NAME
return (
<Stack overflow="auto">
@ -142,23 +151,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
/>
</Stack>
))
const GroupedTags = memo(
({ tags = [], handleElement = true, onDelete = () => undefined }) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
GroupedTags.propTypes = { tags: PropTypes.array }
return (
<Chip key={id} label={original?.NAME ?? id} {...clickElement} />
)
})}
/>
</Stack>
)
)
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default Clusters

View File

@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { Box, Chip, Stack, Typography } from '@mui/material'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import Cancel from 'iconoir-react/dist/Cancel'
import GotoIcon from 'iconoir-react/dist/Pin'
import RefreshDouble from 'iconoir-react/dist/RefreshDouble'
@ -24,11 +25,12 @@ import { Row } from 'react-table'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import SplitPane from 'client/components/SplitPane'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { DatastoresTable } from 'client/components/Tables'
import DatastoreActions from 'client/components/Tables/Datastores/actions'
import DatastoreTabs from 'client/components/Tabs/Datastore'
import { Datastore, T } from 'client/constants'
import { useGeneral } from 'client/features/General'
import {
useLazyGetDatastoreQuery,
useUpdateDatastoreMutation,
@ -40,39 +42,46 @@ import {
* @returns {ReactElement} Datastores list and selected row(s)
*/
function Datastores() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const [selectedRows, setSelectedRows] = useState(() => [])
const actions = DatastoreActions()
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
const { zone } = useGeneral()
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<DatastoresTable
onSelectedRowsChange={onSelectedRowsChange}
globalActions={actions}
useUpdateMutation={useUpdateDatastoreMutation}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
datastore={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
useUpdateMutation={useUpdateDatastoreMutation}
zone={zone}
actions={actions}
table={(props) => (
<DatastoresTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
useUpdateMutation={props.useUpdateMutation}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
datastore: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -87,8 +96,8 @@ function Datastores() {
const InfoTabs = memo(({ datastore, gotoPage, unselect }) => {
const [getDatastore, { data: lazyData, isFetching }] =
useLazyGetDatastoreQuery()
const id = lazyData?.ID ?? datastore.ID
const name = lazyData?.NAME ?? datastore.NAME
const id = lazyData?.ID ?? datastore?.ID
const name = lazyData?.NAME ?? datastore?.NAME
return (
<Stack overflow="auto">
@ -120,7 +129,7 @@ const InfoTabs = memo(({ datastore, gotoPage, unselect }) => {
/>
)}
</Stack>
<DatastoreTabs id={datastore.ID} />
<DatastoreTabs id={id} />
</Stack>
)
})
@ -139,23 +148,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
const GroupedTags = ({
tags = [],
handleElement = true,
onDelete = () => undefined,
}) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
return <Chip key={id} label={original?.NAME ?? id} {...clickElement} />
})}
/>
</Stack>
))
)
GroupedTags.propTypes = { tags: PropTypes.array }
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default Datastores

View File

@ -13,23 +13,25 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { ReactElement, useState, memo } from 'react'
import PropTypes from 'prop-types'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import Cancel from 'iconoir-react/dist/Cancel'
import GotoIcon from 'iconoir-react/dist/Pin'
import RefreshDouble from 'iconoir-react/dist/RefreshDouble'
import Cancel from 'iconoir-react/dist/Cancel'
import { Typography, Box, Stack, Chip } from '@mui/material'
import PropTypes from 'prop-types'
import { ReactElement, memo, useState } from 'react'
import { Row } from 'react-table'
import { useLazyGetImageQuery } from 'client/features/OneApi/image'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { FilesTable } from 'client/components/Tables'
import fileActions from 'client/components/Tables/Files/actions'
import FileTabs from 'client/components/Tabs/File'
import SplitPane from 'client/components/SplitPane'
import MultipleTags from 'client/components/MultipleTags'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import { T, Image } from 'client/constants'
import { Image, T } from 'client/constants'
import { useGeneral } from 'client/features/General'
import { useLazyGetImageQuery } from 'client/features/OneApi/image'
/**
* Displays a list of Files with a split pane between the list and selected row(s).
@ -37,38 +39,44 @@ import { T, Image } from 'client/constants'
* @returns {ReactElement} Files list and selected row(s)
*/
function Files() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const [selectedRows, setSelectedRows] = useState(() => [])
const actions = fileActions()
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
const { zone } = useGeneral()
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<FilesTable
onSelectedRowsChange={onSelectedRowsChange}
globalActions={actions}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
file={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
zone={zone}
actions={actions}
table={(props) => (
<FilesTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
file: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -82,8 +90,8 @@ function Files() {
*/
const InfoTabs = memo(({ file, gotoPage, unselect }) => {
const [getImage, { data: lazyData, isFetching }] = useLazyGetImageQuery()
const id = lazyData?.ID ?? file.ID
const name = lazyData?.NAME ?? file.NAME
const id = lazyData?.ID ?? file?.ID
const name = lazyData?.NAME ?? file?.NAME
return (
<Stack overflow="auto">
@ -115,7 +123,7 @@ const InfoTabs = memo(({ file, gotoPage, unselect }) => {
/>
)}
</Stack>
<FileTabs id={file.ID} />
<FileTabs id={id} />
</Stack>
)
})
@ -134,23 +142,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
const GroupedTags = ({
tags = [],
handleElement = true,
onDelete = () => undefined,
}) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
return <Chip key={id} label={original?.NAME ?? id} {...clickElement} />
})}
/>
</Stack>
))
)
GroupedTags.propTypes = { tags: PropTypes.array }
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default Files

View File

@ -13,25 +13,27 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { ReactElement, useState, memo } from 'react'
import PropTypes from 'prop-types'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import Cancel from 'iconoir-react/dist/Cancel'
import GotoIcon from 'iconoir-react/dist/Pin'
import RefreshDouble from 'iconoir-react/dist/RefreshDouble'
import Cancel from 'iconoir-react/dist/Cancel'
import { Typography, Box, Stack, Chip } from '@mui/material'
import PropTypes from 'prop-types'
import { ReactElement, memo, useState } from 'react'
import { Row } from 'react-table'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { GroupsTable } from 'client/components/Tables'
import GroupTabs from 'client/components/Tabs/Group'
import { Group, T } from 'client/constants'
import { useGeneral } from 'client/features/General'
import {
useLazyGetGroupQuery,
useUpdateGroupMutation,
} from 'client/features/OneApi/group'
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 { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import { T, Group } from 'client/constants'
import GroupActions from 'client/components/Tables/Groups/actions'
@ -41,40 +43,46 @@ import GroupActions from 'client/components/Tables/Groups/actions'
* @returns {ReactElement} Groups list and selected row(s)
*/
function Groups() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
const [selectedRows, setSelectedRows] = useState(() => [])
const actions = GroupActions()
const { zone } = useGeneral()
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<GroupsTable
onSelectedRowsChange={onSelectedRowsChange}
useUpdateMutation={useUpdateGroupMutation}
globalActions={actions}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
group={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
useUpdateMutation={useUpdateGroupMutation}
zone={zone}
actions={actions}
table={(props) => (
<GroupsTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
useUpdateMutation={props.useUpdateMutation}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
group: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -88,8 +96,8 @@ function Groups() {
*/
const InfoTabs = memo(({ group, gotoPage, unselect }) => {
const [get, { data: lazyData, isFetching }] = useLazyGetGroupQuery()
const id = lazyData?.ID ?? group.ID
const name = lazyData?.NAME ?? group.NAME
const id = lazyData?.ID ?? group?.ID
const name = lazyData?.NAME ?? group?.NAME
return (
<Stack overflow="auto">
@ -143,23 +151,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
const GroupedTags = ({
tags = [],
handleElement = true,
onDelete = () => undefined,
}) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
return <Chip key={id} label={original?.NAME ?? id} {...clickElement} />
})}
/>
</Stack>
))
)
GroupedTags.propTypes = { tags: PropTypes.array }
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default Groups

View File

@ -14,8 +14,9 @@
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { ReactElement } from 'react'
import { useParams, Redirect } from 'react-router-dom'
import { Redirect, useParams } from 'react-router-dom'
import BackButton from 'client/components/ResourcesBackButton/BackButton'
import HostTabs from 'client/components/Tabs/Host'
/**
@ -30,7 +31,12 @@ function HostDetail() {
return <Redirect to="/" />
}
return <HostTabs id={id} />
return (
<>
<BackButton />
<HostTabs id={id} />
</>
)
}
export default HostDetail

View File

@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { Box, Chip, Stack, Typography } from '@mui/material'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import Cancel from 'iconoir-react/dist/Cancel'
import GotoIcon from 'iconoir-react/dist/Pin'
import RefreshDouble from 'iconoir-react/dist/RefreshDouble'
@ -24,7 +25,7 @@ import { Row } from 'react-table'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import SplitPane from 'client/components/SplitPane'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { HostsTable } from 'client/components/Tables'
import HostActions from 'client/components/Tables/Hosts/actions'
import HostTabs from 'client/components/Tabs/Host'
@ -41,41 +42,46 @@ import {
* @returns {ReactElement} Hosts list and selected row(s)
*/
function Hosts() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const [selectedRows, setSelectedRows] = useState(() => [])
const actions = HostActions()
const { zone } = useGeneral()
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<HostsTable
onSelectedRowsChange={onSelectedRowsChange}
globalActions={actions}
useUpdateMutation={useUpdateHostMutation}
zoneId={zone}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
host={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
useUpdateMutation={useUpdateHostMutation}
zone={zone}
actions={actions}
table={(props) => (
<HostsTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
useUpdateMutation={props.useUpdateMutation}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
host: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -89,8 +95,8 @@ function Hosts() {
*/
const InfoTabs = memo(({ host, gotoPage, unselect }) => {
const [getVm, { data: lazyData, isFetching }] = useLazyGetHostQuery()
const id = lazyData?.ID ?? host.ID
const name = lazyData?.NAME ?? host.NAME
const id = lazyData?.ID ?? host?.ID
const name = lazyData?.NAME ?? host?.NAME
return (
<Stack overflow="auto">
@ -144,23 +150,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
const GroupedTags = ({
tags = [],
handleElement = true,
onDelete = () => undefined,
}) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
return <Chip key={id} label={original?.NAME ?? id} {...clickElement} />
})}
/>
</Stack>
))
)
GroupedTags.propTypes = { tags: PropTypes.array }
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default Hosts

View File

@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { Box, Chip, Stack, Typography } from '@mui/material'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import Cancel from 'iconoir-react/dist/Cancel'
import GotoIcon from 'iconoir-react/dist/Pin'
import RefreshDouble from 'iconoir-react/dist/RefreshDouble'
@ -24,14 +25,15 @@ import { Row } from 'react-table'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import SplitPane from 'client/components/SplitPane'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { ImagesTable } from 'client/components/Tables'
import ImageActions from 'client/components/Tables/Images/actions'
import ImageTabs from 'client/components/Tabs/Image'
import { Image, T } from 'client/constants'
import { useGeneral } from 'client/features/General'
import {
useUpdateImageMutation,
useLazyGetImageQuery,
useUpdateImageMutation,
} from 'client/features/OneApi/image'
/**
@ -40,39 +42,46 @@ import {
* @returns {ReactElement} Images list and selected row(s)
*/
function Images() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const [selectedRows, setSelectedRows] = useState(() => [])
const actions = ImageActions()
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
const { zone } = useGeneral()
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<ImagesTable
onSelectedRowsChange={onSelectedRowsChange}
globalActions={actions}
useUpdateMutation={useUpdateImageMutation}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
image={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
useUpdateMutation={useUpdateImageMutation}
zone={zone}
actions={actions}
table={(props) => (
<ImagesTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
useUpdateMutation={props.useUpdateMutation}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
image: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -86,8 +95,8 @@ function Images() {
*/
const InfoTabs = memo(({ image, gotoPage, unselect }) => {
const [getImage, { data: lazyData, isFetching }] = useLazyGetImageQuery()
const id = lazyData?.ID ?? image.ID
const name = lazyData?.NAME ?? image.NAME
const id = lazyData?.ID ?? image?.ID
const name = lazyData?.NAME ?? image?.NAME
return (
<Stack overflow="auto">
@ -119,7 +128,7 @@ const InfoTabs = memo(({ image, gotoPage, unselect }) => {
/>
)}
</Stack>
<ImageTabs id={image.ID} />
<ImageTabs id={id} />
</Stack>
)
})
@ -138,23 +147,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
const GroupedTags = ({
tags = [],
handleElement = true,
onDelete = () => undefined,
}) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
return <Chip key={id} label={original?.NAME ?? id} {...clickElement} />
})}
/>
</Stack>
))
)
GroupedTags.propTypes = { tags: PropTypes.array }
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default Images

View File

@ -13,26 +13,28 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { ReactElement, useState, memo } from 'react'
import PropTypes from 'prop-types'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import Cancel from 'iconoir-react/dist/Cancel'
import GotoIcon from 'iconoir-react/dist/Pin'
import RefreshDouble from 'iconoir-react/dist/RefreshDouble'
import Cancel from 'iconoir-react/dist/Cancel'
import { Typography, Box, Stack, Chip } from '@mui/material'
import PropTypes from 'prop-types'
import { ReactElement, memo, useState } from 'react'
import { Row } from 'react-table'
import {
useUpdateAppMutation,
useLazyGetMarketplaceAppQuery,
} from 'client/features/OneApi/marketplaceApp'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { MarketplaceAppsTable } from 'client/components/Tables'
import MarketplaceAppActions from 'client/components/Tables/MarketplaceApps/actions'
import MarketplaceAppsTabs from 'client/components/Tabs/MarketplaceApp'
import SplitPane from 'client/components/SplitPane'
import MultipleTags from 'client/components/MultipleTags'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import { T, MarketplaceApp } from 'client/constants'
import { MarketplaceApp, T } from 'client/constants'
import { useGeneral } from 'client/features/General'
import {
useLazyGetMarketplaceAppQuery,
useUpdateAppMutation,
} from 'client/features/OneApi/marketplaceApp'
/**
* Displays a list of Marketplace Apps with a split pane between the list and selected row(s).
@ -40,39 +42,46 @@ import { T, MarketplaceApp } from 'client/constants'
* @returns {ReactElement} Marketplace Apps list and selected row(s)
*/
function MarketplaceApps() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const [selectedRows, setSelectedRows] = useState(() => [])
const actions = MarketplaceAppActions()
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
const { zone } = useGeneral()
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<MarketplaceAppsTable
onSelectedRowsChange={onSelectedRowsChange}
globalActions={actions}
useUpdateMutation={useUpdateAppMutation}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
app={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
useUpdateMutation={useUpdateAppMutation}
zone={zone}
actions={actions}
table={(props) => (
<MarketplaceAppsTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
useUpdateMutation={props.useUpdateMutation}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
app: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -88,8 +97,8 @@ const InfoTabs = memo(({ app, gotoPage, unselect }) => {
const [get, queryState] = useLazyGetMarketplaceAppQuery()
const { data: lazyData, isFetching } = queryState
const id = lazyData?.ID ?? app.ID
const name = lazyData?.NAME ?? app.NAME
const id = lazyData?.ID ?? app?.ID
const name = lazyData?.NAME ?? app?.NAME
return (
<Stack overflow="auto">
@ -143,23 +152,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
const GroupedTags = ({
tags = [],
handleElement = true,
onDelete = () => undefined,
}) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
return <Chip key={id} label={original?.NAME ?? id} {...clickElement} />
})}
/>
</Stack>
))
)
GroupedTags.propTypes = { tags: PropTypes.array }
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default MarketplaceApps

View File

@ -13,25 +13,27 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { ReactElement, useState, memo } from 'react'
import PropTypes from 'prop-types'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import Cancel from 'iconoir-react/dist/Cancel'
import GotoIcon from 'iconoir-react/dist/Pin'
import RefreshDouble from 'iconoir-react/dist/RefreshDouble'
import Cancel from 'iconoir-react/dist/Cancel'
import { Typography, Box, Stack, Chip } from '@mui/material'
import PropTypes from 'prop-types'
import { ReactElement, memo, useState } from 'react'
import { Row } from 'react-table'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { MarketplacesTable } from 'client/components/Tables'
import MarketplaceTabs from 'client/components/Tabs/Marketplace'
import { Marketplace, T } from 'client/constants'
import { useGeneral } from 'client/features/General'
import {
useLazyGetMarketplaceQuery,
useUpdateMarketplaceMutation,
} from 'client/features/OneApi/marketplace'
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 { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import { T, Marketplace } from 'client/constants'
import MarketplaceActions from 'client/components/Tables/Marketplaces/actions'
@ -41,40 +43,46 @@ import MarketplaceActions from 'client/components/Tables/Marketplaces/actions'
* @returns {ReactElement} Marketplaces list and selected row(s)
*/
function Marketplaces() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
const [selectedRows, setSelectedRows] = useState(() => [])
const actions = MarketplaceActions()
const { zone } = useGeneral()
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<MarketplacesTable
onSelectedRowsChange={onSelectedRowsChange}
useUpdateMutation={useUpdateMarketplaceMutation}
globalActions={actions}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
market={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
useUpdateMutation={useUpdateMarketplaceMutation}
zone={zone}
actions={actions}
table={(props) => (
<MarketplacesTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
useUpdateMutation={props.useUpdateMutation}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
market: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -88,8 +96,8 @@ function Marketplaces() {
*/
const InfoTabs = memo(({ market, gotoPage, unselect }) => {
const [get, { data: lazyData, isFetching }] = useLazyGetMarketplaceQuery()
const id = lazyData?.ID ?? market.ID
const name = lazyData?.NAME ?? market.NAME
const id = lazyData?.ID ?? market?.ID
const name = lazyData?.NAME ?? market?.NAME
return (
<Stack overflow="auto">
@ -143,23 +151,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
const GroupedTags = ({
tags = [],
handleElement = true,
onDelete = () => undefined,
}) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
return <Chip key={id} label={original?.NAME ?? id} {...clickElement} />
})}
/>
</Stack>
))
)
GroupedTags.propTypes = { tags: PropTypes.array }
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default Marketplaces

View File

@ -13,26 +13,28 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { ReactElement, useState, memo } from 'react'
import PropTypes from 'prop-types'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import Cancel from 'iconoir-react/dist/Cancel'
import GotoIcon from 'iconoir-react/dist/Pin'
import RefreshDouble from 'iconoir-react/dist/RefreshDouble'
import Cancel from 'iconoir-react/dist/Cancel'
import { Typography, Box, Stack, Chip } from '@mui/material'
import PropTypes from 'prop-types'
import { ReactElement, memo, useState } from 'react'
import { Row } from 'react-table'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { SecurityGroupsTable } from 'client/components/Tables'
import SecurityGroupsActions from 'client/components/Tables/SecurityGroups/actions'
import SecurityGroupsTabs from 'client/components/Tabs/SecurityGroup'
import { Image, T } from 'client/constants'
import { useGeneral } from 'client/features/General'
import {
useLazyGetSecGroupQuery,
useUpdateSecGroupMutation,
} from 'client/features/OneApi/securityGroup'
import { SecurityGroupsTable } from 'client/components/Tables'
import SecurityGroupsActions from 'client/components/Tables/SecurityGroups/actions'
import SecurityGroupsTabs from 'client/components/Tabs/SecurityGroup'
import SplitPane from 'client/components/SplitPane'
import MultipleTags from 'client/components/MultipleTags'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import { T, Image } from 'client/constants'
/**
* Displays a list of Security Groups with a split pane between the list and selected row(s).
@ -40,39 +42,46 @@ import { T, Image } from 'client/constants'
* @returns {ReactElement} Security Groups list and selected row(s)
*/
function SecurityGroups() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const [selectedRows, setSelectedRows] = useState(() => [])
const actions = SecurityGroupsActions()
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
const { zone } = useGeneral()
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<SecurityGroupsTable
onSelectedRowsChange={onSelectedRowsChange}
globalActions={actions}
useUpdateMutation={useUpdateSecGroupMutation}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
securityGroup={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
useUpdateMutation={useUpdateSecGroupMutation}
zone={zone}
actions={actions}
table={(props) => (
<SecurityGroupsTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
useUpdateMutation={props.useUpdateMutation}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
securityGroup: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -87,8 +96,8 @@ function SecurityGroups() {
const InfoTabs = memo(({ securityGroup, gotoPage, unselect }) => {
const [getSecurityGroup, { data: lazyData, isFetching }] =
useLazyGetSecGroupQuery()
const id = lazyData?.ID ?? securityGroup.ID
const name = lazyData?.NAME ?? securityGroup.NAME
const id = lazyData?.ID ?? securityGroup?.ID
const name = lazyData?.NAME ?? securityGroup?.NAME
return (
<Stack overflow="auto">
@ -120,7 +129,7 @@ const InfoTabs = memo(({ securityGroup, gotoPage, unselect }) => {
/>
)}
</Stack>
<SecurityGroupsTabs id={securityGroup.ID} />
<SecurityGroupsTabs id={id} />
</Stack>
)
})
@ -139,23 +148,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
const GroupedTags = ({
tags = [],
handleElement = true,
onDelete = () => undefined,
}) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
return <Chip key={id} label={original?.NAME ?? id} {...clickElement} />
})}
/>
</Stack>
))
)
GroupedTags.propTypes = { tags: PropTypes.array }
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default SecurityGroups

View File

@ -13,23 +13,25 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { ReactElement, useState, memo } from 'react'
import PropTypes from 'prop-types'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import Cancel from 'iconoir-react/dist/Cancel'
import GotoIcon from 'iconoir-react/dist/Pin'
import RefreshDouble from 'iconoir-react/dist/RefreshDouble'
import Cancel from 'iconoir-react/dist/Cancel'
import { Typography, Box, Stack, Chip } from '@mui/material'
import PropTypes from 'prop-types'
import { ReactElement, memo, useState } from 'react'
import { Row } from 'react-table'
import { useLazyGetServiceTemplateQuery } from 'client/features/OneApi/serviceTemplate'
import { ServiceTemplatesTable } from 'client/components/Tables'
import ServiceTemplateTabs from 'client/components/Tabs/ServiceTemplate'
import SplitPane from 'client/components/SplitPane'
import MultipleTags from 'client/components/MultipleTags'
import ServiceTemplateActions from 'client/components/Tables/ServiceTemplates/actions'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { ServiceTemplatesTable } from 'client/components/Tables'
import ServiceTemplateActions from 'client/components/Tables/ServiceTemplates/actions'
import ServiceTemplateTabs from 'client/components/Tabs/ServiceTemplate'
import { T } from 'client/constants'
import { useGeneral } from 'client/features/General'
import { useLazyGetServiceTemplateQuery } from 'client/features/OneApi/serviceTemplate'
/**
* Displays a list of Service Templates with a split pane between
@ -38,39 +40,44 @@ import { T } from 'client/constants'
* @returns {ReactElement} Service Templates list and selected row(s)
*/
function ServiceTemplates() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const [selectedRows, setSelectedRows] = useState(() => [])
const actions = ServiceTemplateActions()
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
const { zone } = useGeneral()
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<ServiceTemplatesTable
onSelectedRowsChange={onSelectedRowsChange}
globalActions={actions}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
id={selectedRows[0]?.original?.ID}
template={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
zone={zone}
actions={actions}
table={(props) => (
<ServiceTemplatesTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
template: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -84,8 +91,8 @@ function ServiceTemplates() {
*/
const InfoTabs = memo(({ template, gotoPage, unselect }) => {
const [get, { data: lazyData, isFetching }] = useLazyGetServiceTemplateQuery()
const id = lazyData?.ID ?? template.ID
const name = lazyData?.NAME ?? template.NAME
const id = lazyData?.ID ?? template?.ID
const name = lazyData?.NAME ?? template?.NAME
return (
<Stack overflow="auto">
@ -139,23 +146,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
const GroupedTags = ({
tags = [],
handleElement = true,
onDelete = () => undefined,
}) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
return <Chip key={id} label={original?.NAME ?? id} {...clickElement} />
})}
/>
</Stack>
))
)
GroupedTags.propTypes = { tags: PropTypes.array }
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default ServiceTemplates

View File

@ -13,23 +13,25 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { ReactElement, useState, memo } from 'react'
import PropTypes from 'prop-types'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import Cancel from 'iconoir-react/dist/Cancel'
import GotoIcon from 'iconoir-react/dist/Pin'
import RefreshDouble from 'iconoir-react/dist/RefreshDouble'
import Cancel from 'iconoir-react/dist/Cancel'
import { Typography, Box, Stack, Chip } from '@mui/material'
import PropTypes from 'prop-types'
import { ReactElement, memo, useState } from 'react'
import { Row } from 'react-table'
import { useLazyGetServiceQuery } from 'client/features/OneApi/service'
import { ServicesTable } from 'client/components/Tables'
import ServiceTabs from 'client/components/Tabs/Service'
import SplitPane from 'client/components/SplitPane'
import MultipleTags from 'client/components/MultipleTags'
import ServiceActions from 'client/components/Tables/Services/actions'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { ServicesTable } from 'client/components/Tables'
import ServiceActions from 'client/components/Tables/Services/actions'
import ServiceTabs from 'client/components/Tabs/Service'
import { T } from 'client/constants'
import { useGeneral } from 'client/features/General'
import { useLazyGetServiceQuery } from 'client/features/OneApi/service'
/**
* Displays a list of Service with a split pane between
@ -38,38 +40,44 @@ import { T } from 'client/constants'
* @returns {ReactElement} Service list and selected row(s)
*/
function Services() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const [selectedRows, setSelectedRows] = useState(() => [])
const actions = ServiceActions()
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
const { zone } = useGeneral()
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<ServicesTable
onSelectedRowsChange={onSelectedRowsChange}
globalActions={actions}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
service={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
zone={zone}
actions={actions}
table={(props) => (
<ServicesTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
service: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -83,8 +91,8 @@ function Services() {
*/
const InfoTabs = memo(({ service, gotoPage, unselect }) => {
const [get, { data: lazyData, isFetching }] = useLazyGetServiceQuery()
const id = lazyData?.ID ?? service.ID
const name = lazyData?.NAME ?? service.NAME
const id = lazyData?.ID ?? service?.ID
const name = lazyData?.NAME ?? service?.NAME
return (
<Stack overflow="auto">
@ -138,23 +146,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
const GroupedTags = ({
tags = [],
handleElement = true,
onDelete = () => undefined,
}) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
return <Chip key={id} label={original?.NAME ?? id} {...clickElement} />
})}
/>
</Stack>
))
)
GroupedTags.propTypes = { tags: PropTypes.array }
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default Services

View File

@ -107,6 +107,14 @@ const ZONE_ENDPOINT_FIELD = ({ zones = [] }) => ({
grid: { md: 12 },
})
const FULL_SCREEN_INFO_FIELD = {
name: 'FULL_SCREEN_INFO',
label: T.FullScreenInfo,
type: INPUT_TYPES.CHECKBOX,
validation: boolean().yesOrNo(),
grid: { md: 12 },
}
/**
* @param {object} props - Props
* @param {object} props.views - views.
@ -120,6 +128,7 @@ export const FIELDS = (props) => [
VIEW_FIELD(props),
ZONE_ENDPOINT_FIELD(props),
DISABLE_ANIMATIONS_FIELD,
FULL_SCREEN_INFO_FIELD,
]
/**

View File

@ -43,7 +43,7 @@ const Settings = () => {
<Box
display="grid"
gridTemplateColumns={{ sm: '1fr', md: 'repeat(2, minmax(49%, 1fr))' }}
gridTemplateRows="minmax(0, 28em)"
gridTemplateRows="minmax(0, 33em)"
gap="1em"
>
<ConfigurationUISection />

View File

@ -13,26 +13,28 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { ReactElement, useState, memo } from 'react'
import PropTypes from 'prop-types'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import Cancel from 'iconoir-react/dist/Cancel'
import GotoIcon from 'iconoir-react/dist/Pin'
import RefreshDouble from 'iconoir-react/dist/RefreshDouble'
import Cancel from 'iconoir-react/dist/Cancel'
import { Typography, Box, Stack, Chip } from '@mui/material'
import PropTypes from 'prop-types'
import { ReactElement, memo, useState } from 'react'
import { Row } from 'react-table'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { UsersTable } from 'client/components/Tables'
import UserActions from 'client/components/Tables/Users/actions'
import UserTabs from 'client/components/Tabs/User'
import { T, User } from 'client/constants'
import { useGeneral } from 'client/features/General'
import {
useLazyGetUserQuery,
useUpdateUserMutation,
} from 'client/features/OneApi/user'
import { UsersTable } from 'client/components/Tables'
import UserTabs from 'client/components/Tabs/User'
import UserActions from 'client/components/Tables/Users/actions'
import SplitPane from 'client/components/SplitPane'
import MultipleTags from 'client/components/MultipleTags'
import { SubmitButton } from 'client/components/FormControl'
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).
@ -40,39 +42,46 @@ import { T, User } from 'client/constants'
* @returns {ReactElement} Users list and selected row(s)
*/
function Users() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const [selectedRows, setSelectedRows] = useState(() => [])
const actions = UserActions()
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
const { zone } = useGeneral()
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<UsersTable
onSelectedRowsChange={onSelectedRowsChange}
globalActions={actions}
useUpdateMutation={useUpdateUserMutation}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
user={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
useUpdateMutation={useUpdateUserMutation}
zone={zone}
actions={actions}
table={(props) => (
<UsersTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
useUpdateMutation={props.useUpdateMutation}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
user: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -86,8 +95,8 @@ function Users() {
*/
const InfoTabs = memo(({ user, gotoPage, unselect }) => {
const [get, { data: lazyData, isFetching }] = useLazyGetUserQuery()
const id = lazyData?.ID ?? user.ID
const name = lazyData?.NAME ?? user.NAME
const id = lazyData?.ID ?? user?.ID
const name = lazyData?.NAME ?? user?.NAME
return (
<Stack overflow="auto">
@ -141,23 +150,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
const GroupedTags = ({
tags = [],
handleElement = true,
onDelete = () => undefined,
}) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
return <Chip key={id} label={original?.NAME ?? id} {...clickElement} />
})}
/>
</Stack>
))
)
GroupedTags.propTypes = { tags: PropTypes.array }
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default Users

View File

@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { Box, Chip, Stack, Typography } from '@mui/material'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import { Cancel, Pin as GotoIcon, RefreshDouble } from 'iconoir-react'
import PropTypes from 'prop-types'
import { ReactElement, memo, useState } from 'react'
@ -22,11 +23,12 @@ import { Row } from 'react-table'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import SplitPane from 'client/components/SplitPane'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { VDCsTable } from 'client/components/Tables'
import VDCActions from 'client/components/Tables/VirtualDataCenters/actions'
import VDCTabs from 'client/components/Tabs/Vdc'
import { T, VmTemplate as VdcTemplate } from 'client/constants'
import { useGeneral } from 'client/features/General'
import {
useLazyGetVDCQuery,
useUpdateVDCMutation,
@ -38,39 +40,46 @@ import {
* @returns {ReactElement} VDCs list and selected row(s)
*/
function VirtualDataCenters() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const [selectedRows, setSelectedRows] = useState(() => [])
const actions = VDCActions()
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
const { zone } = useGeneral()
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<VDCsTable
onSelectedRowsChange={onSelectedRowsChange}
globalActions={actions}
useUpdateMutation={useUpdateVDCMutation}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
template={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
useUpdateMutation={useUpdateVDCMutation}
zone={zone}
actions={actions}
table={(props) => (
<VDCsTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
useUpdateMutation={props.useUpdateMutation}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
template: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -84,8 +93,8 @@ function VirtualDataCenters() {
*/
const InfoTabs = memo(({ template, gotoPage, unselect }) => {
const [getVDC, { data, isFetching }] = useLazyGetVDCQuery()
const id = data?.ID ?? template.ID
const name = data?.NAME ?? template.NAME
const id = data?.ID ?? template?.ID
const name = data?.NAME ?? template?.NAME
return (
<Stack overflow="auto">
@ -139,23 +148,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
const GroupedTags = ({
tags = [],
handleElement = true,
onDelete = () => undefined,
}) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
return <Chip key={id} label={original?.NAME ?? id} {...clickElement} />
})}
/>
</Stack>
))
)
GroupedTags.propTypes = { tags: PropTypes.array }
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default VirtualDataCenters

View File

@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { Box, Chip, Stack, Typography } from '@mui/material'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import Cancel from 'iconoir-react/dist/Cancel'
import GotoIcon from 'iconoir-react/dist/Pin'
import RefreshDouble from 'iconoir-react/dist/RefreshDouble'
@ -24,11 +25,12 @@ import { Row } from 'react-table'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import SplitPane from 'client/components/SplitPane'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { VNetworkTemplatesTable } from 'client/components/Tables'
import VNetworkTemplateActions from 'client/components/Tables/VNetworkTemplates/actions'
import VNetworkTemplateTabs from 'client/components/Tabs/VNetworkTemplate'
import { T, VNetworkTemplate } from 'client/constants'
import { useGeneral } from 'client/features/General'
import {
useLazyGetVNTemplateQuery,
useUpdateVNTemplateMutation,
@ -40,38 +42,46 @@ import {
* @returns {ReactElement} VNet Templates list and selected row(s)
*/
function VNetworkTemplates() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const [selectedRows, setSelectedRows] = useState(() => [])
const actions = VNetworkTemplateActions()
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
const { zone } = useGeneral()
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<VNetworkTemplatesTable
onSelectedRowsChange={onSelectedRowsChange}
globalActions={actions}
useUpdateMutation={useUpdateVNTemplateMutation}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
vnTemplate={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
useUpdateMutation={useUpdateVNTemplateMutation}
zone={zone}
actions={actions}
table={(props) => (
<VNetworkTemplatesTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
useUpdateMutation={props.useUpdateMutation}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
vnTemplate: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -85,8 +95,8 @@ function VNetworkTemplates() {
*/
const InfoTabs = memo(({ vnTemplate, gotoPage, unselect }) => {
const [get, { data: lazyData, isFetching }] = useLazyGetVNTemplateQuery()
const id = lazyData?.ID ?? vnTemplate.ID
const name = lazyData?.NAME ?? vnTemplate.NAME
const id = lazyData?.ID ?? vnTemplate?.ID
const name = lazyData?.NAME ?? vnTemplate?.NAME
return (
<Stack overflow="auto">
@ -140,23 +150,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
const GroupedTags = ({
tags = [],
handleElement = true,
onDelete = () => undefined,
}) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
return <Chip key={id} label={original?.NAME ?? id} {...clickElement} />
})}
/>
</Stack>
))
)
GroupedTags.propTypes = { tags: PropTypes.array }
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default VNetworkTemplates

View File

@ -13,27 +13,28 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { Box, Chip, Stack, Typography } from '@mui/material'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import Cancel from 'iconoir-react/dist/Cancel'
import GotoIcon from 'iconoir-react/dist/Pin'
import RefreshDouble from 'iconoir-react/dist/RefreshDouble'
import PropTypes from 'prop-types'
import { ReactElement, memo, useState, useEffect } from 'react'
import { ReactElement, memo, useEffect, useState } from 'react'
import { Row } from 'react-table'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import SplitPane from 'client/components/SplitPane'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { VmsTable } from 'client/components/Tables'
import VmActions from 'client/components/Tables/Vms/actions'
import VmTabs from 'client/components/Tabs/Vm'
import { T, VM } from 'client/constants'
import { setSelectedIds, useGeneral } from 'client/features/General'
import {
useLazyGetVmQuery,
useUpdateUserTemplateMutation,
} from 'client/features/OneApi/vm'
import { setSelectedIds } from 'client/features/General'
import { useDispatch } from 'react-redux'
/**
@ -43,11 +44,9 @@ import { useDispatch } from 'react-redux'
*/
function VirtualMachines() {
const dispatch = useDispatch()
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const [selectedRows, setSelectedRows] = useState(() => [])
const actions = VmActions(selectedRows)
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
const { zone } = useGeneral()
useEffect(() => {
const selectedIds = selectedRows.map((row) => row.original.ID)
@ -55,31 +54,41 @@ function VirtualMachines() {
}, [selectedRows, dispatch])
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<VmsTable
onSelectedRowsChange={onSelectedRowsChange}
globalActions={actions}
useUpdateMutation={useUpdateUserTemplateMutation}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
vm={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
useUpdateMutation={useUpdateUserTemplateMutation}
zone={zone}
actions={actions}
table={(props) => (
<VmsTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
useUpdateMutation={props.useUpdateMutation}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
vm: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -93,8 +102,8 @@ function VirtualMachines() {
*/
const InfoTabs = memo(({ vm, gotoPage, unselect }) => {
const [getVm, { data: lazyData, isFetching }] = useLazyGetVmQuery()
const id = lazyData?.ID ?? vm.ID
const name = lazyData?.NAME ?? vm.NAME
const id = lazyData?.ID ?? vm?.ID
const name = lazyData?.NAME ?? vm?.NAME
return (
<Stack overflow="auto">
@ -148,23 +157,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
const GroupedTags = ({
tags = [],
handleElement = true,
onDelete = () => undefined,
}) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
return <Chip key={id} label={original?.NAME ?? id} {...clickElement} />
})}
/>
</Stack>
))
)
GroupedTags.propTypes = { tags: PropTypes.array }
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default VirtualMachines

View File

@ -13,26 +13,28 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { ReactElement, useState, memo } from 'react'
import PropTypes from 'prop-types'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import Cancel from 'iconoir-react/dist/Cancel'
import GotoIcon from 'iconoir-react/dist/Pin'
import RefreshDouble from 'iconoir-react/dist/RefreshDouble'
import Cancel from 'iconoir-react/dist/Cancel'
import { Typography, Box, Stack, Chip } from '@mui/material'
import PropTypes from 'prop-types'
import { ReactElement, memo, useState } from 'react'
import { Row } from 'react-table'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { VNetworksTable } from 'client/components/Tables'
import VNetworkActions from 'client/components/Tables/VNetworks/actions'
import VNetworkTabs from 'client/components/Tabs/VNetwork'
import { T, VirtualNetwork } from 'client/constants'
import { useGeneral } from 'client/features/General'
import {
useLazyGetVNetworkQuery,
useUpdateVNetMutation,
} from 'client/features/OneApi/network'
import { VNetworksTable } from 'client/components/Tables'
import VNetworkActions from 'client/components/Tables/VNetworks/actions'
import VNetworkTabs from 'client/components/Tabs/VNetwork'
import SplitPane from 'client/components/SplitPane'
import MultipleTags from 'client/components/MultipleTags'
import { SubmitButton } from 'client/components/FormControl'
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).
@ -40,39 +42,46 @@ import { T, VirtualNetwork } from 'client/constants'
* @returns {ReactElement} Virtual Networks list and selected row(s)
*/
function VirtualNetworks() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const [selectedRows, setSelectedRows] = useState(() => [])
const actions = VNetworkActions()
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
const { zone } = useGeneral()
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<VNetworksTable
onSelectedRowsChange={onSelectedRowsChange}
globalActions={actions}
useUpdateMutation={useUpdateVNetMutation}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
vnet={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
useUpdateMutation={useUpdateVNetMutation}
zone={zone}
actions={actions}
table={(props) => (
<VNetworksTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
useUpdateMutation={props.useUpdateMutation}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
vnet: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -86,8 +95,8 @@ function VirtualNetworks() {
*/
const InfoTabs = memo(({ vnet, gotoPage, unselect }) => {
const [get, { data: lazyData, isFetching }] = useLazyGetVNetworkQuery()
const id = lazyData?.ID ?? vnet.ID
const name = lazyData?.NAME ?? vnet.NAME
const id = lazyData?.ID ?? vnet?.ID
const name = lazyData?.NAME ?? vnet?.NAME
return (
<Stack overflow="auto">
@ -141,23 +150,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
const GroupedTags = ({
tags = [],
handleElement = true,
onDelete = () => undefined,
}) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
return <Chip key={id} label={original?.NAME ?? id} {...clickElement} />
})}
/>
</Stack>
))
)
GroupedTags.propTypes = { tags: PropTypes.array }
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default VirtualNetworks

View File

@ -13,24 +13,26 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { ReactElement, useState, memo } from 'react'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import { Cancel, Pin as GotoIcon, RefreshDouble } from 'iconoir-react'
import PropTypes from 'prop-types'
import { Pin as GotoIcon, RefreshDouble, Cancel } from 'iconoir-react'
import { Typography, Box, Stack, Chip } from '@mui/material'
import { ReactElement, memo, useState } from 'react'
import { Row } from 'react-table'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { VRouterTemplatesTable } from 'client/components/Tables'
import VRouterTemplateActions from 'client/components/Tables/VRouterTemplates/actions'
import VmTemplateTabs from 'client/components/Tabs/VmTemplate'
import { T, VmTemplate } from 'client/constants'
import { useGeneral } from 'client/features/General'
import {
useLazyGetVRouterTemplateQuery,
useUpdateVRouterTemplateMutation,
} from 'client/features/OneApi/vrouterTemplate'
import { VRouterTemplatesTable } from 'client/components/Tables'
import VRouterTemplateActions from 'client/components/Tables/VRouterTemplates/actions'
import VmTemplateTabs from 'client/components/Tabs/VmTemplate'
import SplitPane from 'client/components/SplitPane'
import MultipleTags from 'client/components/MultipleTags'
import { SubmitButton } from 'client/components/FormControl'
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).
@ -38,39 +40,46 @@ import { T, VmTemplate } from 'client/constants'
* @returns {ReactElement} VM Templates list and selected row(s)
*/
function VRouterTemplates() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const [selectedRows, setSelectedRows] = useState(() => [])
const actions = VRouterTemplateActions()
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
const { zone } = useGeneral()
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<VRouterTemplatesTable
onSelectedRowsChange={onSelectedRowsChange}
globalActions={actions}
useUpdateMutation={useUpdateVRouterTemplateMutation}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
template={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
useUpdateMutation={useUpdateVRouterTemplateMutation}
zone={zone}
actions={actions}
table={(props) => (
<VRouterTemplatesTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
useUpdateMutation={props.useUpdateMutation}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
template: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -84,8 +93,8 @@ function VRouterTemplates() {
*/
const InfoTabs = memo(({ template, gotoPage, unselect }) => {
const [getTemplate, { data, isFetching }] = useLazyGetVRouterTemplateQuery()
const id = data?.ID ?? template.ID
const name = data?.NAME ?? template.NAME
const id = data?.ID ?? template?.ID
const name = data?.NAME ?? template?.NAME
return (
<Stack overflow="auto">
@ -139,23 +148,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
const GroupedTags = ({
tags = [],
handleElement = true,
onDelete = () => undefined,
}) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
return <Chip key={id} label={original?.NAME ?? id} {...clickElement} />
})}
/>
</Stack>
))
)
GroupedTags.propTypes = { tags: PropTypes.array }
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default VRouterTemplates

View File

@ -13,21 +13,23 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { ReactElement, useState, memo } from 'react'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import { Cancel, Pin as GotoIcon, RefreshDouble } from 'iconoir-react'
import PropTypes from 'prop-types'
import { Pin as GotoIcon, RefreshDouble, Cancel } from 'iconoir-react'
import { Typography, Box, Stack, Chip } from '@mui/material'
import { ReactElement, memo, useState } from 'react'
import { Row } from 'react-table'
import { useLazyGetVRouterQuery } from 'client/features/OneApi/vrouter'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { VRoutersTable } from 'client/components/Tables'
import VRouterActions from 'client/components/Tables/VRouters/actions'
import VirtualRouterTabs from 'client/components/Tabs/VirtualRouter'
import SplitPane from 'client/components/SplitPane'
import MultipleTags from 'client/components/MultipleTags'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import { T, VmTemplate } from 'client/constants'
import { useGeneral } from 'client/features/General'
import { useLazyGetVRouterQuery } from 'client/features/OneApi/vrouter'
/**
* Displays a list of VM Templates with a split pane between the list and selected row(s).
@ -35,38 +37,44 @@ import { T, VmTemplate } from 'client/constants'
* @returns {ReactElement} VM Templates list and selected row(s)
*/
function VRouters() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const [selectedRows, setSelectedRows] = useState(() => [])
const actions = VRouterActions()
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
const { zone } = useGeneral()
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<VRoutersTable
onSelectedRowsChange={onSelectedRowsChange}
globalActions={actions}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
template={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
zone={zone}
actions={actions}
table={(props) => (
<VRoutersTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
template: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -80,8 +88,8 @@ function VRouters() {
*/
const InfoTabs = memo(({ template, gotoPage, unselect }) => {
const [getTemplate, { data, isFetching }] = useLazyGetVRouterQuery()
const id = data?.ID ?? template.ID
const name = data?.NAME ?? template.NAME
const id = data?.ID ?? template?.ID
const name = data?.NAME ?? template?.NAME
return (
<Stack overflow="auto">
@ -135,23 +143,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
const GroupedTags = ({
tags = [],
handleElement = true,
onDelete = () => undefined,
}) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
return <Chip key={id} label={original?.NAME ?? id} {...clickElement} />
})}
/>
</Stack>
))
)
GroupedTags.propTypes = { tags: PropTypes.array }
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default VRouters

View File

@ -13,26 +13,28 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { ReactElement, useState, memo } from 'react'
import PropTypes from 'prop-types'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import Cancel from 'iconoir-react/dist/Cancel'
import GotoIcon from 'iconoir-react/dist/Pin'
import RefreshDouble from 'iconoir-react/dist/RefreshDouble'
import Cancel from 'iconoir-react/dist/Cancel'
import { Typography, Box, Stack, Chip } from '@mui/material'
import PropTypes from 'prop-types'
import { ReactElement, memo, useState } from 'react'
import { Row } from 'react-table'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { VmGroupsTable } from 'client/components/Tables'
import VmGroupActions from 'client/components/Tables/VmGroups/actions'
import VmGroupTabs from 'client/components/Tabs/VmGroup'
import { T, VmGroup } from 'client/constants'
import { useGeneral } from 'client/features/General'
import {
useLazyGetVMGroupQuery,
useUpdateVMGroupMutation,
} from 'client/features/OneApi/vmGroup'
import { VmGroupsTable } from 'client/components/Tables'
import VmGroupTabs from 'client/components/Tabs/VmGroup'
import VmGroupActions from 'client/components/Tables/VmGroups/actions'
import SplitPane from 'client/components/SplitPane'
import MultipleTags from 'client/components/MultipleTags'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import { T, VmGroup } from 'client/constants'
/**
* Displays a list of VmGroups with a split pane between the list and selected row(s).
@ -40,39 +42,46 @@ import { T, VmGroup } from 'client/constants'
* @returns {ReactElement} VmGroups list and selected row(s)
*/
function VmGroups() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const [selectedRows, setSelectedRows] = useState(() => [])
const actions = VmGroupActions()
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
const { zone } = useGeneral()
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<VmGroupsTable
onSelectedRowsChange={onSelectedRowsChange}
globalActions={actions}
useUpdateMutation={useUpdateVMGroupMutation}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
user={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
useUpdateMutation={useUpdateVMGroupMutation}
zone={zone}
actions={actions}
table={(props) => (
<VmGroupsTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
useUpdateMutation={props.useUpdateMutation}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
user: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -86,8 +95,8 @@ function VmGroups() {
*/
const InfoTabs = memo(({ user, gotoPage, unselect }) => {
const [get, { data: lazyData, isFetching }] = useLazyGetVMGroupQuery()
const id = lazyData?.ID ?? user.ID
const name = lazyData?.NAME ?? user.NAME
const id = lazyData?.ID ?? user?.ID
const name = lazyData?.NAME ?? user?.NAME
return (
<Stack overflow="auto">
@ -139,23 +148,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
const GroupedTags = ({
tags = [],
handleElement = true,
onDelete = () => undefined,
}) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
return <Chip key={id} label={original?.NAME ?? id} {...clickElement} />
})}
/>
</Stack>
))
)
GroupedTags.propTypes = { tags: PropTypes.array }
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default VmGroups

View File

@ -13,24 +13,26 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { ReactElement, useState, memo } from 'react'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import { Cancel, Pin as GotoIcon, RefreshDouble } from 'iconoir-react'
import PropTypes from 'prop-types'
import { Pin as GotoIcon, RefreshDouble, Cancel } from 'iconoir-react'
import { Typography, Box, Stack, Chip } from '@mui/material'
import { ReactElement, memo, useState } from 'react'
import { Row } from 'react-table'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { VmTemplatesTable } from 'client/components/Tables'
import VmTemplateActions from 'client/components/Tables/VmTemplates/actions'
import VmTemplateTabs from 'client/components/Tabs/VmTemplate'
import { T, VmTemplate } from 'client/constants'
import { useGeneral } from 'client/features/General'
import {
useLazyGetTemplateQuery,
useUpdateTemplateMutation,
} from 'client/features/OneApi/vmTemplate'
import { VmTemplatesTable } from 'client/components/Tables'
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 { SubmitButton } from 'client/components/FormControl'
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).
@ -38,39 +40,46 @@ import { T, VmTemplate } from 'client/constants'
* @returns {ReactElement} VM Templates list and selected row(s)
*/
function VmTemplates() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const [selectedRows, setSelectedRows] = useState(() => [])
const actions = VmTemplateActions()
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
const { zone } = useGeneral()
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<VmTemplatesTable
onSelectedRowsChange={onSelectedRowsChange}
globalActions={actions}
useUpdateMutation={useUpdateTemplateMutation}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
template={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
useUpdateMutation={useUpdateTemplateMutation}
zone={zone}
actions={actions}
table={(props) => (
<VmTemplatesTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
useUpdateMutation={props.useUpdateMutation}
zoneId={props.zone}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
template: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -84,8 +93,8 @@ function VmTemplates() {
*/
const InfoTabs = memo(({ template, gotoPage, unselect }) => {
const [getTemplate, { data, isFetching }] = useLazyGetTemplateQuery()
const id = data?.ID ?? template.ID
const name = data?.NAME ?? template.NAME
const id = data?.ID ?? template?.ID
const name = data?.NAME ?? template?.NAME
return (
<Stack overflow="auto">
@ -139,23 +148,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
const GroupedTags = ({
tags = [],
handleElement = true,
onDelete = () => undefined,
}) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
return <Chip key={id} label={original?.NAME ?? id} {...clickElement} />
})}
/>
</Stack>
))
)
GroupedTags.propTypes = { tags: PropTypes.array }
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default VmTemplates

View File

@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { Box, Chip, Stack, Typography } from '@mui/material'
/* eslint-disable react/prop-types */
import { Chip, Stack, Typography } from '@mui/material'
import Cancel from 'iconoir-react/dist/Cancel'
import GotoIcon from 'iconoir-react/dist/Pin'
import RefreshDouble from 'iconoir-react/dist/RefreshDouble'
@ -24,7 +25,7 @@ import { Row } from 'react-table'
import { SubmitButton } from 'client/components/FormControl'
import { Tr } from 'client/components/HOC'
import MultipleTags from 'client/components/MultipleTags'
import SplitPane from 'client/components/SplitPane'
import ResourcesBackButton from 'client/components/ResourcesBackButton'
import { ZonesTable } from 'client/components/Tables'
import ZoneTabs from 'client/components/Tabs/Zone'
import { T, Zone } from 'client/constants'
@ -39,37 +40,41 @@ import {
* @returns {ReactElement} Zones list and selected row(s)
*/
function Zones() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1
const [selectedRows, setSelectedRows] = useState(() => [])
return (
<SplitPane gridTemplateRows="1fr auto 1fr">
{({ getGridProps, GutterComponent }) => (
<Box height={1} {...(hasSelectedRows && getGridProps())}>
<ZonesTable
onSelectedRowsChange={onSelectedRowsChange}
useUpdateMutation={useUpdateZoneMutation}
/>
{hasSelectedRows && (
<>
<GutterComponent direction="row" track={1} />
{moreThanOneSelected ? (
<GroupedTags tags={selectedRows} />
) : (
<InfoTabs
zone={selectedRows[0]?.original}
gotoPage={selectedRows[0]?.gotoPage}
unselect={() => selectedRows[0]?.toggleRowSelected(false)}
/>
)}
</>
)}
</Box>
<ResourcesBackButton
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
useUpdateMutation={useUpdateZoneMutation}
table={(props) => (
<ZonesTable
onSelectedRowsChange={props.setSelectedRows}
globalActions={props.actions}
useUpdateMutation={props.useUpdateMutation}
initialState={{
selectedRowIds: props.selectedRowsTable,
}}
/>
)}
</SplitPane>
simpleGroupsTags={(props) => (
<GroupedTags
tags={props.selectedRows}
handleElement={props.handleElement}
onDelete={props.handleUnselectRow}
/>
)}
info={(props) => {
const propsInfo = {
zone: props?.selectedRows?.[0]?.original,
selectedRows: props?.selectedRows,
}
props?.gotoPage && (propsInfo.gotoPage = props.gotoPage)
props?.unselect && (propsInfo.unselect = props.unselect)
return <InfoTabs {...propsInfo} />
}}
/>
)
}
@ -83,8 +88,8 @@ function Zones() {
*/
const InfoTabs = memo(({ zone, gotoPage, unselect }) => {
const [get, { data: lazyData, isFetching }] = useLazyGetZoneQuery()
const id = lazyData?.ID ?? zone.ID
const name = lazyData?.NAME ?? zone.NAME
const id = lazyData?.ID ?? zone?.ID
const name = lazyData?.NAME ?? zone?.NAME
return (
<Stack overflow="auto">
@ -138,23 +143,34 @@ InfoTabs.displayName = 'InfoTabs'
* @param {Row[]} tags - Row(s) to display as tags
* @returns {ReactElement} List of tags
*/
const GroupedTags = memo(({ tags = [] }) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map(({ original, id, toggleRowSelected, gotoPage }) => (
<Chip
key={id}
label={original?.NAME ?? id}
onClick={gotoPage}
onDelete={() => toggleRowSelected(false)}
/>
))}
/>
</Stack>
))
const GroupedTags = memo(
({ tags = [], handleElement = true, onDelete = () => undefined }) => (
<Stack direction="row" flexWrap="wrap" gap={1} alignContent="flex-start">
<MultipleTags
limitTags={10}
tags={tags?.map((props) => {
const { original, id, toggleRowSelected, gotoPage } = props
const clickElement = handleElement
? {
onClick: gotoPage,
onDelete: () => onDelete(id) || toggleRowSelected(false),
}
: {}
GroupedTags.propTypes = { tags: PropTypes.array }
return (
<Chip key={id} label={original?.NAME ?? id} {...clickElement} />
)
})}
/>
</Stack>
)
)
GroupedTags.propTypes = {
tags: PropTypes.array,
handleElement: PropTypes.bool,
onDelete: PropTypes.func,
}
GroupedTags.displayName = 'GroupedTags'
export default Zones