mirror of
https://github.com/OpenNebula/one.git
synced 2025-08-29 09:49:28 +03:00
@ -24,6 +24,8 @@ resource_name: "VM"
|
|||||||
# Actions - Which buttons are visible to operate over the resources
|
# Actions - Which buttons are visible to operate over the resources
|
||||||
|
|
||||||
actions:
|
actions:
|
||||||
|
refresh: true
|
||||||
|
create_dialog: true
|
||||||
deploy: true
|
deploy: true
|
||||||
migrate: true
|
migrate: true
|
||||||
migrate_live: true
|
migrate_live: true
|
||||||
@ -46,11 +48,12 @@ actions:
|
|||||||
resched: true
|
resched: true
|
||||||
unresched: true
|
unresched: true
|
||||||
save_as_template: true
|
save_as_template: true
|
||||||
lockU: true
|
chown: true
|
||||||
|
chgrp: true
|
||||||
|
lock: true
|
||||||
unlock: true
|
unlock: true
|
||||||
startvnc: true
|
vmrc: true
|
||||||
startvmrc: true
|
spice: true
|
||||||
startspice: true
|
|
||||||
vnc: true
|
vnc: true
|
||||||
ssh: true
|
ssh: true
|
||||||
rdp: true
|
rdp: true
|
||||||
|
@ -24,6 +24,7 @@ resource_name: "VM"
|
|||||||
# Actions - Which buttons are visible to operate over the resources
|
# Actions - Which buttons are visible to operate over the resources
|
||||||
|
|
||||||
actions:
|
actions:
|
||||||
|
refresh: true
|
||||||
create_dialog: true
|
create_dialog: true
|
||||||
deploy: true
|
deploy: true
|
||||||
migrate: true
|
migrate: true
|
||||||
@ -46,12 +47,13 @@ actions:
|
|||||||
terminate_hard: true
|
terminate_hard: true
|
||||||
resched: true
|
resched: true
|
||||||
unresched: true
|
unresched: true
|
||||||
save_as_template: true
|
save_as_template: false
|
||||||
lockU: true
|
chown: false
|
||||||
|
chgrp: false
|
||||||
|
lock: true
|
||||||
unlock: true
|
unlock: true
|
||||||
startvnc: true
|
vmrc: true
|
||||||
startvmrc: true
|
spice: true
|
||||||
startspice: true
|
|
||||||
vnc: true
|
vnc: true
|
||||||
ssh: true
|
ssh: true
|
||||||
rdp: true
|
rdp: true
|
||||||
@ -82,8 +84,8 @@ info-tabs:
|
|||||||
ownership_panel:
|
ownership_panel:
|
||||||
enabled: true
|
enabled: true
|
||||||
actions:
|
actions:
|
||||||
chown: true
|
chown: false
|
||||||
chgrp: true
|
chgrp: false
|
||||||
vcenter_panel:
|
vcenter_panel:
|
||||||
enabled: true
|
enabled: true
|
||||||
actions:
|
actions:
|
||||||
|
@ -91,35 +91,44 @@ export const PATH = {
|
|||||||
TEMPLATE: {
|
TEMPLATE: {
|
||||||
VMS: {
|
VMS: {
|
||||||
LIST: '/vm-template',
|
LIST: '/vm-template',
|
||||||
|
DETAIL: '/vm-template/:id',
|
||||||
INSTANTIATE: '/vm-template/instantiate'
|
INSTANTIATE: '/vm-template/instantiate'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
STORAGE: {
|
STORAGE: {
|
||||||
DATASTORES: {
|
DATASTORES: {
|
||||||
LIST: '/datastore'
|
LIST: '/datastore',
|
||||||
|
DETAIL: '/datastore/:id'
|
||||||
},
|
},
|
||||||
IMAGES: {
|
IMAGES: {
|
||||||
LIST: '/image'
|
LIST: '/image',
|
||||||
|
DETAIL: '/image/:id'
|
||||||
},
|
},
|
||||||
FILES: {
|
FILES: {
|
||||||
LIST: '/file'
|
LIST: '/file',
|
||||||
|
DETAIL: '/file/:id'
|
||||||
},
|
},
|
||||||
MARKETPLACES: {
|
MARKETPLACES: {
|
||||||
LIST: '/marketplace'
|
LIST: '/marketplace',
|
||||||
|
DETAIL: '/marketplace/:id'
|
||||||
},
|
},
|
||||||
MARKETPLACE_APPS: {
|
MARKETPLACE_APPS: {
|
||||||
LIST: '/marketplaces-app'
|
LIST: '/marketplaces-app',
|
||||||
|
DETAIL: '/marketplaces-app/:id'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
NETWORK: {
|
NETWORK: {
|
||||||
VNETS: {
|
VNETS: {
|
||||||
LIST: '/virtual-network'
|
LIST: '/virtual-network',
|
||||||
|
DETAIL: '/virtual-network/:id'
|
||||||
},
|
},
|
||||||
VN_TEMPLATES: {
|
VN_TEMPLATES: {
|
||||||
LIST: '/network-template'
|
LIST: '/network-template',
|
||||||
|
DETAIL: '/network-template/:id'
|
||||||
},
|
},
|
||||||
SEC_GROUPS: {
|
SEC_GROUPS: {
|
||||||
LIST: '/security-group'
|
LIST: '/security-group',
|
||||||
|
DETAIL: '/security-group/:id'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
INFRASTRUCTURE: {
|
INFRASTRUCTURE: {
|
||||||
@ -132,7 +141,8 @@ export const PATH = {
|
|||||||
DETAIL: '/host/:id'
|
DETAIL: '/host/:id'
|
||||||
},
|
},
|
||||||
ZONES: {
|
ZONES: {
|
||||||
LIST: '/zone'
|
LIST: '/zone',
|
||||||
|
DETAIL: '/zone/:id'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
SYSTEM: {
|
SYSTEM: {
|
||||||
|
@ -43,7 +43,7 @@ const useStyles = makeStyles(theme => ({
|
|||||||
|
|
||||||
const ButtonComponent = forwardRef(
|
const ButtonComponent = forwardRef(
|
||||||
({ icon, endicon, children, size = 'small', ...props }, ref) =>
|
({ icon, endicon, children, size = 'small', ...props }, ref) =>
|
||||||
icon ? (
|
icon && !endicon ? (
|
||||||
<IconButton ref={ref} {...props}>{children}</IconButton>
|
<IconButton ref={ref} {...props}>{children}</IconButton>
|
||||||
) : (
|
) : (
|
||||||
<Button ref={ref}
|
<Button ref={ref}
|
||||||
|
@ -37,7 +37,6 @@ import { Translate } from 'client/components/HOC'
|
|||||||
|
|
||||||
const ButtonToTriggerForm = ({
|
const ButtonToTriggerForm = ({
|
||||||
buttonProps = {},
|
buttonProps = {},
|
||||||
dialogProps = {},
|
|
||||||
options = []
|
options = []
|
||||||
}) => {
|
}) => {
|
||||||
const buttonId = buttonProps['data-cy'] ?? 'main-button-form'
|
const buttonId = buttonProps['data-cy'] ?? 'main-button-form'
|
||||||
@ -47,7 +46,7 @@ const ButtonToTriggerForm = ({
|
|||||||
const open = Boolean(anchorEl)
|
const open = Boolean(anchorEl)
|
||||||
|
|
||||||
const { display, show, hide, values: Form } = useDialog()
|
const { display, show, hide, values: Form } = useDialog()
|
||||||
const { onSubmit: handleSubmit, form, isConfirmDialog = false } = Form ?? {}
|
const { onSubmit: handleSubmit, form, isConfirmDialog = false, dialogProps = {} } = Form ?? {}
|
||||||
|
|
||||||
const formConfig = useMemo(() => form?.() ?? {}, [form])
|
const formConfig = useMemo(() => form?.() ?? {}, [form])
|
||||||
const { steps, defaultValues, resolver, fields, transformBeforeSubmit } = formConfig
|
const { steps, defaultValues, resolver, fields, transformBeforeSubmit } = formConfig
|
||||||
@ -96,9 +95,10 @@ const ButtonToTriggerForm = ({
|
|||||||
<Paper variant='outlined'>
|
<Paper variant='outlined'>
|
||||||
<ClickAwayListener onClickAway={handleClose}>
|
<ClickAwayListener onClickAway={handleClose}>
|
||||||
<MenuList variant='menu' disablePadding dense>
|
<MenuList variant='menu' disablePadding dense>
|
||||||
{options.map(({ cy, icon: Icon, name, ...option }) => (
|
{options.map(({ cy, disabled, icon: Icon, name, ...option }) => (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
key={name}
|
key={name}
|
||||||
|
disabled={disabled}
|
||||||
data-cy={cy}
|
data-cy={cy}
|
||||||
onClick={() => openDialogForm(option)}
|
onClick={() => openDialogForm(option)}
|
||||||
>
|
>
|
||||||
@ -150,11 +150,11 @@ const ButtonToTriggerForm = ({
|
|||||||
|
|
||||||
export const ButtonToTriggerFormPropTypes = {
|
export const ButtonToTriggerFormPropTypes = {
|
||||||
buttonProps: PropTypes.shape(SubmitButtonPropTypes),
|
buttonProps: PropTypes.shape(SubmitButtonPropTypes),
|
||||||
dialogProps: PropTypes.shape(DialogPropTypes),
|
|
||||||
options: PropTypes.arrayOf(
|
options: PropTypes.arrayOf(
|
||||||
PropTypes.shape({
|
PropTypes.shape({
|
||||||
cy: PropTypes.string,
|
cy: PropTypes.string,
|
||||||
isConfirmDialog: PropTypes.bool,
|
isConfirmDialog: PropTypes.bool,
|
||||||
|
dialogProps: PropTypes.shape(DialogPropTypes),
|
||||||
name: PropTypes.string,
|
name: PropTypes.string,
|
||||||
icon: PropTypes.any,
|
icon: PropTypes.any,
|
||||||
form: PropTypes.func,
|
form: PropTypes.func,
|
||||||
|
@ -67,12 +67,10 @@ const Networking = ({ data, setFormData }) => {
|
|||||||
buttonProps={{
|
buttonProps={{
|
||||||
color: 'secondary',
|
color: 'secondary',
|
||||||
'data-cy': 'add-nic',
|
'data-cy': 'add-nic',
|
||||||
label: 'Add nic'
|
label: Tr(T.AttachNic)
|
||||||
}}
|
|
||||||
dialogProps={{
|
|
||||||
title: `Add new: ${Tr(T.NIC)}`
|
|
||||||
}}
|
}}
|
||||||
options={[{
|
options={[{
|
||||||
|
dialogProps: { title: T.AttachNic },
|
||||||
form: () => AttachNicForm({ nics }),
|
form: () => AttachNicForm({ nics }),
|
||||||
onSubmit: handleSave
|
onSubmit: handleSave
|
||||||
}]}
|
}]}
|
||||||
@ -118,10 +116,10 @@ const Networking = ({ data, setFormData }) => {
|
|||||||
icon: <Edit size={18} />,
|
icon: <Edit size={18} />,
|
||||||
tooltip: <Translate word={T.Edit} />
|
tooltip: <Translate word={T.Edit} />
|
||||||
}}
|
}}
|
||||||
dialogProps={{
|
|
||||||
title: <><Translate word={T.Edit} />{`: ${NAME} - ${NETWORK}`}</>
|
|
||||||
}}
|
|
||||||
options={[{
|
options={[{
|
||||||
|
dialogProps: {
|
||||||
|
title: <Translate word={T.EditSomething} values={[`${NAME} - ${NETWORK}`]} />
|
||||||
|
},
|
||||||
form: () => AttachNicForm({ nics }, item),
|
form: () => AttachNicForm({ nics }, item),
|
||||||
onSubmit: newValues => handleSave(newValues, NAME)
|
onSubmit: newValues => handleSave(newValues, NAME)
|
||||||
}]}
|
}]}
|
||||||
|
@ -60,22 +60,19 @@ const ScheduleAction = ({ data, setFormData }) => {
|
|||||||
'data-cy': 'add-sched-action',
|
'data-cy': 'add-sched-action',
|
||||||
label: Tr(T.AddAction)
|
label: Tr(T.AddAction)
|
||||||
}}
|
}}
|
||||||
dialogProps={{
|
|
||||||
title: Tr(T.ScheduledAction)
|
|
||||||
}}
|
|
||||||
options={[{
|
options={[{
|
||||||
cy: 'add-sched-action-punctual',
|
cy: 'add-sched-action-punctual',
|
||||||
name: 'Punctual action',
|
name: 'Punctual action',
|
||||||
|
dialogProps: { title: T.ScheduledAction },
|
||||||
form: () => PunctualForm(),
|
form: () => PunctualForm(),
|
||||||
onSubmit: formData =>
|
onSubmit: formData => handleSave(SCHED_ACTION_SCHEMA.cast(formData))
|
||||||
handleSave(SCHED_ACTION_SCHEMA.cast(formData))
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
cy: 'add-sched-action-relative',
|
cy: 'add-sched-action-relative',
|
||||||
name: 'Relative action',
|
name: 'Relative action',
|
||||||
|
dialogProps: { title: T.ScheduledAction },
|
||||||
form: () => RelativeForm(),
|
form: () => RelativeForm(),
|
||||||
onSubmit: formData =>
|
onSubmit: formData => handleSave(SCHED_ACTION_SCHEMA.cast(formData))
|
||||||
handleSave(SCHED_ACTION_SCHEMA.cast(formData))
|
|
||||||
}]}
|
}]}
|
||||||
/>
|
/>
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
@ -100,10 +97,10 @@ const ScheduleAction = ({ data, setFormData }) => {
|
|||||||
icon: <Edit size={18} />,
|
icon: <Edit size={18} />,
|
||||||
tooltip: <Translate word={T.Edit} />
|
tooltip: <Translate word={T.Edit} />
|
||||||
}}
|
}}
|
||||||
dialogProps={{
|
|
||||||
title: <><Translate word={T.Edit} />{`: ${NAME}`}</>
|
|
||||||
}}
|
|
||||||
options={[{
|
options={[{
|
||||||
|
dialogProps: {
|
||||||
|
title: <><Translate word={T.Edit} />{`: ${NAME}`}</>
|
||||||
|
},
|
||||||
form: () => isRelative
|
form: () => isRelative
|
||||||
? RelativeForm(undefined, item)
|
? RelativeForm(undefined, item)
|
||||||
: PunctualForm(undefined, item),
|
: PunctualForm(undefined, item),
|
||||||
|
@ -75,21 +75,20 @@ const Storage = ({ data, setFormData }) => {
|
|||||||
buttonProps={{
|
buttonProps={{
|
||||||
color: 'secondary',
|
color: 'secondary',
|
||||||
'data-cy': 'add-disk',
|
'data-cy': 'add-disk',
|
||||||
label: 'Add disk'
|
label: Tr(T.AttachDisk)
|
||||||
}}
|
|
||||||
dialogProps={{
|
|
||||||
title: `Add new: ${Tr(T.Disk)}`
|
|
||||||
}}
|
}}
|
||||||
options={[
|
options={[
|
||||||
{
|
{
|
||||||
cy: 'attach-image-disk',
|
cy: 'attach-image-disk',
|
||||||
name: T.Image,
|
name: T.Image,
|
||||||
|
dialogProps: { title: T.AttachImage },
|
||||||
form: () => ImageSteps({ hypervisor: HYPERVISOR }),
|
form: () => ImageSteps({ hypervisor: HYPERVISOR }),
|
||||||
onSubmit: handleSave
|
onSubmit: handleSave
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
cy: 'attach-volatile-disk',
|
cy: 'attach-volatile-disk',
|
||||||
name: T.Volatile,
|
name: T.Volatile,
|
||||||
|
dialogProps: { title: T.AttachVolatile },
|
||||||
form: () => VolatileSteps({ hypervisor: HYPERVISOR }),
|
form: () => VolatileSteps({ hypervisor: HYPERVISOR }),
|
||||||
onSubmit: handleSave
|
onSubmit: handleSave
|
||||||
}
|
}
|
||||||
@ -164,10 +163,10 @@ const Storage = ({ data, setFormData }) => {
|
|||||||
icon: <Edit size={18} />,
|
icon: <Edit size={18} />,
|
||||||
tooltip: <Translate word={T.Edit} />
|
tooltip: <Translate word={T.Edit} />
|
||||||
}}
|
}}
|
||||||
dialogProps={{
|
|
||||||
title: <><Translate word={T.Edit} />{`: ${NAME}`}</>
|
|
||||||
}}
|
|
||||||
options={[{
|
options={[{
|
||||||
|
dialogProps: {
|
||||||
|
title: <Translate word={T.EditSomething} values={[NAME]} />
|
||||||
|
},
|
||||||
form: () => isVolatile
|
form: () => isVolatile
|
||||||
? VolatileSteps({ hypervisor: HYPERVISOR }, item)
|
? VolatileSteps({ hypervisor: HYPERVISOR }, item)
|
||||||
: ImageSteps({ hypervisor: HYPERVISOR }, item),
|
: ImageSteps({ hypervisor: HYPERVISOR }, item),
|
||||||
|
@ -21,6 +21,7 @@ import { sprintf } from 'sprintf-js'
|
|||||||
|
|
||||||
import { useAuth } from 'client/features/Auth'
|
import { useAuth } from 'client/features/Auth'
|
||||||
import { DEFAULT_LANGUAGE, LANGUAGES_URL } from 'client/constants'
|
import { DEFAULT_LANGUAGE, LANGUAGES_URL } from 'client/constants'
|
||||||
|
import { isDevelopment } from 'client/utils'
|
||||||
|
|
||||||
const TranslateContext = createContext()
|
const TranslateContext = createContext()
|
||||||
let languageScript = root.document?.createElement('script')
|
let languageScript = root.document?.createElement('script')
|
||||||
@ -39,7 +40,7 @@ const GenerateScript = (
|
|||||||
root.document.body.appendChild(script)
|
root.document.body.appendChild(script)
|
||||||
languageScript = script
|
languageScript = script
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('Error while generating script language')
|
isDevelopment() && console.error('Error while generating script language', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,12 +85,12 @@ const ActionItem = memo(({ item, selectedRows }) => {
|
|||||||
) : (
|
) : (
|
||||||
<ButtonToTriggerForm
|
<ButtonToTriggerForm
|
||||||
buttonProps={buttonProps}
|
buttonProps={buttonProps}
|
||||||
dialogProps={{
|
options={options?.map(({ form, onSubmit, ...option }) => ({
|
||||||
|
dialogProps: {
|
||||||
...dialogProps,
|
...dialogProps,
|
||||||
title: typeof title === 'function' ? title(selectedRows) : title,
|
title: typeof title === 'function' ? title(selectedRows) : title,
|
||||||
children: typeof children === 'function' ? children(selectedRows) : children
|
children: typeof children === 'function' ? children(selectedRows) : children
|
||||||
}}
|
},
|
||||||
options={options?.map(({ form, onSubmit, ...option }) => ({
|
|
||||||
form: form ? () => form(selectedRows) : undefined,
|
form: form ? () => form(selectedRows) : undefined,
|
||||||
onSubmit: data => onSubmit(data, selectedRows),
|
onSubmit: data => onSubmit(data, selectedRows),
|
||||||
...option
|
...option
|
||||||
|
@ -59,9 +59,9 @@ const GlobalActions = ({ globalActions, selectedRows }) => {
|
|||||||
<Action key={item.accessor} item={item} />
|
<Action key={item.accessor} item={item} />
|
||||||
))}
|
))}
|
||||||
{numberOfRowSelected > 0 && (
|
{numberOfRowSelected > 0 && (
|
||||||
actionsSelected?.map(item => {
|
actionsSelected?.map((item, idx) => {
|
||||||
const { min = 1, max = Number.MAX_SAFE_INTEGER } = item?.selected ?? {}
|
const { min = 1, max = Number.MAX_SAFE_INTEGER } = item?.selected ?? {}
|
||||||
const key = item.accessor ?? item.label
|
const key = item.accessor ?? item.label ?? item.tooltip ?? idx
|
||||||
|
|
||||||
if (min < numberOfRowSelected && numberOfRowSelected > max) {
|
if (min < numberOfRowSelected && numberOfRowSelected > max) {
|
||||||
return null
|
return null
|
||||||
|
@ -21,12 +21,9 @@ import {
|
|||||||
AddSquare,
|
AddSquare,
|
||||||
Import,
|
Import,
|
||||||
Trash,
|
Trash,
|
||||||
|
PlayOutline,
|
||||||
Lock,
|
Lock,
|
||||||
NoLock,
|
|
||||||
UserSquareAlt,
|
|
||||||
Group,
|
Group,
|
||||||
ShareAndroid,
|
|
||||||
Undo,
|
|
||||||
Cart
|
Cart
|
||||||
} from 'iconoir-react'
|
} from 'iconoir-react'
|
||||||
|
|
||||||
@ -84,6 +81,19 @@ const Actions = () => {
|
|||||||
// TODO: go to IMPORT form
|
// TODO: go to IMPORT form
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
accessor: VM_TEMPLATE_ACTIONS.INSTANTIATE_DIALOG,
|
||||||
|
label: 'Instantiate',
|
||||||
|
tooltip: 'Instantiate',
|
||||||
|
icon: PlayOutline,
|
||||||
|
selected: { max: 1 },
|
||||||
|
action: rows => {
|
||||||
|
const template = rows?.[0]?.original ?? {}
|
||||||
|
const path = PATH.TEMPLATE.VMS.INSTANTIATE
|
||||||
|
|
||||||
|
history.push(path, template)
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
accessor: VM_TEMPLATE_ACTIONS.UPDATE_DIALOG,
|
accessor: VM_TEMPLATE_ACTIONS.UPDATE_DIALOG,
|
||||||
label: 'Update',
|
label: 'Update',
|
||||||
@ -97,23 +107,12 @@ const Actions = () => {
|
|||||||
// history.push(path)
|
// history.push(path)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
accessor: VM_TEMPLATE_ACTIONS.INSTANTIATE_DIALOG,
|
|
||||||
label: 'Instantiate',
|
|
||||||
tooltip: 'Instantiate',
|
|
||||||
selected: { max: 1 },
|
|
||||||
action: rows => {
|
|
||||||
const template = rows?.[0]?.original ?? {}
|
|
||||||
const path = PATH.TEMPLATE.VMS.INSTANTIATE
|
|
||||||
|
|
||||||
history.push(path, template)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
accessor: VM_TEMPLATE_ACTIONS.CLONE,
|
accessor: VM_TEMPLATE_ACTIONS.CLONE,
|
||||||
label: 'Clone',
|
label: 'Clone',
|
||||||
tooltip: 'Clone',
|
tooltip: 'Clone',
|
||||||
selected: true,
|
selected: true,
|
||||||
|
options: [{
|
||||||
dialogProps: {
|
dialogProps: {
|
||||||
title: rows => {
|
title: rows => {
|
||||||
const isMultiple = rows?.length > 1
|
const isMultiple = rows?.length > 1
|
||||||
@ -125,7 +124,6 @@ const Actions = () => {
|
|||||||
].filter(Boolean).join(' - ')
|
].filter(Boolean).join(' - ')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
options: [{
|
|
||||||
form: rows => {
|
form: rows => {
|
||||||
const vmTemplates = rows?.map(({ original }) => original)
|
const vmTemplates = rows?.map(({ original }) => original)
|
||||||
const stepProps = { isMultiple: vmTemplates.length > 1 }
|
const stepProps = { isMultiple: vmTemplates.length > 1 }
|
||||||
@ -153,76 +151,69 @@ const Actions = () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
tooltip: 'Change ownership',
|
tooltip: 'Change ownership',
|
||||||
label: 'Ownership',
|
icon: Group,
|
||||||
selected: true,
|
selected: true,
|
||||||
disabled: true,
|
|
||||||
options: [{
|
options: [{
|
||||||
cy: `action.${VM_TEMPLATE_ACTIONS.CHANGE_OWNER}`,
|
cy: `action.${VM_TEMPLATE_ACTIONS.CHANGE_OWNER}`,
|
||||||
icon: UserSquareAlt,
|
|
||||||
name: 'Change owner',
|
name: 'Change owner',
|
||||||
|
disabled: true,
|
||||||
isConfirmDialog: true,
|
isConfirmDialog: true,
|
||||||
onSubmit: () => undefined
|
onSubmit: () => undefined
|
||||||
}, {
|
}, {
|
||||||
cy: `action.${VM_TEMPLATE_ACTIONS.CHANGE_GROUP}`,
|
cy: `action.${VM_TEMPLATE_ACTIONS.CHANGE_GROUP}`,
|
||||||
icon: Group,
|
|
||||||
name: 'Change group',
|
name: 'Change group',
|
||||||
|
disabled: true,
|
||||||
isConfirmDialog: true,
|
isConfirmDialog: true,
|
||||||
onSubmit: () => undefined
|
onSubmit: () => undefined
|
||||||
}, {
|
}, {
|
||||||
cy: `action.${VM_TEMPLATE_ACTIONS.SHARE}`,
|
cy: `action.${VM_TEMPLATE_ACTIONS.SHARE}`,
|
||||||
icon: ShareAndroid,
|
disabled: true,
|
||||||
name: 'Share',
|
name: 'Share',
|
||||||
isConfirmDialog: true,
|
isConfirmDialog: true,
|
||||||
onSubmit: () => undefined
|
onSubmit: () => undefined
|
||||||
}, {
|
}, {
|
||||||
cy: `action.${VM_TEMPLATE_ACTIONS.UNSHARE}`,
|
cy: `action.${VM_TEMPLATE_ACTIONS.UNSHARE}`,
|
||||||
icon: Undo,
|
disabled: true,
|
||||||
name: 'Unshare',
|
name: 'Unshare',
|
||||||
isConfirmDialog: true,
|
isConfirmDialog: true,
|
||||||
onSubmit: () => undefined
|
onSubmit: () => undefined
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessor: VM_TEMPLATE_ACTIONS.LOCK,
|
tooltip: 'Lock/Unlock',
|
||||||
tooltip: 'Lock',
|
|
||||||
label: 'Lock',
|
|
||||||
icon: Lock,
|
icon: Lock,
|
||||||
selected: true,
|
selected: true,
|
||||||
|
options: [{
|
||||||
|
cy: `action.${VM_TEMPLATE_ACTIONS.LOCK}`,
|
||||||
|
name: 'Lock',
|
||||||
|
isConfirmDialog: true,
|
||||||
dialogProps: {
|
dialogProps: {
|
||||||
title: 'Lock',
|
title: 'Lock',
|
||||||
children: rows => {
|
children: rows => {
|
||||||
const templates = rows?.map?.(({ original }) => original?.NAME)
|
const templates = rows?.map?.(({ original }) => original?.NAME)
|
||||||
return 'Lock: ' + templates.join(', ')
|
return 'Templates: ' + templates.join(', ')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
options: [{
|
|
||||||
isConfirmDialog: true,
|
|
||||||
onSubmit: async (_, rows) => {
|
onSubmit: async (_, rows) => {
|
||||||
const templateIds = rows?.map?.(({ original }) => original?.ID)
|
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||||
await Promise.all(templateIds.map(id => lock(id)))
|
await Promise.all(ids.map(id => lock(id)))
|
||||||
await Promise.all(templateIds.map(id => getVmTemplate(id)))
|
await Promise.all(ids.map(id => getVmTemplate(id)))
|
||||||
}
|
}
|
||||||
}]
|
}, {
|
||||||
},
|
cy: `action.${VM_TEMPLATE_ACTIONS.UNLOCK}`,
|
||||||
{
|
name: 'Unlock',
|
||||||
accessor: VM_TEMPLATE_ACTIONS.UNLOCK,
|
isConfirmDialog: true,
|
||||||
tooltip: 'Unlock',
|
|
||||||
label: 'Unlock',
|
|
||||||
icon: NoLock,
|
|
||||||
selected: true,
|
|
||||||
dialogProps: {
|
dialogProps: {
|
||||||
title: 'Unlock',
|
title: 'Unlock',
|
||||||
children: rows => {
|
children: rows => {
|
||||||
const templates = rows?.map?.(({ original }) => original?.NAME)
|
const templates = rows?.map?.(({ original }) => original?.NAME)
|
||||||
return 'Unlock: ' + templates.join(', ')
|
return 'Templates: ' + templates.join(', ')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
options: [{
|
|
||||||
isConfirmDialog: true,
|
|
||||||
onSubmit: async (_, rows) => {
|
onSubmit: async (_, rows) => {
|
||||||
const templateIds = rows?.map?.(({ original }) => original?.ID)
|
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||||
await Promise.all(templateIds.map(id => unlock(id)))
|
await Promise.all(ids.map(id => unlock(id)))
|
||||||
await Promise.all(templateIds.map(id => getVmTemplate(id)))
|
await Promise.all(ids.map(id => getVmTemplate(id)))
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
@ -231,19 +222,19 @@ const Actions = () => {
|
|||||||
tooltip: 'Delete',
|
tooltip: 'Delete',
|
||||||
icon: Trash,
|
icon: Trash,
|
||||||
selected: true,
|
selected: true,
|
||||||
|
options: [{
|
||||||
|
isConfirmDialog: true,
|
||||||
dialogProps: {
|
dialogProps: {
|
||||||
title: 'Delete',
|
title: 'Delete',
|
||||||
children: rows => {
|
children: rows => {
|
||||||
const templates = rows?.map?.(({ original }) => original?.NAME)
|
const templates = rows?.map?.(({ original }) => original?.NAME)
|
||||||
return 'Delete: ' + templates.join(', ')
|
return 'Templates: ' + templates.join(', ')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
options: [{
|
|
||||||
isConfirmDialog: true,
|
|
||||||
onSubmit: async (_, rows) => {
|
onSubmit: async (_, rows) => {
|
||||||
const templateIds = rows?.map?.(({ original }) => original?.ID)
|
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||||
await Promise.all(templateIds.map(id => remove(id)))
|
await Promise.all(ids.map(id => remove(id)))
|
||||||
await getVmTemplates()
|
await Promise.all(ids.map(id => getVmTemplate(id)))
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
@ -14,13 +14,353 @@
|
|||||||
* limitations under the License. *
|
* limitations under the License. *
|
||||||
* ------------------------------------------------------------------------- */
|
* ------------------------------------------------------------------------- */
|
||||||
/* eslint-disable jsdoc/require-jsdoc */
|
/* eslint-disable jsdoc/require-jsdoc */
|
||||||
import * as Icons from 'iconoir-react'
|
import { useMemo } from 'react'
|
||||||
|
import { useHistory } from 'react-router-dom'
|
||||||
|
import {
|
||||||
|
RefreshDouble,
|
||||||
|
AddSquare,
|
||||||
|
PlayOutline,
|
||||||
|
SaveFloppyDisk,
|
||||||
|
TransitionRight,
|
||||||
|
SystemShut,
|
||||||
|
Group,
|
||||||
|
Trash,
|
||||||
|
Lock,
|
||||||
|
Cart
|
||||||
|
} from 'iconoir-react'
|
||||||
|
|
||||||
export default [
|
import { useAuth } from 'client/features/Auth'
|
||||||
{ title: 'Delete', icon: Icons.Trash, handleClick: () => undefined },
|
import { useVmApi } from 'client/features/One'
|
||||||
{ title: 'Resume', icon: Icons.PlayOutline, handleClick: () => undefined },
|
import { Tr } from 'client/components/HOC'
|
||||||
{ title: 'Power Off', icon: Icons.OffRounded, handleClick: () => undefined },
|
|
||||||
{ title: 'Reboot', icon: Icons.Refresh, handleClick: () => undefined },
|
// import { } from 'client/components/Forms/Vm'
|
||||||
{ title: 'Lock', icon: Icons.Lock, handleClick: () => undefined },
|
import { createActions } from 'client/components/Tables/Enhanced/Utils'
|
||||||
{ title: 'Unlock', icon: Icons.NoLock, handleClick: () => undefined }
|
import { PATH } from 'client/apps/sunstone/routesOne'
|
||||||
|
import { T, VM_ACTIONS, MARKETPLACE_APP_ACTIONS } from 'client/constants'
|
||||||
|
|
||||||
|
const Actions = () => {
|
||||||
|
const history = useHistory()
|
||||||
|
const { view, getResourceView } = useAuth()
|
||||||
|
const {
|
||||||
|
getVm,
|
||||||
|
getVms,
|
||||||
|
terminate,
|
||||||
|
terminateHard,
|
||||||
|
undeploy,
|
||||||
|
undeployHard,
|
||||||
|
poweroff,
|
||||||
|
poweroffHard,
|
||||||
|
reboot,
|
||||||
|
rebootHard,
|
||||||
|
hold,
|
||||||
|
release,
|
||||||
|
stop,
|
||||||
|
suspend,
|
||||||
|
resume,
|
||||||
|
resched,
|
||||||
|
unresched,
|
||||||
|
lock,
|
||||||
|
unlock
|
||||||
|
} = useVmApi()
|
||||||
|
|
||||||
|
const vmActions = useMemo(() => createActions({
|
||||||
|
filters: getResourceView('VM')?.actions,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
accessor: VM_ACTIONS.REFRESH,
|
||||||
|
tooltip: T.Refresh,
|
||||||
|
icon: RefreshDouble,
|
||||||
|
action: async () => {
|
||||||
|
await getVms({ state: -1 })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessor: VM_ACTIONS.CREATE_DIALOG,
|
||||||
|
tooltip: T.Create,
|
||||||
|
icon: AddSquare,
|
||||||
|
action: () => {
|
||||||
|
const path = PATH.TEMPLATE.VMS.INSTANTIATE
|
||||||
|
|
||||||
|
history.push(path)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessor: VM_ACTIONS.RESUME,
|
||||||
|
tooltip: T.Resume,
|
||||||
|
selected: true,
|
||||||
|
icon: PlayOutline,
|
||||||
|
action: async rows => {
|
||||||
|
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||||
|
await Promise.all(ids.map(id => resume(id)))
|
||||||
|
await Promise.all(ids.map(id => getVm(id)))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessor: VM_ACTIONS.SAVE_AS_TEMPLATE,
|
||||||
|
tooltip: T.SaveAsTemplate,
|
||||||
|
selected: { max: 1 },
|
||||||
|
disabled: true,
|
||||||
|
icon: SaveFloppyDisk,
|
||||||
|
action: () => {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tooltip: T.Manage,
|
||||||
|
icon: SystemShut,
|
||||||
|
selected: true,
|
||||||
|
options: [{
|
||||||
|
cy: `action.${VM_ACTIONS.SUSPEND}`,
|
||||||
|
name: T.Suspend,
|
||||||
|
isConfirmDialog: true,
|
||||||
|
onSubmit: async (_, rows) => {
|
||||||
|
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||||
|
await Promise.all(ids.map(id => suspend(id)))
|
||||||
|
await Promise.all(ids.map(id => getVm(id)))
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
cy: `action.${VM_ACTIONS.STOP}`,
|
||||||
|
name: T.Stop,
|
||||||
|
isConfirmDialog: true,
|
||||||
|
onSubmit: async (_, rows) => {
|
||||||
|
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||||
|
await Promise.all(ids.map(id => stop(id)))
|
||||||
|
await Promise.all(ids.map(id => getVm(id)))
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
cy: `action.${VM_ACTIONS.POWEROFF}`,
|
||||||
|
name: T.Poweroff,
|
||||||
|
isConfirmDialog: true,
|
||||||
|
onSubmit: async (_, rows) => {
|
||||||
|
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||||
|
await Promise.all(ids.map(id => poweroff(id)))
|
||||||
|
await Promise.all(ids.map(id => getVm(id)))
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
cy: `action.${VM_ACTIONS.POWEROFF_HARD}`,
|
||||||
|
name: T.PoweroffHard,
|
||||||
|
isConfirmDialog: true,
|
||||||
|
onSubmit: async (_, rows) => {
|
||||||
|
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||||
|
await Promise.all(ids.map(id => poweroffHard(id)))
|
||||||
|
await Promise.all(ids.map(id => getVm(id)))
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
cy: `action.${VM_ACTIONS.REBOOT}`,
|
||||||
|
name: T.Reboot,
|
||||||
|
isConfirmDialog: true,
|
||||||
|
onSubmit: async (_, rows) => {
|
||||||
|
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||||
|
await Promise.all(ids.map(id => reboot(id)))
|
||||||
|
await Promise.all(ids.map(id => getVm(id)))
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
cy: `action.${VM_ACTIONS.REBOOT_HARD}`,
|
||||||
|
name: T.RebootHard,
|
||||||
|
isConfirmDialog: true,
|
||||||
|
onSubmit: async (_, rows) => {
|
||||||
|
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||||
|
await Promise.all(ids.map(id => rebootHard(id)))
|
||||||
|
await Promise.all(ids.map(id => getVm(id)))
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
cy: `action.${VM_ACTIONS.UNDEPLOY}`,
|
||||||
|
name: T.Undeploy,
|
||||||
|
isConfirmDialog: true,
|
||||||
|
onSubmit: async (_, rows) => {
|
||||||
|
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||||
|
await Promise.all(ids.map(id => undeploy(id)))
|
||||||
|
await Promise.all(ids.map(id => getVm(id)))
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
cy: `action.${VM_ACTIONS.UNDEPLOY_HARD}`,
|
||||||
|
name: T.UndeployHard,
|
||||||
|
isConfirmDialog: true,
|
||||||
|
onSubmit: async (_, rows) => {
|
||||||
|
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||||
|
await Promise.all(ids.map(id => undeployHard(id)))
|
||||||
|
await Promise.all(ids.map(id => getVm(id)))
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tooltip: 'Hosting',
|
||||||
|
icon: TransitionRight,
|
||||||
|
selected: true,
|
||||||
|
options: [{
|
||||||
|
cy: `action.${VM_ACTIONS.DEPLOY}`,
|
||||||
|
name: T.Deploy,
|
||||||
|
disabled: true,
|
||||||
|
isConfirmDialog: true,
|
||||||
|
onSubmit: () => undefined
|
||||||
|
}, {
|
||||||
|
cy: `action.${VM_ACTIONS.MIGRATE}`,
|
||||||
|
name: T.Migrate,
|
||||||
|
disabled: true,
|
||||||
|
isConfirmDialog: true,
|
||||||
|
onSubmit: () => undefined
|
||||||
|
}, {
|
||||||
|
cy: `action.${VM_ACTIONS.MIGRATE_LIVE}`,
|
||||||
|
name: T.MigrateLive,
|
||||||
|
disabled: true,
|
||||||
|
isConfirmDialog: true,
|
||||||
|
onSubmit: () => undefined
|
||||||
|
}, {
|
||||||
|
cy: `action.${VM_ACTIONS.HOLD}`,
|
||||||
|
name: T.Hold,
|
||||||
|
isConfirmDialog: true,
|
||||||
|
onSubmit: async (_, rows) => {
|
||||||
|
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||||
|
await Promise.all(ids.map(id => hold(id)))
|
||||||
|
await Promise.all(ids.map(id => getVm(id)))
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
cy: `action.${VM_ACTIONS.RELEASE}`,
|
||||||
|
name: T.Release,
|
||||||
|
isConfirmDialog: true,
|
||||||
|
onSubmit: async (_, rows) => {
|
||||||
|
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||||
|
await Promise.all(ids.map(id => release(id)))
|
||||||
|
await Promise.all(ids.map(id => getVm(id)))
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
cy: `action.${VM_ACTIONS.RESCHED}`,
|
||||||
|
name: T.Reschedule,
|
||||||
|
isConfirmDialog: true,
|
||||||
|
onSubmit: async (_, rows) => {
|
||||||
|
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||||
|
await Promise.all(ids.map(id => resched(id)))
|
||||||
|
await Promise.all(ids.map(id => getVm(id)))
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
cy: `action.${VM_ACTIONS.UNRESCHED}`,
|
||||||
|
name: T.UnReschedule,
|
||||||
|
isConfirmDialog: true,
|
||||||
|
onSubmit: async (_, rows) => {
|
||||||
|
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||||
|
await Promise.all(ids.map(id => unresched(id)))
|
||||||
|
await Promise.all(ids.map(id => getVm(id)))
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
cy: `action.${VM_ACTIONS.RECOVER}`,
|
||||||
|
name: T.Recover,
|
||||||
|
disabled: true,
|
||||||
|
isConfirmDialog: true,
|
||||||
|
onSubmit: () => undefined
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tooltip: 'Change ownership',
|
||||||
|
icon: Group,
|
||||||
|
selected: true,
|
||||||
|
options: [{
|
||||||
|
cy: `action.${VM_ACTIONS.CHANGE_OWNER}`,
|
||||||
|
name: T.ChangeOwner,
|
||||||
|
disabled: true,
|
||||||
|
isConfirmDialog: true,
|
||||||
|
onSubmit: () => undefined
|
||||||
|
}, {
|
||||||
|
cy: `action.${VM_ACTIONS.CHANGE_GROUP}`,
|
||||||
|
name: T.ChangeGroup,
|
||||||
|
disabled: true,
|
||||||
|
isConfirmDialog: true,
|
||||||
|
onSubmit: () => undefined
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tooltip: `${Tr(T.Lock)}/${Tr(T.Unlock)}`,
|
||||||
|
icon: Lock,
|
||||||
|
selected: true,
|
||||||
|
options: [{
|
||||||
|
cy: `action.${VM_ACTIONS.LOCK}`,
|
||||||
|
name: T.Lock,
|
||||||
|
isConfirmDialog: true,
|
||||||
|
dialogProps: {
|
||||||
|
title: T.Lock,
|
||||||
|
children: rows => {
|
||||||
|
const templates = rows?.map?.(({ original }) => original?.NAME)
|
||||||
|
return 'VMs: ' + templates.join(', ')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSubmit: async (_, rows) => {
|
||||||
|
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||||
|
await Promise.all(ids.map(id => lock(id)))
|
||||||
|
await Promise.all(ids.map(id => getVm(id)))
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
cy: `action.${VM_ACTIONS.UNLOCK}`,
|
||||||
|
name: T.Unlock,
|
||||||
|
isConfirmDialog: true,
|
||||||
|
dialogProps: {
|
||||||
|
title: T.Unlock,
|
||||||
|
children: rows => {
|
||||||
|
const templates = rows?.map?.(({ original }) => original?.NAME)
|
||||||
|
return 'VMs: ' + templates.join(', ')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSubmit: async (_, rows) => {
|
||||||
|
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||||
|
await Promise.all(ids.map(id => unlock(id)))
|
||||||
|
await Promise.all(ids.map(id => getVm(id)))
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tooltip: T.Terminate,
|
||||||
|
icon: Trash,
|
||||||
|
selected: true,
|
||||||
|
options: [{
|
||||||
|
cy: `action.${VM_ACTIONS.TERMINATE}`,
|
||||||
|
name: T.Terminate,
|
||||||
|
isConfirmDialog: true,
|
||||||
|
dialogProps: {
|
||||||
|
title: T.Terminate,
|
||||||
|
children: rows => {
|
||||||
|
const templates = rows?.map?.(({ original }) => original?.NAME)
|
||||||
|
return 'VMs: ' + templates.join(', ')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSubmit: async (_, rows) => {
|
||||||
|
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||||
|
await Promise.all(ids.map(id => terminate(id)))
|
||||||
|
await Promise.all(ids.map(id => getVm(id)))
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
cy: `action.${VM_ACTIONS.TERMINATE_HARD}`,
|
||||||
|
name: T.TerminateHard,
|
||||||
|
isConfirmDialog: true,
|
||||||
|
dialogProps: {
|
||||||
|
title: T.TerminateHard,
|
||||||
|
children: rows => {
|
||||||
|
const templates = rows?.map?.(({ original }) => original?.NAME)
|
||||||
|
return 'VMs: ' + templates.join(', ')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSubmit: async (_, rows) => {
|
||||||
|
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||||
|
await Promise.all(ids.map(id => terminateHard(id)))
|
||||||
|
await Promise.all(ids.map(id => getVm(id)))
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
}), [view])
|
||||||
|
|
||||||
|
const marketplaceAppActions = useMemo(() => createActions({
|
||||||
|
filters: getResourceView('MARKETPLACE-APP')?.actions,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
accessor: MARKETPLACE_APP_ACTIONS.CREATE_DIALOG,
|
||||||
|
tooltip: 'Create Marketplace App',
|
||||||
|
icon: Cart,
|
||||||
|
selected: { max: 1 },
|
||||||
|
disabled: true,
|
||||||
|
action: rows => {
|
||||||
|
// TODO: go to Marketplace App CREATE form
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}), [view])
|
||||||
|
|
||||||
|
return [...vmActions, ...marketplaceAppActions]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Actions
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
* ------------------------------------------------------------------------- */
|
* ------------------------------------------------------------------------- */
|
||||||
import { memo } from 'react'
|
import { memo } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
import { generatePath } from 'react-router-dom'
|
||||||
|
|
||||||
import { useUserApi, useGroupApi, RESOURCES } from 'client/features/One'
|
import { useUserApi, useGroupApi, RESOURCES } from 'client/features/One'
|
||||||
import { List } from 'client/components/Tabs/Common'
|
import { List } from 'client/components/Tabs/Common'
|
||||||
@ -56,7 +57,7 @@ const Ownership = memo(({
|
|||||||
name: T.Owner,
|
name: T.Owner,
|
||||||
value: userName,
|
value: userName,
|
||||||
valueInOptionList: userId,
|
valueInOptionList: userId,
|
||||||
link: PATH.SYSTEM.USERS.DETAIL.replace(':id', userId),
|
link: generatePath(PATH.SYSTEM.USERS.DETAIL, { id: userId }),
|
||||||
canEdit: actions?.includes?.(ACTIONS.CHANGE_OWNER),
|
canEdit: actions?.includes?.(ACTIONS.CHANGE_OWNER),
|
||||||
handleGetOptionList: getUserOptions,
|
handleGetOptionList: getUserOptions,
|
||||||
handleEdit: (_, user) => handleEdit?.({ user })
|
handleEdit: (_, user) => handleEdit?.({ user })
|
||||||
@ -65,7 +66,7 @@ const Ownership = memo(({
|
|||||||
name: T.Group,
|
name: T.Group,
|
||||||
value: groupName,
|
value: groupName,
|
||||||
valueInOptionList: groupId,
|
valueInOptionList: groupId,
|
||||||
link: PATH.SYSTEM.GROUPS.DETAIL.replace(':id', groupId),
|
link: generatePath(PATH.SYSTEM.GROUPS.DETAIL, { id: groupId }),
|
||||||
canEdit: actions?.includes?.(ACTIONS.CHANGE_GROUP),
|
canEdit: actions?.includes?.(ACTIONS.CHANGE_GROUP),
|
||||||
handleGetOptionList: getGroupOptions,
|
handleGetOptionList: getGroupOptions,
|
||||||
handleEdit: (_, group) => handleEdit?.({ group })
|
handleEdit: (_, group) => handleEdit?.({ group })
|
||||||
|
@ -15,24 +15,26 @@
|
|||||||
* ------------------------------------------------------------------------- */
|
* ------------------------------------------------------------------------- */
|
||||||
/* eslint-disable jsdoc/require-jsdoc */
|
/* eslint-disable jsdoc/require-jsdoc */
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
import { generatePath } from 'react-router'
|
||||||
|
|
||||||
import { StatusChip, LinearProgressWithLabel } from 'client/components/Status'
|
import { StatusChip, LinearProgressWithLabel } from 'client/components/Status'
|
||||||
import { List } from 'client/components/Tabs/Common'
|
import { List } from 'client/components/Tabs/Common'
|
||||||
|
|
||||||
import * as Host from 'client/models/Host'
|
import { getState, getDatastores, getAllocatedInfo } from 'client/models/Host'
|
||||||
import * as Datastore from 'client/models/Datastore'
|
import { getCapacityInfo } from 'client/models/Datastore'
|
||||||
import { T, VM_ACTIONS } from 'client/constants'
|
import { T, VM_ACTIONS } from 'client/constants'
|
||||||
|
import { PATH } from 'client/apps/sunstone/routesOne'
|
||||||
|
|
||||||
const InformationPanel = ({ host = {}, handleRename, actions }) => {
|
const InformationPanel = ({ host = {}, handleRename, actions }) => {
|
||||||
const { ID, NAME, IM_MAD, VM_MAD, CLUSTER_ID, CLUSTER } = host
|
const { ID, NAME, IM_MAD, VM_MAD, CLUSTER_ID, CLUSTER } = host
|
||||||
const { name: stateName, color: stateColor } = Host.getState(host)
|
const { name: stateName, color: stateColor } = getState(host)
|
||||||
const datastores = Host.getDatastores(host)
|
const datastores = getDatastores(host)
|
||||||
const {
|
const {
|
||||||
percentCpuUsed,
|
percentCpuUsed,
|
||||||
percentCpuLabel,
|
percentCpuLabel,
|
||||||
percentMemUsed,
|
percentMemUsed,
|
||||||
percentMemLabel
|
percentMemLabel
|
||||||
} = Host.getAllocatedInfo(host)
|
} = getAllocatedInfo(host)
|
||||||
|
|
||||||
const info = [
|
const info = [
|
||||||
{ name: T.ID, value: ID },
|
{ name: T.ID, value: ID },
|
||||||
@ -46,7 +48,12 @@ const InformationPanel = ({ host = {}, handleRename, actions }) => {
|
|||||||
name: T.State,
|
name: T.State,
|
||||||
value: <StatusChip text={stateName} stateColor={stateColor} />
|
value: <StatusChip text={stateName} stateColor={stateColor} />
|
||||||
},
|
},
|
||||||
{ name: T.Cluster, value: `#${CLUSTER_ID} ${CLUSTER}` },
|
{
|
||||||
|
name: T.Cluster,
|
||||||
|
value: `#${CLUSTER_ID} ${CLUSTER}`,
|
||||||
|
link: !Number.isNaN(+CLUSTER_ID) &&
|
||||||
|
generatePath(PATH.INFRASTRUCTURE.CLUSTERS.DETAIL, { id: CLUSTER_ID })
|
||||||
|
},
|
||||||
{ name: T.IM_MAD, value: IM_MAD },
|
{ name: T.IM_MAD, value: IM_MAD },
|
||||||
{ name: T.VM_MAD, value: VM_MAD }
|
{ name: T.VM_MAD, value: VM_MAD }
|
||||||
]
|
]
|
||||||
@ -60,7 +67,7 @@ const InformationPanel = ({ host = {}, handleRename, actions }) => {
|
|||||||
}]
|
}]
|
||||||
|
|
||||||
const datastore = datastores.map(ds => {
|
const datastore = datastores.map(ds => {
|
||||||
const { percentOfUsed, percentLabel } = Datastore.getCapacityInfo(ds)
|
const { percentOfUsed, percentLabel } = getCapacityInfo(ds)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: `#${ds?.ID}`, // TODO: add datastore name
|
name: `#${ds?.ID}`, // TODO: add datastore name
|
||||||
|
@ -74,10 +74,8 @@ const InformationPanel = ({ actions, vm = {}, handleResizeCapacity }) => {
|
|||||||
'data-cy': 'resize-capacity',
|
'data-cy': 'resize-capacity',
|
||||||
label: T.Resize
|
label: T.Resize
|
||||||
}}
|
}}
|
||||||
dialogProps={{
|
|
||||||
title: T.ResizeCapacity
|
|
||||||
}}
|
|
||||||
options={[{
|
options={[{
|
||||||
|
dialogProps: { title: T.ResizeCapacity },
|
||||||
form: () => ResizeCapacityForm(undefined, vm.TEMPLATE),
|
form: () => ResizeCapacityForm(undefined, vm.TEMPLATE),
|
||||||
onSubmit: handleResizeCapacity
|
onSubmit: handleResizeCapacity
|
||||||
}]}
|
}]}
|
||||||
|
@ -14,28 +14,41 @@
|
|||||||
* limitations under the License. *
|
* limitations under the License. *
|
||||||
* ------------------------------------------------------------------------- */
|
* ------------------------------------------------------------------------- */
|
||||||
/* eslint-disable jsdoc/require-jsdoc */
|
/* eslint-disable jsdoc/require-jsdoc */
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
import { generatePath } from 'react-router-dom'
|
||||||
|
|
||||||
|
import { useCluster, useClusterApi } from 'client/features/One'
|
||||||
import { StatusChip } from 'client/components/Status'
|
import { StatusChip } from 'client/components/Status'
|
||||||
import { List } from 'client/components/Tabs/Common'
|
import { List } from 'client/components/Tabs/Common'
|
||||||
import Multiple from 'client/components/Tables/Vms/multiple'
|
import Multiple from 'client/components/Tables/Vms/multiple'
|
||||||
|
|
||||||
import * as VirtualMachine from 'client/models/VirtualMachine'
|
import { getState, getLastHistory, getIps } from 'client/models/VirtualMachine'
|
||||||
import * as Helper from 'client/models/Helper'
|
import * as Helper from 'client/models/Helper'
|
||||||
import { T, VM_ACTIONS } from 'client/constants'
|
import { T, VM_ACTIONS } from 'client/constants'
|
||||||
import { PATH } from 'client/apps/sunstone/routesOne'
|
import { PATH } from 'client/apps/sunstone/routesOne'
|
||||||
|
|
||||||
const InformationPanel = ({ vm = {}, handleRename, actions }) => {
|
const InformationPanel = ({ vm = {}, handleRename, actions }) => {
|
||||||
|
const clusters = useCluster()
|
||||||
|
const { getCluster } = useClusterApi()
|
||||||
|
|
||||||
const { ID, NAME, RESCHED, STIME, ETIME, LOCK, DEPLOY_ID } = vm
|
const { ID, NAME, RESCHED, STIME, ETIME, LOCK, DEPLOY_ID } = vm
|
||||||
|
const { name: stateName, color: stateColor } = getState(vm)
|
||||||
|
const { HID: hostId, HOSTNAME: hostname = '--', CID: clusterId } = getLastHistory(vm)
|
||||||
|
const ips = getIps(vm)
|
||||||
|
|
||||||
const { name: stateName, color: stateColor } = VirtualMachine.getState(vm)
|
const [clusterName, setClusterName] = useState(
|
||||||
|
() => clusterId === '-1' ? 'default' : clusters.find(c => c.ID === clusterId)?.NAME
|
||||||
|
)
|
||||||
|
|
||||||
const { HID: hostId, HOSTNAME: hostname = '--', CID: clusterId } = VirtualMachine.getLastHistory(vm)
|
useEffect(() => {
|
||||||
const clusterName = clusterId === '-1' ? 'default' : '--' // TODO: get from cluster list
|
const loadCluster = async () => {
|
||||||
const pathToHostDetail = PATH.INFRASTRUCTURE.HOSTS.DETAIL.replace(':id', hostId)
|
const cluster = await getCluster(clusterId)
|
||||||
const pathToClusterDetail = PATH.INFRASTRUCTURE.CLUSTERS.DETAIL.replace(':id', clusterId)
|
cluster?.NAME && setClusterName(cluster.NAME)
|
||||||
|
}
|
||||||
|
|
||||||
const ips = VirtualMachine.getIps(vm)
|
!clusterName && loadCluster()
|
||||||
|
}, [])
|
||||||
|
|
||||||
const info = [
|
const info = [
|
||||||
{ name: T.ID, value: ID },
|
{ name: T.ID, value: ID },
|
||||||
@ -69,21 +82,23 @@ const InformationPanel = ({ vm = {}, handleRename, actions }) => {
|
|||||||
name: T.EndTime,
|
name: T.EndTime,
|
||||||
value: Helper.timeToString(ETIME)
|
value: Helper.timeToString(ETIME)
|
||||||
},
|
},
|
||||||
{
|
hostId && {
|
||||||
name: T.Host,
|
name: T.Host,
|
||||||
value: hostId ? `#${hostId} ${hostname}` : '',
|
value: `#${hostId} ${hostname}`,
|
||||||
link: !Number.isNaN(+hostId) && pathToHostDetail
|
link: !Number.isNaN(+hostId) &&
|
||||||
|
generatePath(PATH.INFRASTRUCTURE.HOSTS.DETAIL, { id: hostId })
|
||||||
},
|
},
|
||||||
{
|
clusterId && {
|
||||||
name: T.Cluster,
|
name: T.Cluster,
|
||||||
value: clusterId ? `#${clusterId} ${clusterName}` : '',
|
value: clusterName ? `#${clusterId} ${clusterName}` : `#${clusterId} --`,
|
||||||
link: !Number.isNaN(+clusterId) && pathToClusterDetail
|
link: !Number.isNaN(+clusterId) &&
|
||||||
|
generatePath(PATH.INFRASTRUCTURE.CLUSTERS.DETAIL, { id: clusterId })
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: T.DeployID,
|
name: T.DeployID,
|
||||||
value: DEPLOY_ID
|
value: DEPLOY_ID
|
||||||
}
|
}
|
||||||
]
|
].filter(Boolean)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<List
|
<List
|
||||||
|
@ -59,12 +59,10 @@ const VmNetworkTab = ({ tabProps: { actions } = {} }) => {
|
|||||||
buttonProps={{
|
buttonProps={{
|
||||||
color: 'secondary',
|
color: 'secondary',
|
||||||
'data-cy': 'attach-nic',
|
'data-cy': 'attach-nic',
|
||||||
label: `${Tr(T.Attach)} ${Tr(T.NIC)}`
|
label: Tr(T.AttachNic)
|
||||||
}}
|
|
||||||
dialogProps={{
|
|
||||||
title: `${Tr(T.Attach)} ${Tr(T.NIC)}`
|
|
||||||
}}
|
}}
|
||||||
options={[{
|
options={[{
|
||||||
|
dialogProps: { title: T.AttachNic },
|
||||||
form: () => AttachNicForm({ nics }),
|
form: () => AttachNicForm({ nics }),
|
||||||
onSubmit: handleAttachNic
|
onSubmit: handleAttachNic
|
||||||
}]}
|
}]}
|
||||||
|
@ -47,18 +47,17 @@ const CreateSchedAction = memo(() => {
|
|||||||
'data-cy': 'create-sched-action',
|
'data-cy': 'create-sched-action',
|
||||||
label: Tr(T.AddAction)
|
label: Tr(T.AddAction)
|
||||||
}}
|
}}
|
||||||
dialogProps={{
|
|
||||||
title: Tr(T.ScheduledAction)
|
|
||||||
}}
|
|
||||||
options={[{
|
options={[{
|
||||||
cy: 'create-sched-action-punctual',
|
cy: 'create-sched-action-punctual',
|
||||||
name: 'Punctual action',
|
name: 'Punctual action',
|
||||||
|
dialogProps: { title: T.ScheduledAction },
|
||||||
form: () => PunctualForm(vm),
|
form: () => PunctualForm(vm),
|
||||||
onSubmit: handleCreateSchedAction
|
onSubmit: handleCreateSchedAction
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
cy: 'create-sched-action-relative',
|
cy: 'create-sched-action-relative',
|
||||||
name: 'Relative action',
|
name: 'Relative action',
|
||||||
|
dialogProps: { title: T.ScheduledAction },
|
||||||
form: () => RelativeForm(vm),
|
form: () => RelativeForm(vm),
|
||||||
onSubmit: handleCreateSchedAction
|
onSubmit: handleCreateSchedAction
|
||||||
}]}
|
}]}
|
||||||
@ -90,10 +89,10 @@ const UpdateSchedAction = memo(({ schedule, name }) => {
|
|||||||
icon: <Edit size={18} />,
|
icon: <Edit size={18} />,
|
||||||
tooltip: <Translate word={T.Edit} />
|
tooltip: <Translate word={T.Edit} />
|
||||||
}}
|
}}
|
||||||
dialogProps={{
|
|
||||||
title: `${Tr(T.Update)} ${T.ScheduledAction}: ${name}`
|
|
||||||
}}
|
|
||||||
options={[{
|
options={[{
|
||||||
|
dialogProps: {
|
||||||
|
title: <Translate word={T.UpdateScheduledAction} values={[name]} />
|
||||||
|
},
|
||||||
form: () => isRelative
|
form: () => isRelative
|
||||||
? RelativeForm(vm, schedule)
|
? RelativeForm(vm, schedule)
|
||||||
: PunctualForm(vm, schedule),
|
: PunctualForm(vm, schedule),
|
||||||
@ -122,12 +121,12 @@ const DeleteSchedAction = memo(({ schedule, name }) => {
|
|||||||
icon: <Trash size={18} />,
|
icon: <Trash size={18} />,
|
||||||
tooltip: <Translate word={T.Delete} />
|
tooltip: <Translate word={T.Delete} />
|
||||||
}}
|
}}
|
||||||
dialogProps={{
|
|
||||||
title: `${Tr(T.Delete)} ${Tr(T.ScheduledAction)}: ${name}`,
|
|
||||||
children: <p>{Tr(T.DoYouWantProceed)}</p>
|
|
||||||
}}
|
|
||||||
options={[{
|
options={[{
|
||||||
isConfirmDialog: true,
|
isConfirmDialog: true,
|
||||||
|
dialogProps: {
|
||||||
|
title: <Translate word={T.DeleteScheduledAction} values={[name]} />,
|
||||||
|
children: <p>{Tr(T.DoYouWantProceed)}</p>
|
||||||
|
},
|
||||||
onSubmit: handleDelete
|
onSubmit: handleDelete
|
||||||
}]}
|
}]}
|
||||||
/>
|
/>
|
||||||
@ -166,7 +165,9 @@ const CharterAction = memo(() => {
|
|||||||
icon: <ClockOutline />,
|
icon: <ClockOutline />,
|
||||||
tooltip: Tr(T.Charter)
|
tooltip: Tr(T.Charter)
|
||||||
}}
|
}}
|
||||||
dialogProps={{
|
options={[{
|
||||||
|
isConfirmDialog: true,
|
||||||
|
dialogProps: {
|
||||||
title: Tr(T.ScheduledAction),
|
title: Tr(T.ScheduledAction),
|
||||||
children: (
|
children: (
|
||||||
<>
|
<>
|
||||||
@ -194,9 +195,7 @@ const CharterAction = memo(() => {
|
|||||||
<p>{Tr(T.DoYouWantProceed)}</p>
|
<p>{Tr(T.DoYouWantProceed)}</p>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}}
|
},
|
||||||
options={[{
|
|
||||||
isConfirmDialog: true,
|
|
||||||
onSubmit: handleCreateCharter
|
onSubmit: handleCreateCharter
|
||||||
}]}
|
}]}
|
||||||
/>
|
/>
|
||||||
|
@ -23,7 +23,7 @@ import { useVmApi } from 'client/features/One'
|
|||||||
import { TabContext } from 'client/components/Tabs/TabProvider'
|
import { TabContext } from 'client/components/Tabs/TabProvider'
|
||||||
import ButtonToTriggerForm from 'client/components/Forms/ButtonToTriggerForm'
|
import ButtonToTriggerForm from 'client/components/Forms/ButtonToTriggerForm'
|
||||||
|
|
||||||
import { Tr } from 'client/components/HOC'
|
import { Tr, Translate } from 'client/components/HOC'
|
||||||
import { T, VM_ACTIONS } from 'client/constants'
|
import { T, VM_ACTIONS } from 'client/constants'
|
||||||
|
|
||||||
const RevertAction = memo(({ snapshot }) => {
|
const RevertAction = memo(({ snapshot }) => {
|
||||||
@ -39,12 +39,12 @@ const RevertAction = memo(({ snapshot }) => {
|
|||||||
'data-cy': `${VM_ACTIONS.SNAPSHOT_REVERT}-${SNAPSHOT_ID}`,
|
'data-cy': `${VM_ACTIONS.SNAPSHOT_REVERT}-${SNAPSHOT_ID}`,
|
||||||
icon: <UndoAction size={18} />
|
icon: <UndoAction size={18} />
|
||||||
}}
|
}}
|
||||||
dialogProps={{
|
|
||||||
title: `${Tr(T.Revert)}: #${SNAPSHOT_ID} - ${NAME}`,
|
|
||||||
children: <p>{Tr(T.DoYouWantProceed)}</p>
|
|
||||||
}}
|
|
||||||
options={[{
|
options={[{
|
||||||
isConfirmDialog: true,
|
isConfirmDialog: true,
|
||||||
|
dialogProps: {
|
||||||
|
title: <Translate word={T.RevertSomething} values={`#${SNAPSHOT_ID} - ${NAME}`} />,
|
||||||
|
children: <p>{Tr(T.DoYouWantProceed)}</p>
|
||||||
|
},
|
||||||
onSubmit: handleRevert
|
onSubmit: handleRevert
|
||||||
}]}
|
}]}
|
||||||
/>
|
/>
|
||||||
@ -64,12 +64,12 @@ const DeleteAction = memo(({ snapshot }) => {
|
|||||||
'data-cy': `${VM_ACTIONS.SNAPSHOT_DELETE}-${SNAPSHOT_ID}`,
|
'data-cy': `${VM_ACTIONS.SNAPSHOT_DELETE}-${SNAPSHOT_ID}`,
|
||||||
icon: <Trash size={18} />
|
icon: <Trash size={18} />
|
||||||
}}
|
}}
|
||||||
dialogProps={{
|
|
||||||
title: `${Tr(T.Delete)}: #${SNAPSHOT_ID} - ${NAME}`,
|
|
||||||
children: <p>{Tr(T.DoYouWantProceed)}</p>
|
|
||||||
}}
|
|
||||||
options={[{
|
options={[{
|
||||||
isConfirmDialog: true,
|
isConfirmDialog: true,
|
||||||
|
dialogProps: {
|
||||||
|
title: <Translate word={T.DeleteSomething} values={`#${SNAPSHOT_ID} - ${NAME}`} />,
|
||||||
|
children: <p>{Tr(T.DoYouWantProceed)}</p>
|
||||||
|
},
|
||||||
onSubmit: handleDelete
|
onSubmit: handleDelete
|
||||||
}]}
|
}]}
|
||||||
/>
|
/>
|
||||||
|
@ -52,10 +52,8 @@ const VmSnapshotTab = ({ tabProps: { actions } = {} }) => {
|
|||||||
'data-cy': 'snapshot-create',
|
'data-cy': 'snapshot-create',
|
||||||
label: Tr(T.TakeSnapshot)
|
label: Tr(T.TakeSnapshot)
|
||||||
}}
|
}}
|
||||||
dialogProps={{
|
|
||||||
title: Tr(T.TakeSnapshot)
|
|
||||||
}}
|
|
||||||
options={[{
|
options={[{
|
||||||
|
dialogProps: { title: T.TakeSnapshot },
|
||||||
form: () => CreateSnapshotForm(),
|
form: () => CreateSnapshotForm(),
|
||||||
onSubmit: handleSnapshotCreate
|
onSubmit: handleSnapshotCreate
|
||||||
}]}
|
}]}
|
||||||
|
@ -24,7 +24,7 @@ import { TabContext } from 'client/components/Tabs/TabProvider'
|
|||||||
import ButtonToTriggerForm from 'client/components/Forms/ButtonToTriggerForm'
|
import ButtonToTriggerForm from 'client/components/Forms/ButtonToTriggerForm'
|
||||||
import { SaveAsDiskForm, CreateDiskSnapshotForm, ResizeDiskForm } from 'client/components/Forms/Vm'
|
import { SaveAsDiskForm, CreateDiskSnapshotForm, ResizeDiskForm } from 'client/components/Forms/Vm'
|
||||||
|
|
||||||
import { Tr } from 'client/components/HOC'
|
import { Tr, Translate } from 'client/components/HOC'
|
||||||
import { T, VM_ACTIONS } from 'client/constants'
|
import { T, VM_ACTIONS } from 'client/constants'
|
||||||
|
|
||||||
const DetachAction = memo(({ disk, name: imageName }) => {
|
const DetachAction = memo(({ disk, name: imageName }) => {
|
||||||
@ -41,12 +41,12 @@ const DetachAction = memo(({ disk, name: imageName }) => {
|
|||||||
icon: <Trash size={18} />,
|
icon: <Trash size={18} />,
|
||||||
tooltip: Tr(T.Detach)
|
tooltip: Tr(T.Detach)
|
||||||
}}
|
}}
|
||||||
dialogProps={{
|
|
||||||
title: `${Tr(T.Detach)}: #${DISK_ID} - ${imageName}`,
|
|
||||||
children: <p>{Tr(T.DoYouWantProceed)}</p>
|
|
||||||
}}
|
|
||||||
options={[{
|
options={[{
|
||||||
isConfirmDialog: true,
|
isConfirmDialog: true,
|
||||||
|
dialogProps: {
|
||||||
|
title: <Translate word={T.DetachSomething} values={`#${DISK_ID} - ${imageName}`} />,
|
||||||
|
children: <p>{Tr(T.DoYouWantProceed)}</p>
|
||||||
|
},
|
||||||
onSubmit: handleDetach
|
onSubmit: handleDetach
|
||||||
}]}
|
}]}
|
||||||
/>
|
/>
|
||||||
@ -74,12 +74,13 @@ const SaveAsAction = memo(({ disk, snapshot, name: imageName }) => {
|
|||||||
icon: <SaveActionFloppy size={18} />,
|
icon: <SaveActionFloppy size={18} />,
|
||||||
tooltip: Tr(T.SaveAs)
|
tooltip: Tr(T.SaveAs)
|
||||||
}}
|
}}
|
||||||
dialogProps={{
|
|
||||||
title: snapshot
|
|
||||||
? `${Tr(T.SaveAs)} ${Tr(T.Image)}: #${snapshotId} - ${snapshotName}`
|
|
||||||
: `${Tr(T.SaveAs)} ${Tr(T.Image)}: #${diskId} - ${imageName}`
|
|
||||||
}}
|
|
||||||
options={[{
|
options={[{
|
||||||
|
dialogProps: {
|
||||||
|
title: snapshot
|
||||||
|
? <Translate word={T.SaveAsImage} values={`#${snapshotId} - ${snapshotName}`} />
|
||||||
|
: <Translate word={T.SaveAsImage} values={`#${diskId} - ${imageName}`} />,
|
||||||
|
children: <p>{Tr(T.DoYouWantProceed)}</p>
|
||||||
|
},
|
||||||
form: () => SaveAsDiskForm(),
|
form: () => SaveAsDiskForm(),
|
||||||
onSubmit: handleSaveAs
|
onSubmit: handleSaveAs
|
||||||
}]}
|
}]}
|
||||||
@ -104,10 +105,15 @@ const ResizeAction = memo(({ disk, name: imageName }) => {
|
|||||||
icon: <Expand size={18} />,
|
icon: <Expand size={18} />,
|
||||||
tooltip: Tr(T.Resize)
|
tooltip: Tr(T.Resize)
|
||||||
}}
|
}}
|
||||||
dialogProps={{
|
|
||||||
title: `${Tr(T.Resize)}: #${DISK_ID} - ${imageName}`
|
|
||||||
}}
|
|
||||||
options={[{
|
options={[{
|
||||||
|
dialogProps: {
|
||||||
|
title: (
|
||||||
|
<Translate
|
||||||
|
word={T.ResizeSomething}
|
||||||
|
values={`#${DISK_ID} - ${imageName}`}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
form: () => ResizeDiskForm(undefined, disk),
|
form: () => ResizeDiskForm(undefined, disk),
|
||||||
onSubmit: handleResize
|
onSubmit: handleResize
|
||||||
}]}
|
}]}
|
||||||
@ -132,10 +138,15 @@ const SnapshotCreateAction = memo(({ disk, name: imageName }) => {
|
|||||||
icon: <Camera size={18} />,
|
icon: <Camera size={18} />,
|
||||||
tooltip: Tr(T.TakeSnapshot)
|
tooltip: Tr(T.TakeSnapshot)
|
||||||
}}
|
}}
|
||||||
dialogProps={{
|
|
||||||
title: `${Tr(T.TakeSnapshot)}: #${DISK_ID} - ${imageName}`
|
|
||||||
}}
|
|
||||||
options={[{
|
options={[{
|
||||||
|
dialogProps: {
|
||||||
|
title: (
|
||||||
|
<Translate
|
||||||
|
word={T.TakeSnapshotSomething}
|
||||||
|
values={`#${DISK_ID} - ${imageName}`}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
form: () => CreateDiskSnapshotForm(),
|
form: () => CreateDiskSnapshotForm(),
|
||||||
onSubmit: handleSnapshotCreate
|
onSubmit: handleSnapshotCreate
|
||||||
}]}
|
}]}
|
||||||
@ -163,10 +174,11 @@ const SnapshotRenameAction = memo(({ disk, snapshot }) => {
|
|||||||
icon: <Edit size={18} />,
|
icon: <Edit size={18} />,
|
||||||
tooltip: Tr(T.Edit)
|
tooltip: Tr(T.Edit)
|
||||||
}}
|
}}
|
||||||
dialogProps={{
|
|
||||||
title: `${Tr(T.Rename)}: #${ID} - ${NAME}`
|
|
||||||
}}
|
|
||||||
options={[{
|
options={[{
|
||||||
|
dialogProps: {
|
||||||
|
title: <Translate word={T.RenameSomething} values={`#${ID} - ${NAME}`} />,
|
||||||
|
children: <p>{Tr(T.DoYouWantProceed)}</p>
|
||||||
|
},
|
||||||
form: () => CreateDiskSnapshotForm(undefined, snapshot),
|
form: () => CreateDiskSnapshotForm(undefined, snapshot),
|
||||||
onSubmit: handleRename
|
onSubmit: handleRename
|
||||||
}]}
|
}]}
|
||||||
@ -192,12 +204,12 @@ const SnapshotRevertAction = memo(({ disk, snapshot }) => {
|
|||||||
icon: <UndoAction size={18} />,
|
icon: <UndoAction size={18} />,
|
||||||
tooltip: Tr(T.Revert)
|
tooltip: Tr(T.Revert)
|
||||||
}}
|
}}
|
||||||
dialogProps={{
|
|
||||||
title: `${Tr(T.Revert)}: #${ID} - ${NAME}`,
|
|
||||||
children: <p>{Tr(T.DoYouWantProceed)}</p>
|
|
||||||
}}
|
|
||||||
options={[{
|
options={[{
|
||||||
isConfirmDialog: true,
|
isConfirmDialog: true,
|
||||||
|
dialogProps: {
|
||||||
|
title: <Translate word={T.RevertSomething} values={`#${ID} - ${NAME}`} />,
|
||||||
|
children: <p>{Tr(T.DoYouWantProceed)}</p>
|
||||||
|
},
|
||||||
onSubmit: handleRevert
|
onSubmit: handleRevert
|
||||||
}]}
|
}]}
|
||||||
/>
|
/>
|
||||||
@ -222,12 +234,12 @@ const SnapshotDeleteAction = memo(({ disk, snapshot }) => {
|
|||||||
icon: <Trash size={18} />,
|
icon: <Trash size={18} />,
|
||||||
tooltip: Tr(T.Delete)
|
tooltip: Tr(T.Delete)
|
||||||
}}
|
}}
|
||||||
dialogProps={{
|
|
||||||
title: `${Tr(T.Delete)}: #${ID} - ${NAME}`,
|
|
||||||
children: <p>{Tr(T.DoYouWantProceed)}</p>
|
|
||||||
}}
|
|
||||||
options={[{
|
options={[{
|
||||||
isConfirmDialog: true,
|
isConfirmDialog: true,
|
||||||
|
dialogProps: {
|
||||||
|
title: <Translate word={T.DeleteSomething} values={`#${ID} - ${NAME}`} />,
|
||||||
|
children: <p>{Tr(T.DoYouWantProceed)}</p>
|
||||||
|
},
|
||||||
onSubmit: handleDelete
|
onSubmit: handleDelete
|
||||||
}]}
|
}]}
|
||||||
/>
|
/>
|
||||||
|
@ -51,21 +51,20 @@ const VmStorageTab = ({ tabProps: { actions } = {} }) => {
|
|||||||
buttonProps={{
|
buttonProps={{
|
||||||
color: 'secondary',
|
color: 'secondary',
|
||||||
'data-cy': 'attach-disk',
|
'data-cy': 'attach-disk',
|
||||||
label: `${Tr(T.Attach)} ${Tr(T.Disk)}`
|
label: Tr(T.AttachDisk)
|
||||||
}}
|
|
||||||
dialogProps={{
|
|
||||||
title: `${Tr(T.Attach)} ${Tr(T.Disk)}`
|
|
||||||
}}
|
}}
|
||||||
options={[
|
options={[
|
||||||
{
|
{
|
||||||
cy: 'attach-image-disk',
|
cy: 'attach-image-disk',
|
||||||
name: T.Image,
|
name: T.Image,
|
||||||
|
dialogProps: { title: T.AttachImage },
|
||||||
form: () => ImageSteps({ hypervisor }),
|
form: () => ImageSteps({ hypervisor }),
|
||||||
onSubmit: handleAttachDisk
|
onSubmit: handleAttachDisk
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
cy: 'attach-volatile-disk',
|
cy: 'attach-volatile-disk',
|
||||||
name: T.Volatile,
|
name: T.Volatile,
|
||||||
|
dialogProps: { title: T.AttachVolatile },
|
||||||
form: () => VolatileSteps({ hypervisor }),
|
form: () => VolatileSteps({ hypervisor }),
|
||||||
onSubmit: handleAttachDisk
|
onSubmit: handleAttachDisk
|
||||||
}
|
}
|
||||||
|
@ -29,41 +29,79 @@ module.exports = {
|
|||||||
Active: 'Active',
|
Active: 'Active',
|
||||||
AddAction: 'Add action',
|
AddAction: 'Add action',
|
||||||
Attach: 'Attach',
|
Attach: 'Attach',
|
||||||
|
AttachDisk: 'Attach disk',
|
||||||
|
AttachImage: 'Attach image disk',
|
||||||
|
AttachVolatile: 'Attach volatile disk',
|
||||||
|
AttachNic: 'Attach NIC',
|
||||||
BackToList: 'Back to %s list',
|
BackToList: 'Back to %s list',
|
||||||
Cancel: 'Cancel',
|
Cancel: 'Cancel',
|
||||||
|
Change: 'Change',
|
||||||
|
ChangeGroup: 'Change group',
|
||||||
|
ChangeOwner: 'Change owner',
|
||||||
Clone: 'Clone',
|
Clone: 'Clone',
|
||||||
Configuration: 'Configuration',
|
Configuration: 'Configuration',
|
||||||
|
Create: 'Create',
|
||||||
Delete: 'Delete',
|
Delete: 'Delete',
|
||||||
DeleteSomething: 'Delete %s',
|
DeleteScheduledAction: 'Delete scheduled action: %s',
|
||||||
|
DeleteSomething: 'Delete: %s',
|
||||||
Deploy: 'Deploy',
|
Deploy: 'Deploy',
|
||||||
Detach: 'Detach',
|
Detach: 'Detach',
|
||||||
DetachSomething: 'Detach %s',
|
DetachSomething: 'Detach: %s',
|
||||||
Done: 'Done',
|
Done: 'Done',
|
||||||
Edit: 'Edit',
|
Edit: 'Edit',
|
||||||
|
EditSomething: 'Edit: %s',
|
||||||
Finish: 'Finish',
|
Finish: 'Finish',
|
||||||
|
Hold: 'Hold',
|
||||||
Info: 'Info',
|
Info: 'Info',
|
||||||
Instantiate: 'Instantiate',
|
Instantiate: 'Instantiate',
|
||||||
|
Lock: 'Lock',
|
||||||
|
Migrate: 'Migrate',
|
||||||
|
MigrateLive: 'Migrate live',
|
||||||
|
Poweroff: 'Poweroff',
|
||||||
|
PoweroffHard: 'Poweroff hard',
|
||||||
|
Reboot: 'Reboot',
|
||||||
|
RebootHard: 'Reboot hard',
|
||||||
|
Recover: 'Recover',
|
||||||
|
Refresh: 'Refresh',
|
||||||
|
Release: 'Release',
|
||||||
Remove: 'Remove',
|
Remove: 'Remove',
|
||||||
Rename: 'Rename',
|
Rename: 'Rename',
|
||||||
|
RenameSomething: 'Rename: %s',
|
||||||
|
Reschedule: 'Reschedule',
|
||||||
Resize: 'Resize',
|
Resize: 'Resize',
|
||||||
|
ResizeSomething: 'Resize: %s',
|
||||||
ResizeCapacity: 'Resize capacity',
|
ResizeCapacity: 'Resize capacity',
|
||||||
|
Resume: 'Resume',
|
||||||
Revert: 'Revert',
|
Revert: 'Revert',
|
||||||
|
RevertSomething: 'Revert: %s',
|
||||||
|
Terminate: 'Terminate',
|
||||||
|
TerminateHard: 'Terminate hard',
|
||||||
Save: 'Save',
|
Save: 'Save',
|
||||||
SaveAs: 'Save as',
|
SaveAs: 'Save as',
|
||||||
|
SaveAsImage: 'Save as Image',
|
||||||
|
SaveAsTemplate: 'Save as Template',
|
||||||
Search: 'Search',
|
Search: 'Search',
|
||||||
Select: 'Select',
|
Select: 'Select',
|
||||||
SelectVmTemplate: 'Select a VM Template',
|
|
||||||
SelectGroup: 'Select a group',
|
SelectGroup: 'Select a group',
|
||||||
SelectRequest: 'Select request',
|
SelectRequest: 'Select request',
|
||||||
|
SelectVmTemplate: 'Select a VM Template',
|
||||||
Show: 'Show',
|
Show: 'Show',
|
||||||
ShowAll: 'Show all',
|
ShowAll: 'Show all',
|
||||||
SignIn: 'Sign In',
|
SignIn: 'Sign In',
|
||||||
SignOut: 'Sign Out',
|
SignOut: 'Sign Out',
|
||||||
|
Stop: 'Stop',
|
||||||
Submit: 'Submit',
|
Submit: 'Submit',
|
||||||
|
Suspend: 'Suspend',
|
||||||
Take: 'Take',
|
Take: 'Take',
|
||||||
TakeSnapshot: 'Take snapshot',
|
TakeSnapshot: 'Take snapshot',
|
||||||
TakeSnapshotOf: 'Take snapshot of %s',
|
TakeSnapshotSomething: 'Take snapshot: %s',
|
||||||
|
TakeSnapshotOf: 'Take snapshot: %s',
|
||||||
|
Undeploy: 'Undeploy',
|
||||||
|
UndeployHard: 'Undeploy hard',
|
||||||
|
Unlock: 'Unlock',
|
||||||
|
UnReschedule: 'Un-Reschedule',
|
||||||
Update: 'Update',
|
Update: 'Update',
|
||||||
|
UpdateScheduledAction: 'Update scheduled action: %s',
|
||||||
|
|
||||||
/* questions */
|
/* questions */
|
||||||
Yes: 'Yes',
|
Yes: 'Yes',
|
||||||
@ -241,7 +279,6 @@ module.exports = {
|
|||||||
|
|
||||||
/* instances schema */
|
/* instances schema */
|
||||||
IP: 'IP',
|
IP: 'IP',
|
||||||
Reschedule: 'Reschedule',
|
|
||||||
DeployID: 'Deploy ID',
|
DeployID: 'Deploy ID',
|
||||||
Deployment: 'Deployment',
|
Deployment: 'Deployment',
|
||||||
Monitoring: 'Monitoring',
|
Monitoring: 'Monitoring',
|
||||||
|
@ -432,39 +432,41 @@ export const VM_LCM_STATES = [
|
|||||||
|
|
||||||
/** @enum {string} Virtual machine actions */
|
/** @enum {string} Virtual machine actions */
|
||||||
export const VM_ACTIONS = {
|
export const VM_ACTIONS = {
|
||||||
|
REFRESH: 'refresh',
|
||||||
CREATE_DIALOG: 'create_dialog',
|
CREATE_DIALOG: 'create_dialog',
|
||||||
DEPLOY: 'deploy',
|
DEPLOY: 'deploy',
|
||||||
MIGRATE: 'migrate',
|
|
||||||
MIGRATE_LIVE: 'migrate_live',
|
|
||||||
MIGRATE_POFF: 'migrate_poff',
|
|
||||||
MIGRATE_POFF_HARD: 'migrate_poff_hard',
|
|
||||||
HOLD: 'hold',
|
HOLD: 'hold',
|
||||||
RELEASE: 'release',
|
LOCK: 'lock',
|
||||||
SUSPEND: 'suspend',
|
MIGRATE_LIVE: 'migrate_live',
|
||||||
RESUME: 'resume',
|
MIGRATE_POFF_HARD: 'migrate_poff_hard',
|
||||||
STOP: 'stop',
|
MIGRATE_POFF: 'migrate_poff',
|
||||||
RECOVER: 'recover',
|
MIGRATE: 'migrate',
|
||||||
REBOOT: 'reboot',
|
|
||||||
REBOOT_HARD: 'reboot_hard',
|
|
||||||
POWEROFF: 'poweroff',
|
|
||||||
POWEROFF_HARD: 'poweroff_hard',
|
POWEROFF_HARD: 'poweroff_hard',
|
||||||
UNDEPLOY: 'undeploy',
|
POWEROFF: 'poweroff',
|
||||||
UNDEPLOY_HARD: 'undeploy_hard',
|
REBOOT_HARD: 'reboot_hard',
|
||||||
TERMINATE: 'terminate',
|
REBOOT: 'reboot',
|
||||||
TERMINATE_HARD: 'terminate_hard',
|
RECOVER: 'recover',
|
||||||
|
RELEASE: 'release',
|
||||||
RESCHED: 'resched',
|
RESCHED: 'resched',
|
||||||
UNRESCHED: 'unresched',
|
RESUME: 'resume',
|
||||||
SAVE_AS_TEMPLATE: 'save_as_template',
|
SAVE_AS_TEMPLATE: 'save_as_template',
|
||||||
LOCK: 'lockU',
|
STOP: 'stop',
|
||||||
|
SUSPEND: 'suspend',
|
||||||
|
TERMINATE_HARD: 'terminate_hard',
|
||||||
|
TERMINATE: 'terminate',
|
||||||
|
UNDEPLOY_HARD: 'undeploy_hard',
|
||||||
|
UNDEPLOY: 'undeploy',
|
||||||
UNLOCK: 'unlock',
|
UNLOCK: 'unlock',
|
||||||
STAR_TVNC: 'startvnc',
|
UNRESCHED: 'unresched',
|
||||||
STAR_TVMRC: 'startvmrc',
|
|
||||||
STAR_TSPICE: 'startspice',
|
// REMOTE
|
||||||
|
VMRC: 'vmrc',
|
||||||
|
SPICE: 'spice',
|
||||||
VNC: 'vnc',
|
VNC: 'vnc',
|
||||||
SSH: 'ssh',
|
SSH: 'ssh',
|
||||||
RDP: 'rdp',
|
RDP: 'rdp',
|
||||||
SAVE_RDP: 'save_rdp',
|
FILE_RDP: 'file_rdp',
|
||||||
SAVE_VIRT_VIEWER: 'save_virt_viewer',
|
FILE_VIRT_VIEWER: 'file_virt_viewer',
|
||||||
|
|
||||||
RENAME: ACTIONS.RENAME,
|
RENAME: ACTIONS.RENAME,
|
||||||
CHANGE_MODE: ACTIONS.CHANGE_MODE,
|
CHANGE_MODE: ACTIONS.CHANGE_MODE,
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
/* eslint-disable jsdoc/require-jsdoc */
|
/* eslint-disable jsdoc/require-jsdoc */
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
import { useHistory } from 'react-router-dom'
|
import { useHistory, generatePath } from 'react-router-dom'
|
||||||
import { Container, Box } from '@material-ui/core'
|
import { Container, Box } from '@material-ui/core'
|
||||||
|
|
||||||
import { PATH } from 'client/apps/sunstone/routesFlow'
|
import { PATH } from 'client/apps/sunstone/routesFlow'
|
||||||
@ -65,9 +65,8 @@ function ApplicationsTemplates () {
|
|||||||
gridProps={{ 'data-cy': 'applications-templates' }}
|
gridProps={{ 'data-cy': 'applications-templates' }}
|
||||||
CardComponent={ApplicationTemplateCard}
|
CardComponent={ApplicationTemplateCard}
|
||||||
cardsProps={({ value }) => ({
|
cardsProps={({ value }) => ({
|
||||||
handleEdit: () => history.push(
|
handleEdit: () =>
|
||||||
PATH.APPLICATIONS_TEMPLATES.EDIT.replace(':id', value?.ID)
|
history.push(generatePath(PATH.APPLICATIONS_TEMPLATES.EDIT, { id: value?.ID })),
|
||||||
),
|
|
||||||
handleDeploy: () => setShowDialog(value),
|
handleDeploy: () => setShowDialog(value),
|
||||||
handleRemove: undefined // TODO
|
handleRemove: undefined // TODO
|
||||||
})}
|
})}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
/* eslint-disable jsdoc/require-jsdoc */
|
/* eslint-disable jsdoc/require-jsdoc */
|
||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
|
|
||||||
import { useHistory } from 'react-router-dom'
|
import { useHistory, generatePath } from 'react-router-dom'
|
||||||
import { useTheme, Container, Box } from '@material-ui/core'
|
import { useTheme, Container, Box } from '@material-ui/core'
|
||||||
import { Trash as DeleteIcon, Settings as EditIcon } from 'iconoir-react'
|
import { Trash as DeleteIcon, Settings as EditIcon } from 'iconoir-react'
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ function Providers () {
|
|||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
handleClick: () =>
|
handleClick: () =>
|
||||||
history.push(PATH.PROVIDERS.EDIT.replace(':id', ID)),
|
history.push(generatePath(PATH.PROVIDERS.EDIT, { id: ID })),
|
||||||
icon: <EditIcon />,
|
icon: <EditIcon />,
|
||||||
cy: 'provider-edit'
|
cy: 'provider-edit'
|
||||||
},
|
},
|
||||||
|
@ -38,12 +38,14 @@ const ResponseForm = ({
|
|||||||
const { control, handleSubmit, errors, formState } = useForm()
|
const { control, handleSubmit, errors, formState } = useForm()
|
||||||
|
|
||||||
const onSubmit = async dataForm => {
|
const onSubmit = async dataForm => {
|
||||||
|
try {
|
||||||
const config = requestConfig(dataForm, { name, httpMethod, params })
|
const config = requestConfig(dataForm, { name, httpMethod, params })
|
||||||
|
|
||||||
const { id, ...res } = await RestClient.request(config) ?? {}
|
const { id, ...res } = await RestClient.request(config) ?? {}
|
||||||
|
handleChangeResponse(JSON.stringify(res, null, '\t'))
|
||||||
id === 401 && console.log('ERROR')
|
} catch (err) {
|
||||||
id === 200 && handleChangeResponse(JSON.stringify(res, null, '\t'))
|
console.log('ERROR', err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -19,11 +19,13 @@ import { useState } from 'react'
|
|||||||
import { Container, Box } from '@material-ui/core'
|
import { Container, Box } from '@material-ui/core'
|
||||||
|
|
||||||
import { VmsTable } from 'client/components/Tables'
|
import { VmsTable } from 'client/components/Tables'
|
||||||
|
import VmActions from 'client/components/Tables/Vms/actions'
|
||||||
import VmTabs from 'client/components/Tabs/Vm'
|
import VmTabs from 'client/components/Tabs/Vm'
|
||||||
import SplitPane from 'client/components/SplitPane'
|
import SplitPane from 'client/components/SplitPane'
|
||||||
|
|
||||||
function VirtualMachines () {
|
function VirtualMachines () {
|
||||||
const [selectedRows, onSelectedRowsChange] = useState([])
|
const [selectedRows, onSelectedRowsChange] = useState([])
|
||||||
|
const actions = VmActions()
|
||||||
|
|
||||||
const getRowIds = () =>
|
const getRowIds = () =>
|
||||||
JSON.stringify(selectedRows?.map(row => row.id).join(', '), null, 2)
|
JSON.stringify(selectedRows?.map(row => row.id).join(', '), null, 2)
|
||||||
@ -38,7 +40,10 @@ function VirtualMachines () {
|
|||||||
component={Container}
|
component={Container}
|
||||||
>
|
>
|
||||||
<SplitPane>
|
<SplitPane>
|
||||||
<VmsTable onSelectedRowsChange={onSelectedRowsChange} />
|
<VmsTable
|
||||||
|
onSelectedRowsChange={onSelectedRowsChange}
|
||||||
|
globalActions={actions}
|
||||||
|
/>
|
||||||
|
|
||||||
{selectedRows?.length > 0 && (
|
{selectedRows?.length > 0 && (
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', overflow: 'auto' }}>
|
<div style={{ display: 'flex', flexDirection: 'column', overflow: 'auto' }}>
|
||||||
|
@ -23,7 +23,7 @@ import { httpCodes } from 'server/utils/constants'
|
|||||||
/**
|
/**
|
||||||
* @param {string} type - Name of redux action
|
* @param {string} type - Name of redux action
|
||||||
* @param {Promise} service - Request from service
|
* @param {Promise} service - Request from service
|
||||||
* @param {Function} [wrapResult] - Function to wrapping the response
|
* @param {function(object, object)} [wrapResult] - Function to wrapping the response
|
||||||
* @returns {AsyncThunkAction} Asynchronous redux action
|
* @returns {AsyncThunkAction} Asynchronous redux action
|
||||||
*/
|
*/
|
||||||
export const createAction = (type, service, wrapResult) =>
|
export const createAction = (type, service, wrapResult) =>
|
||||||
|
@ -26,23 +26,43 @@ export const getVm = createAction(`${VM}/detail`, vmService.getVm)
|
|||||||
export const getVms = createAction(
|
export const getVms = createAction(
|
||||||
`${VM}/pool`,
|
`${VM}/pool`,
|
||||||
vmService.getVms,
|
vmService.getVms,
|
||||||
(response, { vms: currentVms }) => {
|
(response, { [RESOURCES.vm]: currentVms }) => {
|
||||||
const vms = filterBy([...currentVms, ...response], 'ID')
|
const vms = filterBy([...currentVms, ...response], 'ID')
|
||||||
|
|
||||||
return { [RESOURCES.vm]: vms }
|
return { [RESOURCES.vm]: vms }
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
export const terminateVm = createAction(
|
export const terminate = createAction(`${VM}/terminate`,
|
||||||
`${VM}/delete`,
|
({ id }) => vmService.actionVm({ id, action: 'terminate' }))
|
||||||
payload => vmService.actionVm({
|
export const terminateHard = createAction(`${VM}/terminate-hard`,
|
||||||
...payload,
|
({ id }) => vmService.actionVm({ id, action: 'terminate-hard' }))
|
||||||
action: {
|
export const undeploy = createAction(`${VM}/undeploy`,
|
||||||
params: { hard: false },
|
({ id }) => vmService.actionVm({ id, action: 'undeploy' }))
|
||||||
perform: 'terminate'
|
export const undeployHard = createAction(`${VM}/undeploy-hard`,
|
||||||
}
|
({ id }) => vmService.actionVm({ id, action: 'undeploy-hard' }))
|
||||||
})
|
export const poweroff = createAction(`${VM}/poweroff`,
|
||||||
)
|
({ id }) => vmService.actionVm({ id, action: 'poweroff' }))
|
||||||
|
export const poweroffHard = createAction(`${VM}/poweroff-hard`,
|
||||||
|
({ id }) => vmService.actionVm({ id, action: 'poweroff-hard' }))
|
||||||
|
export const reboot = createAction(`${VM}/reboot`,
|
||||||
|
({ id }) => vmService.actionVm({ id, action: 'reboot' }))
|
||||||
|
export const rebootHard = createAction(`${VM}/reboot-hard`,
|
||||||
|
({ id }) => vmService.actionVm({ id, action: 'reboot-hard' }))
|
||||||
|
export const hold = createAction(`${VM}/hold`,
|
||||||
|
({ id }) => vmService.actionVm({ id, action: 'hold' }))
|
||||||
|
export const release = createAction(`${VM}/release`,
|
||||||
|
({ id }) => vmService.actionVm({ id, action: 'release' }))
|
||||||
|
export const stop = createAction(`${VM}/stop`,
|
||||||
|
({ id }) => vmService.actionVm({ id, action: 'stop' }))
|
||||||
|
export const suspend = createAction(`${VM}/suspend`,
|
||||||
|
({ id }) => vmService.actionVm({ id, action: 'suspend' }))
|
||||||
|
export const resume = createAction(`${VM}/resume`,
|
||||||
|
({ id }) => vmService.actionVm({ id, action: 'resume' }))
|
||||||
|
export const resched = createAction(`${VM}/resched`,
|
||||||
|
({ id }) => vmService.actionVm({ id, action: 'resched' }))
|
||||||
|
export const unresched = createAction(`${VM}/unresched`,
|
||||||
|
({ id }) => vmService.actionVm({ id, action: 'unresched' }))
|
||||||
|
|
||||||
export const updateUserTemplate = createAction(`${VM}/update`, vmService.updateUserTemplate)
|
export const updateUserTemplate = createAction(`${VM}/update`, vmService.updateUserTemplate)
|
||||||
export const rename = createAction(`${VM}/rename`, vmService.rename)
|
export const rename = createAction(`${VM}/rename`, vmService.rename)
|
||||||
|
@ -36,7 +36,21 @@ export const useVmApi = () => {
|
|||||||
return {
|
return {
|
||||||
getVm: id => unwrapDispatch(actions.getVm({ id })),
|
getVm: id => unwrapDispatch(actions.getVm({ id })),
|
||||||
getVms: options => unwrapDispatch(actions.getVms(options)),
|
getVms: options => unwrapDispatch(actions.getVms(options)),
|
||||||
terminateVm: id => unwrapDispatch(actions.terminateVm({ id })),
|
terminate: id => unwrapDispatch(actions.terminate({ id })),
|
||||||
|
terminateHard: id => unwrapDispatch(actions.terminateHard({ id })),
|
||||||
|
undeploy: id => unwrapDispatch(actions.undeploy({ id })),
|
||||||
|
undeployHard: id => unwrapDispatch(actions.undeployHard({ id })),
|
||||||
|
poweroff: id => unwrapDispatch(actions.poweroff({ id })),
|
||||||
|
poweroffHard: id => unwrapDispatch(actions.poweroffHard({ id })),
|
||||||
|
reboot: id => unwrapDispatch(actions.reboot({ id })),
|
||||||
|
rebootHard: id => unwrapDispatch(actions.rebootHard({ id })),
|
||||||
|
hold: id => unwrapDispatch(actions.hold({ id })),
|
||||||
|
release: id => unwrapDispatch(actions.release({ id })),
|
||||||
|
stop: id => unwrapDispatch(actions.stop({ id })),
|
||||||
|
suspend: id => unwrapDispatch(actions.suspend({ id })),
|
||||||
|
resume: id => unwrapDispatch(actions.resume({ id })),
|
||||||
|
resched: id => unwrapDispatch(actions.resched({ id })),
|
||||||
|
unresched: id => unwrapDispatch(actions.unresched({ id })),
|
||||||
updateUserTemplate: (id, template, replace) =>
|
updateUserTemplate: (id, template, replace) =>
|
||||||
unwrapDispatch(actions.updateUserTemplate({ id, template, replace })),
|
unwrapDispatch(actions.updateUserTemplate({ id, template, replace })),
|
||||||
rename: (id, name) => unwrapDispatch(actions.rename({ id, name })),
|
rename: (id, name) => unwrapDispatch(actions.rename({ id, name })),
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
* limitations under the License. *
|
* limitations under the License. *
|
||||||
* ------------------------------------------------------------------------- */
|
* ------------------------------------------------------------------------- */
|
||||||
import { useReducer, useCallback, useEffect, useRef, ReducerState, ReducerAction } from 'react'
|
import { useReducer, useCallback, useEffect, useRef, ReducerState, ReducerAction } from 'react'
|
||||||
import { fakeDelay } from 'client/utils'
|
import { fakeDelay, isDevelopment } from 'client/utils'
|
||||||
|
|
||||||
const STATUS = {
|
const STATUS = {
|
||||||
INIT: 'INIT',
|
INIT: 'INIT',
|
||||||
@ -144,7 +144,7 @@ const useFetch = (request, socket) => {
|
|||||||
const { reload = false, delay = 0 } = options
|
const { reload = false, delay = 0 } = options
|
||||||
|
|
||||||
if (!(Number.isInteger(delay) && delay >= 0)) {
|
if (!(Number.isInteger(delay) && delay >= 0)) {
|
||||||
console.error(`
|
isDevelopment() && console.error(`
|
||||||
Delay must be a number >= 0!
|
Delay must be a number >= 0!
|
||||||
If you're using it as a function, it must also return a number >= 0.`)
|
If you're using it as a function, it must also return a number >= 0.`)
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
* limitations under the License. *
|
* limitations under the License. *
|
||||||
* ------------------------------------------------------------------------- */
|
* ------------------------------------------------------------------------- */
|
||||||
import { useReducer, useCallback, useEffect, useRef, ReducerState, ReducerAction } from 'react'
|
import { useReducer, useCallback, useEffect, useRef, ReducerState, ReducerAction } from 'react'
|
||||||
import { fakeDelay } from 'client/utils'
|
import { fakeDelay, isDevelopment } from 'client/utils'
|
||||||
|
|
||||||
const STATUS = {
|
const STATUS = {
|
||||||
INIT: 'INIT',
|
INIT: 'INIT',
|
||||||
@ -126,7 +126,7 @@ const useFetchAll = () => {
|
|||||||
const { reload = false, delay = 0 } = options
|
const { reload = false, delay = 0 } = options
|
||||||
|
|
||||||
if (!(Number.isInteger(delay) && delay >= 0)) {
|
if (!(Number.isInteger(delay) && delay >= 0)) {
|
||||||
console.error(`
|
isDevelopment() && console.error(`
|
||||||
Delay must be a number >= 0!
|
Delay must be a number >= 0!
|
||||||
If you're using it as a function, it must also return a number >= 0.`)
|
If you're using it as a function, it must also return a number >= 0.`)
|
||||||
}
|
}
|
||||||
|
@ -238,11 +238,13 @@ const commandXMLRPC = (resource = '', method = '', defaultMethod = '') => {
|
|||||||
const commandWithDefault = defaultMethod
|
const commandWithDefault = defaultMethod
|
||||||
? `${command}.${defaultMethod}`
|
? `${command}.${defaultMethod}`
|
||||||
: command
|
: command
|
||||||
if (typeof method === 'string' && method !== 'action') {
|
|
||||||
|
if (method) {
|
||||||
command = allowedActions.includes(method)
|
command = allowedActions.includes(method)
|
||||||
? `${command}.${method}`
|
? `${command}.${method}`
|
||||||
: commandWithDefault
|
: commandWithDefault
|
||||||
}
|
}
|
||||||
|
|
||||||
return command
|
return command
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user