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
2887 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
24
const Alert = React.forwardRef<HTMLDivElement, AlertProps>(function Alert (
25
props,
26
ref
27
) {
28
return <MuiAlert elevation={6} ref={ref} variant='filled' {...props} />
29
})
30
31
const LiveView = forwardRef((props, ref) => {
32
let canvas: any = null
33
34
const [open, setOpen] = useState(false)
35
const [message, setMessage] = useState('')
36
const [rfb, setRfb] = useState<RFB>(null)
37
const [openErrorAlert, setOpenErrorAlert] = useState(false)
38
const [openSuccessAlert, setOpenSuccessAlert] = useState(false)
39
40
const handlePasswordDialog = (state: boolean): void => {
41
setOpen(state)
42
}
43
44
const disconnect = () => {
45
if (!rfb) {
46
return
47
}
48
rfb.disconnect()
49
setRfb(null)
50
}
51
52
useImperativeHandle(ref, () => ({
53
disconnect
54
}))
55
56
const connect = () => {
57
disconnect()
58
59
if (!canvas) {
60
return
61
}
62
63
const newRfb = new RFB.default(canvas, props.url, {})
64
newRfb.scaleViewport = props.scaleViewport
65
newRfb.background = 'rgb(247,248,248)'
66
newRfb.addEventListener('credentialsrequired', handleCredentials)
67
newRfb.addEventListener('securityfailure', securityFailed)
68
newRfb.addEventListener('connect', connectedToServer)
69
newRfb.addEventListener('disconnect', disconnect)
70
setRfb(newRfb)
71
}
72
73
const registerChild = ref => {
74
canvas = ref
75
}
76
77
useEffect(() => {
78
connect()
79
return () => {
80
disconnect()
81
}
82
// eslint-disable-next-line
83
}, [])
84
85
useEffect(() => {
86
if (rfb) {
87
rfb.scaleViewport = props.scaleViewport
88
}
89
})
90
91
const securityFailed = (event: any) => {
92
let errorMessage
93
if ('reason' in event.detail) {
94
errorMessage =
95
'Connection has been rejected with reason: ' + event.detail.reason
96
} else {
97
errorMessage = 'New connection has been rejected'
98
}
99
setMessage(errorMessage)
100
setOpenErrorAlert(true)
101
}
102
103
const handleCredentials = () => {
104
handlePasswordDialog(true)
105
}
106
107
const connectedToServer = () => {
108
setOpenSuccessAlert(true)
109
}
110
111
const handleCredentialsEntered = (password: string) => {
112
rfb.sendCredentials({ username: '', password: password })
113
setOpen(false)
114
}
115
116
const handlePasswordDialogClose = () => {
117
disconnect()
118
props.onClose()
119
}
120
121
const handleMouseEnter = () => {
122
if (!rfb) {
123
return
124
}
125
rfb.focus()
126
}
127
128
const handleMouseLeave = () => {
129
if (!rfb) {
130
return
131
}
132
rfb.blur()
133
}
134
135
const handleClose = (event?: React.SyntheticEvent | Event,
136
reason?: string) => {
137
if (reason === 'clickaway') {
138
return
139
}
140
setOpenErrorAlert(false)
141
disconnect()
142
props.onClose()
143
}
144
145
return (
146
<div
147
style={
148
{
149
width: '100%',
150
height: '100%'
151
}
152
}
153
ref={registerChild}
154
onMouseEnter={handleMouseEnter}
155
onMouseLeave={handleMouseLeave}
156
>
157
<PasswordDialog
158
title='LiveView (VNC) Password'
159
open={open}
160
openDialog={handlePasswordDialog}
161
onConfirm={handleCredentialsEntered}
162
onCancel={handlePasswordDialogClose}
163
/>
164
<Snackbar
165
open={openErrorAlert}
166
anchorOrigin={{ vertical: 'top', horizontal: 'center' }}
167
autoHideDuration={6000}
168
onClose={handleClose}
169
>
170
<Alert severity='error' sx={{ width: '100%' }}>
171
{message}
172
</Alert>
173
</Snackbar>
174
<Snackbar
175
open={openSuccessAlert}
176
anchorOrigin={{ vertical: 'top', horizontal: 'center' }}
177
autoHideDuration={4000}
178
onClose={() => setOpenSuccessAlert(false)}
179
>
180
<Alert severity='success' sx={{ width: '100%' }}>
181
Connected successfully!
182
</Alert>
183
</Snackbar>
184
</div>
185
)
186
})
187
188
export default LiveView
189
190