mirror of
https://github.com/OpenNebula/one.git
synced 2025-01-08 21:17:43 +03:00
parent
4083ed1d9b
commit
5313df52c9
@ -19,17 +19,17 @@ import Router from 'client/router'
|
||||
import { ENDPOINTS, PATH } from 'client/apps/provision/routes'
|
||||
import { ENDPOINTS as DEV_ENDPOINTS } from 'client/router/dev'
|
||||
|
||||
import { useGeneralApi } from 'client/features/General'
|
||||
import { useGeneral, useGeneralApi } from 'client/features/General'
|
||||
import { useAuth, useAuthApi } from 'client/features/Auth'
|
||||
import { useProvisionTemplate, useProvisionApi } from 'client/features/One'
|
||||
|
||||
import Sidebar from 'client/components/Sidebar'
|
||||
import Notifier from 'client/components/Notifier'
|
||||
import LoadingScreen from 'client/components/LoadingScreen'
|
||||
import { _APPS } from 'client/constants'
|
||||
import { isDevelopment } from 'client/utils'
|
||||
import { _APPS } from 'client/constants'
|
||||
|
||||
const APP_NAME = _APPS.provision.name
|
||||
export const APP_NAME = _APPS.provision.name
|
||||
|
||||
/**
|
||||
* Provision App component.
|
||||
@ -42,13 +42,18 @@ const ProvisionApp = () => {
|
||||
|
||||
const provisionTemplate = useProvisionTemplate()
|
||||
const { getProvisionsTemplates } = useProvisionApi()
|
||||
|
||||
const { appTitle } = useGeneral()
|
||||
const { changeAppTitle } = useGeneralApi()
|
||||
|
||||
useEffect(() => {
|
||||
appTitle !== APP_NAME && changeAppTitle(APP_NAME)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
if (jwt) {
|
||||
changeAppTitle(APP_NAME)
|
||||
getAuthUser()
|
||||
!providerConfig && await getProviderConfig()
|
||||
!provisionTemplate?.length && await getProvisionsTemplates()
|
||||
|
@ -25,11 +25,9 @@ import MuiProvider from 'client/providers/muiProvider'
|
||||
import NotistackProvider from 'client/providers/notistackProvider'
|
||||
import { TranslateProvider } from 'client/components/HOC'
|
||||
|
||||
import App from 'client/apps/provision/_app'
|
||||
import App, { APP_NAME as ProvisionAppName } from 'client/apps/provision/_app'
|
||||
import theme from 'client/apps/provision/theme'
|
||||
import { _APPS, APP_URL } from 'client/constants'
|
||||
|
||||
const APP_NAME = _APPS.provision.name
|
||||
import { APP_URL } from 'client/constants'
|
||||
|
||||
/**
|
||||
* @param {object} props - Props
|
||||
@ -51,7 +49,7 @@ const Provision = ({ store = {}, location = '', context = {} }) => (
|
||||
</StaticRouter>
|
||||
) : (
|
||||
// browser build
|
||||
<BrowserRouter basename={`${APP_URL}/${APP_NAME}`}>
|
||||
<BrowserRouter basename={`${APP_URL}/${ProvisionAppName}`}>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
)}
|
||||
@ -70,4 +68,6 @@ Provision.propTypes = {
|
||||
|
||||
Provision.displayName = 'ProvisionApp'
|
||||
|
||||
export { ProvisionAppName }
|
||||
|
||||
export default Provision
|
||||
|
@ -14,23 +14,22 @@
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
import { useEffect, useMemo, JSXElementConstructor } from 'react'
|
||||
import { Chip } from '@material-ui/core'
|
||||
|
||||
import Router from 'client/router'
|
||||
import { ENDPOINTS, PATH, getEndpointsByView } from 'client/apps/sunstone/routes'
|
||||
import { ENDPOINTS as ONE_ENDPOINTS } from 'client/apps/sunstone/routesOne'
|
||||
import { ENDPOINTS as DEV_ENDPOINTS } from 'client/router/dev'
|
||||
|
||||
import { useGeneralApi } from 'client/features/General'
|
||||
import { useGeneral, useGeneralApi } from 'client/features/General'
|
||||
import { useAuth, useAuthApi } from 'client/features/Auth'
|
||||
|
||||
import Sidebar from 'client/components/Sidebar'
|
||||
import Notifier from 'client/components/Notifier'
|
||||
import LoadingScreen from 'client/components/LoadingScreen'
|
||||
import { _APPS } from 'client/constants'
|
||||
import { isDevelopment } from 'client/utils'
|
||||
import { _APPS } from 'client/constants'
|
||||
|
||||
const APP_NAME = _APPS.sunstone.name
|
||||
export const APP_NAME = _APPS.sunstone.name
|
||||
|
||||
/**
|
||||
* Sunstone App component.
|
||||
@ -38,23 +37,23 @@ const APP_NAME = _APPS.sunstone.name
|
||||
* @returns {JSXElementConstructor} App rendered.
|
||||
*/
|
||||
const SunstoneApp = () => {
|
||||
const { isLogged, jwt, firstRender, view, views } = useAuth()
|
||||
const { isLogged, jwt, firstRender, view, views, config } = useAuth()
|
||||
const { getAuthUser, logout, getSunstoneViews, getSunstoneConfig } = useAuthApi()
|
||||
|
||||
const { appTitle } = useGeneral()
|
||||
const { changeAppTitle } = useGeneralApi()
|
||||
|
||||
useEffect(() => {
|
||||
appTitle !== APP_NAME && changeAppTitle(APP_NAME)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
if (jwt) {
|
||||
changeAppTitle(
|
||||
<>
|
||||
{APP_NAME}
|
||||
<Chip size='small' label='BETA' color='primary' />
|
||||
</>
|
||||
)
|
||||
getAuthUser()
|
||||
await getSunstoneViews()
|
||||
await getSunstoneConfig()
|
||||
!view && await getSunstoneViews()
|
||||
!config && await getSunstoneConfig()
|
||||
}
|
||||
} catch {
|
||||
logout()
|
||||
|
@ -24,11 +24,9 @@ import MuiProvider from 'client/providers/muiProvider'
|
||||
import NotistackProvider from 'client/providers/notistackProvider'
|
||||
import { TranslateProvider } from 'client/components/HOC'
|
||||
|
||||
import App from 'client/apps/sunstone/_app'
|
||||
import App, { APP_NAME as SunstoneAppName } from 'client/apps/sunstone/_app'
|
||||
import theme from 'client/apps/sunstone/theme'
|
||||
import { _APPS, APP_URL } from 'client/constants'
|
||||
|
||||
const APP_NAME = _APPS.sunstone.name
|
||||
import { APP_URL } from 'client/constants'
|
||||
|
||||
/**
|
||||
* @param {object} props - Props
|
||||
@ -49,7 +47,7 @@ const Sunstone = ({ store = {}, location = '', context = {} }) => (
|
||||
</StaticRouter>
|
||||
) : (
|
||||
// browser build
|
||||
<BrowserRouter basename={`${APP_URL}/${APP_NAME}`}>
|
||||
<BrowserRouter basename={`${APP_URL}/${SunstoneAppName}`}>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
)}
|
||||
@ -67,4 +65,6 @@ Sunstone.propTypes = {
|
||||
|
||||
Sunstone.displayName = 'SunstoneApp'
|
||||
|
||||
export { SunstoneAppName }
|
||||
|
||||
export default Sunstone
|
||||
|
@ -16,7 +16,7 @@
|
||||
/* eslint-disable jsdoc/require-jsdoc */
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { AppBar, Box, Toolbar, Typography, IconButton, useMediaQuery } from '@material-ui/core'
|
||||
import { AppBar, Box, Toolbar, Typography, IconButton, Chip, useMediaQuery } from '@material-ui/core'
|
||||
import { Menu as MenuIcon } from 'iconoir-react'
|
||||
|
||||
import { useAuth } from 'client/features/Auth'
|
||||
@ -30,7 +30,7 @@ import headerStyles from 'client/components/Header/styles'
|
||||
|
||||
const Header = () => {
|
||||
const { isOneAdmin } = useAuth()
|
||||
const { appTitle, title } = useGeneral()
|
||||
const { appTitle, title, isBeta } = useGeneral()
|
||||
const { fixMenu } = useGeneralApi()
|
||||
|
||||
const isUpLg = useMediaQuery(theme => theme.breakpoints.up('lg'))
|
||||
@ -58,7 +58,10 @@ const Header = () => {
|
||||
data-cy='header-app-title'
|
||||
>
|
||||
{'One'}
|
||||
<span className={classes.app}>{appTitle}</span>
|
||||
<span className={classes.app}>
|
||||
{appTitle}
|
||||
{isBeta && <Chip size='small' label='BETA' color='primary' />}
|
||||
</span>
|
||||
</Typography>
|
||||
)}
|
||||
<Typography
|
||||
|
@ -17,10 +17,12 @@ import { memo } from 'react'
|
||||
import { number, string, bool, oneOfType } from 'prop-types'
|
||||
import { useTheme } from '@material-ui/core'
|
||||
|
||||
import { useGeneral } from 'client/features/General'
|
||||
import { SCHEMES } from 'client/constants'
|
||||
|
||||
const OpenNebulaLogo = memo(
|
||||
({ width, height, spinner, withText, withBeta, viewBox, ...props }) => {
|
||||
({ width, height, spinner, withText, viewBox, disabledBetaText, ...props }) => {
|
||||
const { isBeta } = useGeneral()
|
||||
const { palette: { type } } = useTheme()
|
||||
const isDarkMode = type === SCHEMES.DARK
|
||||
|
||||
@ -142,7 +144,7 @@ const OpenNebulaLogo = memo(
|
||||
/>
|
||||
</g>
|
||||
)}
|
||||
{withBeta && (
|
||||
{!disabledBetaText && isBeta && (
|
||||
<g id="beta">
|
||||
<path
|
||||
fill={textColor.beta}
|
||||
@ -186,7 +188,7 @@ OpenNebulaLogo.propTypes = {
|
||||
viewBox: string,
|
||||
spinner: bool,
|
||||
withText: bool,
|
||||
withBeta: bool
|
||||
disabledBetaText: bool
|
||||
}
|
||||
|
||||
OpenNebulaLogo.defaultProps = {
|
||||
@ -195,7 +197,7 @@ OpenNebulaLogo.defaultProps = {
|
||||
viewBox: '0 0 120 45',
|
||||
spinner: false,
|
||||
withText: false,
|
||||
withBeta: false
|
||||
disabledBetaText: false
|
||||
}
|
||||
|
||||
OpenNebulaLogo.displayName = 'OpenNebulaLogo'
|
||||
|
@ -46,7 +46,6 @@ const LoadingScreen = () => {
|
||||
height={360}
|
||||
spinner
|
||||
withText
|
||||
withBeta
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
|
@ -76,6 +76,7 @@ const Sidebar = ({ endpoints }) => {
|
||||
height={50}
|
||||
withText
|
||||
className={classes.svg}
|
||||
disabledBetaText
|
||||
/>
|
||||
<IconButton onClick={handleSwapMenu}>
|
||||
{isUpLg ? <MenuIcon /> : <CloseIcon />}
|
||||
|
@ -65,7 +65,6 @@ const ActionItem = memo(({ item, selectedRows }) => {
|
||||
label,
|
||||
color = 'secondary',
|
||||
icon: Icon,
|
||||
dialogProps: { title, children, ...dialogProps } = {},
|
||||
options,
|
||||
action,
|
||||
disabled
|
||||
@ -85,16 +84,21 @@ const ActionItem = memo(({ item, selectedRows }) => {
|
||||
) : (
|
||||
<ButtonToTriggerForm
|
||||
buttonProps={buttonProps}
|
||||
options={options?.map(({ form, onSubmit, ...option }) => ({
|
||||
dialogProps: {
|
||||
...dialogProps,
|
||||
title: typeof title === 'function' ? title(selectedRows) : title,
|
||||
children: typeof children === 'function' ? children(selectedRows) : children
|
||||
},
|
||||
form: form ? () => form(selectedRows) : undefined,
|
||||
onSubmit: data => onSubmit(data, selectedRows),
|
||||
...option
|
||||
}))}
|
||||
options={options?.map(option => {
|
||||
const { form, onSubmit, dialogProps } = option ?? {}
|
||||
const { title, children } = dialogProps ?? {}
|
||||
|
||||
return {
|
||||
...option,
|
||||
dialogProps: {
|
||||
...dialogProps,
|
||||
title: typeof title === 'function' ? title(selectedRows) : title,
|
||||
children: typeof children === 'function' ? children(selectedRows) : children
|
||||
},
|
||||
form: form ? () => form(selectedRows) : undefined,
|
||||
onSubmit: data => onSubmit(data, selectedRows)
|
||||
}
|
||||
})}
|
||||
/>
|
||||
)
|
||||
}, (prev, next) => prev.selectedRows?.length === next.selectedRows?.length)
|
||||
@ -115,14 +119,14 @@ export const ActionPropTypes = PropTypes.shape({
|
||||
]),
|
||||
action: PropTypes.func,
|
||||
isConfirmDialog: PropTypes.bool,
|
||||
dialogProps: PropTypes.shape(DialogPropTypes),
|
||||
options: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
cy: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
icon: PropTypes.any,
|
||||
form: PropTypes.func,
|
||||
onSubmit: PropTypes.func
|
||||
onSubmit: PropTypes.func,
|
||||
dialogProps: PropTypes.shape(DialogPropTypes)
|
||||
})
|
||||
)
|
||||
})
|
||||
|
@ -29,11 +29,30 @@ import {
|
||||
|
||||
import { useAuth } from 'client/features/Auth'
|
||||
import { useVmTemplateApi } from 'client/features/One'
|
||||
import { Tr, Translate } from 'client/components/HOC'
|
||||
|
||||
import { CloneForm } from 'client/components/Forms/VmTemplate'
|
||||
import { createActions } from 'client/components/Tables/Enhanced/Utils'
|
||||
import { PATH } from 'client/apps/sunstone/routesOne'
|
||||
import { VM_TEMPLATE_ACTIONS, MARKETPLACE_APP_ACTIONS } from 'client/constants'
|
||||
import { T, VM_TEMPLATE_ACTIONS, MARKETPLACE_APP_ACTIONS } from 'client/constants'
|
||||
|
||||
const MessageToConfirmAction = rows => {
|
||||
const names = rows?.map?.(({ original }) => original?.NAME)
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
<Translate word={T.VMTemplates} />
|
||||
{`: ${names.join(', ')}`}
|
||||
</p>
|
||||
<p>
|
||||
<Translate word={T.DoYouWantProceed} />
|
||||
</p>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
MessageToConfirmAction.displayName = 'MessageToConfirmAction'
|
||||
|
||||
const Actions = () => {
|
||||
const history = useHistory()
|
||||
@ -52,7 +71,7 @@ const Actions = () => {
|
||||
actions: [
|
||||
{
|
||||
accessor: VM_TEMPLATE_ACTIONS.REFRESH,
|
||||
tooltip: 'Refresh',
|
||||
tooltip: Tr(T.Refresh),
|
||||
icon: RefreshDouble,
|
||||
action: async () => {
|
||||
await getVmTemplates()
|
||||
@ -60,7 +79,7 @@ const Actions = () => {
|
||||
},
|
||||
{
|
||||
accessor: VM_TEMPLATE_ACTIONS.CREATE_DIALOG,
|
||||
tooltip: 'Create',
|
||||
tooltip: Tr(T.Create),
|
||||
icon: AddSquare,
|
||||
disabled: true,
|
||||
action: rows => {
|
||||
@ -73,7 +92,7 @@ const Actions = () => {
|
||||
},
|
||||
{
|
||||
accessor: VM_TEMPLATE_ACTIONS.IMPORT_DIALOG,
|
||||
tooltip: 'Import',
|
||||
tooltip: Tr(T.Import),
|
||||
icon: Import,
|
||||
selected: { max: 1 },
|
||||
disabled: true,
|
||||
@ -83,8 +102,7 @@ const Actions = () => {
|
||||
},
|
||||
{
|
||||
accessor: VM_TEMPLATE_ACTIONS.INSTANTIATE_DIALOG,
|
||||
label: 'Instantiate',
|
||||
tooltip: 'Instantiate',
|
||||
tooltip: Tr(T.Instantiate),
|
||||
icon: PlayOutline,
|
||||
selected: { max: 1 },
|
||||
action: rows => {
|
||||
@ -96,8 +114,8 @@ const Actions = () => {
|
||||
},
|
||||
{
|
||||
accessor: VM_TEMPLATE_ACTIONS.UPDATE_DIALOG,
|
||||
label: 'Update',
|
||||
tooltip: 'Update',
|
||||
label: Tr(T.Update),
|
||||
tooltip: Tr(T.Update),
|
||||
selected: { max: 1 },
|
||||
disabled: true,
|
||||
action: rows => {
|
||||
@ -109,8 +127,8 @@ const Actions = () => {
|
||||
},
|
||||
{
|
||||
accessor: VM_TEMPLATE_ACTIONS.CLONE,
|
||||
label: 'Clone',
|
||||
tooltip: 'Clone',
|
||||
label: Tr(T.Clone),
|
||||
tooltip: Tr(T.Clone),
|
||||
selected: true,
|
||||
options: [{
|
||||
dialogProps: {
|
||||
@ -119,7 +137,7 @@ const Actions = () => {
|
||||
const { ID, NAME } = rows?.[0]?.original
|
||||
|
||||
return [
|
||||
isMultiple ? 'Clone several Templates' : 'Clone Template',
|
||||
Tr(isMultiple ? T.CloneSeveralTemplates : T.CloneTemplate),
|
||||
!isMultiple && `#${ID} ${NAME}`
|
||||
].filter(Boolean).join(' - ')
|
||||
}
|
||||
@ -150,49 +168,46 @@ const Actions = () => {
|
||||
}]
|
||||
},
|
||||
{
|
||||
tooltip: 'Change ownership',
|
||||
tooltip: Tr(T.Ownership),
|
||||
icon: Group,
|
||||
selected: true,
|
||||
options: [{
|
||||
cy: `action.${VM_TEMPLATE_ACTIONS.CHANGE_OWNER}`,
|
||||
name: 'Change owner',
|
||||
name: T.ChangeOwner,
|
||||
disabled: true,
|
||||
isConfirmDialog: true,
|
||||
onSubmit: () => undefined
|
||||
}, {
|
||||
cy: `action.${VM_TEMPLATE_ACTIONS.CHANGE_GROUP}`,
|
||||
name: 'Change group',
|
||||
name: T.ChangeGroup,
|
||||
disabled: true,
|
||||
isConfirmDialog: true,
|
||||
onSubmit: () => undefined
|
||||
}, {
|
||||
cy: `action.${VM_TEMPLATE_ACTIONS.SHARE}`,
|
||||
disabled: true,
|
||||
name: 'Share',
|
||||
name: T.Share,
|
||||
isConfirmDialog: true,
|
||||
onSubmit: () => undefined
|
||||
}, {
|
||||
cy: `action.${VM_TEMPLATE_ACTIONS.UNSHARE}`,
|
||||
disabled: true,
|
||||
name: 'Unshare',
|
||||
name: T.Unshare,
|
||||
isConfirmDialog: true,
|
||||
onSubmit: () => undefined
|
||||
}]
|
||||
},
|
||||
{
|
||||
tooltip: 'Lock/Unlock',
|
||||
tooltip: `${Tr(T.Lock)}/${Tr(T.Unlock)}`,
|
||||
icon: Lock,
|
||||
selected: true,
|
||||
options: [{
|
||||
cy: `action.${VM_TEMPLATE_ACTIONS.LOCK}`,
|
||||
name: 'Lock',
|
||||
name: T.Lock,
|
||||
isConfirmDialog: true,
|
||||
dialogProps: {
|
||||
title: 'Lock',
|
||||
children: rows => {
|
||||
const templates = rows?.map?.(({ original }) => original?.NAME)
|
||||
return 'Templates: ' + templates.join(', ')
|
||||
}
|
||||
title: T.Lock,
|
||||
children: MessageToConfirmAction
|
||||
},
|
||||
onSubmit: async (_, rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
@ -201,14 +216,11 @@ const Actions = () => {
|
||||
}
|
||||
}, {
|
||||
cy: `action.${VM_TEMPLATE_ACTIONS.UNLOCK}`,
|
||||
name: 'Unlock',
|
||||
name: T.Unlock,
|
||||
isConfirmDialog: true,
|
||||
dialogProps: {
|
||||
title: 'Unlock',
|
||||
children: rows => {
|
||||
const templates = rows?.map?.(({ original }) => original?.NAME)
|
||||
return 'Templates: ' + templates.join(', ')
|
||||
}
|
||||
title: T.Unlock,
|
||||
children: MessageToConfirmAction
|
||||
},
|
||||
onSubmit: async (_, rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
@ -219,17 +231,14 @@ const Actions = () => {
|
||||
},
|
||||
{
|
||||
accessor: VM_TEMPLATE_ACTIONS.DELETE,
|
||||
tooltip: 'Delete',
|
||||
tooltip: T.Delete,
|
||||
icon: Trash,
|
||||
selected: true,
|
||||
options: [{
|
||||
isConfirmDialog: true,
|
||||
dialogProps: {
|
||||
title: 'Delete',
|
||||
children: rows => {
|
||||
const templates = rows?.map?.(({ original }) => original?.NAME)
|
||||
return 'Templates: ' + templates.join(', ')
|
||||
}
|
||||
title: T.Delete,
|
||||
children: MessageToConfirmAction
|
||||
},
|
||||
onSubmit: async (_, rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
@ -246,7 +255,7 @@ const Actions = () => {
|
||||
actions: [
|
||||
{
|
||||
accessor: MARKETPLACE_APP_ACTIONS.CREATE_DIALOG,
|
||||
tooltip: 'Create Marketplace App',
|
||||
tooltip: T.CreateMarketApp,
|
||||
icon: Cart,
|
||||
selected: { max: 1 },
|
||||
disabled: true,
|
||||
|
@ -31,13 +31,31 @@ import {
|
||||
|
||||
import { useAuth } from 'client/features/Auth'
|
||||
import { useVmApi } from 'client/features/One'
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import { Tr, Translate } from 'client/components/HOC'
|
||||
|
||||
// import { } from 'client/components/Forms/Vm'
|
||||
import { createActions } from 'client/components/Tables/Enhanced/Utils'
|
||||
import { PATH } from 'client/apps/sunstone/routesOne'
|
||||
import { T, VM_ACTIONS, MARKETPLACE_APP_ACTIONS } from 'client/constants'
|
||||
|
||||
const MessageToConfirmAction = rows => {
|
||||
const names = rows?.map?.(({ original }) => original?.NAME)
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
<Translate word={T.VMs} />
|
||||
{`: ${names.join(', ')}`}
|
||||
</p>
|
||||
<p>
|
||||
<Translate word={T.DoYouWantProceed} />
|
||||
</p>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
MessageToConfirmAction.displayName = 'MessageToConfirmAction'
|
||||
|
||||
const Actions = () => {
|
||||
const history = useHistory()
|
||||
const { view, getResourceView } = useAuth()
|
||||
@ -68,7 +86,7 @@ const Actions = () => {
|
||||
actions: [
|
||||
{
|
||||
accessor: VM_ACTIONS.REFRESH,
|
||||
tooltip: T.Refresh,
|
||||
tooltip: Tr(T.Refresh),
|
||||
icon: RefreshDouble,
|
||||
action: async () => {
|
||||
await getVms({ state: -1 })
|
||||
@ -76,7 +94,7 @@ const Actions = () => {
|
||||
},
|
||||
{
|
||||
accessor: VM_ACTIONS.CREATE_DIALOG,
|
||||
tooltip: T.Create,
|
||||
tooltip: Tr(T.Create),
|
||||
icon: AddSquare,
|
||||
action: () => {
|
||||
const path = PATH.TEMPLATE.VMS.INSTANTIATE
|
||||
@ -86,7 +104,7 @@ const Actions = () => {
|
||||
},
|
||||
{
|
||||
accessor: VM_ACTIONS.RESUME,
|
||||
tooltip: T.Resume,
|
||||
tooltip: Tr(T.Resume),
|
||||
selected: true,
|
||||
icon: PlayOutline,
|
||||
action: async rows => {
|
||||
@ -97,20 +115,24 @@ const Actions = () => {
|
||||
},
|
||||
{
|
||||
accessor: VM_ACTIONS.SAVE_AS_TEMPLATE,
|
||||
tooltip: T.SaveAsTemplate,
|
||||
tooltip: Tr(T.SaveAsTemplate),
|
||||
selected: { max: 1 },
|
||||
disabled: true,
|
||||
icon: SaveFloppyDisk,
|
||||
action: () => {}
|
||||
},
|
||||
{
|
||||
tooltip: T.Manage,
|
||||
tooltip: Tr(T.Manage),
|
||||
icon: SystemShut,
|
||||
selected: true,
|
||||
options: [{
|
||||
cy: `action.${VM_ACTIONS.SUSPEND}`,
|
||||
name: T.Suspend,
|
||||
isConfirmDialog: true,
|
||||
dialogProps: {
|
||||
title: T.Suspend,
|
||||
children: MessageToConfirmAction
|
||||
},
|
||||
onSubmit: async (_, rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
await Promise.all(ids.map(id => suspend(id)))
|
||||
@ -120,6 +142,10 @@ const Actions = () => {
|
||||
cy: `action.${VM_ACTIONS.STOP}`,
|
||||
name: T.Stop,
|
||||
isConfirmDialog: true,
|
||||
dialogProps: {
|
||||
title: T.Stop,
|
||||
children: MessageToConfirmAction
|
||||
},
|
||||
onSubmit: async (_, rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
await Promise.all(ids.map(id => stop(id)))
|
||||
@ -129,6 +155,10 @@ const Actions = () => {
|
||||
cy: `action.${VM_ACTIONS.POWEROFF}`,
|
||||
name: T.Poweroff,
|
||||
isConfirmDialog: true,
|
||||
dialogProps: {
|
||||
title: T.Poweroff,
|
||||
children: MessageToConfirmAction
|
||||
},
|
||||
onSubmit: async (_, rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
await Promise.all(ids.map(id => poweroff(id)))
|
||||
@ -138,6 +168,10 @@ const Actions = () => {
|
||||
cy: `action.${VM_ACTIONS.POWEROFF_HARD}`,
|
||||
name: T.PoweroffHard,
|
||||
isConfirmDialog: true,
|
||||
dialogProps: {
|
||||
title: T.PoweroffHard,
|
||||
children: MessageToConfirmAction
|
||||
},
|
||||
onSubmit: async (_, rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
await Promise.all(ids.map(id => poweroffHard(id)))
|
||||
@ -147,6 +181,10 @@ const Actions = () => {
|
||||
cy: `action.${VM_ACTIONS.REBOOT}`,
|
||||
name: T.Reboot,
|
||||
isConfirmDialog: true,
|
||||
dialogProps: {
|
||||
title: T.Reboot,
|
||||
children: MessageToConfirmAction
|
||||
},
|
||||
onSubmit: async (_, rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
await Promise.all(ids.map(id => reboot(id)))
|
||||
@ -156,6 +194,10 @@ const Actions = () => {
|
||||
cy: `action.${VM_ACTIONS.REBOOT_HARD}`,
|
||||
name: T.RebootHard,
|
||||
isConfirmDialog: true,
|
||||
dialogProps: {
|
||||
title: T.RebootHard,
|
||||
children: MessageToConfirmAction
|
||||
},
|
||||
onSubmit: async (_, rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
await Promise.all(ids.map(id => rebootHard(id)))
|
||||
@ -165,6 +207,10 @@ const Actions = () => {
|
||||
cy: `action.${VM_ACTIONS.UNDEPLOY}`,
|
||||
name: T.Undeploy,
|
||||
isConfirmDialog: true,
|
||||
dialogProps: {
|
||||
title: T.Undeploy,
|
||||
children: MessageToConfirmAction
|
||||
},
|
||||
onSubmit: async (_, rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
await Promise.all(ids.map(id => undeploy(id)))
|
||||
@ -174,6 +220,10 @@ const Actions = () => {
|
||||
cy: `action.${VM_ACTIONS.UNDEPLOY_HARD}`,
|
||||
name: T.UndeployHard,
|
||||
isConfirmDialog: true,
|
||||
dialogProps: {
|
||||
title: T.UndeployHard,
|
||||
children: MessageToConfirmAction
|
||||
},
|
||||
onSubmit: async (_, rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
await Promise.all(ids.map(id => undeployHard(id)))
|
||||
@ -182,7 +232,7 @@ const Actions = () => {
|
||||
}]
|
||||
},
|
||||
{
|
||||
tooltip: 'Hosting',
|
||||
tooltip: Tr(T.Host),
|
||||
icon: TransitionRight,
|
||||
selected: true,
|
||||
options: [{
|
||||
@ -207,6 +257,10 @@ const Actions = () => {
|
||||
cy: `action.${VM_ACTIONS.HOLD}`,
|
||||
name: T.Hold,
|
||||
isConfirmDialog: true,
|
||||
dialogProps: {
|
||||
title: T.Hold,
|
||||
children: MessageToConfirmAction
|
||||
},
|
||||
onSubmit: async (_, rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
await Promise.all(ids.map(id => hold(id)))
|
||||
@ -216,6 +270,10 @@ const Actions = () => {
|
||||
cy: `action.${VM_ACTIONS.RELEASE}`,
|
||||
name: T.Release,
|
||||
isConfirmDialog: true,
|
||||
dialogProps: {
|
||||
title: T.Release,
|
||||
children: MessageToConfirmAction
|
||||
},
|
||||
onSubmit: async (_, rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
await Promise.all(ids.map(id => release(id)))
|
||||
@ -225,6 +283,10 @@ const Actions = () => {
|
||||
cy: `action.${VM_ACTIONS.RESCHED}`,
|
||||
name: T.Reschedule,
|
||||
isConfirmDialog: true,
|
||||
dialogProps: {
|
||||
title: T.Reschedule,
|
||||
children: MessageToConfirmAction
|
||||
},
|
||||
onSubmit: async (_, rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
await Promise.all(ids.map(id => resched(id)))
|
||||
@ -234,6 +296,10 @@ const Actions = () => {
|
||||
cy: `action.${VM_ACTIONS.UNRESCHED}`,
|
||||
name: T.UnReschedule,
|
||||
isConfirmDialog: true,
|
||||
dialogProps: {
|
||||
title: T.UnReschedule,
|
||||
children: MessageToConfirmAction
|
||||
},
|
||||
onSubmit: async (_, rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
await Promise.all(ids.map(id => unresched(id)))
|
||||
@ -248,7 +314,7 @@ const Actions = () => {
|
||||
}]
|
||||
},
|
||||
{
|
||||
tooltip: 'Change ownership',
|
||||
tooltip: Tr(T.Ownership),
|
||||
icon: Group,
|
||||
selected: true,
|
||||
options: [{
|
||||
@ -275,10 +341,7 @@ const Actions = () => {
|
||||
isConfirmDialog: true,
|
||||
dialogProps: {
|
||||
title: T.Lock,
|
||||
children: rows => {
|
||||
const templates = rows?.map?.(({ original }) => original?.NAME)
|
||||
return 'VMs: ' + templates.join(', ')
|
||||
}
|
||||
children: MessageToConfirmAction
|
||||
},
|
||||
onSubmit: async (_, rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
@ -291,10 +354,7 @@ const Actions = () => {
|
||||
isConfirmDialog: true,
|
||||
dialogProps: {
|
||||
title: T.Unlock,
|
||||
children: rows => {
|
||||
const templates = rows?.map?.(({ original }) => original?.NAME)
|
||||
return 'VMs: ' + templates.join(', ')
|
||||
}
|
||||
children: MessageToConfirmAction
|
||||
},
|
||||
onSubmit: async (_, rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
@ -304,7 +364,7 @@ const Actions = () => {
|
||||
}]
|
||||
},
|
||||
{
|
||||
tooltip: T.Terminate,
|
||||
tooltip: Tr(T.Terminate),
|
||||
icon: Trash,
|
||||
selected: true,
|
||||
options: [{
|
||||
@ -313,10 +373,7 @@ const Actions = () => {
|
||||
isConfirmDialog: true,
|
||||
dialogProps: {
|
||||
title: T.Terminate,
|
||||
children: rows => {
|
||||
const templates = rows?.map?.(({ original }) => original?.NAME)
|
||||
return 'VMs: ' + templates.join(', ')
|
||||
}
|
||||
children: MessageToConfirmAction
|
||||
},
|
||||
onSubmit: async (_, rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
@ -329,10 +386,7 @@ const Actions = () => {
|
||||
isConfirmDialog: true,
|
||||
dialogProps: {
|
||||
title: T.TerminateHard,
|
||||
children: rows => {
|
||||
const templates = rows?.map?.(({ original }) => original?.NAME)
|
||||
return 'VMs: ' + templates.join(', ')
|
||||
}
|
||||
children: MessageToConfirmAction
|
||||
},
|
||||
onSubmit: async (_, rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
@ -349,7 +403,7 @@ const Actions = () => {
|
||||
actions: [
|
||||
{
|
||||
accessor: MARKETPLACE_APP_ACTIONS.CREATE_DIALOG,
|
||||
tooltip: 'Create Marketplace App',
|
||||
tooltip: Tr(T.CreateMarketApp),
|
||||
icon: Cart,
|
||||
selected: { max: 1 },
|
||||
disabled: true,
|
||||
|
@ -119,7 +119,7 @@ const StorageItem = ({ disk, actions = [] }) => {
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{SNAPSHOTS && (
|
||||
{SNAPSHOTS?.length > 0 && (
|
||||
<div style={{ flexBasis: '100%' }}>
|
||||
{SNAPSHOTS?.map(snapshot => (
|
||||
<StorageSubItem
|
||||
|
@ -26,6 +26,7 @@ export const BY = {
|
||||
export const TIME_HIDE_LOGO = 1500
|
||||
export const _APPS = defaultApps
|
||||
export const APPS = Object.keys(defaultApps)
|
||||
export const APPS_IN_BETA = [_APPS.sunstone.name]
|
||||
export const APP_URL = defaultAppName ? `/${defaultAppName}` : ''
|
||||
export const WEBSOCKET_URL = `${APP_URL}/websockets`
|
||||
export const STATIC_FILES_URL = `${APP_URL}/client/assets`
|
||||
|
@ -31,16 +31,19 @@ module.exports = {
|
||||
Attach: 'Attach',
|
||||
AttachDisk: 'Attach disk',
|
||||
AttachImage: 'Attach image disk',
|
||||
AttachVolatile: 'Attach volatile disk',
|
||||
AttachNic: 'Attach NIC',
|
||||
AttachVolatile: 'Attach volatile disk',
|
||||
BackToList: 'Back to %s list',
|
||||
Cancel: 'Cancel',
|
||||
Change: 'Change',
|
||||
ChangeGroup: 'Change group',
|
||||
ChangeOwner: 'Change owner',
|
||||
Clone: 'Clone',
|
||||
CloneSeveralTemplates: 'Clone several Templates',
|
||||
CloneTemplate: 'Clone Template',
|
||||
Configuration: 'Configuration',
|
||||
Create: 'Create',
|
||||
CreateMarketApp: 'Create Marketplace App',
|
||||
Delete: 'Delete',
|
||||
DeleteScheduledAction: 'Delete scheduled action: %s',
|
||||
DeleteSomething: 'Delete: %s',
|
||||
@ -52,6 +55,7 @@ module.exports = {
|
||||
EditSomething: 'Edit: %s',
|
||||
Finish: 'Finish',
|
||||
Hold: 'Hold',
|
||||
Import: 'Import',
|
||||
Info: 'Info',
|
||||
Instantiate: 'Instantiate',
|
||||
Lock: 'Lock',
|
||||
@ -69,13 +73,11 @@ module.exports = {
|
||||
RenameSomething: 'Rename: %s',
|
||||
Reschedule: 'Reschedule',
|
||||
Resize: 'Resize',
|
||||
ResizeSomething: 'Resize: %s',
|
||||
ResizeCapacity: 'Resize capacity',
|
||||
ResizeSomething: 'Resize: %s',
|
||||
Resume: 'Resume',
|
||||
Revert: 'Revert',
|
||||
RevertSomething: 'Revert: %s',
|
||||
Terminate: 'Terminate',
|
||||
TerminateHard: 'Terminate hard',
|
||||
Save: 'Save',
|
||||
SaveAs: 'Save as',
|
||||
SaveAsImage: 'Save as Image',
|
||||
@ -85,6 +87,7 @@ module.exports = {
|
||||
SelectGroup: 'Select a group',
|
||||
SelectRequest: 'Select request',
|
||||
SelectVmTemplate: 'Select a VM Template',
|
||||
Share: 'Share',
|
||||
Show: 'Show',
|
||||
ShowAll: 'Show all',
|
||||
SignIn: 'Sign In',
|
||||
@ -94,12 +97,15 @@ module.exports = {
|
||||
Suspend: 'Suspend',
|
||||
Take: 'Take',
|
||||
TakeSnapshot: 'Take snapshot',
|
||||
TakeSnapshotSomething: 'Take snapshot: %s',
|
||||
TakeSnapshotOf: 'Take snapshot: %s',
|
||||
TakeSnapshotSomething: 'Take snapshot: %s',
|
||||
Terminate: 'Terminate',
|
||||
TerminateHard: 'Terminate hard',
|
||||
Undeploy: 'Undeploy',
|
||||
UndeployHard: 'Undeploy hard',
|
||||
Unlock: 'Unlock',
|
||||
UnReschedule: 'Un-Reschedule',
|
||||
Unshare: 'Unshare',
|
||||
Update: 'Update',
|
||||
UpdateScheduledAction: 'Update scheduled action: %s',
|
||||
|
||||
|
@ -83,7 +83,6 @@ function Login () {
|
||||
height={100}
|
||||
width='100%'
|
||||
withText
|
||||
withBeta
|
||||
/>
|
||||
), [])}
|
||||
<Box className={classes.wrapperForm}>
|
||||
|
@ -17,6 +17,7 @@ import { JSXElementConstructor } from 'react'
|
||||
|
||||
import SunstoneApp from 'client/apps/sunstone'
|
||||
import ProvisionApp from 'client/apps/provision'
|
||||
import LoadingScreen from 'client/components/LoadingScreen'
|
||||
|
||||
import { isDevelopment, isBackend } from 'client/utils'
|
||||
import { _APPS, APPS } from 'client/constants'
|
||||
@ -31,21 +32,16 @@ const DevelopmentApp = props => {
|
||||
let appName = ''
|
||||
|
||||
if (isDevelopment() && !isBackend()) {
|
||||
const parseUrl = window.location.pathname
|
||||
appName = window.location.pathname
|
||||
.split(/\//gi)
|
||||
.filter(sub => sub?.length > 0)
|
||||
|
||||
parseUrl.forEach(resource => {
|
||||
if (resource && APPS.includes(resource)) {
|
||||
appName = resource
|
||||
}
|
||||
})
|
||||
.find(resource => APPS.includes(resource))
|
||||
}
|
||||
|
||||
return {
|
||||
[_APPS.provision.name]: <ProvisionApp {...props} />,
|
||||
[_APPS.sunstone.name]: <SunstoneApp {...props} />
|
||||
}[appName]
|
||||
}[appName] ?? <LoadingScreen />
|
||||
}
|
||||
|
||||
DevelopmentApp.displayName = 'DevelopmentApp'
|
||||
|
@ -18,6 +18,6 @@ import { render } from 'react-dom'
|
||||
import { createStore } from 'client/store'
|
||||
import App from 'client/dev/_app'
|
||||
|
||||
const { store } = createStore({ initState: window.REDUX_DATA })
|
||||
const { store } = createStore({ initState: window.__PRELOADED_STATE__ })
|
||||
|
||||
render(<App store={store} />, document.getElementById('root'))
|
||||
|
@ -14,14 +14,14 @@
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
/* eslint-disable jsdoc/require-jsdoc */
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import { useDispatch, useSelector, shallowEqual } from 'react-redux'
|
||||
|
||||
import * as actions from 'client/features/General/actions'
|
||||
import { name } from 'client/features/General/slice'
|
||||
import { name as generalSlice } from 'client/features/General/slice'
|
||||
import { generateKey } from 'client/utils'
|
||||
|
||||
export const useGeneral = () => (
|
||||
useSelector(state => state[name])
|
||||
useSelector(state => state[generalSlice], shallowEqual)
|
||||
)
|
||||
|
||||
export const useGeneralApi = () => {
|
||||
|
@ -18,11 +18,13 @@ import { createSlice } from '@reduxjs/toolkit'
|
||||
import { logout } from 'client/features/Auth/actions'
|
||||
import * as actions from 'client/features/General/actions'
|
||||
import { generateKey } from 'client/utils'
|
||||
import { APPS_IN_BETA } from 'client/constants'
|
||||
|
||||
const initial = {
|
||||
zone: 0,
|
||||
title: null,
|
||||
appTitle: null,
|
||||
isBeta: false,
|
||||
isLoading: false,
|
||||
isFixMenu: false,
|
||||
|
||||
@ -45,7 +47,9 @@ const { name, reducer } = createSlice({
|
||||
return { ...state, title: payload }
|
||||
})
|
||||
.addCase(actions.changeAppTitle, (state, { payload }) => {
|
||||
return { ...state, appTitle: payload }
|
||||
const isBeta = APPS_IN_BETA?.includes(String(payload).toLowerCase())
|
||||
|
||||
return { ...state, appTitle: payload, isBeta }
|
||||
})
|
||||
.addCase(actions.changeZone, (state, { payload }) => {
|
||||
return { ...state, zone: payload }
|
||||
|
@ -18,7 +18,7 @@ import { hydrate, render } from 'react-dom'
|
||||
import { createStore } from 'client/store'
|
||||
import App from 'client/apps/provision'
|
||||
|
||||
const { store } = createStore({ initState: window.REDUX_DATA })
|
||||
const { store } = createStore({ initState: window.__PRELOADED_STATE__ })
|
||||
|
||||
const rootHTML = document.getElementById('root')?.innerHTML
|
||||
const renderMethod = rootHTML !== '' ? hydrate : render
|
||||
|
@ -13,14 +13,18 @@
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
/* eslint-disable jsdoc/require-jsdoc */
|
||||
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit'
|
||||
|
||||
import { configureStore, getDefaultMiddleware, EnhancedStore } from '@reduxjs/toolkit'
|
||||
import thunkMiddleware from 'redux-thunk'
|
||||
|
||||
import rootReducer from 'client/store/reducers'
|
||||
import { isDevelopment } from 'client/utils'
|
||||
|
||||
/**
|
||||
* @param {object} props - Props
|
||||
* @param {object} props.initState - Initial state
|
||||
* @param {*} props.services - Services
|
||||
* @returns {{ store: EnhancedStore }} Configured Redux Store
|
||||
*/
|
||||
export const createStore = ({ initState = {}, services }) => {
|
||||
const middleware = getDefaultMiddleware({
|
||||
immutableCheck: true,
|
||||
|
@ -18,7 +18,7 @@ import { hydrate, render } from 'react-dom'
|
||||
import { createStore } from 'client/store'
|
||||
import App from 'client/apps/sunstone'
|
||||
|
||||
const { store } = createStore({ initState: window.REDUX_DATA })
|
||||
const { store } = createStore({ initState: window.__PRELOADED_STATE__ })
|
||||
|
||||
const rootHTML = document.getElementById('root')?.innerHTML
|
||||
const renderMethod = rootHTML !== '' ? hydrate : render
|
||||
|
Loading…
Reference in New Issue
Block a user