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:
parent
168bd86983
commit
4f8e837fd9
@ -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
|
200
src/fireedge/src/client/components/ResourcesBackButton/index.js
Normal file
200
src/fireedge/src/client/components/ResourcesBackButton/index.js
Normal 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
|
@ -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
|
||||
|
||||
|
@ -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'
|
||||
|
@ -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'
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
]
|
||||
|
||||
/**
|
||||
|
@ -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 />
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user