mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-28 14:50:08 +03:00
parent
6fe6728da9
commit
9f77261af5
src/fireedge/src/client
@ -20,6 +20,7 @@ import { StaticRouter, BrowserRouter } from 'react-router-dom'
|
||||
import { Provider as ReduxProvider } from 'react-redux'
|
||||
import root from 'window-or-global'
|
||||
|
||||
import SocketProvider from 'client/providers/socketProvider'
|
||||
import MuiProvider from 'client/providers/muiProvider'
|
||||
import NotistackProvider from 'client/providers/notistackProvider'
|
||||
import { TranslateProvider } from 'client/components/HOC'
|
||||
@ -48,19 +49,21 @@ const App = ({ location, context, store, app }) => {
|
||||
<MuiProvider app={appName} location={location}>
|
||||
<ReduxProvider store={store}>
|
||||
<NotistackProvider>
|
||||
<TranslateProvider>
|
||||
{location && context ? (
|
||||
// server build
|
||||
<StaticRouter location={location} context={context}>
|
||||
<Router app={appName} />
|
||||
</StaticRouter>
|
||||
) : (
|
||||
// browser build
|
||||
<BrowserRouter basename={`/${appName}`}>
|
||||
<Router app={appName} />
|
||||
</BrowserRouter>
|
||||
)}
|
||||
</TranslateProvider>
|
||||
<SocketProvider>
|
||||
<TranslateProvider>
|
||||
{location && context ? (
|
||||
// server build
|
||||
<StaticRouter location={location} context={context}>
|
||||
<Router app={appName} />
|
||||
</StaticRouter>
|
||||
) : (
|
||||
// browser build
|
||||
<BrowserRouter basename={`/${appName}`}>
|
||||
<Router app={appName} />
|
||||
</BrowserRouter>
|
||||
)}
|
||||
</TranslateProvider>
|
||||
</SocketProvider>
|
||||
</NotistackProvider>
|
||||
</ReduxProvider>
|
||||
</MuiProvider>
|
||||
|
@ -1,12 +1,13 @@
|
||||
import React from 'react'
|
||||
import React, { memo } from 'react'
|
||||
|
||||
import { MenuItem, MenuList } from '@material-ui/core'
|
||||
import LanguageIcon from '@material-ui/icons/Language'
|
||||
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import HeaderPopover from 'client/components/Header/Popover'
|
||||
import { Tr } from 'client/components/HOC'
|
||||
import { ZoneLabel } from 'client/constants/translates'
|
||||
|
||||
const Zone = React.memo(() => (
|
||||
const Zone = memo(() => (
|
||||
<HeaderPopover
|
||||
id="zone-menu"
|
||||
icon={<LanguageIcon />}
|
||||
@ -15,7 +16,9 @@ const Zone = React.memo(() => (
|
||||
>
|
||||
{({ handleClose }) => (
|
||||
<MenuList>
|
||||
<MenuItem onClick={handleClose}>{Tr('Zone')}</MenuItem>
|
||||
<MenuItem onClick={handleClose}>
|
||||
{Tr(ZoneLabel)}
|
||||
</MenuItem>
|
||||
</MenuList>
|
||||
)}
|
||||
</HeaderPopover>
|
||||
|
@ -33,6 +33,7 @@ module.exports = {
|
||||
/* sections */
|
||||
Dashboard: 'Dashboard',
|
||||
Settings: 'Settings',
|
||||
ZoneLabel: 'Zone',
|
||||
ApplicationsTemplates: 'Applications templates',
|
||||
ApplicationsInstances: 'Applications instances',
|
||||
ProviderLabel: 'Provider',
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright 2002-2019, OpenNebula Project, OpenNebula Systems */
|
||||
/* Copyright 2002-2020, OpenNebula Project, OpenNebula Systems */
|
||||
/* */
|
||||
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
|
||||
/* not use this file except in compliance with the License. You may obtain */
|
||||
@ -13,31 +13,67 @@
|
||||
/* limitations under the License. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import io from 'socket.io-client'
|
||||
import { findStorageData } from 'client/utils'
|
||||
import { JWT_NAME } from 'client/constants'
|
||||
import { defaultPort } from 'server/utils/constants/defaults'
|
||||
import React, { useState, useEffect, memo } from 'react'
|
||||
|
||||
const ENDPOINT = `http://127.0.0.1:${defaultPort}`
|
||||
import { Button, makeStyles } from '@material-ui/core'
|
||||
import useSocket from 'client/hooks/useSocket'
|
||||
|
||||
const Webconsole = ({ zone }) => {
|
||||
const [response, setResponse] = useState({})
|
||||
const useStyles = makeStyles(() => ({
|
||||
sticky: { position: 'sticky', top: 0, backgroundColor: '#fafafa' },
|
||||
loading: {
|
||||
'&::after': {
|
||||
overflow: 'hidden',
|
||||
display: 'inline-block',
|
||||
verticalAlign: 'bottom',
|
||||
animation: '$ellipsis steps(4,end) 1000ms infinite',
|
||||
content: '"\\2026"', /* ascii code for the ellipsis character */
|
||||
width: 0
|
||||
}
|
||||
},
|
||||
'@keyframes ellipsis': {
|
||||
to: { width: 20 }
|
||||
}
|
||||
}))
|
||||
|
||||
const ResponseComponent = memo(response => (
|
||||
<p style={{ wordBreak: 'break-all' }}>{JSON.stringify(response)}</p>
|
||||
))
|
||||
|
||||
ResponseComponent.displayName = 'ResponseComponent'
|
||||
|
||||
const Webconsole = () => {
|
||||
const classes = useStyles()
|
||||
const [listening, setListening] = useState(false)
|
||||
const [response, setResponse] = useState([])
|
||||
const { getHooks } = useSocket()
|
||||
|
||||
const toggleListening = () => setListening(list => !list)
|
||||
|
||||
useEffect(() => {
|
||||
const socket = io(ENDPOINT, {
|
||||
path: '/websocket',
|
||||
query: {
|
||||
token: findStorageData(JWT_NAME),
|
||||
zone
|
||||
}
|
||||
})
|
||||
socket.on('hooks', data => {
|
||||
setResponse(data)
|
||||
})
|
||||
return () => { socket.disconnect() }
|
||||
}, [zone])
|
||||
console.log('-->', response)
|
||||
return <p />
|
||||
listening
|
||||
? getHooks.on(data => setResponse(prev => [...prev, data]))
|
||||
: getHooks.off()
|
||||
|
||||
return getHooks.off
|
||||
}, [listening])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={classes.sticky}>
|
||||
<p className={listening ? classes.loading : ''}>
|
||||
{`socket is ${listening ? '' : 'not'} listening`}
|
||||
</p>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={toggleListening}>
|
||||
{listening ? 'Disconnect' : 'Connect'}
|
||||
</Button>
|
||||
</div>
|
||||
{response?.map((res, index) =>
|
||||
<ResponseComponent key={index} {...res} />
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
export default Webconsole
|
||||
|
@ -4,7 +4,7 @@ import { useSelector, useDispatch, shallowEqual } from 'react-redux'
|
||||
import * as actions from 'client/actions/general'
|
||||
|
||||
export default function useGeneral () {
|
||||
const { isLoading, isOpenMenu, isFixMenu } = useSelector(
|
||||
const { zone, isLoading, isOpenMenu, isFixMenu } = useSelector(
|
||||
state => state?.General,
|
||||
shallowEqual
|
||||
)
|
||||
@ -38,6 +38,7 @@ export default function useGeneral () {
|
||||
)
|
||||
|
||||
return {
|
||||
zone,
|
||||
isLoading,
|
||||
isOpenMenu,
|
||||
isFixMenu,
|
||||
|
24
src/fireedge/src/client/hooks/useSocket.js
Normal file
24
src/fireedge/src/client/hooks/useSocket.js
Normal file
@ -0,0 +1,24 @@
|
||||
import { useContext, useMemo } from 'react'
|
||||
|
||||
import { SocketContext } from 'client/providers/socketProvider'
|
||||
|
||||
const SOCKETS = {
|
||||
hooks: 'hooks',
|
||||
provision: 'provision'
|
||||
}
|
||||
|
||||
export default function useSocket () {
|
||||
const { socket, isConnected } = useContext(SocketContext)
|
||||
|
||||
const getHooks = useMemo(() => ({
|
||||
on: (func) => isConnected && socket.on(SOCKETS.hooks, func),
|
||||
off: () => isConnected && socket.off()
|
||||
}), [socket, isConnected])
|
||||
|
||||
const getProvision = useMemo(() => ({
|
||||
on: (func) => isConnected && socket.on(SOCKETS.provision, func),
|
||||
off: () => isConnected && socket.off()
|
||||
}), [socket, isConnected])
|
||||
|
||||
return { isConnected, getHooks, getProvision }
|
||||
}
|
52
src/fireedge/src/client/providers/socketProvider.js
Normal file
52
src/fireedge/src/client/providers/socketProvider.js
Normal file
@ -0,0 +1,52 @@
|
||||
import React, { createContext, useEffect, useState } from 'react'
|
||||
import { useSelector } from 'react-redux'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import * as serviceSocket from 'client/services/socket'
|
||||
|
||||
const CONNECT = 'connect'
|
||||
const DISCONNECT = 'disconnect'
|
||||
|
||||
export const SocketContext = createContext(null)
|
||||
|
||||
const SocketProvider = ({ children }) => {
|
||||
const [socket, setSocket] = useState({})
|
||||
const [isConnected, setConnected] = useState(false)
|
||||
const { jwt, zone } = useSelector(state => ({
|
||||
zone: state?.General?.zone,
|
||||
jwt: state?.Authenticated?.jwt
|
||||
}))
|
||||
|
||||
useEffect(() => {
|
||||
if (!jwt) return
|
||||
|
||||
const client = serviceSocket.websocket({ token: jwt, zone })
|
||||
client.on(CONNECT, () => setConnected(true))
|
||||
client.on(DISCONNECT, () => setConnected(false))
|
||||
setSocket(client)
|
||||
|
||||
return () => {
|
||||
setSocket(null)
|
||||
return client.disconnect()
|
||||
}
|
||||
}, [jwt, zone])
|
||||
|
||||
return (
|
||||
<SocketContext.Provider value={{ socket, isConnected }}>
|
||||
{children}
|
||||
</SocketContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
SocketProvider.propTypes = {
|
||||
children: PropTypes.oneOfType([
|
||||
PropTypes.node,
|
||||
PropTypes.arrayOf(PropTypes.node)
|
||||
])
|
||||
}
|
||||
|
||||
SocketProvider.defaultProps = {
|
||||
children: undefined
|
||||
}
|
||||
|
||||
export default SocketProvider
|
8
src/fireedge/src/client/services/socket.js
Normal file
8
src/fireedge/src/client/services/socket.js
Normal file
@ -0,0 +1,8 @@
|
||||
import io from 'socket.io-client'
|
||||
|
||||
export const websocket = query => io({
|
||||
path: '/websocket',
|
||||
query
|
||||
})
|
||||
|
||||
export default { websocket }
|
Loading…
x
Reference in New Issue
Block a user