Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/javascript/grid-ui/src/components/LiveView/LiveView.tsx
3987 views
1
// Licensed to the Software Freedom Conservancy (SFC) under one
2
// or more contributor license agreements. See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership. The SFC licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License. You may obtain a copy of the License at
8
//
9
// http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied. See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
import React, { useEffect, useState, useImperativeHandle, forwardRef } from 'react'
19
import RFB from '@novnc/novnc/lib/rfb'
20
import PasswordDialog from './PasswordDialog'
21
import MuiAlert, { AlertProps } from '@mui/material/Alert'
22
import Snackbar from '@mui/material/Snackbar'
23
import { useTheme } from '@mui/material/styles'
24
25
const Alert = React.forwardRef<HTMLDivElement, AlertProps>(function Alert (
26
props,
27
ref
28
) {
29
return <MuiAlert elevation={6} ref={ref} variant='filled' {...props} />
30
})
31
32
const LiveView = forwardRef((props, ref) => {
33
let canvas: any = null
34
const theme = useTheme()
35
36
const [open, setOpen] = useState(false)
37
const [message, setMessage] = useState('')
38
const [rfb, setRfb] = useState<RFB>(null)
39
const [openErrorAlert, setOpenErrorAlert] = useState(false)
40
const [openSuccessAlert, setOpenSuccessAlert] = useState(false)
41
42
const handlePasswordDialog = (state: boolean): void => {
43
setOpen(state)
44
}
45
46
const disconnect = () => {
47
if (!rfb) {
48
return
49
}
50
rfb.disconnect()
51
setRfb(null)
52
}
53
54
useImperativeHandle(ref, () => ({
55
disconnect
56
}))
57
58
const connect = () => {
59
disconnect()
60
61
if (!canvas) {
62
return
63
}
64
65
const newRfb = new RFB.default(canvas, props.url, {})
66
newRfb.scaleViewport = props.scaleViewport
67
newRfb.background = theme.palette.background.default
68
newRfb.addEventListener('credentialsrequired', handleCredentials)
69
newRfb.addEventListener('securityfailure', securityFailed)
70
newRfb.addEventListener('connect', connectedToServer)
71
newRfb.addEventListener('disconnect', disconnect)
72
setRfb(newRfb)
73
}
74
75
const registerChild = ref => {
76
canvas = ref
77
}
78
79
useEffect(() => {
80
connect()
81
return () => {
82
disconnect()
83
}
84
// eslint-disable-next-line
85
}, [])
86
87
useEffect(() => {
88
if (rfb) {
89
rfb.scaleViewport = props.scaleViewport
90
}
91
})
92
93
const securityFailed = (event: any) => {
94
let errorMessage
95
if ('reason' in event.detail) {
96
errorMessage =
97
'Connection has been rejected with reason: ' + event.detail.reason
98
} else {
99
errorMessage = 'New connection has been rejected'
100
}
101
setMessage(errorMessage)
102
setOpenErrorAlert(true)
103
}
104
105
const handleCredentials = () => {
106
handlePasswordDialog(true)
107
}
108
109
const connectedToServer = () => {
110
setOpenSuccessAlert(true)
111
}
112
113
const handleCredentialsEntered = (password: string) => {
114
rfb.sendCredentials({ username: '', password: password })
115
setOpen(false)
116
}
117
118
const handlePasswordDialogClose = () => {
119
disconnect()
120
props.onClose()
121
}
122
123
const handleMouseEnter = () => {
124
if (!rfb) {
125
return
126
}
127
rfb.focus()
128
}
129
130
const handleMouseLeave = () => {
131
if (!rfb) {
132
return
133
}
134
rfb.blur()
135
}
136
137
const handleClose = (event?: React.SyntheticEvent | Event,
138
reason?: string) => {
139
if (reason === 'clickaway') {
140
return
141
}
142
setOpenErrorAlert(false)
143
disconnect()
144
props.onClose()
145
}
146
147
return (
148
<div
149
style={
150
{
151
width: '100%',
152
height: '100%'
153
}
154
}
155
ref={registerChild}
156
onMouseEnter={handleMouseEnter}
157
onMouseLeave={handleMouseLeave}
158
>
159
<PasswordDialog
160
title='LiveView (VNC) Password'
161
open={open}
162
openDialog={handlePasswordDialog}
163
onConfirm={handleCredentialsEntered}
164
onCancel={handlePasswordDialogClose}
165
/>
166
<Snackbar
167
open={openErrorAlert}
168
anchorOrigin={{ vertical: 'top', horizontal: 'center' }}
169
autoHideDuration={6000}
170
onClose={handleClose}
171
>
172
<Alert severity='error' sx={{ width: '100%' }}>
173
{message}
174
</Alert>
175
</Snackbar>
176
<Snackbar
177
open={openSuccessAlert}
178
anchorOrigin={{ vertical: 'top', horizontal: 'center' }}
179
autoHideDuration={4000}
180
onClose={() => setOpenSuccessAlert(false)}
181
>
182
<Alert severity='success' sx={{ width: '100%' }}>
183
Connected successfully!
184
</Alert>
185
</Snackbar>
186
</div>
187
)
188
})
189
190
export default LiveView
191
192