mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-06 12:58:18 +03:00
parent
4664a46460
commit
a2b328bbe8
@ -62,3 +62,5 @@ info-tabs:
|
||||
delete: true
|
||||
vms:
|
||||
enabled: true
|
||||
increments:
|
||||
enabled: true
|
||||
|
@ -62,3 +62,5 @@ info-tabs:
|
||||
delete: true
|
||||
vms:
|
||||
enabled: true
|
||||
increments:
|
||||
enabled: true
|
||||
|
@ -121,6 +121,12 @@ const CreateSecurityGroups = loadable(
|
||||
const Backups = loadable(() => import('client/containers/Backups'), {
|
||||
ssr: false,
|
||||
})
|
||||
const BackupDetail = loadable(
|
||||
() => import('client/containers/Backups/Detail'),
|
||||
{
|
||||
ssr: false,
|
||||
}
|
||||
)
|
||||
const CreateImages = loadable(() => import('client/containers/Images/Create'), {
|
||||
ssr: false,
|
||||
})
|
||||
@ -441,6 +447,12 @@ const ENDPOINTS = [
|
||||
icon: BackupIcon,
|
||||
Component: Backups,
|
||||
},
|
||||
{
|
||||
title: T.Backup,
|
||||
description: (params) => `#${params?.id}`,
|
||||
path: PATH.STORAGE.BACKUPS.DETAIL,
|
||||
Component: BackupDetail,
|
||||
},
|
||||
{
|
||||
title: T.Marketplaces,
|
||||
path: PATH.STORAGE.MARKETPLACES.LIST,
|
||||
|
@ -28,26 +28,27 @@ const DS_ID = {
|
||||
return arrayToOptions(
|
||||
datastores.filter(({ TEMPLATE }) => TEMPLATE.TYPE === 'BACKUP_DS'),
|
||||
{
|
||||
addEmpty: false,
|
||||
addEmpty: true,
|
||||
getText: ({ NAME, ID } = {}) => `${ID}: ${NAME}`,
|
||||
getValue: ({ ID } = {}) => ID,
|
||||
getValue: ({ ID } = {}) => parseInt(ID),
|
||||
}
|
||||
)
|
||||
},
|
||||
validation: number()
|
||||
.positive()
|
||||
.required()
|
||||
.default(() => undefined),
|
||||
.default(() => undefined)
|
||||
.transform((_, val) => parseInt(val)),
|
||||
}
|
||||
|
||||
const RESET = {
|
||||
name: 'reset',
|
||||
label: T.Reset,
|
||||
label: T.ResetBackup,
|
||||
type: INPUT_TYPES.SWITCH,
|
||||
validation: boolean(),
|
||||
grid: { xs: 12, md: 6 },
|
||||
grid: { xs: 12 },
|
||||
}
|
||||
|
||||
export const FIELDS = [DS_ID, RESET]
|
||||
export const FIELDS = [RESET, DS_ID]
|
||||
|
||||
export const SCHEMA = object(getValidationFromFields(FIELDS))
|
||||
|
@ -0,0 +1,46 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { ReactElement } from 'react'
|
||||
import { Stack } from '@mui/material'
|
||||
|
||||
import { FormWithSchema } from 'client/components/Forms'
|
||||
|
||||
import { SECTIONS } from 'client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/backup/schema'
|
||||
import { T } from 'client/constants'
|
||||
|
||||
/**
|
||||
* @returns {ReactElement} IO section component
|
||||
*/
|
||||
const Backup = () => (
|
||||
<Stack
|
||||
display="grid"
|
||||
gap="1em"
|
||||
sx={{ gridTemplateColumns: { sm: '1fr', md: '1fr 1fr' } }}
|
||||
>
|
||||
{SECTIONS.map(({ id, ...section }) => (
|
||||
<FormWithSchema
|
||||
key={id}
|
||||
cy="backups-conf"
|
||||
legend={T.Backup}
|
||||
{...section}
|
||||
/>
|
||||
))}
|
||||
</Stack>
|
||||
)
|
||||
|
||||
Backup.displayName = 'Backup'
|
||||
|
||||
export default Backup
|
@ -0,0 +1,23 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { object, ObjectSchema } from 'yup'
|
||||
|
||||
import { BACKUP_SCHEMA } from 'client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/backup/schema'
|
||||
|
||||
/**
|
||||
* @returns {ObjectSchema} Backup schema
|
||||
*/
|
||||
export const SCHEMA = () => object().concat(BACKUP_SCHEMA)
|
@ -20,11 +20,13 @@ import {
|
||||
SystemShut as OsIcon,
|
||||
DataTransferBoth as IOIcon,
|
||||
Folder as ContextIcon,
|
||||
RefreshDouble as BackupIcon,
|
||||
} from 'iconoir-react'
|
||||
|
||||
import InputOutput from 'client/components/Forms/Vm/UpdateConfigurationForm/inputOutput'
|
||||
import Booting from 'client/components/Forms/Vm/UpdateConfigurationForm/booting'
|
||||
import Context from 'client/components/Forms/Vm/UpdateConfigurationForm/context'
|
||||
import Backup from 'client/components/Forms/Vm/UpdateConfigurationForm/backup'
|
||||
|
||||
import Tabs from 'client/components/Tabs'
|
||||
import { Translate } from 'client/components/HOC'
|
||||
@ -63,6 +65,15 @@ const Content = ({ hypervisor }) => {
|
||||
renderContent: () => <Context hypervisor={hypervisor} />,
|
||||
error: !!errors?.CONTEXT,
|
||||
},
|
||||
{
|
||||
id: 'backup_config',
|
||||
icon: BackupIcon,
|
||||
label: <Translate word={T.Backup} />,
|
||||
renderContent: () => <Backup />,
|
||||
error: ['BACKUP_VOLATILE', 'FS_FREEZE', 'KEEP_LAST', 'MODE'].some(
|
||||
(id) => errors?.[`BACKUP_CONFIG.${id}`]
|
||||
),
|
||||
},
|
||||
],
|
||||
[errors, hypervisor]
|
||||
)
|
||||
|
@ -25,6 +25,7 @@ const UpdateConfigurationForm = createForm(SCHEMA, undefined, {
|
||||
transformInitialValue: (vmTemplate, schema) => {
|
||||
const template = vmTemplate?.TEMPLATE ?? {}
|
||||
const context = template?.CONTEXT ?? {}
|
||||
const backupConfig = vmTemplate?.BACKUPS?.BACKUP_CONFIG ?? {}
|
||||
|
||||
const knownTemplate = schema.cast(
|
||||
{ ...vmTemplate, ...template },
|
||||
@ -37,12 +38,27 @@ const UpdateConfigurationForm = createForm(SCHEMA, undefined, {
|
||||
context: { ...template },
|
||||
})
|
||||
|
||||
// Get the custom vars from the context
|
||||
const knownBackupConfig = reach(schema, 'BACKUP_CONFIG').cast(
|
||||
backupConfig,
|
||||
{
|
||||
stripUnknown: true,
|
||||
context: { ...template },
|
||||
}
|
||||
)
|
||||
|
||||
// Merge known and unknown context custom vars
|
||||
knownTemplate.CONTEXT = {
|
||||
...knownContext,
|
||||
...getUnknownAttributes(context, knownContext),
|
||||
}
|
||||
|
||||
// Merge known and unknown context custom vars
|
||||
knownTemplate.BACKUP_CONFIG = {
|
||||
...knownBackupConfig,
|
||||
...getUnknownAttributes(backupConfig, knownBackupConfig),
|
||||
}
|
||||
|
||||
return knownTemplate
|
||||
},
|
||||
transformBeforeSubmit: (formData) => ensureContextWithScript(formData),
|
||||
|
@ -19,6 +19,7 @@ import { HYPERVISORS } from 'client/constants'
|
||||
import { SCHEMA as OS_SCHEMA } from './booting/schema'
|
||||
import { SCHEMA as IO_SCHEMA } from './inputOutput/schema'
|
||||
import { SCHEMA as CONTEXT_SCHEMA } from './context/schema'
|
||||
import { SCHEMA as BACKUP_SCHEMA } from './backup/schema'
|
||||
|
||||
/**
|
||||
* @param {object} [formProps] - Form props
|
||||
@ -30,5 +31,6 @@ export const SCHEMA = ({ hypervisor }) =>
|
||||
.concat(IO_SCHEMA({ hypervisor }))
|
||||
.concat(OS_SCHEMA({ hypervisor }))
|
||||
.concat(CONTEXT_SCHEMA({ hypervisor }))
|
||||
.concat(BACKUP_SCHEMA())
|
||||
|
||||
export { IO_SCHEMA, OS_SCHEMA, CONTEXT_SCHEMA }
|
||||
export { IO_SCHEMA, OS_SCHEMA, CONTEXT_SCHEMA, BACKUP_SCHEMA }
|
||||
|
@ -13,9 +13,14 @@
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
import { string, boolean, number } from 'yup'
|
||||
import { string, boolean, number, ObjectSchema } from 'yup'
|
||||
|
||||
import { Field, Section, arrayToOptions } from 'client/utils'
|
||||
import {
|
||||
Field,
|
||||
Section,
|
||||
arrayToOptions,
|
||||
getObjectSchemaFromFields,
|
||||
} from 'client/utils'
|
||||
import {
|
||||
T,
|
||||
INPUT_TYPES,
|
||||
@ -28,6 +33,7 @@ const BACKUP_VOLATILE_FIELD = {
|
||||
label: T.BackupVolatileDisksQuestion,
|
||||
type: INPUT_TYPES.SWITCH,
|
||||
validation: boolean().yesOrNo().notRequired(),
|
||||
grid: { xs: 12, md: 6 },
|
||||
}
|
||||
|
||||
const FS_FREEZE_FIELD = {
|
||||
@ -42,6 +48,7 @@ const FS_FREEZE_FIELD = {
|
||||
validation: string()
|
||||
.trim()
|
||||
.default(() => undefined),
|
||||
grid: { xs: 12, md: 6 },
|
||||
}
|
||||
|
||||
const KEEP_LAST_FIELD = {
|
||||
@ -53,13 +60,13 @@ const KEEP_LAST_FIELD = {
|
||||
.notRequired()
|
||||
.nullable(true)
|
||||
.default(() => undefined)
|
||||
.transform((_, val) => (val !== '' ? val : null)),
|
||||
.transform((_, val) => (val !== '' ? parseInt(val) : null)),
|
||||
grid: { xs: 12, md: 6 },
|
||||
}
|
||||
|
||||
const MODE_FIELD = {
|
||||
name: 'BACKUP_CONFIG.MODE',
|
||||
label: T.FSFreeze,
|
||||
tooltip: T.FSFreezeConcept,
|
||||
label: T.Mode,
|
||||
type: INPUT_TYPES.SELECT,
|
||||
values: arrayToOptions(Object.keys(BACKUP_MODE_OPTIONS), {
|
||||
addEmpty: true,
|
||||
@ -69,10 +76,11 @@ const MODE_FIELD = {
|
||||
validation: string()
|
||||
.trim()
|
||||
.default(() => undefined),
|
||||
grid: { xs: 12, md: 6 },
|
||||
}
|
||||
|
||||
/** @type {Section[]} Sections */
|
||||
const SECTIONS = [
|
||||
export const SECTIONS = [
|
||||
{
|
||||
id: 'backup-configuration',
|
||||
fields: [
|
||||
@ -85,11 +93,12 @@ const SECTIONS = [
|
||||
]
|
||||
|
||||
/** @type {Field[]} List of Placement fields */
|
||||
const FIELDS = [
|
||||
export const FIELDS = [
|
||||
BACKUP_VOLATILE_FIELD,
|
||||
FS_FREEZE_FIELD,
|
||||
KEEP_LAST_FIELD,
|
||||
MODE_FIELD,
|
||||
]
|
||||
|
||||
export { SECTIONS, FIELDS }
|
||||
/** @type {ObjectSchema} Graphics schema */
|
||||
export const BACKUP_SCHEMA = getObjectSchemaFromFields(FIELDS)
|
||||
|
@ -43,7 +43,6 @@ const Row = ({ original, value, ...props }) => {
|
||||
UNAME,
|
||||
GNAME,
|
||||
REGTIME,
|
||||
TYPE,
|
||||
DISK_TYPE,
|
||||
PERSISTENT,
|
||||
locked,
|
||||
@ -52,7 +51,12 @@ const Row = ({ original, value, ...props }) => {
|
||||
RUNNING_VMS,
|
||||
} = value
|
||||
|
||||
const labels = [...new Set([TYPE])].filter(Boolean)
|
||||
const {
|
||||
BACKUP_INCREMENTS: { INCREMENT = undefined },
|
||||
} = original
|
||||
|
||||
const BACKUP_TYPE = INCREMENT ? T.Incremental : T.Full
|
||||
const labels = [...new Set([BACKUP_TYPE])].filter(Boolean)
|
||||
|
||||
const { color: stateColor, name: stateName } = ImageModel.getState(original)
|
||||
|
||||
@ -74,7 +78,7 @@ const Row = ({ original, value, ...props }) => {
|
||||
</span>
|
||||
</div>
|
||||
<div className={classes.caption}>
|
||||
<span>{`${ID}`}</span>
|
||||
<span>{`#${ID}`}</span>
|
||||
<span title={time.toFormat('ff')}>
|
||||
<Timer translateWord={T.RegisteredAt} initial={time} />
|
||||
</span>
|
||||
|
@ -74,7 +74,7 @@ const Row = ({ original, value, ...props }) => {
|
||||
</span>
|
||||
</div>
|
||||
<div className={classes.caption}>
|
||||
<span>{`${ID}`}</span>
|
||||
<span>{`#${ID}`}</span>
|
||||
<span title={time.toFormat('ff')}>
|
||||
<Timer translateWord={T.RegisteredAt} initial={time} />
|
||||
</span>
|
||||
|
@ -74,7 +74,7 @@ const Row = ({ original, value, ...props }) => {
|
||||
</span>
|
||||
</div>
|
||||
<div className={classes.caption}>
|
||||
<span>{`${ID}`}</span>
|
||||
<span>{`#${ID}`}</span>
|
||||
<span title={time.toFormat('ff')}>
|
||||
<Timer translateWord={T.RegisteredAt} initial={time} />
|
||||
</span>
|
||||
|
@ -0,0 +1,23 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
export default [
|
||||
{ Header: 'ID', accessor: 'ID', sortType: 'number' },
|
||||
{ Header: 'Type', accessor: 'TYPE' },
|
||||
{ Header: 'Date', accessor: 'DATE' },
|
||||
{ Header: 'Size', accessor: 'SIZE' },
|
||||
{ Header: 'Source', accessor: 'SOURCE' },
|
||||
]
|
@ -0,0 +1,50 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { useMemo, ReactElement } from 'react'
|
||||
|
||||
import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced'
|
||||
import IncrementColumns from 'client/components/Tables/Increments/columns'
|
||||
import IncrementRow from 'client/components/Tables/Increments/row'
|
||||
|
||||
const DEFAULT_DATA_CY = 'increments'
|
||||
|
||||
/**
|
||||
* @param {object} props - Props
|
||||
* @returns {ReactElement} Backups table
|
||||
*/
|
||||
const IncrementsTable = (props) => {
|
||||
const { rootProps = {}, increments, ...rest } = props ?? {}
|
||||
rootProps['data-cy'] ??= DEFAULT_DATA_CY
|
||||
|
||||
const columns = createColumns({
|
||||
columns: IncrementColumns,
|
||||
})
|
||||
|
||||
return (
|
||||
<EnhancedTable
|
||||
columns={columns}
|
||||
data={useMemo(() => increments, [increments])}
|
||||
rootProps={rootProps}
|
||||
getRowId={(row) => String(row.ID)}
|
||||
RowComponent={IncrementRow}
|
||||
{...rest}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
IncrementsTable.displayName = 'IncrementsTable'
|
||||
|
||||
export default IncrementsTable
|
83
src/fireedge/src/client/components/Tables/Increments/row.js
Normal file
83
src/fireedge/src/client/components/Tables/Increments/row.js
Normal file
@ -0,0 +1,83 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
/* eslint-disable jsdoc/require-jsdoc */
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import {
|
||||
HardDrive as SizeIcon,
|
||||
RefreshCircular as FullIcon,
|
||||
Refresh as IncrementIcon,
|
||||
} from 'iconoir-react'
|
||||
import { Typography } from '@mui/material'
|
||||
|
||||
import Timer from 'client/components/Timer'
|
||||
import { StatusChip } from 'client/components/Status'
|
||||
import { rowStyles } from 'client/components/Tables/styles'
|
||||
import { T } from 'client/constants'
|
||||
import { prettyBytes } from 'client/utils'
|
||||
|
||||
import * as Helper from 'client/models/Helper'
|
||||
|
||||
const Row = ({ original, value, ...props }) => {
|
||||
const classes = rowStyles()
|
||||
const { ID, TYPE, DATE, SIZE, SOURCE } = value
|
||||
|
||||
const labels = [...new Set([TYPE])].filter(Boolean)
|
||||
|
||||
const time = Helper.timeFromMilliseconds(+DATE)
|
||||
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
data-cy={`increment-${ID}`}
|
||||
style={{ marginLeft: TYPE === 'FULL' ? '' : '1.5em' }}
|
||||
>
|
||||
<div className={classes.main}>
|
||||
<div className={classes.title}>
|
||||
<span>{TYPE === 'FULL' ? <FullIcon /> : <IncrementIcon />}</span>
|
||||
<Typography noWrap component="span" data-cy="name">
|
||||
{SOURCE}
|
||||
</Typography>
|
||||
<span className={classes.labels}>
|
||||
{labels.map((label) => (
|
||||
<StatusChip key={label} text={label} />
|
||||
))}
|
||||
</span>
|
||||
</div>
|
||||
<div className={classes.caption}>
|
||||
<span>{`#${ID}`}</span>
|
||||
<span title={time.toFormat('ff')}>
|
||||
<Timer translateWord={T.RegisteredAt} initial={time} />
|
||||
</span>
|
||||
<span title={`${T.BackupSize}: ${prettyBytes(SIZE, 'MB')}`}>
|
||||
<SizeIcon />
|
||||
<span>{` ${prettyBytes(SIZE, 'MB')}`}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.secondary}></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Row.propTypes = {
|
||||
original: PropTypes.object,
|
||||
value: PropTypes.object,
|
||||
isSelected: PropTypes.bool,
|
||||
handleClick: PropTypes.func,
|
||||
}
|
||||
|
||||
export default Row
|
@ -21,6 +21,7 @@ import EnhancedTable from 'client/components/Tables/Enhanced'
|
||||
import GroupsTable from 'client/components/Tables/Groups'
|
||||
import HostsTable from 'client/components/Tables/Hosts'
|
||||
import ImagesTable from 'client/components/Tables/Images'
|
||||
import IncrementsTable from 'client/components/Tables/Increments'
|
||||
import FilesTable from 'client/components/Tables/Files'
|
||||
import MarketplaceAppsTable from 'client/components/Tables/MarketplaceApps'
|
||||
import MarketplacesTable from 'client/components/Tables/Marketplaces'
|
||||
@ -51,6 +52,7 @@ export {
|
||||
GroupsTable,
|
||||
HostsTable,
|
||||
ImagesTable,
|
||||
IncrementsTable,
|
||||
MarketplaceAppsTable,
|
||||
MarketplacesTable,
|
||||
SecurityGroupsTable,
|
||||
|
@ -0,0 +1,52 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { ReactElement } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { useGetImageQuery } from 'client/features/OneApi/image'
|
||||
import { IncrementsTable } from 'client/components/Tables'
|
||||
|
||||
/**
|
||||
* Renders mainly Increments tab.
|
||||
*
|
||||
* @param {object} props - Props
|
||||
* @param {string} props.id - Image id
|
||||
* @returns {ReactElement} Increments tab
|
||||
*/
|
||||
const IncrementsTab = ({ id }) => {
|
||||
const { data: image = {} } = useGetImageQuery({ id })
|
||||
const increments = image?.BACKUP_INCREMENTS?.INCREMENT
|
||||
? Array.isArray(image.BACKUP_INCREMENTS.INCREMENT)
|
||||
? image.BACKUP_INCREMENTS.INCREMENT
|
||||
: [image.BACKUP_INCREMENTS.INCREMENT]
|
||||
: []
|
||||
|
||||
return (
|
||||
<IncrementsTable
|
||||
disableGlobalSort
|
||||
disableRowSelect
|
||||
increments={increments || []}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
IncrementsTab.propTypes = {
|
||||
tabProps: PropTypes.object,
|
||||
id: PropTypes.string,
|
||||
}
|
||||
|
||||
IncrementsTab.displayName = 'IncrementsTab'
|
||||
|
||||
export default IncrementsTab
|
@ -126,7 +126,7 @@ const ImageInfoTab = ({ tabProps = {}, id }) => {
|
||||
{attributesPanel?.enabled && (
|
||||
<AttributePanel
|
||||
{...ATTRIBUTE_FUNCTION}
|
||||
attributes={TEMPLATE}
|
||||
attributes={TEMPLATE === '' ? {} : TEMPLATE}
|
||||
actions={getActions(attributesPanel?.actions)}
|
||||
title={Tr(T.Attributes)}
|
||||
/>
|
||||
|
@ -25,11 +25,13 @@ import { RESOURCE_NAMES } from 'client/constants'
|
||||
import Tabs from 'client/components/Tabs'
|
||||
import Info from 'client/components/Tabs/Backup/Info'
|
||||
import Vms from 'client/components/Tabs/Backup/Vms'
|
||||
import Increments from 'client/components/Tabs/Backup/Increments'
|
||||
|
||||
const getTabComponent = (tabName) =>
|
||||
({
|
||||
info: Info,
|
||||
vms: Vms,
|
||||
increments: Increments,
|
||||
}[tabName])
|
||||
|
||||
const BackupTabs = memo(({ id }) => {
|
||||
@ -37,7 +39,7 @@ const BackupTabs = memo(({ id }) => {
|
||||
const { isLoading, isError, error } = useGetImageQuery({ id })
|
||||
|
||||
const tabsAvailable = useMemo(() => {
|
||||
const resource = RESOURCE_NAMES.IMAGE
|
||||
const resource = RESOURCE_NAMES.BACKUP
|
||||
const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {}
|
||||
|
||||
return getAvailableInfoTabs(infoTabs, getTabComponent, id)
|
||||
|
@ -17,6 +17,8 @@ import { ReactElement } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { useGetVmQuery } from 'client/features/OneApi/vm'
|
||||
import { BackupsTable } from 'client/components/Tables'
|
||||
import { useHistory, generatePath } from 'react-router-dom'
|
||||
import { PATH } from 'client/apps/sunstone/routesOne'
|
||||
|
||||
/**
|
||||
* Renders the list of backups from a VM.
|
||||
@ -27,8 +29,22 @@ import { BackupsTable } from 'client/components/Tables'
|
||||
*/
|
||||
const VmBackupTab = ({ id }) => {
|
||||
const { data: vm = {} } = useGetVmQuery({ id })
|
||||
const path = PATH.STORAGE.BACKUPS.DETAIL
|
||||
const history = useHistory()
|
||||
|
||||
return <BackupsTable disableRowSelect disableGlobalSort vm={vm} />
|
||||
const handleRowClick = (rowId) => {
|
||||
console.log('going to: ', generatePath(path, { id: String(rowId) }))
|
||||
history.push(generatePath(path, { id: String(rowId) }))
|
||||
}
|
||||
|
||||
return (
|
||||
<BackupsTable
|
||||
disableRowSelect
|
||||
disableGlobalSort
|
||||
vm={vm}
|
||||
onRowClick={(row) => handleRowClick(row.ID)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
VmBackupTab.propTypes = {
|
||||
|
@ -43,7 +43,7 @@ const { UPDATE_CONF } = VM_ACTIONS
|
||||
const VmConfigurationTab = ({ tabProps: { actions } = {}, id }) => {
|
||||
const [updateConf] = useUpdateConfigurationMutation()
|
||||
const { data: vm = {}, isFetching } = useGetVmQuery({ id })
|
||||
const { TEMPLATE } = vm
|
||||
const { TEMPLATE, BACKUPS } = vm
|
||||
|
||||
const hypervisor = useMemo(() => getHypervisor(vm), [vm])
|
||||
|
||||
@ -59,7 +59,7 @@ const VmConfigurationTab = ({ tabProps: { actions } = {}, id }) => {
|
||||
const sections = useMemo(() => {
|
||||
const filterSection = (section) => {
|
||||
const supported = ATTR_CONF_CAN_BE_UPDATED[section] || '*'
|
||||
const attributes = TEMPLATE[section] || {}
|
||||
const attributes = TEMPLATE[section] || BACKUPS[section] || {}
|
||||
const sectionAttributes = []
|
||||
|
||||
const getAttrFromEntry = (key, value, idx) => {
|
||||
@ -106,6 +106,7 @@ const VmConfigurationTab = ({ tabProps: { actions } = {}, id }) => {
|
||||
graphicsAttributes,
|
||||
rawAttributes,
|
||||
contextAttributes,
|
||||
backupAttributes,
|
||||
] = sections
|
||||
|
||||
return (
|
||||
@ -145,6 +146,9 @@ const VmConfigurationTab = ({ tabProps: { actions } = {}, id }) => {
|
||||
{osAttributes?.length > 0 && (
|
||||
<List title={T.OSAndCpu} list={osAttributes} />
|
||||
)}
|
||||
{backupAttributes?.length > 0 && (
|
||||
<List title={T.Backup} list={backupAttributes} />
|
||||
)}
|
||||
{featuresAttributes?.length > 0 && (
|
||||
<List title={T.Features} list={featuresAttributes} />
|
||||
)}
|
||||
|
@ -399,6 +399,11 @@ module.exports = {
|
||||
Running: 'Running',
|
||||
DoNotRestoreNICAttributes: 'Do not restore NIC attributes',
|
||||
DoNotRestoreIPAttributes: 'Do not restore IP attributes',
|
||||
Full: 'Full',
|
||||
Increment: 'Increment',
|
||||
Incremental: 'Incremental',
|
||||
Mode: 'Mode',
|
||||
ResetBackup: 'Reset',
|
||||
|
||||
/* sections - templates & instances */
|
||||
Instances: 'Instances',
|
||||
|
@ -1738,4 +1738,5 @@ export const ATTR_CONF_CAN_BE_UPDATED = {
|
||||
GRAPHICS: ['TYPE', 'LISTEN', 'PASSWD', 'KEYMAP'],
|
||||
RAW: ['DATA', 'DATA_VMX', 'TYPE'],
|
||||
CONTEXT: '*',
|
||||
BACKUP_CONFIG: '*',
|
||||
}
|
||||
|
36
src/fireedge/src/client/containers/Backups/Detail.js
Normal file
36
src/fireedge/src/client/containers/Backups/Detail.js
Normal file
@ -0,0 +1,36 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2022, 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 { ReactElement } from 'react'
|
||||
import { useParams, Redirect } from 'react-router-dom'
|
||||
|
||||
import BackupTab from 'client/components/Tabs/Backup'
|
||||
|
||||
/**
|
||||
* Displays the detail information about a Virtual Machine.
|
||||
*
|
||||
* @returns {ReactElement} Virtual Machine detail component.
|
||||
*/
|
||||
function BackupDetail() {
|
||||
const { id } = useParams()
|
||||
|
||||
if (Number.isNaN(+id)) {
|
||||
return <Redirect to="/" />
|
||||
}
|
||||
|
||||
return <BackupTab id={id} />
|
||||
}
|
||||
|
||||
export default BackupDetail
|
@ -55,17 +55,13 @@ const imageApi = oneApi.injectEndpoints({
|
||||
return { params, command }
|
||||
},
|
||||
transformResponse: (data) => {
|
||||
const imagesPool = data?.IMAGE_POOL?.IMAGE
|
||||
? Array.isArray(data.IMAGE_POOL.IMAGE)
|
||||
? data.IMAGE_POOL.IMAGE
|
||||
: [data.IMAGE_POOL.IMAGE]
|
||||
: []
|
||||
|
||||
const images = imagesPool?.filter?.((image) =>
|
||||
IMAGE_TYPES_FOR_IMAGES.some(() => getType(image))
|
||||
const images = data?.IMAGE_POOL?.IMAGE?.filter?.((image) =>
|
||||
IMAGE_TYPES_FOR_IMAGES.some(
|
||||
(imageType) => imageType === getType(image)
|
||||
)
|
||||
)
|
||||
|
||||
return images.flat()
|
||||
return [images ?? []].flat()
|
||||
},
|
||||
providesTags: (images) =>
|
||||
images
|
||||
|
@ -690,7 +690,7 @@ module.exports = {
|
||||
},
|
||||
reset: {
|
||||
from: postBody,
|
||||
default: 0,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user