Skip to content

Commit

Permalink
F #5766: Add new functionality to VNC/RPD/SSH (#3271)
Browse files Browse the repository at this point in the history
  • Loading branch information
jloboescalona2 authored Oct 21, 2024
1 parent 5333608 commit f6e6372
Show file tree
Hide file tree
Showing 14 changed files with 429 additions and 67 deletions.
301 changes: 292 additions & 9 deletions src/fireedge/src/client/components/Consoles/Guacamole/buttons.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,51 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { memo, useCallback, useState, ReactElement } from 'react'
import PropTypes from 'prop-types'
import { Refresh, Maximize, Camera } from 'iconoir-react'
import {
Tooltip,
Typography,
Button,
IconButton,
CircularProgress,
IconButton,
Popper,
Stack,
TextField,
Tooltip,
Typography,
} from '@mui/material'
import makeStyles from '@mui/styles/makeStyles'
import {
Camera,
CloudDownload,
Code,
Edit,
Lock,
Maximize,
Refresh,
} from 'iconoir-react'
import PropTypes from 'prop-types'
import { ReactElement, memo, useCallback, useRef, useState } from 'react'

import { Translate } from 'client/components/HOC'
import { GuacamoleSession, T } from 'client/constants'
import { downloadFile } from 'client/utils'
import { T, GuacamoleSession } from 'client/constants'

import { useLazyGetGuacamoleSessionQuery } from 'client/features/OneApi/vm'

const useStyles = makeStyles(({ palette }) => ({
customPopper: {
backgroundColor: palette.background.default,
padding: '16px',
borderRadius: '8px',
zIndex: 1,
boxShadow: '0 4px 8px rgba(0,0,0,0.1)',
},
customScheme: {
width: '100%',
},
customSubmitButton: {
width: '100%',
marginTop: '1rem',
},
}))

