mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-21 14:50:08 +03:00
parent
3ff275e1b7
commit
a3307765e9
@ -144,7 +144,7 @@ const NicCard = memo(
|
||||
const rulesById = Object.entries(groupBy(SECURITY_GROUPS, 'ID'))
|
||||
|
||||
return (
|
||||
<Accordion>
|
||||
<Accordion variant="outlined">
|
||||
<AccordionSummary>
|
||||
<Typography variant="body1">
|
||||
<Translate word={T.SecurityGroups} />
|
||||
|
@ -14,11 +14,17 @@
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
/* eslint-disable jsdoc/require-jsdoc */
|
||||
import { createElement, useMemo, isValidElement } from 'react'
|
||||
import {
|
||||
Fragment,
|
||||
createElement,
|
||||
useMemo,
|
||||
useCallback,
|
||||
isValidElement,
|
||||
} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { FormControl, Grid } from '@mui/material'
|
||||
import { useFormContext } from 'react-hook-form'
|
||||
import { FormControl, Accordion, AccordionSummary, Grid } from '@mui/material'
|
||||
|
||||
import * as FC from 'client/components/FormControl'
|
||||
import Legend from 'client/components/Forms/Legend'
|
||||
@ -46,6 +52,7 @@ const INPUT_CONTROLLER = {
|
||||
}
|
||||
|
||||
const FormWithSchema = ({
|
||||
accordion = false,
|
||||
id,
|
||||
cy,
|
||||
fields,
|
||||
@ -59,6 +66,26 @@ const FormWithSchema = ({
|
||||
|
||||
const { sx: sxRoot, ...restOfRootProps } = rootProps ?? {}
|
||||
|
||||
const RootWrapper = useMemo(
|
||||
() =>
|
||||
accordion && legend
|
||||
? ({ children }) => (
|
||||
<Accordion
|
||||
variant="transparent"
|
||||
TransitionProps={{ unmountOnExit: false }}
|
||||
>
|
||||
{children}
|
||||
</Accordion>
|
||||
)
|
||||
: Fragment,
|
||||
[accordion, legend]
|
||||
)
|
||||
|
||||
const LegendWrapper = useMemo(
|
||||
() => (accordion && legend ? AccordionSummary : Fragment),
|
||||
[accordion, legend]
|
||||
)
|
||||
|
||||
const getFields = useMemo(
|
||||
() => (typeof fields === 'function' ? fields() : fields),
|
||||
[fields?.length]
|
||||
@ -66,12 +93,15 @@ const FormWithSchema = ({
|
||||
|
||||
if (!getFields || getFields?.length === 0) return null
|
||||
|
||||
const addIdToName = (name) =>
|
||||
name.startsWith('$')
|
||||
? name.slice(1) // removes character '$' and returns
|
||||
: id
|
||||
? `${id}.${name}`
|
||||
: name // concat form ID if exists
|
||||
const addIdToName = useCallback(
|
||||
(name) =>
|
||||
name.startsWith('$')
|
||||
? name.slice(1) // removes character '$' and returns
|
||||
: id
|
||||
? `${id}.${name}` // concat form ID if exists
|
||||
: name,
|
||||
[id]
|
||||
)
|
||||
|
||||
return (
|
||||
<FormControl
|
||||
@ -80,65 +110,75 @@ const FormWithSchema = ({
|
||||
sx={{ width: '100%', ...sxRoot }}
|
||||
{...restOfRootProps}
|
||||
>
|
||||
{legend && <Legend title={legend} tooltip={legendTooltip} />}
|
||||
<Grid container spacing={1} alignContent="flex-start">
|
||||
{getFields?.map?.(({ dependOf, ...attributes }) => {
|
||||
let valueOfDependField = null
|
||||
let nameOfDependField = null
|
||||
<RootWrapper>
|
||||
<LegendWrapper>
|
||||
{legend && (
|
||||
<Legend
|
||||
title={legend}
|
||||
tooltip={legendTooltip}
|
||||
disableGutters={accordion}
|
||||
/>
|
||||
)}
|
||||
</LegendWrapper>
|
||||
<Grid container spacing={1} alignContent="flex-start">
|
||||
{getFields?.map?.(({ dependOf, ...attributes }) => {
|
||||
let valueOfDependField = null
|
||||
let nameOfDependField = null
|
||||
|
||||
if (dependOf) {
|
||||
nameOfDependField = Array.isArray(dependOf)
|
||||
? dependOf.map(addIdToName)
|
||||
: addIdToName(dependOf)
|
||||
if (dependOf) {
|
||||
nameOfDependField = Array.isArray(dependOf)
|
||||
? dependOf.map(addIdToName)
|
||||
: addIdToName(dependOf)
|
||||
|
||||
valueOfDependField = watch(nameOfDependField)
|
||||
}
|
||||
valueOfDependField = watch(nameOfDependField)
|
||||
}
|
||||
|
||||
const { name, type, htmlType, grid, ...fieldProps } = Object.entries(
|
||||
attributes
|
||||
).reduce((field, attribute) => {
|
||||
const [key, value] = attribute
|
||||
const isNotDependAttribute = NOT_DEPEND_ATTRIBUTES.includes(key)
|
||||
const { name, type, htmlType, grid, ...fieldProps } =
|
||||
Object.entries(attributes).reduce((field, attribute) => {
|
||||
const [key, value] = attribute
|
||||
const isNotDependAttribute = NOT_DEPEND_ATTRIBUTES.includes(key)
|
||||
|
||||
const finalValue =
|
||||
typeof value === 'function' &&
|
||||
!isNotDependAttribute &&
|
||||
!isValidElement(value())
|
||||
? value(valueOfDependField, formContext)
|
||||
: value
|
||||
const finalValue =
|
||||
typeof value === 'function' &&
|
||||
!isNotDependAttribute &&
|
||||
!isValidElement(value())
|
||||
? value(valueOfDependField, formContext)
|
||||
: value
|
||||
|
||||
return { ...field, [key]: finalValue }
|
||||
}, {})
|
||||
return { ...field, [key]: finalValue }
|
||||
}, {})
|
||||
|
||||
const dataCy = `${cy}-${name}`.replaceAll('.', '-')
|
||||
const inputName = addIdToName(name)
|
||||
const dataCy = `${cy}-${name}`.replaceAll('.', '-')
|
||||
const inputName = addIdToName(name)
|
||||
|
||||
const isHidden = htmlType === INPUT_TYPES.HIDDEN
|
||||
const isHidden = htmlType === INPUT_TYPES.HIDDEN
|
||||
|
||||
if (isHidden) return null
|
||||
if (isHidden) return null
|
||||
|
||||
return (
|
||||
INPUT_CONTROLLER[type] && (
|
||||
<Grid key={dataCy} item xs={12} md={6} {...grid}>
|
||||
{createElement(INPUT_CONTROLLER[type], {
|
||||
control,
|
||||
cy: dataCy,
|
||||
formContext,
|
||||
dependencies: nameOfDependField,
|
||||
name: inputName,
|
||||
type: htmlType === false ? undefined : htmlType,
|
||||
...fieldProps,
|
||||
})}
|
||||
</Grid>
|
||||
return (
|
||||
INPUT_CONTROLLER[type] && (
|
||||
<Grid key={dataCy} item xs={12} md={6} {...grid}>
|
||||
{createElement(INPUT_CONTROLLER[type], {
|
||||
control,
|
||||
cy: dataCy,
|
||||
formContext,
|
||||
dependencies: nameOfDependField,
|
||||
name: inputName,
|
||||
type: htmlType === false ? undefined : htmlType,
|
||||
...fieldProps,
|
||||
})}
|
||||
</Grid>
|
||||
)
|
||||
)
|
||||
)
|
||||
})}
|
||||
</Grid>
|
||||
})}
|
||||
</Grid>
|
||||
</RootWrapper>
|
||||
</FormControl>
|
||||
)
|
||||
}
|
||||
|
||||
FormWithSchema.propTypes = {
|
||||
accordion: PropTypes.bool,
|
||||
id: PropTypes.string,
|
||||
cy: PropTypes.string,
|
||||
fields: PropTypes.oneOfType([
|
||||
|
@ -18,24 +18,30 @@ import PropTypes from 'prop-types'
|
||||
import { styled, Typography } from '@mui/material'
|
||||
|
||||
import AdornmentWithTooltip from 'client/components/FormControl/Tooltip'
|
||||
import { Translate, labelCanBeTranslated } from 'client/components/HOC'
|
||||
import { Translate } from 'client/components/HOC'
|
||||
|
||||
const StyledLegend = styled((props) => (
|
||||
<Typography variant="subtitle1" component="legend" {...props} />
|
||||
))(({ theme, tooltip }) => ({
|
||||
marginBottom: '1em',
|
||||
padding: '0em 1em 0.2em 0.5em',
|
||||
borderBottom: `2px solid ${theme.palette.secondary.main}`,
|
||||
...(!!tooltip && {
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
))(
|
||||
({ theme }) => ({
|
||||
padding: '0em 1em 0.2em 0.5em',
|
||||
borderBottom: `2px solid ${theme.palette.secondary.main}`,
|
||||
}),
|
||||
}))
|
||||
({ ownerState }) => ({
|
||||
...(ownerState.tooltip && {
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
}),
|
||||
...(!ownerState.disableGutters && {
|
||||
marginBottom: '1em',
|
||||
}),
|
||||
})
|
||||
)
|
||||
|
||||
const Legend = memo(
|
||||
({ title, tooltip }) => (
|
||||
<StyledLegend tooltip={tooltip}>
|
||||
{labelCanBeTranslated(title) ? <Translate word={title} /> : title}
|
||||
({ title, tooltip, disableGutters }) => (
|
||||
<StyledLegend ownerState={{ tooltip, disableGutters }}>
|
||||
<Translate word={title} />
|
||||
{!!tooltip && <AdornmentWithTooltip title={tooltip} />}
|
||||
</StyledLegend>
|
||||
),
|
||||
@ -45,6 +51,7 @@ const Legend = memo(
|
||||
Legend.propTypes = {
|
||||
title: PropTypes.any,
|
||||
tooltip: PropTypes.string,
|
||||
disableGutters: PropTypes.bool,
|
||||
}
|
||||
|
||||
Legend.displayName = 'FieldsetLegend'
|
||||
|
@ -64,12 +64,17 @@ const ConfigurationSection = () => {
|
||||
<Stack direction="row" gap="1em">
|
||||
<Button
|
||||
onClick={handleAddUserKey}
|
||||
color="secondary"
|
||||
variant="contained"
|
||||
data-cy={`${EXTRA_ID}-add-context-ssh-public-key`}
|
||||
>
|
||||
{T.AddUserSshPublicKey}
|
||||
</Button>
|
||||
<Button onClick={handleClearKey} variant="outlined">
|
||||
<Button
|
||||
onClick={handleClearKey}
|
||||
color="secondary"
|
||||
variant="outlined"
|
||||
>
|
||||
{T.Clear}
|
||||
</Button>
|
||||
</Stack>
|
||||
|
@ -31,6 +31,7 @@ export const SECTION_ID = 'CONTEXT'
|
||||
*/
|
||||
const FilesSection = ({ hypervisor }) => (
|
||||
<FormWithSchema
|
||||
accordion
|
||||
cy={`${EXTRA_ID}-context-files`}
|
||||
legend={T.Files}
|
||||
fields={() => FILES_FIELDS(hypervisor)}
|
||||
|
@ -30,8 +30,8 @@ export const TAB_ID = ['CONTEXT', USER_INPUTS_ID]
|
||||
const Context = (props) => (
|
||||
<>
|
||||
<ConfigurationSection />
|
||||
<FilesSection {...props} />
|
||||
<UserInputsSection />
|
||||
<FilesSection {...props} />
|
||||
</>
|
||||
)
|
||||
|
||||
|
@ -116,7 +116,7 @@ const AttributeList = ({
|
||||
|
||||
return (
|
||||
<RootElement variant="outlined" {...containerProps}>
|
||||
<ListElement {...listProps}>
|
||||
<ListElement variant="outlined" {...listProps}>
|
||||
{/* TITLE */}
|
||||
{title && (
|
||||
<TitleElement>
|
||||
|
@ -43,7 +43,7 @@ const AppTemplateTab = ({ id }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Accordion>
|
||||
<Accordion variant="outlined">
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<Translate word={T.AppTemplate} />
|
||||
</AccordionSummary>
|
||||
|
@ -34,7 +34,7 @@ const VmConfigurationTab = ({ id }) => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Accordion>
|
||||
<Accordion variant="outlined">
|
||||
<AccordionSummary>
|
||||
<Translate word={T.UserTemplate} />
|
||||
</AccordionSummary>
|
||||
@ -46,7 +46,7 @@ const VmConfigurationTab = ({ id }) => {
|
||||
</pre>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
<Accordion>
|
||||
<Accordion variant="outlined">
|
||||
<AccordionSummary>
|
||||
<Translate word={T.Template} />
|
||||
</AccordionSummary>
|
||||
|
@ -30,7 +30,7 @@ const TemplateTab = ({ id }) => {
|
||||
const { data: vmTemplate = {} } = useGetTemplateQuery({ id })
|
||||
|
||||
return (
|
||||
<Accordion expanded>
|
||||
<Accordion variant="outlined" expanded>
|
||||
<AccordionDetails>
|
||||
<Box component="pre">
|
||||
<Box
|
||||
|
@ -287,9 +287,18 @@ const createAppTheme = (appTheme, mode = SCHEMES.DARK) => {
|
||||
},
|
||||
},
|
||||
MuiPaper: {
|
||||
defaultProps: {
|
||||
elevation: 0,
|
||||
},
|
||||
styleOverrides: {
|
||||
root: { backgroundImage: 'unset' },
|
||||
},
|
||||
variants: [
|
||||
{
|
||||
props: { variant: 'transparent' },
|
||||
style: { backgroundColor: 'transparent' },
|
||||
},
|
||||
],
|
||||
},
|
||||
MuiButtonBase: {
|
||||
defaultProps: {
|
||||
@ -461,39 +470,18 @@ const createAppTheme = (appTheme, mode = SCHEMES.DARK) => {
|
||||
dense: true,
|
||||
},
|
||||
},
|
||||
MuiChip: {
|
||||
variants: [
|
||||
{
|
||||
props: { variant: 'text' },
|
||||
style: {
|
||||
border: 0,
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
MuiAccordion: {
|
||||
defaultProps: {
|
||||
elevation: 0,
|
||||
square: true,
|
||||
disableGutters: true,
|
||||
TransitionProps: { unmountOnExit: true },
|
||||
},
|
||||
styleOverrides: {
|
||||
root: {
|
||||
flexBasis: '100%',
|
||||
border: `1px solid ${defaultTheme.palette.divider}`,
|
||||
'&:before': { display: 'none' },
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiAccordionDetails: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderTop: `1px solid ${defaultTheme.palette.divider}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiAccordionSummary: {
|
||||
defaultProps: {
|
||||
expandIcon: <ExpandMoreIcon />,
|
||||
|
Loading…
x
Reference in New Issue
Block a user