Merge pull request #175 from Tsu-ba-me/issues/151-vnc-frontend
Web UI: add the front-end counterpart for VNCmain
commit
f1af3d4e14
54 changed files with 2130 additions and 730 deletions
@ -0,0 +1,239 @@ |
||||
import { useState, useRef, useEffect, Dispatch, SetStateAction } from 'react'; |
||||
import dynamic from 'next/dynamic'; |
||||
import { Box, Menu, MenuItem, Typography, Button } from '@material-ui/core'; |
||||
import { makeStyles } from '@material-ui/core/styles'; |
||||
import CloseIcon from '@material-ui/icons/Close'; |
||||
import KeyboardIcon from '@material-ui/icons/Keyboard'; |
||||
import IconButton from '@material-ui/core/IconButton'; |
||||
import RFB from '@novnc/novnc/core/rfb'; |
||||
import { Panel } from '../Panels'; |
||||
import { BLACK, RED, TEXT } from '../../lib/consts/DEFAULT_THEME'; |
||||
import keyCombinations from './keyCombinations'; |
||||
import putFetch from '../../lib/fetchers/putFetch'; |
||||
import putFetchWithTimeout from '../../lib/fetchers/putFetchWithTimeout'; |
||||
import { HeaderText } from '../Text'; |
||||
import Spinner from '../Spinner'; |
||||
|
||||
const VncDisplay = dynamic(() => import('./VncDisplay'), { ssr: false }); |
||||
|
||||
const useStyles = makeStyles(() => ({ |
||||
displayBox: { |
||||
width: '75vw', |
||||
height: '75vh', |
||||
paddingTop: '1em', |
||||
paddingBottom: 0, |
||||
paddingLeft: 0, |
||||
paddingRight: 0, |
||||
}, |
||||
spinnerBox: { |
||||
flexDirection: 'column', |
||||
width: '75vw', |
||||
height: '75vh', |
||||
alignItems: 'center', |
||||
justifyContent: 'center', |
||||
}, |
||||
closeButton: { |
||||
borderRadius: 8, |
||||
backgroundColor: RED, |
||||
'&:hover': { |
||||
backgroundColor: RED, |
||||
}, |
||||
}, |
||||
keyboardButton: { |
||||
borderRadius: 8, |
||||
backgroundColor: TEXT, |
||||
'&:hover': { |
||||
backgroundColor: TEXT, |
||||
}, |
||||
}, |
||||
closeBox: { |
||||
paddingBottom: '1em', |
||||
paddingLeft: '.7em', |
||||
paddingRight: 0, |
||||
}, |
||||
buttonsBox: { |
||||
paddingTop: 0, |
||||
}, |
||||
keysItem: { |
||||
backgroundColor: TEXT, |
||||
paddingRight: '3em', |
||||
'&:hover': { |
||||
backgroundColor: TEXT, |
||||
}, |
||||
}, |
||||
buttonText: { |
||||
color: BLACK, |
||||
}, |
||||
})); |
||||
|
||||
interface PreviewProps { |
||||
setMode: Dispatch<SetStateAction<boolean>>; |
||||
uuid: string; |
||||
serverName: string | string[] | undefined; |
||||
} |
||||
|
||||
interface VncConnectionProps { |
||||
protocol: string; |
||||
forward_port: number; |
||||
} |
||||
|
||||
const FullSize = ({ setMode, uuid, serverName }: PreviewProps): JSX.Element => { |
||||
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null); |
||||
const rfb = useRef<typeof RFB>(); |
||||
const hostname = useRef<string | undefined>(undefined); |
||||
const [vncConnection, setVncConnection] = useState< |
||||
VncConnectionProps | undefined |
||||
>(undefined); |
||||
const [isError, setIsError] = useState<boolean>(false); |
||||
const classes = useStyles(); |
||||
|
||||
useEffect(() => { |
||||
if (typeof window !== 'undefined') { |
||||
hostname.current = window.location.hostname; |
||||
} |
||||
|
||||
if (!vncConnection) |
||||
(async () => { |
||||
try { |
||||
const res = await putFetchWithTimeout( |
||||
`${process.env.NEXT_PUBLIC_API_URL}/manage_vnc_pipes`, |
||||
{ |
||||
server_uuid: uuid, |
||||
is_open: true, |
||||
}, |
||||
120000, |
||||
); |
||||
setVncConnection(await res.json()); |
||||
} catch { |
||||
setIsError(true); |
||||
} |
||||
})(); |
||||
}, [uuid, vncConnection, isError]); |
||||
|
||||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>): void => { |
||||
setAnchorEl(event.currentTarget); |
||||
}; |
||||
|
||||
const handleClickClose = async () => { |
||||
await putFetch(`${process.env.NEXT_PUBLIC_API_URL}/manage_vnc_pipes`, { |
||||
server_uuid: uuid, |
||||
is_open: false, |
||||
}); |
||||
}; |
||||
|
||||
const handleSendKeys = (scans: string[]) => { |
||||
if (rfb.current) { |
||||
if (!scans.length) rfb.current.sendCtrlAltDel(); |
||||
else { |
||||
// Send pressing keys
|
||||
for (let i = 0; i <= scans.length - 1; i += 1) { |
||||
rfb.current.sendKey(scans[i], 1); |
||||
} |
||||
|
||||
// Send releasing keys in reverse order
|
||||
for (let i = scans.length - 1; i >= 0; i -= 1) { |
||||
rfb.current.sendKey(scans[i], 0); |
||||
} |
||||
} |
||||
setAnchorEl(null); |
||||
} |
||||
}; |
||||
|
||||
return ( |
||||
<Panel> |
||||
<Box flexGrow={1}> |
||||
<HeaderText text={`Server: ${serverName}`} /> |
||||
</Box> |
||||
{vncConnection ? ( |
||||
<Box display="flex" className={classes.displayBox}> |
||||
<VncDisplay |
||||
rfb={rfb} |
||||
url={`${vncConnection.protocol}://${hostname.current}:${vncConnection.forward_port}`} |
||||
viewOnly={false} |
||||
focusOnClick={false} |
||||
clipViewport={false} |
||||
dragViewport={false} |
||||
scaleViewport |
||||
resizeSession |
||||
showDotCursor={false} |
||||
background="" |
||||
qualityLevel={6} |
||||
compressionLevel={2} |
||||
/> |
||||
<Box> |
||||
<Box className={classes.closeBox}> |
||||
<IconButton |
||||
className={classes.closeButton} |
||||
style={{ color: TEXT }} |
||||
component="span" |
||||
onClick={() => { |
||||
handleClickClose(); |
||||
setMode(true); |
||||
}} |
||||
> |
||||
<CloseIcon /> |
||||
</IconButton> |
||||
</Box> |
||||
<Box className={classes.closeBox}> |
||||
<IconButton |
||||
className={classes.keyboardButton} |
||||
style={{ color: BLACK }} |
||||
component="span" |
||||
onClick={handleClick} |
||||
> |
||||
<KeyboardIcon /> |
||||
</IconButton> |
||||
<Menu |
||||
anchorEl={anchorEl} |
||||
keepMounted |
||||
open={Boolean(anchorEl)} |
||||
onClose={() => setAnchorEl(null)} |
||||
> |
||||
{keyCombinations.map(({ keys, scans }) => { |
||||
return ( |
||||
<MenuItem |
||||
onClick={() => handleSendKeys(scans)} |
||||
className={classes.keysItem} |
||||
key={keys} |
||||
> |
||||
<Typography variant="subtitle1">{keys}</Typography> |
||||
</MenuItem> |
||||
); |
||||
})} |
||||
</Menu> |
||||
</Box> |
||||
</Box> |
||||
</Box> |
||||
) : ( |
||||
<Box display="flex" className={classes.spinnerBox}> |
||||
{!isError ? ( |
||||
<> |
||||
<HeaderText text={`Establishing connection with ${serverName}`} /> |
||||
<HeaderText text="This may take a few minutes" /> |
||||
<Spinner /> |
||||
</> |
||||
) : ( |
||||
<> |
||||
<Box style={{ paddingBottom: '2em' }}> |
||||
<HeaderText text="There was a problem connecting to the server, please try again" /> |
||||
</Box> |
||||
<Button |
||||
variant="contained" |
||||
onClick={() => { |
||||
setIsError(false); |
||||
}} |
||||
style={{ textTransform: 'none' }} |
||||
> |
||||
<Typography className={classes.buttonText} variant="subtitle1"> |
||||
Reconnect |
||||
</Typography> |
||||
</Button> |
||||
</> |
||||
)} |
||||
</Box> |
||||
)} |
||||
</Panel> |
||||
); |
||||
}; |
||||
|
||||
export default FullSize; |
@ -0,0 +1,79 @@ |
||||
import { Dispatch, SetStateAction } from 'react'; |
||||
import { Box } from '@material-ui/core'; |
||||
import { makeStyles } from '@material-ui/core/styles'; |
||||
import IconButton from '@material-ui/core/IconButton'; |
||||
import DesktopWindowsIcon from '@material-ui/icons/DesktopWindows'; |
||||
import CropOriginal from '@material-ui/icons/Image'; |
||||
import { Panel } from '../Panels'; |
||||
import { BLACK, GREY, TEXT } from '../../lib/consts/DEFAULT_THEME'; |
||||
import { HeaderText } from '../Text'; |
||||
|
||||
interface PreviewProps { |
||||
setMode: Dispatch<SetStateAction<boolean>>; |
||||
serverName: string | string[] | undefined; |
||||
} |
||||
|
||||
const useStyles = makeStyles(() => ({ |
||||
displayBox: { |
||||
padding: 0, |
||||
paddingTop: '.7em', |
||||
width: '100%', |
||||
}, |
||||
fullScreenButton: { |
||||
borderRadius: 8, |
||||
backgroundColor: TEXT, |
||||
'&:hover': { |
||||
backgroundColor: TEXT, |
||||
}, |
||||
}, |
||||
fullScreenBox: { |
||||
paddingLeft: '1em', |
||||
padding: 0, |
||||
}, |
||||
imageButton: { |
||||
padding: 0, |
||||
color: TEXT, |
||||
}, |
||||
imageIcon: { |
||||
borderRadius: 8, |
||||
padding: 0, |
||||
backgroundColor: GREY, |
||||
fontSize: '8em', |
||||
}, |
||||
})); |
||||
|
||||
const Preview = ({ setMode, serverName }: PreviewProps): JSX.Element => { |
||||
const classes = useStyles(); |
||||
|
||||
return ( |
||||
<Panel> |
||||
<Box flexGrow={1}> |
||||
<HeaderText text={`Server: ${serverName}`} /> |
||||
</Box> |
||||
<Box display="flex" className={classes.displayBox}> |
||||
<Box> |
||||
<IconButton |
||||
className={classes.imageButton} |
||||
style={{ color: BLACK }} |
||||
component="span" |
||||
onClick={() => setMode(false)} |
||||
> |
||||
<CropOriginal className={classes.imageIcon} /> |
||||
</IconButton> |
||||
</Box> |
||||
<Box className={classes.fullScreenBox}> |
||||
<IconButton |
||||
className={classes.fullScreenButton} |
||||
style={{ color: BLACK }} |
||||
component="span" |
||||
onClick={() => setMode(false)} |
||||
> |
||||
<DesktopWindowsIcon /> |
||||
</IconButton> |
||||
</Box> |
||||
</Box> |
||||
</Panel> |
||||
); |
||||
}; |
||||
|
||||
export default Preview; |
@ -0,0 +1,96 @@ |
||||
import { useEffect, useRef, MutableRefObject, memo } from 'react'; |
||||
import RFB from '@novnc/novnc/core/rfb'; |
||||
|
||||
type Props = { |
||||
rfb: MutableRefObject<typeof RFB | undefined>; |
||||
url: string; |
||||
viewOnly: boolean; |
||||
focusOnClick: boolean; |
||||
clipViewport: boolean; |
||||
dragViewport: boolean; |
||||
scaleViewport: boolean; |
||||
resizeSession: boolean; |
||||
showDotCursor: boolean; |
||||
background: string; |
||||
qualityLevel: number; |
||||
compressionLevel: number; |
||||
}; |
||||
|
||||
const VncDisplay = (props: Props): JSX.Element => { |
||||
const screen = useRef<HTMLDivElement>(null); |
||||
|
||||
const { |
||||
rfb, |
||||
url, |
||||
viewOnly, |
||||
focusOnClick, |
||||
clipViewport, |
||||
dragViewport, |
||||
scaleViewport, |
||||
resizeSession, |
||||
showDotCursor, |
||||
background, |
||||
qualityLevel, |
||||
compressionLevel, |
||||
} = props; |
||||
|
||||
useEffect(() => { |
||||
if (!screen.current) { |
||||
return (): void => { |
||||
if (rfb.current) { |
||||
rfb?.current.disconnect(); |
||||
rfb.current = undefined; |
||||
} |
||||
}; |
||||
} |
||||
|
||||
if (!rfb.current) { |
||||
screen.current.innerHTML = ''; |
||||
|
||||
rfb.current = new RFB(screen.current, url); |
||||
|
||||
rfb.current.viewOnly = viewOnly; |
||||
rfb.current.focusOnClick = focusOnClick; |
||||
rfb.current.clipViewport = clipViewport; |
||||
rfb.current.dragViewport = dragViewport; |
||||
rfb.current.resizeSession = resizeSession; |
||||
rfb.current.scaleViewport = scaleViewport; |
||||
rfb.current.showDotCursor = showDotCursor; |
||||
rfb.current.background = background; |
||||
rfb.current.qualityLevel = qualityLevel; |
||||
rfb.current.compressionLevel = compressionLevel; |
||||
} |
||||
|
||||
/* eslint-disable consistent-return */ |
||||
if (!rfb.current) return; |
||||
|
||||
return (): void => { |
||||
if (rfb.current) { |
||||
rfb.current.disconnect(); |
||||
rfb.current = undefined; |
||||
} |
||||
}; |
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [rfb]); |
||||
|
||||
const handleMouseEnter = () => { |
||||
if ( |
||||
document.activeElement && |
||||
document.activeElement instanceof HTMLElement |
||||
) { |
||||
document.activeElement.blur(); |
||||
} |
||||
|
||||
if (rfb?.current) rfb.current.focus(); |
||||
}; |
||||
|
||||
return ( |
||||
<div |
||||
style={{ width: '100%', height: '75vh' }} |
||||
ref={screen} |
||||
onMouseEnter={handleMouseEnter} |
||||
/> |
||||
); |
||||
}; |
||||
|
||||
export default memo(VncDisplay); |
@ -0,0 +1,4 @@ |
||||
import FullSize from './FullSize'; |
||||
import Preview from './Preview'; |
||||
|
||||
export { FullSize, Preview }; |
@ -0,0 +1,27 @@ |
||||
const ControlL = '0xffe3'; |
||||
const AltL = '0xffe9'; |
||||
|
||||
const F1 = '0xffbe'; |
||||
const F2 = '0xffbf'; |
||||
const F3 = '0xffc0'; |
||||
const F4 = '0xffc1'; |
||||
const F5 = '0xffc2'; |
||||
const F6 = '0xffc3'; |
||||
const F7 = '0xffc4'; |
||||
const F8 = '0xffc5'; |
||||
const F9 = '0xffc6'; |
||||
|
||||
const keyCombinations: Array<{ keys: string; scans: string[] }> = [ |
||||
{ keys: 'Ctrl + Alt + Delete', scans: [] }, |
||||
{ keys: 'Ctrl + Alt + F1', scans: [ControlL, AltL, F1] }, |
||||
{ keys: 'Ctrl + Alt + F2', scans: [ControlL, AltL, F2] }, |
||||
{ keys: 'Ctrl + Alt + F3', scans: [ControlL, AltL, F3] }, |
||||
{ keys: 'Ctrl + Alt + F4', scans: [ControlL, AltL, F4] }, |
||||
{ keys: 'Ctrl + Alt + F5', scans: [ControlL, AltL, F5] }, |
||||
{ keys: 'Ctrl + Alt + F6', scans: [ControlL, AltL, F6] }, |
||||
{ keys: 'Ctrl + Alt + F7', scans: [ControlL, AltL, F7] }, |
||||
{ keys: 'Ctrl + Alt + F8', scans: [ControlL, AltL, F8] }, |
||||
{ keys: 'Ctrl + Alt + F9', scans: [ControlL, AltL, F9] }, |
||||
]; |
||||
|
||||
export default keyCombinations; |
@ -0,0 +1,12 @@ |
||||
import { Panel } from './Panels'; |
||||
import { HeaderText } from './Text'; |
||||
|
||||
const Domain = (): JSX.Element => { |
||||
return ( |
||||
<Panel> |
||||
<HeaderText text="Domain Settings" /> |
||||
</Panel> |
||||
); |
||||
}; |
||||
|
||||
export default Domain; |
@ -0,0 +1,131 @@ |
||||
import * as prettyBytes from 'pretty-bytes'; |
||||
import { makeStyles, Box, Divider } from '@material-ui/core'; |
||||
import InsertLinkIcon from '@material-ui/icons/InsertLink'; |
||||
import { InnerPanel, PanelHeader } from '../Panels'; |
||||
import { BodyText } from '../Text'; |
||||
import Decorator, { Colours } from '../Decorator'; |
||||
import { DIVIDER } from '../../lib/consts/DEFAULT_THEME'; |
||||
|
||||
const useStyles = makeStyles((theme) => ({ |
||||
root: { |
||||
overflow: 'auto', |
||||
height: '100%', |
||||
paddingLeft: '.3em', |
||||
[theme.breakpoints.down('md')]: { |
||||
overflow: 'hidden', |
||||
}, |
||||
}, |
||||
connection: { |
||||
paddingLeft: '.7em', |
||||
paddingRight: '.7em', |
||||
paddingTop: '1em', |
||||
paddingBottom: '.7em', |
||||
}, |
||||
bar: { |
||||
paddingLeft: '.7em', |
||||
paddingRight: '.7em', |
||||
}, |
||||
header: { |
||||
paddingTop: '.3em', |
||||
paddingRight: '.7em', |
||||
}, |
||||
label: { |
||||
paddingTop: '.3em', |
||||
}, |
||||
decoratorBox: { |
||||
paddingRight: '.3em', |
||||
}, |
||||
divider: { |
||||
background: DIVIDER, |
||||
}, |
||||
})); |
||||
|
||||
const selectDecorator = (state: string): Colours => { |
||||
switch (state) { |
||||
case 'connected': |
||||
return 'ok'; |
||||
case 'connecting': |
||||
return 'warning'; |
||||
default: |
||||
return 'error'; |
||||
} |
||||
}; |
||||
|
||||
const ResourceVolumes = ({ |
||||
resource, |
||||
}: { |
||||
resource: AnvilReplicatedStorage; |
||||
}): JSX.Element => { |
||||
const classes = useStyles(); |
||||
|
||||
return ( |
||||
<Box className={classes.root}> |
||||
{resource && |
||||
resource.volumes.map((volume) => { |
||||
return ( |
||||
<InnerPanel key={volume.drbd_device_minor}> |
||||
<PanelHeader> |
||||
<Box display="flex" width="100%" className={classes.header}> |
||||
<Box flexGrow={1}> |
||||
<BodyText text={`Volume: ${volume.number}`} /> |
||||
</Box> |
||||
<Box> |
||||
<BodyText |
||||
text={`Size: ${prettyBytes.default(volume.size, { |
||||
binary: true, |
||||
})}`}
|
||||
/> |
||||
</Box> |
||||
</Box> |
||||
</PanelHeader> |
||||
{volume.connections.map( |
||||
(connection, index): JSX.Element => { |
||||
return ( |
||||
<> |
||||
<Box |
||||
key={connection.fencing} |
||||
display="flex" |
||||
width="100%" |
||||
className={classes.connection} |
||||
> |
||||
<Box className={classes.decoratorBox}> |
||||
<Decorator |
||||
colour={selectDecorator( |
||||
connection.connection_state, |
||||
)} |
||||
/> |
||||
</Box> |
||||
<Box> |
||||
<Box display="flex" width="100%"> |
||||
<BodyText |
||||
text={connection.targets[0].target_name} |
||||
/> |
||||
<InsertLinkIcon style={{ color: DIVIDER }} /> |
||||
<BodyText |
||||
text={connection.targets[1].target_name} |
||||
/> |
||||
</Box> |
||||
<Box |
||||
display="flex" |
||||
justifyContent="center" |
||||
width="100%" |
||||
> |
||||
<BodyText text={connection.connection_state} /> |
||||
</Box> |
||||
</Box> |
||||
</Box> |
||||
{volume.connections.length - 1 !== index ? ( |
||||
<Divider className={classes.divider} /> |
||||
) : null} |
||||
</> |
||||
); |
||||
}, |
||||
)} |
||||
</InnerPanel> |
||||
); |
||||
})} |
||||
</Box> |
||||
); |
||||
}; |
||||
|
||||
export default ResourceVolumes; |
@ -0,0 +1,18 @@ |
||||
import { Panel } from '../Panels'; |
||||
import { HeaderText } from '../Text'; |
||||
import ResourceVolumes from './ResourceVolumes'; |
||||
|
||||
const Resource = ({ |
||||
resource, |
||||
}: { |
||||
resource: AnvilReplicatedStorage; |
||||
}): JSX.Element => { |
||||
return ( |
||||
<Panel> |
||||
<HeaderText text={`Resource: ${resource.resource_name}`} /> |
||||
<ResourceVolumes resource={resource} /> |
||||
</Panel> |
||||
); |
||||
}; |
||||
|
||||
export default Resource; |
@ -0,0 +1,19 @@ |
||||
import { useEffect, useState } from 'react'; |
||||
|
||||
const useWindowDimensions = (): number | undefined => { |
||||
const [windowDimensions, setWindowDimensions] = useState<number | undefined>( |
||||
undefined, |
||||
); |
||||
useEffect(() => { |
||||
const handleResize = (): void => { |
||||
setWindowDimensions(window.innerWidth); |
||||
}; |
||||
handleResize(); |
||||
window.addEventListener('resize', handleResize); |
||||
return (): void => window.removeEventListener('resize', handleResize); |
||||
}, []); // Empty array ensures that effect is only run on mount
|
||||
|
||||
return windowDimensions; |
||||
}; |
||||
|
||||
export default useWindowDimensions; |
@ -0,0 +1,12 @@ |
||||
/* eslint-disable @typescript-eslint/no-explicit-any */ |
||||
const putFetch = <T>(uri: string, data: T): Promise<any> => { |
||||
return fetch(uri, { |
||||
method: 'PUT', |
||||
headers: { |
||||
'Content-Type': 'application/json', |
||||
}, |
||||
body: JSON.stringify(data), |
||||
}); |
||||
}; |
||||
|
||||
export default putFetch; |
@ -0,0 +1,25 @@ |
||||
/* eslint-disable @typescript-eslint/no-explicit-any */ |
||||
const putFetchTimeout = async <T>( |
||||
uri: string, |
||||
data: T, |
||||
timeout: number, |
||||
): Promise<any> => { |
||||
const controller = new AbortController(); |
||||
|
||||
const id = setTimeout(() => controller.abort(), timeout); |
||||
|
||||
const res = await fetch(uri, { |
||||
method: 'PUT', |
||||
headers: { |
||||
'Content-Type': 'application/json', |
||||
'Keep-Alive': 'timeout=120', |
||||
}, |
||||
signal: controller.signal, |
||||
body: JSON.stringify(data), |
||||
}); |
||||
clearTimeout(id); |
||||
|
||||
return res; |
||||
}; |
||||
|
||||
export default putFetchTimeout; |
@ -1,11 +0,0 @@ |
||||
const putJSON = <T>(uri: string, data: T): void => { |
||||
fetch(`${process.env.NEXT_PUBLIC_API_URL}${uri}`, { |
||||
method: 'PUT', |
||||
headers: { |
||||
'Content-Type': 'application/json', |
||||
}, |
||||
body: JSON.stringify(data), |
||||
}); |
||||
}; |
||||
|
||||
export default putJSON; |
@ -1 +0,0 @@ |
||||
self.__BUILD_MANIFEST={__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":["static/chunks/642-0e4040fe0a744c110cab.js","static/chunks/pages/index-ca8a2930d2c5ccf8a7f5.js"],"/_error":["static/chunks/pages/_error-a9f53acb468cbab8a6cb.js"],sortedPages:["/","/_app","/_error"]},self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB(); |
@ -0,0 +1 @@ |
||||
self.__BUILD_MANIFEST=function(e){return{__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":[e,"static/chunks/254-408dda06d3f8a3c7f26d.js","static/chunks/pages/index-c61930195d75a6c617a7.js"],"/_error":["static/chunks/pages/_error-a9f53acb468cbab8a6cb.js"],"/server":[e,"static/chunks/643-8d1f5368d89a6ae0ce2a.js","static/chunks/pages/server-70802da45b05d679f5bd.js"],sortedPages:["/","/_app","/_error","/server"]}}("static/chunks/642-ebd3de567e50b02b8111.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB(); |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1 @@ |
||||
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[340],{340:function(e,r,n){"use strict";n.r(r);var t=n(5893),c=n(7294),u=n(8753),o=function(e){var r=(0,c.useRef)(null),n=e.rfb,o=e.url,i=e.viewOnly,s=e.focusOnClick,l=e.clipViewport,f=e.dragViewport,v=e.scaleViewport,a=e.resizeSession,d=e.showDotCursor,w=e.background,p=e.qualityLevel,m=e.compressionLevel;(0,c.useEffect)((function(){return r.current?(n.current||(r.current.innerHTML="",n.current=new u.Z(r.current,o),n.current.viewOnly=i,n.current.focusOnClick=s,n.current.clipViewport=l,n.current.dragViewport=f,n.current.resizeSession=a,n.current.scaleViewport=v,n.current.showDotCursor=d,n.current.background=w,n.current.qualityLevel=p,n.current.compressionLevel=m),n.current?function(){n.current&&(n.current.disconnect(),n.current=void 0)}:void 0):function(){n.current&&(null===n||void 0===n||n.current.disconnect(),n.current=void 0)}}),[n]);return(0,t.jsx)("div",{style:{width:"100%",height:"75vh"},ref:r,onMouseEnter:function(){document.activeElement&&document.activeElement instanceof HTMLElement&&document.activeElement.blur(),null!==n&&void 0!==n&&n.current&&n.current.focus()}})};r.default=(0,c.memo)(o)}}]); |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@ |
||||
!function(){"use strict";var r={},e={};function t(n){var o=e[n];if(void 0!==o)return o.exports;var i=e[n]={exports:{}},u=!0;try{r[n](i,i.exports,t),u=!1}finally{u&&delete e[n]}return i.exports}t.m=r,function(){var r=[];t.O=function(e,n,o,i){if(!n){var u=1/0;for(a=0;a<r.length;a++){n=r[a][0],o=r[a][1],i=r[a][2];for(var c=!0,f=0;f<n.length;f++)(!1&i||u>=i)&&Object.keys(t.O).every((function(r){return t.O[r](n[f])}))?n.splice(f--,1):(c=!1,i<u&&(u=i));c&&(r.splice(a--,1),e=o())}return e}i=i||0;for(var a=r.length;a>0&&r[a-1][2]>i;a--)r[a]=r[a-1];r[a]=[n,o,i]}}(),t.n=function(r){var e=r&&r.__esModule?function(){return r.default}:function(){return r};return t.d(e,{a:e}),e},t.d=function(r,e){for(var n in e)t.o(e,n)&&!t.o(r,n)&&Object.defineProperty(r,n,{enumerable:!0,get:e[n]})},t.g=function(){if("object"===typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(r){if("object"===typeof window)return window}}(),t.o=function(r,e){return Object.prototype.hasOwnProperty.call(r,e)},t.r=function(r){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(r,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(r,"__esModule",{value:!0})},function(){var r;t.g.importScripts&&(r=t.g.location+"");var e=t.g.document;if(!r&&e&&(e.currentScript&&(r=e.currentScript.src),!r)){var n=e.getElementsByTagName("script");n.length&&(r=n[n.length-1].src)}if(!r)throw new Error("Automatic publicPath is not supported in this browser");r=r.replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),t.p=r+"../../"}(),function(){var r={272:0};t.O.j=function(e){return 0===r[e]};var e=function(e,n){var o,i,u=n[0],c=n[1],f=n[2],a=0;for(o in c)t.o(c,o)&&(t.m[o]=c[o]);if(f)var l=f(t);for(e&&e(n);a<u.length;a++)i=u[a],t.o(r,i)&&r[i]&&r[i][0](),r[u[a]]=0;return t.O(l)},n=self.webpackChunk_N_E=self.webpackChunk_N_E||[];n.forEach(e.bind(null,0)),n.push=e.bind(null,n.push.bind(n))}()}(); |
@ -0,0 +1 @@ |
||||
!function(){"use strict";var e={},t={};function r(n){var o=t[n];if(void 0!==o)return o.exports;var i=t[n]={exports:{}},u=!0;try{e[n](i,i.exports,r),u=!1}finally{u&&delete t[n]}return i.exports}r.m=e,function(){var e=[];r.O=function(t,n,o,i){if(!n){var u=1/0;for(f=0;f<e.length;f++){n=e[f][0],o=e[f][1],i=e[f][2];for(var c=!0,a=0;a<n.length;a++)(!1&i||u>=i)&&Object.keys(r.O).every((function(e){return r.O[e](n[a])}))?n.splice(a--,1):(c=!1,i<u&&(u=i));c&&(e.splice(f--,1),t=o())}return t}i=i||0;for(var f=e.length;f>0&&e[f-1][2]>i;f--)e[f]=e[f-1];e[f]=[n,o,i]}}(),r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,{a:t}),t},r.d=function(e,t){for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.f={},r.e=function(e){return Promise.all(Object.keys(r.f).reduce((function(t,n){return r.f[n](e,t),t}),[]))},r.u=function(e){return"static/chunks/"+e+"."+{204:"04ef0f70c11fb4c25e5c",340:"717e8436d6d29df37ce9"}[e]+".js"},r.miniCssF=function(e){return"static/css/1b1a1a5807b24bb728c2.css"},r.g=function(){if("object"===typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"===typeof window)return window}}(),r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},function(){var e={},t="_N_E:";r.l=function(n,o,i,u){if(e[n])e[n].push(o);else{var c,a;if(void 0!==i)for(var f=document.getElementsByTagName("script"),l=0;l<f.length;l++){var s=f[l];if(s.getAttribute("src")==n||s.getAttribute("data-webpack")==t+i){c=s;break}}c||(a=!0,(c=document.createElement("script")).charset="utf-8",c.timeout=120,r.nc&&c.setAttribute("nonce",r.nc),c.setAttribute("data-webpack",t+i),c.src=n),e[n]=[o];var d=function(t,r){c.onerror=c.onload=null,clearTimeout(p);var o=e[n];if(delete e[n],c.parentNode&&c.parentNode.removeChild(c),o&&o.forEach((function(e){return e(r)})),t)return t(r)},p=setTimeout(d.bind(null,void 0,{type:"timeout",target:c}),12e4);c.onerror=d.bind(null,c.onerror),c.onload=d.bind(null,c.onload),a&&document.head.appendChild(c)}}}(),r.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},function(){var e;r.g.importScripts&&(e=r.g.location+"");var t=r.g.document;if(!e&&t&&(t.currentScript&&(e=t.currentScript.src),!e)){var n=t.getElementsByTagName("script");n.length&&(e=n[n.length-1].src)}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),r.p=e+"../../"}(),function(){var e={272:0};r.f.j=function(t,n){var o=r.o(e,t)?e[t]:void 0;if(0!==o)if(o)n.push(o[2]);else if(272!=t){var i=new Promise((function(r,n){o=e[t]=[r,n]}));n.push(o[2]=i);var u=r.p+r.u(t),c=new Error;r.l(u,(function(n){if(r.o(e,t)&&(0!==(o=e[t])&&(e[t]=void 0),o)){var i=n&&("load"===n.type?"missing":n.type),u=n&&n.target&&n.target.src;c.message="Loading chunk "+t+" failed.\n("+i+": "+u+")",c.name="ChunkLoadError",c.type=i,c.request=u,o[1](c)}}),"chunk-"+t,t)}else e[t]=0},r.O.j=function(t){return 0===e[t]};var t=function(t,n){var o,i,u=n[0],c=n[1],a=n[2],f=0;for(o in c)r.o(c,o)&&(r.m[o]=c[o]);if(a)var l=a(r);for(t&&t(n);f<u.length;f++)i=u[f],r.o(e,i)&&e[i]&&e[i][0](),e[u[f]]=0;return r.O(l)},n=self.webpackChunk_N_E=self.webpackChunk_N_E||[];n.forEach(t.bind(null,0)),n.push=t.bind(null,n.push.bind(n))}()}(); |
@ -0,0 +1,516 @@ |
||||
<!DOCTYPE html><html><head><meta name="viewport" content="width=device-width"/><meta charSet="utf-8"/><title></title><meta name="next-head-count" content="3"/><link rel="preload" href="/_next/static/css/1b1a1a5807b24bb728c2.css" as="style"/><link rel="stylesheet" href="/_next/static/css/1b1a1a5807b24bb728c2.css" data-n-g=""/><noscript data-n-css=""></noscript><link rel="preload" href="/_next/static/chunks/webpack-279cb3a826ca5d40fce3.js" as="script"/><link rel="preload" href="/_next/static/chunks/framework-c93ed74a065331c4bd75.js" as="script"/><link rel="preload" href="/_next/static/chunks/main-6c0a2257b76a50556a7f.js" as="script"/><link rel="preload" href="/_next/static/chunks/pages/_app-f07dad954b186d55bf72.js" as="script"/><link rel="preload" href="/_next/static/chunks/642-ebd3de567e50b02b8111.js" as="script"/><link rel="preload" href="/_next/static/chunks/643-8d1f5368d89a6ae0ce2a.js" as="script"/><link rel="preload" href="/_next/static/chunks/pages/server-70802da45b05d679f5bd.js" as="script"/><style id="jss-server-side">.MuiButtonBase-root { |
||||
color: inherit; |
||||
border: 0; |
||||
cursor: pointer; |
||||
margin: 0; |
||||
display: inline-flex; |
||||
outline: 0; |
||||
padding: 0; |
||||
position: relative; |
||||
align-items: center; |
||||
user-select: none; |
||||
border-radius: 0; |
||||
vertical-align: middle; |
||||
-moz-appearance: none; |
||||
justify-content: center; |
||||
text-decoration: none; |
||||
background-color: transparent; |
||||
-webkit-appearance: none; |
||||
-webkit-tap-highlight-color: transparent; |
||||
} |
||||
.MuiButtonBase-root::-moz-focus-inner { |
||||
border-style: none; |
||||
} |
||||
.MuiButtonBase-root.Mui-disabled { |
||||
cursor: default; |
||||
pointer-events: none; |
||||
} |
||||
@media print { |
||||
.MuiButtonBase-root { |
||||
color-adjust: exact; |
||||
} |
||||
} |
||||
|
||||
.jss9 { |
||||
display: flex; |
||||
flex-direction: row; |
||||
justify-content: space-between; |
||||
} |
||||
.jss10 { } |
||||
.jss11 { } |
||||
.MuiButton-root { |
||||
color: rgba(0, 0, 0, 0.87); |
||||
padding: 6px 16px; |
||||
font-size: 0.875rem; |
||||
min-width: 64px; |
||||
box-sizing: border-box; |
||||
transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,border 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; |
||||
font-family: Roboto Condensed; |
||||
font-weight: 500; |
||||
line-height: 1.75; |
||||
border-radius: 4px; |
||||
text-transform: uppercase; |
||||
} |
||||
.MuiButton-root:hover { |
||||
text-decoration: none; |
||||
background-color: rgba(0, 0, 0, 0.04); |
||||
} |
||||
.MuiButton-root.Mui-disabled { |
||||
color: rgba(0, 0, 0, 0.26); |
||||
} |
||||
@media (hover: none) { |
||||
.MuiButton-root:hover { |
||||
background-color: transparent; |
||||
} |
||||
} |
||||
.MuiButton-root:hover.Mui-disabled { |
||||
background-color: transparent; |
||||
} |
||||
.MuiButton-label { |
||||
width: 100%; |
||||
display: inherit; |
||||
align-items: inherit; |
||||
justify-content: inherit; |
||||
} |
||||
.MuiButton-text { |
||||
padding: 6px 8px; |
||||
} |
||||
.MuiButton-textPrimary { |
||||
color: #343434; |
||||
} |
||||
.MuiButton-textPrimary:hover { |
||||
background-color: rgba(52, 52, 52, 0.04); |
||||
} |
||||
@media (hover: none) { |
||||
.MuiButton-textPrimary:hover { |
||||
background-color: transparent; |
||||
} |
||||
} |
||||
.MuiButton-textSecondary { |
||||
color: #F2F2F2; |
||||
} |
||||
.MuiButton-textSecondary:hover { |
||||
background-color: rgba(242, 242, 242, 0.04); |
||||
} |
||||
@media (hover: none) { |
||||
.MuiButton-textSecondary:hover { |
||||
background-color: transparent; |
||||
} |
||||
} |
||||
.MuiButton-outlined { |
||||
border: 1px solid rgba(0, 0, 0, 0.23); |
||||
padding: 5px 15px; |
||||
} |
||||
.MuiButton-outlined.Mui-disabled { |
||||
border: 1px solid rgba(0, 0, 0, 0.12); |
||||
} |
||||
.MuiButton-outlinedPrimary { |
||||
color: #343434; |
||||
border: 1px solid rgba(52, 52, 52, 0.5); |
||||
} |
||||
.MuiButton-outlinedPrimary:hover { |
||||
border: 1px solid #343434; |
||||
background-color: rgba(52, 52, 52, 0.04); |
||||
} |
||||
@media (hover: none) { |
||||
.MuiButton-outlinedPrimary:hover { |
||||
background-color: transparent; |
||||
} |
||||
} |
||||
.MuiButton-outlinedSecondary { |
||||
color: #F2F2F2; |
||||
border: 1px solid rgba(242, 242, 242, 0.5); |
||||
} |
||||
.MuiButton-outlinedSecondary:hover { |
||||
border: 1px solid #F2F2F2; |
||||
background-color: rgba(242, 242, 242, 0.04); |
||||
} |
||||
.MuiButton-outlinedSecondary.Mui-disabled { |
||||
border: 1px solid rgba(0, 0, 0, 0.26); |
||||
} |
||||
@media (hover: none) { |
||||
.MuiButton-outlinedSecondary:hover { |
||||
background-color: transparent; |
||||
} |
||||
} |
||||
.MuiButton-contained { |
||||
color: rgba(0, 0, 0, 0.87); |
||||
box-shadow: 0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12); |
||||
background-color: #e0e0e0; |
||||
} |
||||
.MuiButton-contained:hover { |
||||
box-shadow: 0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12); |
||||
background-color: #d5d5d5; |
||||
} |
||||
.MuiButton-contained.Mui-focusVisible { |
||||
box-shadow: 0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiButton-contained:active { |
||||
box-shadow: 0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiButton-contained.Mui-disabled { |
||||
color: rgba(0, 0, 0, 0.26); |
||||
box-shadow: none; |
||||
background-color: rgba(0, 0, 0, 0.12); |
||||
} |
||||
@media (hover: none) { |
||||
.MuiButton-contained:hover { |
||||
box-shadow: 0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12); |
||||
background-color: #e0e0e0; |
||||
} |
||||
} |
||||
.MuiButton-contained:hover.Mui-disabled { |
||||
background-color: rgba(0, 0, 0, 0.12); |
||||
} |
||||
.MuiButton-containedPrimary { |
||||
color: #fff; |
||||
background-color: #343434; |
||||
} |
||||
.MuiButton-containedPrimary:hover { |
||||
background-color: rgb(36, 36, 36); |
||||
} |
||||
@media (hover: none) { |
||||
.MuiButton-containedPrimary:hover { |
||||
background-color: #343434; |
||||
} |
||||
} |
||||
.MuiButton-containedSecondary { |
||||
color: rgba(0, 0, 0, 0.87); |
||||
background-color: #F2F2F2; |
||||
} |
||||
.MuiButton-containedSecondary:hover { |
||||
background-color: rgb(169, 169, 169); |
||||
} |
||||
@media (hover: none) { |
||||
.MuiButton-containedSecondary:hover { |
||||
background-color: #F2F2F2; |
||||
} |
||||
} |
||||
.MuiButton-disableElevation { |
||||
box-shadow: none; |
||||
} |
||||
.MuiButton-disableElevation:hover { |
||||
box-shadow: none; |
||||
} |
||||
.MuiButton-disableElevation.Mui-focusVisible { |
||||
box-shadow: none; |
||||
} |
||||
.MuiButton-disableElevation:active { |
||||
box-shadow: none; |
||||
} |
||||
.MuiButton-disableElevation.Mui-disabled { |
||||
box-shadow: none; |
||||
} |
||||
.MuiButton-colorInherit { |
||||
color: inherit; |
||||
border-color: currentColor; |
||||
} |
||||
.MuiButton-textSizeSmall { |
||||
padding: 4px 5px; |
||||
font-size: 0.8125rem; |
||||
} |
||||
.MuiButton-textSizeLarge { |
||||
padding: 8px 11px; |
||||
font-size: 0.9375rem; |
||||
} |
||||
.MuiButton-outlinedSizeSmall { |
||||
padding: 3px 9px; |
||||
font-size: 0.8125rem; |
||||
} |
||||
.MuiButton-outlinedSizeLarge { |
||||
padding: 7px 21px; |
||||
font-size: 0.9375rem; |
||||
} |
||||
.MuiButton-containedSizeSmall { |
||||
padding: 4px 10px; |
||||
font-size: 0.8125rem; |
||||
} |
||||
.MuiButton-containedSizeLarge { |
||||
padding: 8px 22px; |
||||
font-size: 0.9375rem; |
||||
} |
||||
.MuiButton-fullWidth { |
||||
width: 100%; |
||||
} |
||||
.MuiButton-startIcon { |
||||
display: inherit; |
||||
margin-left: -4px; |
||||
margin-right: 8px; |
||||
} |
||||
.MuiButton-startIcon.MuiButton-iconSizeSmall { |
||||
margin-left: -2px; |
||||
} |
||||
.MuiButton-endIcon { |
||||
display: inherit; |
||||
margin-left: 8px; |
||||
margin-right: -4px; |
||||
} |
||||
.MuiButton-endIcon.MuiButton-iconSizeSmall { |
||||
margin-right: -2px; |
||||
} |
||||
.MuiButton-iconSizeSmall > *:first-child { |
||||
font-size: 18px; |
||||
} |
||||
.MuiButton-iconSizeMedium > *:first-child { |
||||
font-size: 20px; |
||||
} |
||||
.MuiButton-iconSizeLarge > *:first-child { |
||||
font-size: 22px; |
||||
} |
||||
.MuiDrawer-docked { |
||||
flex: 0 0 auto; |
||||
} |
||||
.MuiDrawer-paper { |
||||
top: 0; |
||||
flex: 1 0 auto; |
||||
height: 100%; |
||||
display: flex; |
||||
outline: 0; |
||||
z-index: 1200; |
||||
position: fixed; |
||||
overflow-y: auto; |
||||
flex-direction: column; |
||||
-webkit-overflow-scrolling: touch; |
||||
} |
||||
.MuiDrawer-paperAnchorLeft { |
||||
left: 0; |
||||
right: auto; |
||||
} |
||||
.MuiDrawer-paperAnchorRight { |
||||
left: auto; |
||||
right: 0; |
||||
} |
||||
.MuiDrawer-paperAnchorTop { |
||||
top: 0; |
||||
left: 0; |
||||
right: 0; |
||||
bottom: auto; |
||||
height: auto; |
||||
max-height: 100%; |
||||
} |
||||
.MuiDrawer-paperAnchorBottom { |
||||
top: auto; |
||||
left: 0; |
||||
right: 0; |
||||
bottom: 0; |
||||
height: auto; |
||||
max-height: 100%; |
||||
} |
||||
.MuiDrawer-paperAnchorDockedLeft { |
||||
border-right: 1px solid rgba(0, 0, 0, 0.12); |
||||
} |
||||
.MuiDrawer-paperAnchorDockedTop { |
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.12); |
||||
} |
||||
.MuiDrawer-paperAnchorDockedRight { |
||||
border-left: 1px solid rgba(0, 0, 0, 0.12); |
||||
} |
||||
.MuiDrawer-paperAnchorDockedBottom { |
||||
border-top: 1px solid rgba(0, 0, 0, 0.12); |
||||
} |
||||
.MuiPaper-root { |
||||
color: rgba(0, 0, 0, 0.87); |
||||
transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; |
||||
background-color: #343434; |
||||
} |
||||
.MuiPaper-rounded { |
||||
border-radius: 4px; |
||||
} |
||||
.MuiPaper-outlined { |
||||
border: 1px solid rgba(0, 0, 0, 0.12); |
||||
} |
||||
.MuiPaper-elevation0 { |
||||
box-shadow: none; |
||||
} |
||||
.MuiPaper-elevation1 { |
||||
box-shadow: 0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation2 { |
||||
box-shadow: 0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation3 { |
||||
box-shadow: 0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation4 { |
||||
box-shadow: 0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation5 { |
||||
box-shadow: 0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation6 { |
||||
box-shadow: 0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation7 { |
||||
box-shadow: 0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation8 { |
||||
box-shadow: 0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation9 { |
||||
box-shadow: 0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation10 { |
||||
box-shadow: 0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation11 { |
||||
box-shadow: 0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation12 { |
||||
box-shadow: 0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation13 { |
||||
box-shadow: 0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation14 { |
||||
box-shadow: 0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation15 { |
||||
box-shadow: 0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation16 { |
||||
box-shadow: 0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation17 { |
||||
box-shadow: 0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation18 { |
||||
box-shadow: 0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation19 { |
||||
box-shadow: 0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation20 { |
||||
box-shadow: 0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation21 { |
||||
box-shadow: 0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation22 { |
||||
box-shadow: 0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation23 { |
||||
box-shadow: 0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiPaper-elevation24 { |
||||
box-shadow: 0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12); |
||||
} |
||||
.MuiAppBar-root { |
||||
width: 100%; |
||||
display: flex; |
||||
z-index: 1100; |
||||
box-sizing: border-box; |
||||
flex-shrink: 0; |
||||
flex-direction: column; |
||||
} |
||||
.MuiAppBar-positionFixed { |
||||
top: 0; |
||||
left: auto; |
||||
right: 0; |
||||
position: fixed; |
||||
} |
||||
@media print { |
||||
.MuiAppBar-positionFixed { |
||||
position: absolute; |
||||
} |
||||
} |
||||
.MuiAppBar-positionAbsolute { |
||||
top: 0; |
||||
left: auto; |
||||
right: 0; |
||||
position: absolute; |
||||
} |
||||
.MuiAppBar-positionSticky { |
||||
top: 0; |
||||
left: auto; |
||||
right: 0; |
||||
position: sticky; |
||||
} |
||||
.MuiAppBar-positionStatic { |
||||
position: static; |
||||
} |
||||
.MuiAppBar-positionRelative { |
||||
position: relative; |
||||
} |
||||
.MuiAppBar-colorDefault { |
||||
color: rgba(0, 0, 0, 0.87); |
||||
background-color: #f5f5f5; |
||||
} |
||||
.MuiAppBar-colorPrimary { |
||||
color: #fff; |
||||
background-color: #343434; |
||||
} |
||||
.MuiAppBar-colorSecondary { |
||||
color: rgba(0, 0, 0, 0.87); |
||||
background-color: #F2F2F2; |
||||
} |
||||
.MuiAppBar-colorInherit { |
||||
color: inherit; |
||||
} |
||||
.MuiAppBar-colorTransparent { |
||||
color: inherit; |
||||
background-color: transparent; |
||||
} |
||||
.jss12 { |
||||
width: 200px; |
||||
} |
||||
.jss13 { |
||||
background: #888; |
||||
} |
||||
.jss14 { |
||||
padding-top: .5em; |
||||
padding-left: 1.5em; |
||||
} |
||||
.jss15 { |
||||
padding-left: .1em; |
||||
} |
||||
.jss16 { |
||||
color: #E5E5E5; |
||||
font-size: 2.3em; |
||||
} |
||||
.jss3 { |
||||
padding-top: 4px; |
||||
padding-left: 24px; |
||||
border-bottom: solid 1px; |
||||
padding-right: 24px; |
||||
padding-bottom: 4px; |
||||
border-bottom-color: #D02724; |
||||
} |
||||
.jss4 { |
||||
width: 30vw; |
||||
height: 2.8em; |
||||
border-radius: 3px; |
||||
background-color: #F2F2F2; |
||||
} |
||||
.jss5 { |
||||
padding: 0; |
||||
} |
||||
@media (max-width:959.95px) { |
||||
.jss6 { |
||||
display: none; |
||||
} |
||||
} |
||||
@media (max-width:959.95px) { |
||||
.jss7 { |
||||
flex-grow: 1; |
||||
padding-left: 15vw; |
||||
} |
||||
} |
||||
.jss8 { |
||||
padding-left: .1em; |
||||
padding-right: .1em; |
||||
} |
||||
.jss1 { |
||||
width: 25%; |
||||
height: 100%; |
||||
} |
||||
@media (max-width:1279.95px) { |
||||
.jss1 { |
||||
width: 100%; |
||||
} |
||||
} |
||||
.jss2 { |
||||
width: 100%; |
||||
display: flex; |
||||
flex-direction: row; |
||||
justify-content: center; |
||||
}</style></head><body><div id="__next"><header class="MuiPaper-root MuiAppBar-root MuiAppBar-positionStatic MuiAppBar-colorPrimary jss3 MuiPaper-elevation4"><div class="MuiBox-root jss9"><div class="MuiBox-root jss10 jss5"><button class="MuiButtonBase-root MuiButton-root MuiButton-text" tabindex="0" type="button"><span class="MuiButton-label"><img alt="" src="/pngs/logo.png" width="160" height="40"/></span></button></div><div class="MuiBox-root jss11 jss5 jss6"><a href="/cgi-bin/striker?files=true"><img alt="" src="/pngs/files_on.png" width="40em" height="40em" class="jss8"/></a><a href="/cgi-bin/striker?jobs=true"><img alt="" src="/pngs/tasks_no-jobs_icon.png" width="40em" height="40em" class="jss8"/></a><a href="/cgi-bin/striker?configure=true"><img alt="" src="/pngs/configure_icon_on.png" width="40em" height="40em" class="jss8"/></a><a href="/cgi-bin/striker?striker=true"><img alt="" src="/pngs/striker_icon_on.png" width="40em" height="40em" class="jss8"/></a><a href="/cgi-bin/striker?anvil=true"><img alt="" src="/pngs/anvil_icon_on.png" width="40em" height="40em" class="jss8"/></a><a href="/cgi-bin/striker?email=true"><img alt="" src="/pngs/email_on.png" width="40em" height="40em" class="jss8"/></a><a href="/cgi-bin/striker?logout=true"><img alt="" src="/pngs/users_icon_on.png" width="40em" height="40em" class="jss8"/></a><a href="https://alteeve.com/w/Support"><img alt="" src="/pngs/help_icon_on.png" width="40em" height="40em" class="jss8"/></a></div></div></header></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/server","query":{},"buildId":"WegM9eT5kchrLUpg3bXOi","nextExport":true,"autoExport":true,"isFallback":false}</script><script nomodule="" src="/_next/static/chunks/polyfills-eef578260fd80f8fff94.js"></script><script src="/_next/static/chunks/webpack-279cb3a826ca5d40fce3.js" async=""></script><script src="/_next/static/chunks/framework-c93ed74a065331c4bd75.js" async=""></script><script src="/_next/static/chunks/main-6c0a2257b76a50556a7f.js" async=""></script><script src="/_next/static/chunks/pages/_app-f07dad954b186d55bf72.js" async=""></script><script src="/_next/static/chunks/642-ebd3de567e50b02b8111.js" async=""></script><script src="/_next/static/chunks/643-8d1f5368d89a6ae0ce2a.js" async=""></script><script src="/_next/static/chunks/pages/server-70802da45b05d679f5bd.js" async=""></script><script src="/_next/static/WegM9eT5kchrLUpg3bXOi/_buildManifest.js" async=""></script><script src="/_next/static/WegM9eT5kchrLUpg3bXOi/_ssgManifest.js" async=""></script></body></html> |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,57 @@ |
||||
import { useState } from 'react'; |
||||
import { useRouter } from 'next/router'; |
||||
import Head from 'next/head'; |
||||
import { Box } from '@material-ui/core'; |
||||
import { makeStyles } from '@material-ui/core/styles'; |
||||
|
||||
import { FullSize, Preview } from '../../components/Display'; |
||||
import Header from '../../components/Header'; |
||||
|
||||
const useStyles = makeStyles((theme) => ({ |
||||
preview: { |
||||
width: '25%', |
||||
height: '100%', |
||||
[theme.breakpoints.down('md')]: { |
||||
width: '100%', |
||||
}, |
||||
}, |
||||
fullView: { |
||||
display: 'flex', |
||||
flexDirection: 'row', |
||||
width: '100%', |
||||
justifyContent: 'center', |
||||
}, |
||||
})); |
||||
|
||||
const Server = (): JSX.Element => { |
||||
const [previewMode, setPreviewMode] = useState<boolean>(true); |
||||
const classes = useStyles(); |
||||
|
||||
const router = useRouter(); |
||||
const { uuid, server_name } = router.query; |
||||
|
||||
return ( |
||||
<> |
||||
<Head> |
||||
<title>{server_name}</title> |
||||
</Head> |
||||
<Header /> |
||||
{typeof uuid === 'string' && |
||||
(previewMode ? ( |
||||
<Box className={classes.preview}> |
||||
<Preview setMode={setPreviewMode} serverName={server_name} /> |
||||
</Box> |
||||
) : ( |
||||
<Box className={classes.fullView}> |
||||
<FullSize |
||||
setMode={setPreviewMode} |
||||
uuid={uuid} |
||||
serverName={server_name} |
||||
/> |
||||
</Box> |
||||
))} |
||||
</> |
||||
); |
||||
}; |
||||
|
||||
export default Server; |
@ -0,0 +1 @@ |
||||
declare module '@novnc/novnc/core/rfb'; |
Loading…
Reference in new issue