1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-04-24 14:50:08 +03:00

M #-: Several fix for FSunstone 6.4 tests(#2472)

This commit is contained in:
Jorge Miguel Lobo Escalona 2023-01-31 17:33:11 +01:00 committed by GitHub
parent 4157b6b6cf
commit 9dad79ad38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 230 additions and 252 deletions

View File

@ -128,21 +128,7 @@ const Chartist = ({
Chartist.propTypes = {
name: PropTypes.string,
filter: PropTypes.arrayOf(PropTypes.string),
data: PropTypes.arrayOf(
PropTypes.shape({
TIMESTAMP: PropTypes.string,
DISK_SIZE: PropTypes.arrayOf(PropTypes.shape({})),
ID: PropTypes.string,
CPU: PropTypes.string,
DISKRDBYTES: PropTypes.string,
DISKRDIOPS: PropTypes.string,
DISKWRBYTES: PropTypes.string,
DISKWRIOPS: PropTypes.string,
MEMORY: PropTypes.string,
NETRX: PropTypes.string,
NETTX: PropTypes.string,
})
),
data: PropTypes.array,
x: PropTypes.string,
y: PropTypes.string,
interpolationY: PropTypes.func,

View File

@ -13,16 +13,16 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { boolean, number, string, ObjectSchema } from 'yup'
import { ObjectSchema, boolean, number, string } from 'yup'
import { HYPERVISORS, INPUT_TYPES, Nic, T, VN_DRIVERS } from 'client/constants'
import {
Field,
Section,
filterFieldsByHypervisor,
filterFieldsByDriver,
filterFieldsByHypervisor,
getObjectSchemaFromFields,
} from 'client/utils'
import { T, INPUT_TYPES, HYPERVISORS, VN_DRIVERS, Nic } from 'client/constants'
import { useDisableInputByUserAndConfig } from 'client/features/Auth'
@ -221,16 +221,6 @@ const GENERAL_FIELDS = ({ nics = [] } = {}) =>
.default(() => undefined),
grid: { sm: 6 },
},
{
name: 'EXTERNAL',
label: T.External,
tooltip: T.ExternalConcept,
type: INPUT_TYPES.SWITCH,
dependOf: 'PARENT',
htmlType: (parent) => !parent?.length && INPUT_TYPES.HIDDEN,
validation: boolean().yesOrNo(),
grid: { sm: 6 },
},
].filter(Boolean)
/** @type {Field[]} List of IPv4 fields */

View File

@ -14,9 +14,10 @@
* limitations under the License. *
* ------------------------------------------------------------------------- */
// eslint-disable-next-line no-unused-vars
import { memo, ReactElement, useCallback, useMemo } from 'react'
import PropTypes from 'prop-types'
// eslint-disable-next-line no-unused-vars
import { memo, ReactElement, useCallback, useMemo } from 'react'
// eslint-disable-next-line no-unused-vars
import { Row } from 'react-table'
import QueryButton from 'client/components/Buttons/QueryButton'
@ -24,9 +25,9 @@ import { Action } from 'client/components/Cards/SelectCard'
import { ButtonToTriggerForm } from 'client/components/Forms'
import { Tr } from 'client/components/HOC'
// eslint-disable-next-line no-unused-vars
import { DialogPropTypes, DialogProps } from 'client/components/Dialogs'
import { DialogProps } from 'client/components/Dialogs'
// eslint-disable-next-line no-unused-vars
import { CreateStepsCallback, CreateFormCallback } from 'client/utils'
import { CreateFormCallback, CreateStepsCallback } from 'client/utils'
/**
* @typedef {object} Option
@ -54,97 +55,86 @@ import { CreateStepsCallback, CreateFormCallback } from 'client/utils'
* @property {function(Row[]):object} [useQuery] - Function to get rtk query result
*/
const ActionItem = memo(
({ item, selectedRows }) => {
/** @type {GlobalAction} */
const {
accessor,
dataCy,
tooltip,
label,
color,
variant = 'contained',
icon: Icon,
options,
action,
disabled,
useQuery,
selected = false,
} = item
const ActionItem = memo(({ item, selectedRows }) => {
/** @type {GlobalAction} */
const {
accessor,
dataCy,
tooltip,
label,
color,
variant = 'contained',
icon: Icon,
options,
action,
disabled,
useQuery,
selected = false,
} = item
const isDisabledByNumberOfSelectedRows = useMemo(() => {
const numberOfRowSelected = selectedRows.length
const min = selected?.min ?? 1
const max = selected?.max ?? Number.MAX_SAFE_INTEGER
return (
(selected === true && !numberOfRowSelected) ||
(selected && min > numberOfRowSelected && numberOfRowSelected < max)
)
}, [selectedRows.length, selected])
const buttonProps = {
color,
variant,
'data-cy':
(dataCy && `action-${dataCy}`) ?? (accessor && `action-${accessor}`),
disabled:
isDisabledByNumberOfSelectedRows ||
(typeof disabled === 'function' ? disabled(selectedRows) : disabled),
icon: Icon && <Icon />,
label: label && Tr(label),
title: tooltip && Tr(tooltip),
}
const addRowsToFn = useCallback(
(fn) => (typeof fn === 'function' ? fn(selectedRows) : fn),
[selectedRows]
)
const addRowsToEntries = useCallback(
(entries) =>
Object.entries(entries).reduce(
(res, [prop, value]) => ({ ...res, [prop]: addRowsToFn(value) }),
{}
),
[addRowsToFn]
)
return action ? (
<Action {...buttonProps} handleClick={() => addRowsToFn(action)} />
) : useQuery ? (
<QueryButton {...buttonProps} useQuery={() => addRowsToFn(useQuery)} />
) : (
<ButtonToTriggerForm
buttonProps={buttonProps}
options={options?.map((option) => {
const {
form,
accessor: optionAccessor,
dialogProps = {},
...restOfOption
} = option ?? {}
return {
...addRowsToEntries(restOfOption),
form: form ? () => addRowsToFn(form) : undefined,
cy: optionAccessor && `action-${optionAccessor}`,
dialogProps: addRowsToEntries(dialogProps),
}
})}
/>
)
},
(prev, next) => {
const prevStates = prev.selectedRows?.map?.(({ values }) => values?.STATE)
const nextStates = next.selectedRows?.map?.(({ values }) => values?.STATE)
const isDisabledByNumberOfSelectedRows = useMemo(() => {
const numberOfRowSelected = selectedRows.length
const min = selected?.min ?? 1
const max = selected?.max ?? Number.MAX_SAFE_INTEGER
return (
prev.selectedRows?.length === next.selectedRows?.length &&
prevStates?.every((prevState) => nextStates?.includes(prevState))
(selected === true && !numberOfRowSelected) ||
(selected && min > numberOfRowSelected && numberOfRowSelected < max)
)
}, [selectedRows.length, selected])
const buttonProps = {
color,
variant,
'data-cy':
(dataCy && `action-${dataCy}`) ?? (accessor && `action-${accessor}`),
disabled:
isDisabledByNumberOfSelectedRows ||
(typeof disabled === 'function' ? disabled(selectedRows) : disabled),
icon: Icon && <Icon />,
label: label && Tr(label),
title: tooltip && Tr(tooltip),
}
)
const addRowsToFn = useCallback(
(fn) => (typeof fn === 'function' ? fn(selectedRows) : fn),
[selectedRows]
)
const addRowsToEntries = useCallback(
(entries) =>
Object.entries(entries).reduce(
(res, [prop, value]) => ({ ...res, [prop]: addRowsToFn(value) }),
{}
),
[addRowsToFn]
)
return action ? (
<Action {...buttonProps} handleClick={() => addRowsToFn(action)} />
) : useQuery ? (
<QueryButton {...buttonProps} useQuery={() => addRowsToFn(useQuery)} />
) : (
<ButtonToTriggerForm
buttonProps={buttonProps}
options={options?.map((option) => {
const {
form,
accessor: optionAccessor,
dialogProps = {},
...restOfOption
} = option ?? {}
return {
...addRowsToEntries(restOfOption),
form: form ? () => addRowsToFn(form) : undefined,
cy: optionAccessor && `action-${optionAccessor}`,
dialogProps: addRowsToEntries(dialogProps),
}
})}
/>
)
})
ActionItem.propTypes = {
item: PropTypes.object,

View File

@ -32,14 +32,14 @@ const getTabComponent = (tabName) =>
const ClusterTabs = memo(({ id }) => {
const { view, getResourceView } = useViews()
const { isLoading, isError, error } = useGetClusterQuery({ id })
const { isError, error, status, data } = useGetClusterQuery({ id })
const tabsAvailable = useMemo(() => {
const resource = RESOURCE_NAMES.CLUSTER
const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {}
return getAvailableInfoTabs(infoTabs, getTabComponent, id)
}, [view])
}, [view, id])
if (isError) {
return (
@ -49,11 +49,11 @@ const ClusterTabs = memo(({ id }) => {
)
}
return isLoading ? (
<LinearProgress color="secondary" sx={{ width: '100%' }} />
) : (
<Tabs addBorder tabs={tabsAvailable ?? []} />
)
if (status === 'fulfilled' || id === data?.ID) {
return <Tabs addBorder tabs={tabsAvailable ?? []} />
}
return <LinearProgress color="secondary" sx={{ width: '100%' }} />
})
ClusterTabs.propTypes = { id: PropTypes.string.isRequired }

View File

@ -32,14 +32,16 @@ const getTabComponent = (tabName) =>
const DatastoreTabs = memo(({ id }) => {
const { view, getResourceView } = useViews()
const { isLoading, isError, error } = useGetDatastoreQuery({ id })
const { isError, error, status, data } = useGetDatastoreQuery({
id,
})
const tabsAvailable = useMemo(() => {
const resource = RESOURCE_NAMES.DATASTORE
const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {}
return getAvailableInfoTabs(infoTabs, getTabComponent, id)
}, [view])
}, [view, id])
if (isError) {
return (
@ -49,11 +51,11 @@ const DatastoreTabs = memo(({ id }) => {
)
}
return isLoading ? (
<LinearProgress color="secondary" sx={{ width: '100%' }} />
) : (
<Tabs addBorder tabs={tabsAvailable ?? []} />
)
if (status === 'fulfilled' || id === data?.ID) {
return <Tabs addBorder tabs={tabsAvailable ?? []} />
}
return <LinearProgress color="secondary" sx={{ width: '100%' }} />
})
DatastoreTabs.propTypes = { id: PropTypes.string.isRequired }

View File

@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { memo, useMemo } from 'react'
import PropTypes from 'prop-types'
import { Alert, LinearProgress } from '@mui/material'
import PropTypes from 'prop-types'
import { memo, useMemo } from 'react'
import { RESOURCE_NAMES } from 'client/constants'
import { useViews } from 'client/features/Auth'
import { useGetImageQuery } from 'client/features/OneApi/image'
import { getAvailableInfoTabs } from 'client/models/Helper'
import { RESOURCE_NAMES } from 'client/constants'
import Tabs from 'client/components/Tabs'
import Info from 'client/components/Tabs/Image/Info'
@ -32,14 +32,14 @@ const getTabComponent = (tabName) =>
const FileTabs = memo(({ id }) => {
const { view, getResourceView } = useViews()
const { isLoading, isError, error } = useGetImageQuery({ id })
const { isError, error, status, data } = useGetImageQuery({ id })
const tabsAvailable = useMemo(() => {
const resource = RESOURCE_NAMES.IMAGE
const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {}
return getAvailableInfoTabs(infoTabs, getTabComponent, id)
}, [view])
}, [view, id])
if (isError) {
return (
@ -49,11 +49,11 @@ const FileTabs = memo(({ id }) => {
)
}
return isLoading ? (
<LinearProgress color="secondary" sx={{ width: '100%' }} />
) : (
<Tabs addBorder tabs={tabsAvailable ?? []} />
)
if (status === 'fulfilled' || id === data?.ID) {
return <Tabs addBorder tabs={tabsAvailable} />
}
return <LinearProgress color="secondary" sx={{ width: '100%' }} />
})
FileTabs.propTypes = { id: PropTypes.string.isRequired }

View File

@ -32,14 +32,14 @@ const getTabComponent = (tabName) =>
const GroupTabs = memo(({ id }) => {
const { view, getResourceView } = useViews()
const { isLoading, isError, error } = useGetGroupQuery({ id })
const { isError, error, status, data } = useGetGroupQuery({ id })
const tabsAvailable = useMemo(() => {
const resource = RESOURCE_NAMES.GROUP
const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {}
return getAvailableInfoTabs(infoTabs, getTabComponent, id)
}, [view])
}, [view, id])
if (isError) {
return (
@ -49,11 +49,11 @@ const GroupTabs = memo(({ id }) => {
)
}
return isLoading ? (
<LinearProgress color="secondary" sx={{ width: '100%' }} />
) : (
<Tabs addBorder tabs={tabsAvailable ?? []} />
)
if (status === 'fulfilled' || id === data?.ID) {
return <Tabs addBorder tabs={tabsAvailable ?? []} />
}
return <LinearProgress color="secondary" sx={{ width: '100%' }} />
})
GroupTabs.propTypes = { id: PropTypes.string.isRequired }

View File

@ -40,7 +40,7 @@ const getTabComponent = (tabName) =>
const HostTabs = memo(({ id }) => {
const { view, getResourceView } = useViews()
const { isLoading, isError, error } = useGetHostQuery(
const { isError, error, status, data } = useGetHostQuery(
{ id },
{ refetchOnMountOrArgChange: 10 }
)
@ -50,7 +50,7 @@ const HostTabs = memo(({ id }) => {
const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {}
return getAvailableInfoTabs(infoTabs, getTabComponent, id)
}, [view])
}, [view, id])
if (isError) {
return (
@ -60,11 +60,11 @@ const HostTabs = memo(({ id }) => {
)
}
return isLoading ? (
<LinearProgress color="secondary" sx={{ width: '100%' }} />
) : (
<Tabs addBorder tabs={tabsAvailable} />
)
if (status === 'fulfilled' || id === data?.ID) {
return <Tabs addBorder tabs={tabsAvailable} />
}
return <LinearProgress color="secondary" sx={{ width: '100%' }} />
})
HostTabs.propTypes = { id: PropTypes.string.isRequired }

View File

@ -36,14 +36,14 @@ const getTabComponent = (tabName) =>
const ImageTabs = memo(({ id }) => {
const { view, getResourceView } = useViews()
const { isLoading, isError, error } = useGetImageQuery({ id })
const { isError, error, status, data } = useGetImageQuery({ id })
const tabsAvailable = useMemo(() => {
const resource = RESOURCE_NAMES.IMAGE
const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {}
return getAvailableInfoTabs(infoTabs, getTabComponent, id)
}, [view])
}, [view, id])
if (isError) {
return (
@ -53,11 +53,11 @@ const ImageTabs = memo(({ id }) => {
)
}
return isLoading ? (
<LinearProgress color="secondary" sx={{ width: '100%' }} />
) : (
<Tabs addBorder tabs={tabsAvailable ?? []} />
)
if (status === 'fulfilled' || id === data?.ID) {
return <Tabs addBorder tabs={tabsAvailable ?? []} />
}
return <LinearProgress color="secondary" sx={{ width: '100%' }} />
})
ImageTabs.propTypes = { id: PropTypes.string.isRequired }

View File

@ -32,14 +32,14 @@ const getTabComponent = (tabName) =>
const MarketplaceTabs = memo(({ id }) => {
const { view, getResourceView } = useViews()
const { isLoading, isError, error } = useGetMarketplaceQuery({ id })
const { isError, error, status, data } = useGetMarketplaceQuery({ id })
const tabsAvailable = useMemo(() => {
const resource = RESOURCE_NAMES.MARKETPLACE
const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {}
return getAvailableInfoTabs(infoTabs, getTabComponent, id)
}, [view])
}, [view, id])
if (isError) {
return (
@ -49,11 +49,11 @@ const MarketplaceTabs = memo(({ id }) => {
)
}
return isLoading ? (
<LinearProgress color="secondary" sx={{ width: '100%' }} />
) : (
<Tabs addBorder tabs={tabsAvailable ?? []} />
)
if (status === 'fulfilled' || id === data?.ID) {
return <Tabs addBorder tabs={tabsAvailable ?? []} />
}
return <LinearProgress color="secondary" sx={{ width: '100%' }} />
})
MarketplaceTabs.propTypes = { id: PropTypes.string.isRequired }

View File

@ -34,7 +34,7 @@ const getTabComponent = (tabName) =>
const MarketplaceAppTabs = memo(({ id }) => {
const { view, getResourceView } = useViews()
const { isLoading, isError, error } = useGetMarketplaceAppQuery(
const { isError, error, status, data } = useGetMarketplaceAppQuery(
{ id },
{ refetchOnMountOrArgChange: 10 }
)
@ -44,7 +44,7 @@ const MarketplaceAppTabs = memo(({ id }) => {
const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {}
return getAvailableInfoTabs(infoTabs, getTabComponent, id)
}, [view])
}, [view, id])
if (isError) {
return (
@ -54,11 +54,11 @@ const MarketplaceAppTabs = memo(({ id }) => {
)
}
return isLoading ? (
<LinearProgress color="secondary" sx={{ width: '100%' }} />
) : (
<Tabs addBorder tabs={tabsAvailable ?? []} />
)
if (status === 'fulfilled' || id === data?.ID) {
return <Tabs addBorder tabs={tabsAvailable ?? []} />
}
return <LinearProgress color="secondary" sx={{ width: '100%' }} />
})
MarketplaceAppTabs.propTypes = { id: PropTypes.string.isRequired }

View File

@ -34,14 +34,14 @@ const getTabComponent = (tabName) =>
const SecurityGroupTabs = memo(({ id }) => {
const { view, getResourceView } = useViews()
const { isLoading, isError, error } = useGetSecGroupQuery({ id })
const { isError, error, status, data } = useGetSecGroupQuery({ id })
const tabsAvailable = useMemo(() => {
const resource = RESOURCE_NAMES.SEC_GROUP
const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {}
return getAvailableInfoTabs(infoTabs, getTabComponent, id)
}, [view])
}, [view, id])
if (isError) {
return (
@ -51,11 +51,11 @@ const SecurityGroupTabs = memo(({ id }) => {
)
}
return isLoading ? (
<LinearProgress color="secondary" sx={{ width: '100%' }} />
) : (
<Tabs addBorder tabs={tabsAvailable ?? []} />
)
if (status === 'fulfilled' || id === data?.ID) {
return <Tabs addBorder tabs={tabsAvailable ?? []} />
}
return <LinearProgress color="secondary" sx={{ width: '100%' }} />
})
SecurityGroupTabs.propTypes = { id: PropTypes.string.isRequired }

View File

@ -38,14 +38,14 @@ const getTabComponent = (tabName) =>
const ServiceTabs = memo(({ id }) => {
const { view, getResourceView } = useViews()
const { isLoading, isError, error } = useGetServiceQuery({ id })
const { isError, error, status, data } = useGetServiceQuery({ id })
const tabsAvailable = useMemo(() => {
const resource = RESOURCE_NAMES.SERVICE
const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {}
return getAvailableInfoTabs(infoTabs, getTabComponent, id)
}, [view])
}, [view, id])
if (isError) {
return (
@ -55,11 +55,11 @@ const ServiceTabs = memo(({ id }) => {
)
}
return isLoading ? (
<LinearProgress color="secondary" sx={{ width: '100%' }} />
) : (
<Tabs addBorder tabs={tabsAvailable ?? []} />
)
if (status === 'fulfilled' || id === data?.ID) {
return <Tabs addBorder tabs={tabsAvailable ?? []} />
}
return <LinearProgress color="secondary" sx={{ width: '100%' }} />
})
ServiceTabs.propTypes = { id: PropTypes.string.isRequired }

View File

@ -36,14 +36,16 @@ const getTabComponent = (tabName) =>
const ServiceTemplateTabs = memo(({ id }) => {
const { view, getResourceView } = useViews()
const { isLoading, isError, error } = useGetServiceTemplateQuery({ id })
const { isError, error, status, data } = useGetServiceTemplateQuery({
id,
})
const tabsAvailable = useMemo(() => {
const resource = RESOURCE_NAMES.SERVICE_TEMPLATE
const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {}
return getAvailableInfoTabs(infoTabs, getTabComponent, id)
}, [view])
}, [view, id])
if (isError) {
return (
@ -53,11 +55,11 @@ const ServiceTemplateTabs = memo(({ id }) => {
)
}
return isLoading ? (
<LinearProgress color="secondary" sx={{ width: '100%' }} />
) : (
<Tabs addBorder tabs={tabsAvailable ?? []} />
)
if (status === 'fulfilled' || id === data?.ID) {
return <Tabs addBorder tabs={tabsAvailable ?? []} />
}
return <LinearProgress color="secondary" sx={{ width: '100%' }} />
})
ServiceTemplateTabs.propTypes = { id: PropTypes.string.isRequired }

View File

@ -32,14 +32,14 @@ const getTabComponent = (tabName) =>
const UserTabs = memo(({ id }) => {
const { view, getResourceView } = useViews()
const { isLoading, isError, error } = useGetUserQuery({ id })
const { isError, error, status, data } = useGetUserQuery({ id })
const tabsAvailable = useMemo(() => {
const resource = RESOURCE_NAMES.USER
const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {}
return getAvailableInfoTabs(infoTabs, getTabComponent, id)
}, [view])
}, [view, id])
if (isError) {
return (
@ -49,11 +49,11 @@ const UserTabs = memo(({ id }) => {
)
}
return isLoading ? (
<LinearProgress color="secondary" sx={{ width: '100%' }} />
) : (
<Tabs addBorder tabs={tabsAvailable ?? []} />
)
if (status === 'fulfilled' || id === data?.ID) {
return <Tabs addBorder tabs={tabsAvailable ?? []} />
}
return <LinearProgress color="secondary" sx={{ width: '100%' }} />
})
UserTabs.propTypes = { id: PropTypes.string.isRequired }

View File

@ -42,14 +42,16 @@ const getTabComponent = (tabName) =>
const VNetworkTabs = memo(({ id }) => {
const { view, getResourceView } = useViews()
const { isLoading, isError, error } = useGetVNetworkQuery({ id })
const { isLoading, isError, error, status } = useGetVNetworkQuery({
id,
})
const tabsAvailable = useMemo(() => {
const resource = RESOURCE_NAMES.VNET
const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {}
return getAvailableInfoTabs(infoTabs, getTabComponent, id)
}, [view])
}, [view, id])
if (isError) {
return (
@ -59,11 +61,15 @@ const VNetworkTabs = memo(({ id }) => {
)
}
return isLoading ? (
<LinearProgress color="secondary" sx={{ width: '100%' }} />
) : (
<Tabs addBorder tabs={tabsAvailable ?? []} />
)
if (isLoading || status === 'pending') {
return <LinearProgress color="secondary" sx={{ width: '100%' }} />
}
if (status === 'fulfilled') {
return <Tabs addBorder tabs={tabsAvailable ?? []} />
}
return <LinearProgress color="secondary" sx={{ width: '100%' }} />
})
VNetworkTabs.propTypes = { id: PropTypes.string.isRequired }

View File

@ -32,14 +32,14 @@ const getTabComponent = (tabName) =>
const VNetTemplateTabs = memo(({ id }) => {
const { view, getResourceView } = useViews()
const { isLoading, isError, error } = useGetVNTemplateQuery({ id })
const { isError, error, status, data } = useGetVNTemplateQuery({ id })
const tabsAvailable = useMemo(() => {
const resource = RESOURCE_NAMES.VN_TEMPLATE
const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {}
return getAvailableInfoTabs(infoTabs, getTabComponent, id)
}, [view])
}, [view, id])
if (isError) {
return (
@ -49,11 +49,11 @@ const VNetTemplateTabs = memo(({ id }) => {
)
}
return isLoading ? (
<LinearProgress color="secondary" sx={{ width: '100%' }} />
) : (
<Tabs addBorder tabs={tabsAvailable ?? []} />
)
if (status === 'fulfilled' || id === data?.ID) {
return <Tabs addBorder tabs={tabsAvailable ?? []} />
}
return <LinearProgress color="secondary" sx={{ width: '100%' }} />
})
VNetTemplateTabs.propTypes = { id: PropTypes.string.isRequired }

View File

@ -70,14 +70,14 @@ const VmTabs = memo(({ id }) => {
const classes = useStyles()
const { view, getResourceView } = useViews()
const {
isLoading,
status,
isError,
error,
data: vm = {},
} = useGetVmQuery({ id }, { refetchOnMountOrArgChange: 10 })
const [dismissError] = useUpdateUserTemplateMutation()
const { USER_TEMPLATE } = vm
const { USER_TEMPLATE, ID } = vm
const handleDismissError = async () => {
const { ERROR, SCHED_MESSAGE, ...templateWithoutError } = USER_TEMPLATE
@ -103,30 +103,32 @@ const VmTabs = memo(({ id }) => {
)
}
return isLoading ? (
<LinearProgress color="secondary" sx={{ width: '100%' }} />
) : (
<>
<Fade in={!!vmError} unmountOnExit>
<Alert
variant="outlined"
severity="error"
className={classes.vmError}
sx={{ gridColumn: 'span 2' }}
action={
<SubmitButton
onClick={handleDismissError}
icon={<CloseIcon />}
tooltip={<Translate word={T.Dismiss} />}
/>
}
>
{vmError}
</Alert>
</Fade>
<Tabs addBorder tabs={tabsAvailable} />
</>
)
if (status === 'fulfilled' || id === ID) {
return (
<>
<Fade in={!!vmError} unmountOnExit>
<Alert
variant="outlined"
severity="error"
className={classes.vmError}
sx={{ gridColumn: 'span 2' }}
action={
<SubmitButton
onClick={handleDismissError}
icon={<CloseIcon />}
tooltip={<Translate word={T.Dismiss} />}
/>
}
>
{vmError}
</Alert>
</Fade>
<Tabs addBorder tabs={tabsAvailable} />
</>
)
}
return <LinearProgress color="secondary" sx={{ width: '100%' }} />
})
VmTabs.propTypes = { id: PropTypes.string.isRequired }

View File

@ -34,14 +34,14 @@ const getTabComponent = (tabName) =>
const VmTemplateTabs = memo(({ id }) => {
const { view, getResourceView } = useViews()
const { isLoading, isError, error } = useGetTemplateQuery({ id })
const { isError, error, status, data } = useGetTemplateQuery({ id })
const tabsAvailable = useMemo(() => {
const resource = RESOURCE_NAMES.VM_TEMPLATE
const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {}
return getAvailableInfoTabs(infoTabs, getTabComponent, id)
}, [view])
}, [view, id])
if (isError) {
return (
@ -51,11 +51,11 @@ const VmTemplateTabs = memo(({ id }) => {
)
}
return isLoading ? (
<LinearProgress color="secondary" sx={{ width: '100%' }} />
) : (
<Tabs addBorder tabs={tabsAvailable ?? []} />
)
if (status === 'fulfilled' || id === data?.ID) {
return <Tabs addBorder tabs={tabsAvailable ?? []} />
}
return <LinearProgress color="secondary" sx={{ width: '100%' }} />
})
VmTemplateTabs.propTypes = { id: PropTypes.string.isRequired }

View File

@ -41,7 +41,7 @@ import { T, VM } from 'client/constants'
*/
function VirtualMachines() {
const [selectedRows, onSelectedRowsChange] = useState(() => [])
const actions = VmActions()
const actions = VmActions(selectedRows)
const hasSelectedRows = selectedRows?.length > 0
const moreThanOneSelected = selectedRows?.length > 1