mirror of
https://github.com/OpenNebula/one.git
synced 2025-01-20 14:03:36 +03:00
F OpenNebula/one#6029: Add NAME and INCREMENT_ID on FSunstone (#2505)
(cherry picked from commit ef6faaa0cdf9a72b65830e6e01441099c8c7daa7)
This commit is contained in:
parent
f47bfa4a5c
commit
7591cf0dd3
@ -13,9 +13,10 @@
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
import { boolean, object, ObjectSchema } from 'yup'
|
||||
import { Field, getValidationFromFields } from 'client/utils'
|
||||
import { T, INPUT_TYPES } from 'client/constants'
|
||||
import { INPUT_TYPES, T } from 'client/constants'
|
||||
import { timeFromMilliseconds } from 'client/models/Helper'
|
||||
import { Field, arrayToOptions, getValidationFromFields } from 'client/utils'
|
||||
import { ObjectSchema, boolean, object, string } from 'yup'
|
||||
|
||||
const NO_NIC = {
|
||||
name: 'no_nic',
|
||||
@ -33,14 +34,41 @@ const NO_IP = {
|
||||
grid: { xs: 12, md: 6 },
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Field[]} Fields
|
||||
*/
|
||||
export const FIELDS = () => [NO_NIC, NO_IP]
|
||||
const NAME = {
|
||||
name: 'name',
|
||||
label: T.Name,
|
||||
type: INPUT_TYPES.TEXT,
|
||||
validation: string(),
|
||||
grid: { xs: 12, md: 6 },
|
||||
}
|
||||
|
||||
const INCREMENT_ID = ({ increments = [] }) => ({
|
||||
name: 'increment_id',
|
||||
label: T.IncrementId,
|
||||
type: INPUT_TYPES.SELECT,
|
||||
values: arrayToOptions(increments, {
|
||||
addEmpty: true,
|
||||
getText: (increment) =>
|
||||
`${increment.id}: ${timeFromMilliseconds(increment.date)
|
||||
.toFormat('ff')
|
||||
.replace(',', '')} (${increment.source})`,
|
||||
getValue: (increment) => increment.id,
|
||||
}),
|
||||
validation: string(),
|
||||
grid: { xs: 12, md: 6 },
|
||||
fieldProps: {
|
||||
disabled: increments.length === 0,
|
||||
},
|
||||
})
|
||||
|
||||
/**
|
||||
* @param {object} [stepProps] - Step props
|
||||
* @param {object} [data] - Backup data
|
||||
* @returns {Field[]} Fields
|
||||
*/
|
||||
export const FIELDS = (data = {}) => [NAME, INCREMENT_ID(data), NO_NIC, NO_IP]
|
||||
|
||||
/**
|
||||
* @param {object} [data] - Backup data
|
||||
* @returns {ObjectSchema} Schema
|
||||
*/
|
||||
export const SCHEMA = (stepProps) =>
|
||||
object(getValidationFromFields(FIELDS(stepProps)))
|
||||
export const SCHEMA = (data) => object(getValidationFromFields(FIELDS(data)))
|
||||
|
@ -21,21 +21,32 @@ import DatastoresTable, {
|
||||
} from 'client/components/Forms/Backup/RestoreForm/Steps/DatastoresTable'
|
||||
import { createSteps } from 'client/utils'
|
||||
|
||||
const Steps = createSteps(
|
||||
(app) => [BasicConfiguration, DatastoresTable].filter(Boolean),
|
||||
{
|
||||
transformInitialValue: (app, schema) =>
|
||||
schema.cast({}, { context: { app } }),
|
||||
transformBeforeSubmit: (formData) => {
|
||||
const { [BASIC_ID]: configuration, [DATASTORE_ID]: [datastore] = [] } =
|
||||
formData
|
||||
const Steps = createSteps([BasicConfiguration, DatastoresTable], {
|
||||
transformInitialValue: (increments, schema) => {
|
||||
const castedValuesBasic = schema.cast(
|
||||
{ [BASIC_ID]: { increments } },
|
||||
{ stripUnknown: true }
|
||||
)
|
||||
|
||||
return {
|
||||
datastore: datastore?.ID,
|
||||
...configuration,
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
const castedValuesDatastore = schema.cast(
|
||||
{ [DATASTORE_ID]: {} },
|
||||
{ stripUnknown: true }
|
||||
)
|
||||
|
||||
return {
|
||||
[BASIC_ID]: castedValuesBasic[BASIC_ID],
|
||||
[DATASTORE_ID]: castedValuesDatastore[DATASTORE_ID],
|
||||
}
|
||||
},
|
||||
transformBeforeSubmit: (formData) => {
|
||||
const { [BASIC_ID]: configuration, [DATASTORE_ID]: [datastore] = [] } =
|
||||
formData
|
||||
|
||||
return {
|
||||
datastore: datastore?.ID,
|
||||
...configuration,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
export default Steps
|
||||
|
@ -24,11 +24,11 @@ import {
|
||||
useRestoreBackupMutation,
|
||||
} from 'client/features/OneApi/image'
|
||||
|
||||
import { ChangeGroupForm, ChangeUserForm } from 'client/components/Forms/Vm'
|
||||
import { RestoreForm } from 'client/components/Forms/Backup'
|
||||
import { ChangeGroupForm, ChangeUserForm } from 'client/components/Forms/Vm'
|
||||
import {
|
||||
createActions,
|
||||
GlobalAction,
|
||||
createActions,
|
||||
} from 'client/components/Tables/Enhanced/Utils'
|
||||
|
||||
import { Translate } from 'client/components/HOC'
|
||||
@ -67,7 +67,7 @@ const MessageToConfirmAction = (rows) => (
|
||||
)
|
||||
|
||||
/**
|
||||
* Generates the actions to operate resources on Image table.
|
||||
* Generates the actions to operate resources on Backup table.
|
||||
*
|
||||
* @returns {GlobalAction} - Actions
|
||||
*/
|
||||
@ -79,7 +79,7 @@ const Actions = () => {
|
||||
|
||||
const resourcesView = getResourceView(RESOURCE_NAMES.BACKUP)?.actions
|
||||
|
||||
const imageActions = useMemo(
|
||||
const backupActions = useMemo(
|
||||
() =>
|
||||
createActions({
|
||||
filters: resourcesView,
|
||||
@ -90,22 +90,42 @@ const Actions = () => {
|
||||
dataCy: `image-${IMAGE_ACTIONS.RESTORE}`,
|
||||
label: T.Restore,
|
||||
tooltip: T.Restore,
|
||||
selected: { min: 1 },
|
||||
selected: { max: 1 },
|
||||
options: [
|
||||
{
|
||||
dialogProps: {
|
||||
title: T.SelectCluster,
|
||||
title: T.RestoreBackup,
|
||||
dataCy: 'modal-select-cluster',
|
||||
},
|
||||
form: (rows) => RestoreForm(),
|
||||
form: (row) => {
|
||||
const backup = row?.[0]?.original
|
||||
let increments = backup?.BACKUP_INCREMENTS?.INCREMENT || []
|
||||
increments = Array.isArray(increments)
|
||||
? increments
|
||||
: [increments]
|
||||
increments = increments.map((increment) => ({
|
||||
id: increment.ID,
|
||||
date: increment.DATE,
|
||||
source: increment.SOURCE,
|
||||
}))
|
||||
|
||||
return RestoreForm({
|
||||
stepProps: { increments },
|
||||
initialValues: increments,
|
||||
})
|
||||
},
|
||||
onSubmit: (rows) => async (formData) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
let options = `NO_IP="${formData.no_ip}"\nNO_NIC="${formData.no_nic}"\n`
|
||||
if (formData.name) options += `NAME="${formData.name}"\n`
|
||||
if (formData.increment_id !== '')
|
||||
options += `INCREMENT_ID="${formData.increment_id}"\n`
|
||||
await Promise.all(
|
||||
ids.map((id) =>
|
||||
restoreBackup({
|
||||
id: id,
|
||||
datastore: formData.datastore,
|
||||
options: `NO_IP="${formData.no_ip}"\nNO_NIC="${formData.no_nic}"`,
|
||||
options,
|
||||
})
|
||||
)
|
||||
)
|
||||
@ -183,7 +203,7 @@ const Actions = () => {
|
||||
[view]
|
||||
)
|
||||
|
||||
return imageActions
|
||||
return backupActions
|
||||
}
|
||||
|
||||
export default Actions
|
||||
|
@ -413,6 +413,8 @@ module.exports = {
|
||||
Incremental: 'Incremental',
|
||||
Mode: 'Mode',
|
||||
ResetBackup: 'Reset',
|
||||
IncrementId: 'Increment ID',
|
||||
RestoreBackup: 'Restore backup',
|
||||
|
||||
/* sections - templates & instances */
|
||||
Instances: 'Instances',
|
||||
|
@ -13,23 +13,23 @@
|
||||
* 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, 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 SplitPane from 'client/components/SplitPane'
|
||||
import { BackupsTable } from 'client/components/Tables'
|
||||
import BackupActions from 'client/components/Tables/Backups/actions'
|
||||
import BackupTabs from 'client/components/Tabs/Backup'
|
||||
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 { useLazyGetImageQuery } from 'client/features/OneApi/image'
|
||||
|
||||
/**
|
||||
* Displays a list of Backups with a split pane between the list and selected row(s).
|
||||
@ -38,7 +38,7 @@ import { T, Image } from 'client/constants'
|
||||
*/
|
||||
function Backups() {
|
||||
const [selectedRows, onSelectedRowsChange] = useState(() => [])
|
||||
const actions = BackupActions()
|
||||
const actions = BackupActions(selectedRows)
|
||||
|
||||
const hasSelectedRows = selectedRows?.length > 0
|
||||
const moreThanOneSelected = selectedRows?.length > 1
|
||||
|
Loading…
x
Reference in New Issue
Block a user