const GuacamoleCtrlAltDelButton = memo(
/**
Expand Down Expand Up @@ -77,7 +108,7 @@ const GuacamoleReconnectButton = (session) => {
if (isLoading) return

setReconnecting(true)
await handleReconnect()
await handleReconnect({ force: true })
setReconnecting(false)
}

Expand Down Expand Up @@ -105,6 +136,205 @@ const GuacamoleReconnectButton = (session) => {
)
}

/**
* @param {GuacamoleSession} session - Guacamole session
* @returns {ReactElement} Button to perform reconnect action
*/
const GuacamoleReconnectReadOnlyButton = (session) => {
const { id, isLoading, handleReconnect } = session
const [reconnecting, setReconnecting] = useState(false)
const [enabled, setEnabled] = useState(true)

const handleReconnectSession = async () => {
if (isLoading) return

setReconnecting(true)
const reconectParams = enabled ? { readOnly: true } : {}
await handleReconnect(reconectParams)
setEnabled(!enabled)
setReconnecting(false)
}

return (
<Tooltip
arrow
placement="bottom"
title={
<Typography variant="subtitle2">
<Translate word={enabled ? T.Lock : T.Unlock} />
</Typography>
}
>
<IconButton
data-cy={`${id}-read-only-button`}
onClick={handleReconnectSession}
>
{reconnecting || isLoading ? (
<CircularProgress color="secondary" size={20} />
) : enabled ? (
<Lock />
) : (
<Edit />
)}
</IconButton>
</Tooltip>
)
}

const FormData = ({
command,
setCommand,
colorSchema,
setColorSchema,
fontName,
setFontName,
fontSize,
setFontSize,
}) => {
const classes = useStyles()

return (
<>
<Stack
direction="column"
alignItems="center"
style={{ justifyContent: 'center' }}
gap="1em"
>
<TextField
value={command}
label={T.SSHCommand}
onChange={(event) => {
setCommand(event.target.value)
}}
/>
<TextField
value={colorSchema}
label={T.Schema}
multiline
rows={4}
className={classes.customScheme}
onChange={(event) => {
setColorSchema(event.target.value)
}}
/>
<TextField
value={fontName}
label={T.FontName}
onChange={(event) => {
setFontName(event.target.value)
}}
/>
<TextField
value={fontSize}
label={T.FontSize}
type="number"
onChange={(event) => {
setFontSize(event.target.value)
}}
/>
</Stack>
</>
)
}
FormData.displayName = 'FormData'
FormData.propTypes = {
command: PropTypes.string,
setCommand: PropTypes.func,
colorSchema: PropTypes.string,
setColorSchema: PropTypes.func,
fontName: PropTypes.string,
setFontName: PropTypes.func,
fontSize: PropTypes.number,
setFontSize: PropTypes.func,
}

/**
* @param {GuacamoleSession} session - Guacamole session
* @returns {ReactElement} Button to perform reconnect action
*/
const GuacamoleSSHParams = (session) => {
const buttonRef = useRef(null)
const { id, isLoading, handleReconnect } = session
const [reconnecting, setReconnecting] = useState(false)
const [enabled, setEnabled] = useState(false)
const [command, setCommand] = useState('')
const [colorSchema, setColorSchema] = useState('')
const [fontName, setFontName] = useState('')
const [fontSize, setFontSize] = useState('')

const classes = useStyles()

const handleReconnectSession = async () => {
if (isLoading) return

setReconnecting(true)
const requestOptions = { force: true }
command && (requestOptions.command = command)
colorSchema && (requestOptions.colorSchema = colorSchema)
fontName && (requestOptions.fontName = fontName)
fontSize && (requestOptions.fontSize = fontSize)

Object.keys(requestOptions).length > 0 &&
(await handleReconnect(requestOptions))

setEnabled(false)
setReconnecting(false)
}

return (
<>
{reconnecting || isLoading ? (
<CircularProgress color="secondary" size={20} />
) : (
<>
<IconButton
ref={buttonRef}
data-cy={`${id}-edit-params-ssh`}
onClick={() => setEnabled(!enabled)}
>
<Code />
</IconButton>
<Popper
open={enabled}
anchorEl={buttonRef.current}
placement="bottom"
className={classes.customPopper}
modifiers={[
{
name: 'preventOverflow',
options: {
padding: 8,
},
},
]}
>
<FormData
command={command}
setCommand={setCommand}
colorSchema={colorSchema}
setColorSchema={setColorSchema}
fontName={fontName}
setFontName={setFontName}
fontSize={fontSize}
setFontSize={setFontSize}
/>
<Button
variant="contained"
size="small"
onClick={handleReconnectSession}
data-cy={`${id}-ssh-command-button`}
className={classes.customSubmitButton}
>
<Translate word={T.Submit} />
</Button>
</Popper>
</>
)}
</>
)
}

const GuacamoleFullScreenButton = memo(
/**
* @param {GuacamoleSession} session - Guacamole session
Expand Down Expand Up @@ -140,6 +370,49 @@ const GuacamoleFullScreenButton = memo(
}
)

const GuacamoleDownloadConButton = memo(
/**
* @param {GuacamoleSession} session - Guacamole session
* @returns {ReactElement} Button to make screenshot form current session
*/
(session) => {
const [getSession] = useLazyGetGuacamoleSessionQuery()

const { id, vmID, client } = session

const handleClick = useCallback(async () => {
if (!client) return

const res = await getSession({
id: vmID,
type: 'rdp',
download: true,
}).unwrap()

if (res) {
const blob = new Blob([atob(res)], { type: 'text/plain' })
downloadFile(new File([blob], 'connection.txt'))
}
}, [client])

return (
<Tooltip
arrow
placement="bottom"
title={
<Typography variant="subtitle2">
<Translate word={T.DownloadConecctionFile} />
</Typography>
}
>
<IconButton data-cy={`${id}-download-button`} onClick={handleClick}>
<CloudDownload />
</IconButton>
</Tooltip>
)
}
)

const GuacamoleScreenshotButton = memo(
/**
* @param {GuacamoleSession} session - Guacamole session
Expand Down Expand Up @@ -185,14 +458,24 @@ GuacamoleCtrlAltDelButton.displayName = 'GuacamoleCtrlAltDelButton'
GuacamoleCtrlAltDelButton.propTypes = ButtonPropTypes
GuacamoleReconnectButton.displayName = 'GuacamoleReconnectButton'
GuacamoleReconnectButton.propTypes = ButtonPropTypes
GuacamoleReconnectReadOnlyButton.displayName =
'GuacamoleReconnectReadOnlyButton'
GuacamoleReconnectReadOnlyButton.propTypes = ButtonPropTypes
GuacamoleFullScreenButton.displayName = 'GuacamoleFullScreenButton'
GuacamoleFullScreenButton.propTypes = ButtonPropTypes
GuacamoleScreenshotButton.displayName = 'GuacamoleScreenshotButton'
GuacamoleScreenshotButton.propTypes = ButtonPropTypes
GuacamoleSSHParams.displayName = 'GuacamoleSSHParams'
GuacamoleSSHParams.propTypes = ButtonPropTypes
GuacamoleDownloadConButton.displayName = 'GuacamoleDownloadConButton'
GuacamoleDownloadConButton.propTypes = ButtonPropTypes

export {
GuacamoleCtrlAltDelButton,
GuacamoleReconnectButton,
GuacamoleDownloadConButton,
GuacamoleFullScreenButton,
GuacamoleReconnectButton,
GuacamoleReconnectReadOnlyButton,
GuacamoleSSHParams,
GuacamoleScreenshotButton,
}
Loading

0 comments on commit f6e6372

Please sign in to comment.