mirror of
https://github.com/OpenNebula/one.git
synced 2025-01-08 21:17:43 +03:00
parent
12b783fd2a
commit
4b89382035
@ -18,6 +18,7 @@ import PropTypes from 'prop-types'
|
||||
|
||||
import { Db as ProviderIcon, Cloud as ProvisionIcon } from 'iconoir-react'
|
||||
|
||||
import ButtonToTriggerForm from 'client/components/Forms/ButtonToTriggerForm'
|
||||
import SelectCard, { Action } from 'client/components/Cards/SelectCard'
|
||||
import { StatusBadge } from 'client/components/Status'
|
||||
import Image from 'client/components/Image'
|
||||
@ -31,7 +32,7 @@ import {
|
||||
} from 'client/constants'
|
||||
|
||||
const ProvisionCard = memo(
|
||||
({ value, image: propImage, isSelected, handleClick, isProvider, actions }) => {
|
||||
({ value, image: propImage, isSelected, handleClick, isProvider, actions, deleteAction }) => {
|
||||
const { ID, NAME, TEMPLATE: { BODY = {} } } = value
|
||||
|
||||
const IMAGES_URL = isProvider ? PROVIDER_IMAGES_URL : PROVISION_IMAGES_URL
|
||||
@ -48,8 +49,15 @@ const ProvisionCard = memo(
|
||||
|
||||
return (
|
||||
<SelectCard
|
||||
action={actions?.map(action =>
|
||||
<Action key={action?.cy} {...action} />
|
||||
action={(actions?.length > 0 || deleteAction) && (
|
||||
<>
|
||||
{actions?.map(action =>
|
||||
<Action key={action?.cy} {...action} />
|
||||
)}
|
||||
{deleteAction && (
|
||||
<ButtonToTriggerForm {...deleteAction} />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
dataCy={isProvider ? 'provider' : 'provision'}
|
||||
handleClick={handleClick}
|
||||
@ -89,6 +97,7 @@ ProvisionCard.propTypes = {
|
||||
handleClick: PropTypes.func,
|
||||
isProvider: PropTypes.bool,
|
||||
image: PropTypes.string,
|
||||
deleteAction: PropTypes.func,
|
||||
actions: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
handleClick: PropTypes.func.isRequired,
|
||||
@ -104,6 +113,7 @@ ProvisionCard.defaultProps = {
|
||||
isProvider: false,
|
||||
isSelected: undefined,
|
||||
image: undefined,
|
||||
deleteAction: undefined,
|
||||
value: {}
|
||||
}
|
||||
|
||||
|
@ -30,8 +30,8 @@ import { NavArrowDown } from 'iconoir-react'
|
||||
|
||||
import { useDialog } from 'client/hooks'
|
||||
import { DialogConfirmation, DialogForm, DialogPropTypes } from 'client/components/Dialogs'
|
||||
import { SubmitButton, SubmitButtonPropTypes } from 'client/components/FormControl'
|
||||
import FormWithSchema from 'client/components/Forms/FormWithSchema'
|
||||
import SubmitButton, { SubmitButtonPropTypes } from 'client/components/FormControl/SubmitButton'
|
||||
import FormStepper from 'client/components/FormStepper'
|
||||
import { Translate } from 'client/components/HOC'
|
||||
|
||||
|
@ -57,18 +57,14 @@ const Provider = () => ({
|
||||
|
||||
const {
|
||||
handleSelect,
|
||||
handleUnselect
|
||||
handleClear
|
||||
} = useListForm({ key: STEP_ID, setList: setFormData })
|
||||
|
||||
const handleClick = (provider, isSelected) => {
|
||||
const { ID } = provider
|
||||
|
||||
// reset inputs when selected provider changes
|
||||
setFormData(prev => ({ ...prev, [INPUTS_ID]: undefined }))
|
||||
|
||||
isSelected
|
||||
? handleUnselect(ID, item => item.ID !== ID)
|
||||
: handleSelect(provider)
|
||||
isSelected ? handleClear() : handleSelect(provider)
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -0,0 +1,21 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2021, 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 { createForm } from 'client/utils'
|
||||
import { SCHEMA, FIELDS } from 'client/components/Forms/Provision/DeleteForm/schema'
|
||||
|
||||
const DeleteForm = createForm(SCHEMA, FIELDS)
|
||||
|
||||
export default DeleteForm
|
@ -0,0 +1,35 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Copyright 2002-2021, 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 * as yup from 'yup'
|
||||
import { INPUT_TYPES } from 'client/constants'
|
||||
import { getValidationFromFields } from 'client/utils'
|
||||
|
||||
const CLEANUP = {
|
||||
name: 'cleanup',
|
||||
label: 'Cleanup',
|
||||
type: INPUT_TYPES.SWITCH,
|
||||
tooltip: `
|
||||
Force to terminate VMs running on provisioned Hosts
|
||||
and delete all images in the datastores.`,
|
||||
validation: yup.boolean().notRequired().default(() => false)
|
||||
}
|
||||
|
||||
export const FIELDS = [
|
||||
CLEANUP
|
||||
]
|
||||
|
||||
export const SCHEMA = yup.object(getValidationFromFields(FIELDS))
|
@ -14,7 +14,9 @@
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
import CreateForm from 'client/components/Forms/Provision/CreateForm'
|
||||
import DeleteForm from 'client/components/Forms/Provision/DeleteForm'
|
||||
|
||||
export {
|
||||
CreateForm
|
||||
CreateForm,
|
||||
DeleteForm
|
||||
}
|
||||
|
@ -25,9 +25,11 @@ import { useFetch, useSearch } from 'client/hooks'
|
||||
import { useProvision, useProvisionApi } from 'client/features/One'
|
||||
import { useGeneralApi } from 'client/features/General'
|
||||
|
||||
import { DeleteForm } from 'client/components/Forms/Provision'
|
||||
import { ListHeader, ListCards } from 'client/components/List'
|
||||
import AlertError from 'client/components/Alerts/Error'
|
||||
import { ProvisionCard } from 'client/components/Cards'
|
||||
import { Translate } from 'client/components/HOC'
|
||||
|
||||
import { DialogRequest } from 'client/components/Dialogs'
|
||||
import DialogInfo from 'client/containers/Provisions/DialogInfo'
|
||||
@ -98,28 +100,34 @@ function Provisions () {
|
||||
.then(() => fetchRequest(undefined, { reload: true })),
|
||||
icon: <EditIcon />,
|
||||
cy: 'provision-configure'
|
||||
},
|
||||
{
|
||||
handleClick: () => setShowDialog({
|
||||
id: ID,
|
||||
content: props => createElement(DialogInfo, {
|
||||
...props,
|
||||
disableAllActions: true,
|
||||
displayName: 'DialogDeleteProvision'
|
||||
}),
|
||||
title: `DELETE - #${ID} ${NAME}`,
|
||||
handleAccept: () => {
|
||||
handleCloseDialog()
|
||||
|
||||
return deleteProvision(ID)
|
||||
.then(() => enqueueInfo(`Deleting provision - ID: ${ID}`))
|
||||
.then(() => fetchRequest(undefined, { reload: true }))
|
||||
}
|
||||
}),
|
||||
icon: <DeleteIcon color={theme.palette.error.dark} />,
|
||||
cy: 'provision-delete'
|
||||
}
|
||||
]
|
||||
],
|
||||
deleteAction: {
|
||||
buttonProps: {
|
||||
'data-cy': 'provision-delete',
|
||||
icon: <DeleteIcon color={theme.palette.error.dark} />
|
||||
},
|
||||
options: [{
|
||||
dialogProps: {
|
||||
title: (
|
||||
<Translate
|
||||
word={T.DeleteSomething}
|
||||
values={`#${ID} ${NAME}`}
|
||||
/>
|
||||
)
|
||||
},
|
||||
form: DeleteForm,
|
||||
onSubmit: async formData => {
|
||||
try {
|
||||
await deleteProvision(ID, formData)
|
||||
enqueueInfo(`Deleting provision - ID: ${ID}`)
|
||||
} finally {
|
||||
handleCloseDialog()
|
||||
fetchRequest(undefined, { reload: true })
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
|
@ -19,14 +19,14 @@ import { useDispatch, useSelector } from 'react-redux'
|
||||
import { unwrapResult } from '@reduxjs/toolkit'
|
||||
|
||||
import * as actions from 'client/features/One/provision/actions'
|
||||
import { RESOURCES } from 'client/features/One/slice'
|
||||
import { name, RESOURCES } from 'client/features/One/slice'
|
||||
|
||||
export const useProvisionTemplate = () => (
|
||||
useSelector(state => state.one[RESOURCES.document.defaults])
|
||||
useSelector(state => state[name]?.[RESOURCES.document.defaults])
|
||||
)
|
||||
|
||||
export const useProvision = () => (
|
||||
useSelector(state => state.one[RESOURCES.document[103]])
|
||||
useSelector(state => state[name]?.[RESOURCES.document[103]])
|
||||
)
|
||||
|
||||
export const useProvisionApi = () => {
|
||||
@ -45,7 +45,7 @@ export const useProvisionApi = () => {
|
||||
getProvisions: () => dispatch(actions.getProvisions()),
|
||||
createProvision: data => unwrapDispatch(actions.createProvision({ data })),
|
||||
configureProvision: id => unwrapDispatch(actions.configureProvision({ id })),
|
||||
deleteProvision: id => unwrapDispatch(actions.deleteProvision({ id })),
|
||||
deleteProvision: (id, data) => unwrapDispatch(actions.deleteProvision({ id, ...data })),
|
||||
getProvisionLog: id => unwrapDispatch(actions.getProvisionLog({ id })),
|
||||
|
||||
deleteDatastore: id => unwrapDispatch(actions.deleteDatastore({ id })),
|
||||
|
@ -138,13 +138,17 @@ export const provisionService = ({
|
||||
*
|
||||
* @param {object} params - Request parameters
|
||||
* @param {object} params.id - Provider id
|
||||
* @param {object} params.cleanup
|
||||
* - If `true`, force to terminate VMs running
|
||||
* on provisioned Hosts and delete all images in the datastores
|
||||
* @returns {object} Object of document deleted
|
||||
* @throws Fails when response isn't code 200
|
||||
*/
|
||||
deleteProvision: async ({ id }) => {
|
||||
deleteProvision: async ({ id, ...data }) => {
|
||||
const res = await RestClient.request({
|
||||
method: DELETE,
|
||||
url: `/api/${PROVISION}/delete/${id}`
|
||||
url: `/api/${PROVISION}/delete/${id}`,
|
||||
data
|
||||
})
|
||||
|
||||
if (!res?.id || res?.id !== httpCodes.ok.id) {
|
||||
|
@ -498,7 +498,8 @@ const deleteProvision = (res = {}, next = defaultEmptyFunction, params = {}, use
|
||||
const command = 'delete'
|
||||
const endpoint = getEndpoint()
|
||||
const authCommand = ['--user', user, '--password', password]
|
||||
const paramsCommand = [command, params.id, '--batch', '--debug', '--json', ...authCommand, ...endpoint]
|
||||
const cleanup = params.cleanup ? ['--cleanup'] : []
|
||||
const paramsCommand = [command, params.id, '--batch', '--debug', '--json', ...cleanup, ...authCommand, ...endpoint]
|
||||
|
||||
// get Log file
|
||||
const dataLog = logData(params.id, true)
|
||||
|
@ -142,7 +142,8 @@ const routes = {
|
||||
delete: {
|
||||
action: deleteProvision,
|
||||
params: {
|
||||
id: { from: fromData.resource, name: 'id', front: true }
|
||||
id: { from: fromData.resource, name: 'id', front: true },
|
||||
cleanup: { from: fromData.postBody, name: 'cleanup', front: true }
|
||||
},
|
||||
websocket: true
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user