{"version":3,"sources":["containers/Viewport/styles.css.js","components/Navigation/index.js","containers/Stats/style.css.js","components/Browsers/style.css.js","components/Browsers/Browser.js","components/Browsers/index.js","containers/Stats/index.js","containers/Capabilities/style.css.js","containers/Capabilities/index.js","components/Stats/StatsElement.js","components/Stats/Status.js","components/Sessions/style.css.js","components/Sessions/index.js","components/Sessions/service.js","components/Session/SessionInfo.js","util/urlTo.js","util/isSecure.js","components/VncCard/VncScreen.js","components/VncCard/style.css.js","components/VncCard/index.js","components/Log/style.css.js","components/Log/index.js","components/Session/style.css.js","components/Session/index.js","components/Videos/style.css.js","components/Videos/index.js","components/Videos/service.js","components/Stats/Quota.js","components/Stats/Queue.js","components/Stats/Used.js","components/Stats/Separator.js","containers/Viewport/index.js","App.js","serviceWorker.js","index.js"],"names":["GlobalStyle","createGlobalStyle","StyledViewport","styled","div","StyledTopBar","Nav","Navigation","links","map","link","exact","key","href","className","activeClassName","to","title","StyledStats","StyledBrowsers","StyledBrowser","countColor","percentile","pct","percentColors","color","r","g","b","i","length","lower","upper","range","rangePct","pctLower","pctUpper","Math","floor","colors","col","toString","join","Browser","name","used","totalUsed","perc","toFixed","style","width","borderBottomColor","Browsers","browsers","undefined","Object","keys","sort","a","descendingCount","browser","Stats","state","StyledCapabilities","Launch","version","history","defaultAdditionalCaps","operaOptions","binary","useState","loading","onLoading","error","onError","useMoreCaps","toggleMoreCaps","moreCapsError","onMoreCapsError","JSON","stringify","moreCaps","setMoreCaps","useEventCallback","event$","inputs$","combineLatest","pipe","tap","flatMap","_","desiredCapabilities","browserName","enableVNC","labels","manual","sessionTimeout","selenoidOptions","additionalCaps","parse","assign","ajax","url","method","headers","timeout","body","capabilities","alwaysMatch","browserVersion","firstMatch","filter","status","res","push","response","sessionId","value","sessionIdFrom","catchError","err","caught","console","createSession","onClick","disabled","onMouseLeave","size","spellCheck","rows","onChange","e","target","defaultValue","withRouter","origin","onBrowserChange","lang","onLanguageChange","available","concat","label","caps","Url","yaml","curl","java","python","javascript","host","port","PHP","ruby","go","code","find","item","options","placeholder","isLoading","clearable","noResultsText","next","StatsElement","StyledStatus","Status","header","StyledSessions","Session","id","session","quota","mapTo","of","startWith","deleteSession","useSessionDelete","deleting","SessionId","substring","screenResolution","Actions","Capabilities","Sessions","sessions","query","ids","includes","toLowerCase","withQuery","TransitionGroup","CSSTransition","classNames","unmountOnExit","in","exit","SessionInfo","urlTo","lnk","document","createElement","setAttribute","isSecure","protocol","VncScreen","Component","onVNCDisconnect","this","connection","onVNCConnect","rfb","resizeSession","scaleViewport","props","onUpdateState","componentDidMount","window","location","defaultPort","disconnect","createRFB","componentDidUpdate","prevProps","prevOrigin","componentWillUnmount","removeEventListener","secure","RFB","canvas","hostname","credentials","password","addEventListener","viewOnly","lock","unlocked","_rfb_connection_state","render","ref","screen","resizeVnc","StyledVNC","VncCard","setState","handleFullscreen","onVNCFullscreenChange","fullscreen","handleLock","connected","Back","Connection","Lock","locked","Fullscreen","instance","icon","StyledLog","Log","constructor","super","terminal","Terminal","cursorBlink","tabStopWidth","disableStdin","enableBold","fontSize","lineHeight","theme","background","fitAddon","FitAddon","loadAddon","term","props$","BehaviorSubject","UNSAFE_componentWillReceiveProps","nextProps","open","termel","fit","writeln","fg","getRgb","reset","resize","fromEvent","debounceTime","subscribe","subscription","it","distinctUntilChanged","prev","wsProxyUrl","switchMap","ws","defer","clear","Observable","observer","socket","WebSocket","decoder","TextDecoder","binaryType","onmessage","event","decode","data","onopen","onclose","readyState","CLOSED","close","msg","write","unsubscribe","dispose","hidden","StyledSession","prevBrowser","useRef","useEffect","current","usePrevious","isLogHidden","VncContainer","StyledVideo","StyledVideos","RecordedVideo","src","file","preload","deleteVideo","useDeleteVideo","controls","type","Videos","videos","preloadVal","filtered","fname","match","StyledQuota","Quota","pending","total","StyledQueue","Queue","queued","Used","Separator","PanelFilter","select","onQuery","StyledPanelFilter","focus","inputStyle","height","outline","backgroundColor","statsBgColor","border","padding","marginLeft","fontWeight","visibility","Viewport","sse","onStatus","useObservable","in$","pushStatus","merge","pluck","EventSource","x","onerror","errors","retryWhen","errs","delayWhen","timer","StatsBar","Logo","path","params","App","Boolean","ReactDOM","getElementById","navigator","serviceWorker","ready","then","registration","unregister"],"mappings":"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","file":"static/js/main.7e3b4ddb.chunk.js","sourcesContent":["import styled, { createGlobalStyle } from \"styled-components/macro\";\n\nconst bgColor = \"#30363C\";\n\nexport const GlobalStyle = createGlobalStyle`\nhtml,\n body {\n margin: 0;\n padding: 0;\n width: 100%; //fallback\n width: 100vw;\n height: 100%; //fallback\n height: 100vh;\n min-height: 100vh;\n min-width: 100vw;\n overflow: auto;\n}\n\nbody {\n font-size: 14px;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n margin: 0 auto;\n background: ${bgColor};\n font-weight: 100;\n}\n`;\n\nexport const StyledViewport = styled.div`\n display: flex;\n flex-direction: column;\n`;\n\nexport const StyledTopBar = styled.div`\n display: flex;\n justify-content: flex-end;\n`;\n","import React from \"react\";\nimport { NavLink } from \"react-router-dom\";\nimport styled from \"styled-components/macro\";\n\nconst border = \"#353b42\";\n\nconst Nav = styled.div`\n display: flex;\n flex-wrap: wrap;\n line-height: 30px;\n font-size: 1em;\n border-bottom: 1px solid ${border};\n letter-spacing: 1px;\n padding-right: 30px;\n\n .element {\n color: #fff;\n text-decoration: none;\n margin-left: 10px;\n }\n\n .active {\n border-bottom: 1px solid #59a781;\n }\n`;\n\nconst Navigation = ({ links }) => {\n return (\n \n );\n};\n\nexport default Navigation;\n","import styled from \"styled-components/macro\";\n\nconst borderStatsColor = \"#3d444c\";\nconst borderSectionColor = \"#353b42\";\n\nexport const StyledStats = styled.div`\n min-height: 100px;\n min-width: 350px;\n display: flex;\n justify-content: center;\n align-items: center;\n flex-shrink: 0;\n overflow: auto;\n\n .section-title {\n color: #666;\n position: absolute;\n top: 0;\n left: 0;\n padding-left: 5%;\n border-bottom: 1px solid ${borderSectionColor};\n width: 95%;\n letter-spacing: 1px;\n font-size: 10px;\n line-height: 20px;\n }\n\n .quota {\n border-right: 1px dashed ${borderStatsColor};\n margin-right: 10px;\n }\n`;\n","import styled from \"styled-components/macro\";\n\nexport const StyledBrowsers = styled.div`\n color: #fff;\n display: flex;\n flex-direction: column;\n flex-basis: 30%;\n min-width: 250px;\n`;\n\nexport const StyledBrowser = styled.div`\n overflow: hidden;\n display: inline-flex;\n line-height: 30px;\n position: relative;\n\n .stats {\n display: flex;\n\n .name {\n overflow: hidden;\n letter-spacing: 1px;\n }\n\n .count {\n font-size: 2em;\n width: 80px;\n }\n\n .percent {\n font-size: 0.8em;\n line-height: 20px;\n width: 30px;\n padding-left: 5px;\n }\n }\n\n .usage-bar {\n position: absolute;\n bottom: 0;\n left: 0;\n border-bottom: 1px dashed;\n transition: all 300ms ease-in;\n }\n`;\n","import React from \"react\";\nimport { StyledBrowser } from \"./style.css\";\nimport PropTypes from \"prop-types\";\n\n/**\n * Color depending on percentage\n * @param percentile unsigned integer\n * @returns {string} HEX color\n */\nfunction countColor(percentile) {\n const pct = (percentile > 100 ? 100 : percentile) / 100;\n const percentColors = [\n { pct: 0.0, color: { r: 0x41, g: 0x59, b: 0xd3 } }, //#4159D3\n { pct: 0.3, color: { r: 0x66, g: 0x9d, b: 0x9e } }, //#F09876\n { pct: 0.5, color: { r: 0x66, g: 0x9d, b: 0x9e } }, //#A44057\n { pct: 0.7, color: { r: 0xeb, g: 0xa8, b: 0x98 } }, //#EBA898\n { pct: 1.0, color: { r: 0xe8, g: 0x78, b: 0x6f } }, //#E8786F\n ];\n\n const color = {};\n\n for (let i = 1; i <= percentColors.length - 1; i++) {\n if (pct < percentColors[i - 1].pct) {\n break;\n }\n const lower = percentColors[i - 1];\n const upper = percentColors[i];\n\n const range = upper.pct - lower.pct;\n const rangePct = (pct - lower.pct) / range;\n const pctLower = 1 - rangePct;\n const pctUpper = rangePct;\n\n color.r = Math.floor(lower.color.r * pctLower + upper.color.r * pctUpper);\n color.g = Math.floor(lower.color.g * pctLower + upper.color.g * pctUpper);\n color.b = Math.floor(lower.color.b * pctLower + upper.color.b * pctUpper);\n }\n\n const colors = [color.r, color.g, color.b].map(col => col.toString(16)).join(\"\");\n\n return `#${colors}`;\n}\n\nconst Browser = ({ name, used, totalUsed }) => {\n const perc = totalUsed > 0 ? ((used / totalUsed) * 100).toFixed() : 0;\n\n return (\n \n
\n
{perc}%
\n
{used}
\n
{name}
\n
\n \n
\n );\n};\n\nBrowser.propTypes = {\n name: PropTypes.string.isRequired,\n used: PropTypes.number.isRequired,\n totalUsed: PropTypes.number.isRequired,\n};\n\nexport default Browser;\n","import React from \"react\";\n\nimport PropTypes from \"prop-types\";\nimport { StyledBrowsers } from \"./style.css\";\nimport Browser from \"./Browser\";\n\nfunction descendingCount(browsers) {\n return Object.keys(browsers)\n .sort((a, b) => browsers[b] - browsers[a])\n .map(name => ({\n name,\n used: browsers[name],\n }));\n}\n\nconst Browsers = ({ totalUsed, browsers }) => {\n if (totalUsed === undefined) {\n return null;\n }\n\n return (\n \n {descendingCount(browsers).map(browser => (\n \n ))}\n \n );\n};\n\nBrowsers.propTypes = {\n totalUsed: PropTypes.number,\n browsers: PropTypes.object.isRequired,\n};\n\nexport default Browsers;\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\nimport { StyledStats } from \"./style.css\";\n\nimport Browsers from \"../../components/Browsers\";\n\nconst Stats = ({ state, browsers }) => {\n return (\n \n \n \n );\n};\n\nStats.propTypes = {\n state: PropTypes.shape({\n used: PropTypes.number,\n }),\n browsers: PropTypes.object,\n};\n\nexport default Stats;\n","import styled from \"styled-components/macro\";\n\nconst borderLangsColor = \"#3d444c\";\nconst borderSectionColor = \"#353b42\";\nconst unselectedColor = \"#376e52\";\nconst selectedColor = \"#59a781\";\nconst errorColor = \"#ff6e59\";\nconst grayColor = \"#666\";\n\nconst selectBgColor = \"#30363C\";\n\nexport const StyledCapabilities = styled.div`\n width: 100%;\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n align-items: center;\n position: relative;\n\n .section-title {\n color: ${grayColor};\n position: relative;\n top: 0;\n left: 0;\n padding-left: 5%;\n border-bottom: 1px solid ${borderSectionColor};\n width: 95%;\n letter-spacing: 1px;\n font-size: 10px;\n line-height: 20px;\n }\n\n .setup {\n width: 200px;\n margin-right: 30px;\n\n button {\n width: 100%;\n margin-top: 10px;\n cursor: pointer;\n }\n \n \n .Select-control {\n background-color: inherit;\n border-radius: 0;\n border: none;\n color: #fff;\n height: 30px;\n\n &:hover {\n box-shadow: none;\n }\n\n & .Select-input {\n outline: none;\n\n input {\n color: #fff;\n }\n }\n }\n\n .has-value.Select--single > .Select-control .Select-value .Select-value-label,\n .has-value.is-pseudo-focused.Select--single > .Select-control .Select-value .Select-value-label {\n color: #fff;\n text-transform: uppercase;\n letter-spacing: 2px;\n }\n \n .Select-menu-outer {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n background-color: inherit;\n border: 0;\n box-shadow: none;\n }\n \n .Select-option {\n background-color: ${selectBgColor};\n color: #ccc;\n text-transform: uppercase;\n }\n .Select-option:last-child {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n }\n .Select-option.is-selected {\n background-color: ${selectBgColor};\n color: ${selectedColor};\n }\n .Select-option.is-focused {\n background-color: ${selectBgColor};\n color: ${selectedColor};\n }\n \n }\n\n .lang-selector {\n margin-left: 50px;\n margin-top: 20px;\n }\n\n .new-session {\n height: 2rem;\n border: 1px solid ${unselectedColor};\n border-radius: 3px;\n background-color: ${borderSectionColor};\n color: ${selectedColor};\n text-transform: uppercase;\n font-size: 1.1em;\n outline: none;\n\n &:hover {\n border-color: ${selectedColor};\n background-color: ${borderLangsColor};\n }\n\n &.disabled-true {\n border-color: ${borderLangsColor};\n background-color: ${borderLangsColor};\n color: ${grayColor};\n\n &:hover {\n border-color: ${borderLangsColor};\n cursor: default;\n }\n }\n \n &.error-true {\n border-color: ${errorColor};\n color: ${errorColor};\n }\n }\n \n .new-session-more-capabilities {\n background: none;\n border: none;\n color: ${grayColor};\n text-align: left;\n padding: 0;\n }\n \n textarea.more-capabilities {\n border: 1px solid ${unselectedColor};\n border-radius: 3px;\n background-color: ${borderSectionColor};\n color: ${selectedColor};\n font-size: 13px;\n font-family: \"Source Code Pro\",Menlo,Monaco,Consolas,\"Courier New\",monospace;\n outline: none;\n padding: 5px;\n resize: vertical;\n width: 100%;\n box-sizing: border-box;\n margin-top: 10px;\n \n &.error-true {\n border-color: ${errorColor};\n color: ${errorColor};\n }\n }\n\n}\n\npre.hljs, code.hljs {\n font-family: \"Source Code Pro\", Menlo, Monaco, Consolas, \"Courier New\", monospace;\n font-size: 13px;\n line-height: 1.2;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n background: inherit;\n}\n\n.capabilities-langs {\n height: 100%;\n display: flex;\n flex-wrap: wrap;\n flex-direction: column;\n}\n\n.capabilities-lang {\n color: #fff;\n padding: 10px;\n text-transform: capitalize;\n line-height: 20px;\n border-left: 3px solid ${borderLangsColor};\n cursor: pointer;\n transition: border-color 0.2s ease-out 0s;\n min-width: 80px;\n\n &_active {\n border-left-color: ${selectedColor};\n }\n}\n`;\n","import React, { useState } from \"react\";\nimport { withRouter } from \"react-router-dom\";\nimport PropTypes from \"prop-types\";\nimport { ajax } from \"rxjs/ajax\";\nimport { combineLatest } from \"rxjs\";\nimport { catchError, filter, flatMap, tap } from \"rxjs/operators\";\n\nimport Highlight from \"react-highlight\";\nimport \"highlight.js/styles/sunburst.css\";\n\nimport Select from \"react-select\";\n\nimport { StyledCapabilities } from \"./style.css\";\nimport BeatLoader from \"react-spinners/BeatLoader\";\nimport { useEventCallback } from \"rxjs-hooks\";\n\nimport Url from \"url-parse\";\n\nconst code = (browser = \"UNKNOWN\", version = \"\", origin = \"http://selenoid-uri:4444\") => {\n const url = new Url(origin);\n return {\n yaml: `# selenium: \"${origin}\"\n# please note that real accessible selenoid uri can be different \nbrowserName: \"${browser}\"\nbrowserVersion: \"${version}\"\nenableVNC: true\nenableVideo: false \n`,\n curl: `curl -X POST '${origin}/wd/hub/session' -d '{ \n \"desiredCapabilities\":{\n \"browserName\":\"${browser}\", \n \"browserVersion\": \"${version}\", \n \"platformName\":\"ANY\",\n \"selenoid:options\": {\n \"enableVNC\": true,\n \"name\": \"this.test.is.launched.by.curl\",\n \"sessionTimeout\": \"120s\"\n }\n }\n }'\n`,\n java: `DesiredCapabilities capabilities = new DesiredCapabilities();\ncapabilities.setCapability(\"browserName\", \"${browser}\");\ncapabilities.setCapability(\"browserVersion\", \"${version}\");\ncapabilities.setCapability(\"selenoid:options\", Map.of(\n \"enableVNC\", true,\n \"enableVideo\", true\n));\nRemoteWebDriver driver = new RemoteWebDriver(\n URI.create(\"${origin}/wd/hub\").toURL(), \n capabilities\n);\n`,\n \"C#\": `var capabilities = new DesiredCapabilities();\ncapabilities.SetCapability(CapabilityType.BrowserName, \"${browser}\");\ncapabilities.SetCapability(CapabilityType.BrowserVersion, \"${version}\");\nvar driver = new RemoteWebDriver(new Uri(\"${origin}/wd/hub\"), capabilities);\n`,\n python: `from selenium import webdriver\n \ncapabilities = {\n \"browserName\": \"${browser}\",\n \"browserVersion\": \"${version}\",\n \"selenoid:options\": {\n \"enableVNC\": True,\n \"enableVideo\": False\n }\n}\n\ndriver = webdriver.Remote(\n command_executor=\"${origin}/wd/hub\",\n desired_capabilities=capabilities)\n`,\n javascript: `var webdriverio = require('webdriverio');\n \nvar options = { \n hostname: '${url.host}',\n port: ${url.port},\n capabilities: { \n browserName: '${browser}', \n browserVersion: '${version}',\n 'selenoid:options': {\n enableVNC: true,\n enableVideo: false \n } \n } \n};\nvar client = webdriverio.remote(options);\n`,\n PHP: `$web_driver = RemoteWebDriver::create(\"${origin}/wd/hub\",\narray(\"browserName\"=>\"${browser}\", \"browserVersion\"=>\"${version}\")\n);\n`,\n ruby: `caps = Selenium::WebDriver::Remote::Capabilities.new\ncaps[\"browserName\"] = \"${browser}\"\ncaps[\"browserVersion\"] = \"${version}\"\n\ndriver = Selenium::WebDriver.for(:remote,\n :url => \"${origin}/wd/hub\",\n :desired_capabilities => caps)\n`,\n go: `// \"github.com/tebeka/selenium\"\ncaps := selenium.Capabilities{\"browserName\": \"${browser}\", \"browserVersion\": \"${version}\"}\ndriver, err := selenium.NewRemote(caps, \"${origin}/wd/hub\")\nif err != nil {\n\tpanic(\"create selenium session: %v\\n\", err)\n}\ndefer driver.Quit()\n`,\n };\n};\n\nexport const sessionIdFrom = ({ response }) => {\n return response.sessionId || (response.value && response.value.sessionId) || \"\";\n};\n\nconst Capabilities = ({ browsers = {}, origin, history }) => {\n const [browser, onBrowserChange] = useState({});\n const [lang, onLanguageChange] = useState(\"yaml\");\n\n const available = [].concat(\n ...Object.keys(browsers).map(name =>\n Object.keys(browsers[name]).map(version => {\n return {\n value: `${name}_${version}`,\n label: `${name}: ${version}`,\n name,\n version,\n };\n })\n )\n );\n\n const { name, version, value } = browser || {};\n const caps = code(name, version, origin);\n\n return (\n \n
Capabilities
\n
\n item.value === value)}\n options={available}\n onChange={browser => onBrowserChange(browser)}\n placeholder=\"Select browser...\"\n isLoading={!origin}\n clearable={false}\n noResultsText=\"No information about browsers\"\n />\n \n
\n {caps[lang]}\n\n
\n
\n {Object.keys(caps).map(next => (\n onLanguageChange(next)}\n >\n {next}\n
\n ))}\n
\n \n
\n );\n};\n\nconst Launch = ({ browser: { name, version }, history }) => {\n const defaultAdditionalCaps = { operaOptions: { binary: \"/usr/bin/opera\" } };\n\n const [loading, onLoading] = useState(false);\n const [error, onError] = useState(\"\");\n const [useMoreCaps, toggleMoreCaps] = useState(false);\n const [moreCapsError, onMoreCapsError] = useState(false);\n const [moreCaps, setMoreCaps] = useState(JSON.stringify(defaultAdditionalCaps));\n\n const [createSession] = useEventCallback(\n (event$, inputs$) =>\n combineLatest(event$, inputs$).pipe(\n tap(() => {\n onError(\"\");\n onLoading(true);\n }),\n flatMap(([_, [name, version, history, useMoreCaps, moreCapsError, moreCaps]]) => {\n let desiredCapabilities = {\n browserName: `${name}`,\n version: `${version}`,\n enableVNC: true,\n labels: { manual: \"true\" },\n sessionTimeout: \"60m\",\n name: \"Manual session\",\n };\n let selenoidOptions = {\n enableVNC: true,\n sessionTimeout: \"60m\",\n labels: { manual: \"true\" },\n };\n\n if (useMoreCaps && !moreCapsError) {\n const additionalCaps = JSON.parse(moreCaps);\n desiredCapabilities = Object.assign(desiredCapabilities, additionalCaps);\n selenoidOptions = Object.assign(selenoidOptions, additionalCaps);\n }\n\n return ajax({\n url: \"/wd/hub/session\",\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n timeout: 300000,\n body: {\n desiredCapabilities,\n capabilities: {\n alwaysMatch: {\n browserName: `${name}`,\n browserVersion: `${version}`,\n \"selenoid:options\": selenoidOptions,\n },\n firstMatch: [{}],\n },\n },\n }).pipe(\n filter(({ status }) => status === 200),\n tap(res => history.push(`/sessions/${sessionIdFrom(res)}`))\n );\n }),\n catchError((err, caught) => {\n console.error(\"Can't start session manually\", err);\n onError(err);\n onLoading(false);\n return caught;\n })\n ),\n [name, version, history],\n [name, version, history, useMoreCaps, moreCapsError, moreCaps]\n );\n\n const onTextareaUpdate = e => {\n setMoreCaps(e.target.value);\n try {\n JSON.parse(e.target.value);\n onMoreCapsError(false);\n } catch (e) {\n onMoreCapsError(e);\n }\n };\n\n return (\n
\n onError(\"\")}\n title={error}\n >\n {loading ? : `Create Session`}\n \n {!name || loading ? null : (\n \n )}\n {!useMoreCaps ? null : (\n \n )}\n
\n );\n};\n\nCapabilities.propTypes = {\n browsers: PropTypes.object,\n origin: PropTypes.string,\n};\n\nexport default withRouter(Capabilities);\n","import styled from \"styled-components/macro\";\n\nexport const StatsElement = styled.div`\n height: 80px;\n text-transform: uppercase;\n color: #fff;\n width: 80px;\n display: flex;\n flex-direction: column;\n justify-content: center;\n margin-right: 15px;\n margin-left: 15px;\n\n .title {\n padding-top: 10px;\n font-size: 0.8em;\n flex: 1;\n }\n`;\n","import React from \"react\";\nimport styled from \"styled-components/macro\";\nimport { StatsElement } from \"./StatsElement\";\n\nconst brightGreen = \"#57ff76\";\nconst brightRed = \"#FF5757\";\n\nconst StyledStatus = styled(StatsElement)`\n .indicator {\n height: 80px;\n transition: all 0.5s ease-out 0.2s;\n text-transform: uppercase;\n display: flex;\n flex-direction: column;\n justify-content: center;\n\n box-shadow: inset 0px -8px 5px -10px #ffffff;\n\n &_ok {\n .status {\n color: ${brightGreen};\n }\n\n box-shadow: inset 0px -9px 5px -10px ${brightGreen};\n }\n\n &_error {\n .status {\n color: ${brightRed};\n }\n\n box-shadow: inset 0px -10px 5px -10px ${brightRed};\n }\n\n .status {\n flex: 1;\n font-weight: 300;\n }\n }\n`;\n\nconst state = status => {\n switch (status) {\n case \"ok\":\n return \"CONNECTED\";\n case \"error\":\n return \"ISSUE\";\n default:\n return \"UNKNOWN\";\n }\n};\n\nconst Status = ({ status = \"unknown\", header, version = \"unknown\" }) => {\n return (\n \n
\n
{header}
\n
\n {state(status)}\n
\n
\n
\n );\n};\n\nexport default Status;\n","import styled from \"styled-components/macro\";\n\nconst colorAccent = \"#59a781\";\nconst colorBorder = \"#555f6a\";\nconst borderSectionColor = \"#353b42\";\nconst secondaryColor = \"#aaa\";\nconst manualColor = \"#F0A202\";\n\nexport const StyledSessions = styled.div`\n overflow: auto;\n\n .section-title {\n color: #666;\n position: relative;\n top: 0;\n left: 0;\n padding-left: 5%;\n border-bottom: 1px solid ${borderSectionColor};\n width: 95%;\n letter-spacing: 1px;\n font-size: 10px;\n line-height: 20px;\n margin-bottom: 20px;\n \n &_hidden-true {\n display: none;\n }\n \n }\n\n .no-any {\n color: #fff;\n display: flex;\n flex-wrap: wrap;\n flex-direction: column;\n align-items: center;\n font-size: 1.2em;\n justify-content: center;\n\n .nosession-any-text {\n margin: 10px;\n }\n\n // don't show until all sessions are gone\n &_state-enter-active {\n display: none;\n }\n }\n}\n\n.sessions__list {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n padding: 0 50px;\n box-sizing: border-box;\n\n .session {\n transition: all 0.5s;\n min-height: 60px;\n display: flex;\n justify-content: flex-start;\n min-width: 350px;\n border-bottom: 1px dashed ${colorBorder};\n color: #fff;\n padding: 10px 0 0;\n overflow: auto;\n\n //TRANSITIONS\n &_state-enter {\n opacity: 0.01;\n }\n\n &_state-enter-active {\n opacity: 1;\n transition: opacity 500ms ease-in;\n }\n\n &_state-exit {\n opacity: 1;\n }\n\n &_state-exit-active {\n opacity: 0.01;\n transition: opacity 500ms ease-out;\n }\n \n .identity {\n display: flex;\n flex-direction: column;\n text-decoration: none;\n color: #fff;\n max-width: 50%;\n flex: 0 0 50%;\n padding-right: 15px;\n \n .browser {\n display: flex;\n\n .name {\n text-transform: uppercase;\n font-weight: 300;\n line-height: 30px;\n }\n \n .version {\n font-weight: 300;\n text-transform: lowercase;\n font-size: 0.8em;\n color: ${secondaryColor};\n margin-left: 5px;\n }\n }\n \n .session-name {\n overflow: hidden;\n border-left: 2px solid ${colorBorder};\n color: ${secondaryColor};\n font-family: \"Source Code Pro\", Menlo, Monaco, Consolas, \"Courier New\", monospace;\n\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n padding-left: 5px;\n }\n }\n \n &_manual {\n .identity {\n .session-name {\n border-color: ${manualColor};\n }\n }\n }\n\n \n\n .capability {\n font-family: open sans,helvetica neue,Helvetica,Arial,sans-serif;\n background-color: ${colorAccent};\n margin: 0 .5em;\n padding: .3em .4em .4em;\n display: inline-block;\n vertical-align: middle;\n border-radius: 2px;\n font-weight: 500;\n font-size: 11px;\n line-height: 1;\n letter-spacing: .1px;\n \n &__manual {\n background-color: ${manualColor};\n color: ${borderSectionColor};\n }\n \n &__resolution {\n background: none;\n color: ${secondaryColor};\n font-weight: 400;\n }\n\n &__session-delete {\n background: none;\n cursor: pointer;\n }\n }\n }\n`;\n","import React from \"react\";\nimport { Link } from \"react-router-dom\";\nimport { CSSTransition, TransitionGroup } from \"react-transition-group\";\nimport { StyledSessions } from \"./style.css\";\nimport BeatLoader from \"react-spinners/BeatLoader\";\n\nimport styled from \"styled-components/macro\";\nimport { useSessionDelete } from \"./service\";\n\nconst Sessions = ({ sessions = {}, query = \"\" }) => {\n function withQuery(query, sessions) {\n return id => {\n if (id.includes(query)) {\n return true;\n }\n\n if (sessions[id].caps.name && sessions[id].caps.name.toLowerCase().includes(query.toLowerCase())) {\n return true;\n }\n\n if (sessions[id].caps.browserName.toLowerCase().includes(query.toLowerCase())) {\n return true;\n }\n\n return query === \"\";\n };\n }\n\n const ids = Object.keys(sessions)\n .filter(withQuery(query, sessions))\n // moving manual on top\n // can be moved to golang actually\n .sort(a => (sessions[a].caps.labels && sessions[a].caps.labels.manual ? -1 : 1));\n\n return (\n \n
Sessions
\n \n {ids.map(id => {\n return (\n \n \n \n );\n })}\n \n \n
\n
\n
NO SESSIONS YET :'(
\n
\n \n \n );\n};\n\nconst Session = ({ id, session: { quota, caps } }) => {\n const [deleting, deleteSession] = useSessionDelete(id);\n\n return (\n
\n \n {quota} /{\" \"}\n \n {id.substring(0, 8)}\n \n \n \n
\n {caps.browserName}\n {caps.version}\n
\n\n {caps.name && (\n
\n {caps.name}\n
\n )}\n \n\n \n {caps.labels && caps.labels.manual && MANUAL}\n {caps.enableVNC && VNC}\n {caps.screenResolution && (\n {caps.screenResolution}\n )}\n \n \n {caps.labels && caps.labels.manual && (\n
\n {deleting ? (\n \n ) : (\n \n )}\n
\n )}\n
\n
\n );\n};\n\nconst primaryColor = \"#fff\";\nconst secondaryColor = \"#aaa\";\n\nconst SessionId = styled.div`\n display: flex;\n align-items: center;\n flex-shrink: 0;\n flex-basis: 140px;\n padding-right: 5px;\n\n .quota {\n color: ${secondaryColor};\n margin-right: 3px;\n }\n\n .id {\n margin-left: 3px;\n text-decoration: none;\n color: ${primaryColor};\n }\n`;\n\nconst Capabilities = styled.div`\n display: flex;\n align-items: center;\n flex: 1;\n`;\n\nconst Actions = styled.div`\n display: flex;\n align-items: center;\n`;\n\nexport default Sessions;\n","import { of } from \"rxjs\";\nimport { catchError, flatMap, mapTo, startWith } from \"rxjs/operators\";\nimport { ajax } from \"rxjs/ajax\";\nimport { useEventCallback } from \"rxjs-hooks\";\n\nexport function useSessionDelete(id) {\n const [deleteSession, deleted] = useEventCallback(\n event$ =>\n event$.pipe(\n flatMap(() =>\n ajax({\n url: `/wd/hub/session/${id}`,\n method: \"DELETE\",\n }).pipe(\n mapTo(true),\n catchError(e => {\n console.error(\"Can't delete session\", id, e);\n return of(false);\n }),\n startWith(true)\n )\n )\n ),\n false\n );\n\n return [deleted, () => deleteSession(id)];\n}\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\n\nimport BeatLoader from \"react-spinners/BeatLoader\";\n\nconst SessionInfo = ({ session = \"\", browser = { caps: {} } }) => {\n return (\n
\n
\n
\n \n {browser.quota}\n {browser.quota && /}\n {browser.caps.browserName}\n {browser.caps.browserName && /}\n {browser.caps.version}\n {browser.caps.version && /}\n {browser.caps.screenResolution}\n
\n\n
{session.substring(0, 8)}
\n
\n\n
\n
\n {browser.caps.name &&
{browser.caps.name}
}\n
\n
\n
\n );\n};\n\nSessionInfo.propTypes = {\n session: PropTypes.string,\n browser: PropTypes.shape({\n quota: PropTypes.string,\n caps: PropTypes.shape({\n browserName: PropTypes.string.isRequired,\n version: PropTypes.string.isRequired,\n screenResolution: PropTypes.string,\n name: PropTypes.string,\n }).isRequired,\n }),\n};\n\nexport default SessionInfo;\n","export default function urlTo(href) {\n let lnk = document.createElement(\"a\");\n lnk.setAttribute(\"href\", href);\n return lnk;\n}\n","export default function isSecure({ protocol }) {\n return protocol === \"https:\";\n}\n","import React, { Component } from \"react\";\nimport RFB from \"@novnc/novnc/core/rfb\";\nimport urlTo from \"../../util/urlTo\";\nimport isSecure from \"../../util/isSecure\";\n\nexport default class VncScreen extends Component {\n static resizeVnc(rfb) {\n if (rfb) {\n rfb.resizeSession = true;\n rfb.scaleViewport = true;\n }\n }\n\n static defaultPort({ port, protocol }) {\n return port || (protocol === \"https:\" ? \"443\" : \"80\");\n }\n\n connection(connection) {\n this.props.onUpdateState(connection);\n }\n\n onVNCDisconnect = () => {\n this.connection(\"disconnected\");\n };\n\n onVNCConnect = () => {\n this.connection(\"connected\");\n };\n\n componentDidMount() {\n const { session, origin } = this.props;\n this.connection(\"connecting\");\n\n if (origin && session) {\n const link = urlTo(window.location.href);\n const port = VncScreen.defaultPort(link);\n\n this.disconnect(this.rfb);\n this.rfb = this.createRFB(link, port, session, isSecure(link));\n }\n }\n\n componentDidUpdate(prevProps) {\n const prevOrigin = prevProps.origin;\n const { session, origin } = this.props;\n\n if (origin && session && prevOrigin !== origin) {\n const link = urlTo(window.location.href);\n const port = VncScreen.defaultPort(link);\n\n this.disconnect(this.rfb);\n this.rfb = this.createRFB(link, port, session, isSecure(link));\n }\n }\n\n componentWillUnmount() {\n this.rfb && this.rfb.removeEventListener(\"disconnect\", this.onVNCDisconnect);\n this.rfb && this.rfb.removeEventListener(\"connect\", this.onVNCConnect);\n this.disconnect(this.rfb);\n }\n\n createRFB(link, port, session, secure) {\n const rfb = new RFB(this.canvas, `${secure ? \"wss\" : \"ws\"}://${link.hostname}:${port}/ws/vnc/${session}`, {\n credentials: {\n password: \"selenoid\",\n },\n });\n\n rfb.addEventListener(\"connect\", this.onVNCConnect);\n rfb.addEventListener(\"disconnect\", this.onVNCDisconnect);\n\n rfb.scaleViewport = true;\n rfb.resizeSession = true;\n rfb.viewOnly = true;\n return rfb;\n }\n\n lock(unlocked) {\n if (this.rfb) {\n this.rfb.viewOnly = !unlocked;\n }\n }\n\n disconnect(rfb) {\n if (rfb && rfb._rfb_connection_state && rfb._rfb_connection_state !== \"disconnected\") {\n rfb.disconnect();\n }\n }\n\n render() {\n return (\n {\n this.canvas = screen;\n VncScreen.resizeVnc(this.rfb);\n }}\n >
\n );\n }\n}\n","import styled from \"styled-components/macro\";\n\nconst colorDisconnected = \"#ff6e59\";\nconst colorConnecting = \"#6883d3\";\nconst colorDisconnecting = \" #ca9eff\";\nconst colorFullscreen = \"#59a781\";\nconst backgroundColorLighter = \"#3d444c\";\n\nexport const StyledVNC = styled.div`\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n align-items: center;\n\n &.fullscreen {\n position: absolute;\n height: 100%;\n width: 100%;\n z-index: 2;\n top: 0;\n left: 0;\n }\n\n .vnc-connection-status {\n color: #fff;\n text-transform: uppercase;\n margin-left: 55px;\n transition: color 0.5s ease-out 0s;\n line-height: 20px;\n\n &:before {\n content: \"\";\n display: block;\n width: 35px;\n margin-left: -45px;\n border-bottom: 1px solid #fff;\n position: relative;\n top: 11px;\n }\n\n &_disconnected {\n color: ${colorDisconnected};\n &:before {\n border-bottom-color: ${colorDisconnected};\n }\n }\n\n &_connecting {\n color: ${colorConnecting};\n &:before {\n border-bottom-color: ${colorConnecting};\n }\n }\n }\n\n .vnc-card {\n height: 450px;\n width: 100%;\n display: flex;\n flex-direction: column;\n box-shadow: 0 1px 6px rgba(0, 0, 0, 0.12), 0 1px 4px rgba(0, 0, 0, 0.12);\n\n &_fullscreen {\n height: 100%;\n width: 100%;\n z-index: 2;\n }\n\n &_small {\n height: 30px;\n width: 65px;\n }\n\n &__controls {\n height: 30px;\n width: 100%;\n display: flex;\n align-items: center;\n background-color: ${backgroundColorLighter};\n\n .control {\n width: 15px;\n height: 15px;\n line-height: 15px;\n border-radius: 50%;\n background-color: ${colorDisconnected};\n text-align: center;\n text-decoration: none;\n margin-left: 10px;\n font-size: 10px;\n color: #fff;\n transition: background-color 0.5s ease-out 0s;\n\n &_fullscreen {\n cursor: pointer;\n background-color: ${colorFullscreen};\n color: ${colorFullscreen};\n\n &:hover {\n color: #fff;\n }\n }\n\n &_back {\n cursor: pointer;\n background-color: ${colorDisconnected};\n color: ${colorDisconnected};\n\n &:hover {\n color: #fff;\n }\n }\n\n &_lock {\n cursor: pointer;\n background-color: ${colorConnecting};\n color: ${colorConnecting};\n\n &:hover {\n color: #fff;\n }\n }\n\n &_disconnected {\n background-color: ${colorDisconnected};\n height: 30px;\n width: 30px;\n line-height: 30px;\n font-size: 1em;\n border-radius: 0;\n }\n\n &_connecting {\n background-color: ${colorConnecting};\n height: 30px;\n width: 30px;\n line-height: 30px;\n font-size: 1em;\n border-radius: 0;\n }\n\n &_connected {\n display: none;\n }\n\n &_disconnecting {\n background-color: ${colorDisconnecting};\n }\n }\n }\n\n &__content {\n width: 100%;\n height: calc(100% - 30px);\n display: flex;\n flex-direction: column;\n background-color: #000;\n\n .vnc-screen {\n height: 100%;\n }\n }\n }\n`;\n","import React, { Component } from \"react\";\nimport { Link } from \"react-router-dom\";\n\nimport VncScreen from \"./VncScreen\";\nimport { StyledVNC } from \"./style.css\";\n\nexport default class VncCard extends Component {\n state = { connection: \"connecting\" };\n\n connection = connection => {\n this.setState({ connection: connection });\n };\n\n handleFullscreen = () => {\n this.props.onVNCFullscreenChange(!this.state.fullscreen);\n this.setState({ fullscreen: !this.state.fullscreen });\n };\n\n handleLock = () => {\n this.setState({ unlocked: !this.state.unlocked });\n this.screen && this.screen.lock(!this.state.unlocked);\n };\n\n render() {\n const { origin, session, browser = {}, className } = this.props;\n const { connection, fullscreen, unlocked } = this.state;\n const connected = connection === \"connected\";\n\n if (browser.caps && !browser.caps.enableVNC) {\n return ;\n }\n\n return (\n \n
\n
\n \n \n {connected && }\n {connected && }\n
\n\n
\n {\n this.screen = instance;\n }}\n session={session}\n origin={origin}\n onUpdateState={state => this.connection(state)}\n />\n
\n
\n\n {!connected && (\n
VNC {connection}
\n )}\n
\n );\n }\n}\n\nfunction Back() {\n return (\n \n
X
\n \n );\n}\n\nfunction Connection(props) {\n const { connection } = props;\n const icon = function(connection) {\n switch (connection) {\n default:\n case \"disconnected\": {\n return \"dripicons-document-delete\";\n }\n case \"disconnecting\":\n case \"connecting\": {\n return \"dripicons-dots-3\";\n }\n }\n };\n\n return (\n
\n \n
\n );\n}\n\nfunction Fullscreen(props) {\n const { handleFullscreen, fullscreen } = props;\n return (\n
\n
\n
\n );\n}\n\nfunction Lock(props) {\n const { locked, handleLock } = props;\n return (\n
\n
\n
\n );\n}\n","import styled from \"styled-components/macro\";\n\nconst termBg = \"#151515\";\nconst lightFont = \"#999\";\n\nexport const StyledLog = styled.div`\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n align-items: center;\n\n &.hidden-true {\n display: none;\n }\n\n .log-card {\n height: 450px;\n width: 100%;\n display: flex;\n flex-direction: column;\n flex-wrap: wrap;\n\n &__content {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n background-color: ${termBg};\n\n .term {\n height: calc(100% - 30px);\n padding: 20px 20px 10px;\n\n .terminal {\n color: #fff;\n font-family: \"Source Code Pro\", Menlo, Monaco, Consolas, \"Courier New\", monospace;\n font-size: 13px;\n line-height: 20px;\n\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n\n .xterm-viewport {\n background-color: ${termBg};\n }\n }\n }\n }\n }\n\n .log-info {\n display: inline-flex;\n margin: auto;\n justify-content: center;\n line-height: 20px;\n width: 200px;\n color: ${lightFont};\n\n &__version-separator {\n margin-right: 4px;\n margin-left: 4px;\n font-size: 0.6em;\n color: #fff;\n }\n\n &__session {\n line-height: 20px;\n font-size: 0.8em;\n color: ${lightFont};\n text-align: center;\n }\n }\n`;\n","import React, { Component } from \"react\";\nimport { Terminal } from \"xterm\";\nimport { FitAddon } from \"xterm-addon-fit\";\nimport urlTo from \"../../util/urlTo\";\nimport isSecure from \"../../util/isSecure\";\n\nimport \"xterm/css/xterm.css\";\nimport { StyledLog } from \"./style.css\";\nimport colors from \"ansi-256-colors\";\nimport { BehaviorSubject, defer, fromEvent, Observable } from \"rxjs\";\nimport { debounceTime, distinctUntilChanged, filter, map, startWith, switchMap, tap } from \"rxjs/operators\";\n\nexport default class Log extends Component {\n constructor(props) {\n super(props);\n\n const terminal = new Terminal({\n cursorBlink: false,\n tabStopWidth: 4,\n disableStdin: true,\n enableBold: false,\n fontSize: 13,\n lineHeight: 1,\n theme: {\n background: \"#151515\",\n },\n });\n const fitAddon = new FitAddon();\n terminal.loadAddon(fitAddon);\n this.term = terminal;\n this.fitAddon = fitAddon;\n this.props$ = new BehaviorSubject(props);\n }\n\n UNSAFE_componentWillReceiveProps(nextProps) {\n this.props$.next(nextProps);\n }\n\n componentDidMount() {\n this.term.open(this.termel);\n this.fitAddon.fit();\n this.term.writeln(colors.fg.getRgb(2, 3, 4) + \"Initialize...\\n\\r\" + colors.reset);\n\n this.resize = fromEvent(window, \"resize\")\n .pipe(\n debounceTime(100),\n startWith({}),\n tap(() => this.fitAddon.fit())\n )\n .subscribe();\n\n this.subscription = this.props$\n .pipe(\n filter(it => it && it.session && it.origin && it.browser),\n distinctUntilChanged((prev, { origin }) => prev.origin === origin),\n map(({ session }) => {\n const wsProxyUrl = urlTo(window.location.href);\n return `${isSecure(wsProxyUrl) ? \"wss\" : \"ws\"}://${wsProxyUrl.host}/ws/logs/${session}`;\n }),\n switchMap(ws => {\n return defer(() => {\n this.term.clear();\n\n return new Observable(observer => {\n observer.next(`Connecting to ${ws}...\\n\\r`);\n\n const socket = new WebSocket(ws);\n const decoder = new TextDecoder(\"utf8\");\n\n socket.binaryType = \"arraybuffer\";\n socket.onmessage = event => {\n if (event) {\n observer.next(decoder.decode(event.data) + \"\\r\");\n }\n };\n\n socket.onopen = () => {\n observer.next(colors.fg.getRgb(0, 2, 0) + \"Connected!\\n\\r\" + colors.reset);\n };\n\n socket.onclose = () => {\n observer.next(colors.fg.getRgb(5, 1, 1) + \"Disconnected\\n\\r\" + colors.reset);\n };\n\n return () => {\n socket && socket.readyState !== WebSocket.CLOSED && socket.close();\n };\n });\n });\n })\n )\n .subscribe(msg => this.term.write(msg));\n }\n\n componentWillUnmount() {\n this.resize && this.resize.unsubscribe();\n this.subscription && this.subscription.unsubscribe();\n this.term.dispose();\n }\n\n render() {\n const { hidden, className } = this.props;\n\n return (\n \n
\n
\n {\n this.termel = term;\n }}\n />\n
\n
\n
\n );\n }\n}\n","import styled from \"styled-components/macro\";\n\nconst backgroundColorLighter = \"#3d444c\";\nconst colorSessionName = \"#555f6a\";\n\nexport const StyledSession = styled.div`\n flex: 1;\n width: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-start;\n\n .interactive {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n width: 100%;\n }\n\n .session-interactive-card {\n max-width: 1000px;\n flex: 1;\n flex-basis: 45%;\n min-width: 450px;\n margin: 20px 0 0;\n }\n\n .session-info {\n color: #fff;\n padding: 0 30px;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 80px;\n margin-bottom: 30px;\n\n &__main {\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n min-width: 350px;\n border-bottom: 1px dashed ${backgroundColorLighter};\n margin: 15px 0;\n flex-shrink: 0;\n\n .session-browser {\n line-height: 40px;\n display: inline-flex;\n\n &__name {\n text-transform: uppercase;\n font-weight: 200;\n }\n\n &__version-separator {\n margin-right: 3px;\n margin-left: 3px;\n font-size: 1.5em;\n color: ${backgroundColorLighter};\n }\n\n &__version {\n font-size: 0.8em;\n }\n\n &__quota {\n font-size: 0.8em;\n color: #999;\n }\n\n &__resolution {\n font-size: 0.8em;\n color: #999;\n }\n }\n }\n\n &__additional {\n .custom-capabilities {\n &__name {\n height: 25px;\n line-height: 25px;\n box-shadow: 0 1px 6px rgba(0, 0, 0, 0.12), 0 1px 4px rgba(0, 0, 0, 0.12);\n margin: -3px 5px 0;\n padding: 0 5px;\n\n background-color: ${colorSessionName};\n font-family: \"Source Code Pro\", Menlo, Monaco, Consolas, \"Courier New\", monospace;\n\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n font-size: 13px;\n }\n }\n }\n }\n`;\n","import React, { useEffect, useState, useRef } from \"react\";\nimport { withRouter } from \"react-router-dom\";\n\nimport SessionInfo from \"./SessionInfo\";\nimport VncCard from \"../VncCard\";\nimport Log from \"../Log\";\nimport { StyledSession } from \"./style.css\";\n\n/**\n * The ref object is a generic container whose current property is mutable\n * and can hold any value, similar to an instance property on a class\n */\nfunction usePrevious(value) {\n const ref = useRef();\n\n useEffect(() => {\n ref.current = value;\n }, [value]); // Only re-run if value changes\n\n // Return previous value (happens before update in useEffect above)\n return ref.current;\n}\n\nconst Session = ({ origin, session, browser, history }) => {\n const prevBrowser = usePrevious(browser);\n\n useEffect(() => {\n if (prevBrowser && !browser) {\n // if browser disappears only\n history.push(\"/\");\n }\n }, [browser, history, prevBrowser]);\n\n const [isLogHidden, onVNCFullscreenChange] = useState(false);\n\n return (\n \n \n\n {browser && (\n
\n \n
\n
\n
\n )}\n
\n );\n};\n\nexport default withRouter(Session);\n\nfunction VncContainer({ origin, session, browser = {}, onVNCFullscreenChange }) {\n if (browser.caps && !browser.caps.enableVNC) {\n return ;\n }\n\n return (\n
\n \n
\n );\n}\n","import styled from \"styled-components/macro\";\n\nconst contentBgColor = \"#131614\";\nconst colorBorder = \"#555f6a\";\nconst colorAccent = \"#59a781\";\nconst colorDelete = \"#ff6e59\";\n\nexport const StyledVideo = styled.div`\n display: flex;\n flex-direction: column;\n flex: 1 1 45%;\n padding: 10px 20px;\n margin-bottom: 30px;\n max-width: 70%;\n\n &:hover {\n .video {\n .controls {\n visibility: visible;\n }\n }\n }\n\n .name {\n color: #fff;\n font-size: 1.3em;\n font-weight: 300;\n padding: 0 5px 10px 0;\n border-bottom: 1px dashed ${colorBorder};\n overflow-y: scroll;\n line-height: 30px;\n height: 30px;\n }\n\n .video {\n display: flex;\n flex: 1;\n min-width: 300px;\n min-height: 300px;\n\n .controls {\n display: flex;\n flex-direction: column;\n align-items: center;\n flex: 0;\n flex-basis: 40px;\n color: #fff;\n visibility: hidden;\n\n .control {\n flex-basis: 50px;\n display: flex;\n justify-content: center;\n align-items: center;\n width: 100%;\n border-bottom: 1px dashed ${colorBorder};\n\n a {\n text-decoration: none;\n color: #fff;\n\n &:hover {\n color: ${colorAccent};\n }\n }\n\n .delete {\n cursor: pointer;\n &:hover {\n color: ${colorDelete};\n }\n }\n }\n }\n\n .content {\n display: flex;\n flex: 1;\n padding: 5px;\n flex-basis: 300px;\n background-color: ${contentBgColor};\n justify-content: center;\n align-items: center;\n\n video {\n width: 100%;\n height: 100%;\n }\n }\n }\n`;\n\nexport const StyledVideos = styled.div`\n .videos__list {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n }\n\n .video__container {\n //TRANSITIONS\n &_state-enter {\n opacity: 0.01;\n }\n\n &_state-enter-active {\n opacity: 1;\n transition: opacity 500ms ease-in;\n }\n\n &_state-exit {\n opacity: 1;\n }\n\n &_state-exit-active {\n opacity: 0.01;\n transition: opacity 500ms ease-out;\n }\n }\n\n .no-any {\n color: #fff;\n display: flex;\n flex-wrap: wrap;\n flex-direction: column;\n align-items: center;\n font-size: 1.2em;\n justify-content: center;\n\n .nosession-any-text {\n margin: 10px;\n }\n\n // don't show until all videos are gone\n &_state-enter-active {\n display: none;\n }\n }\n`;\n","import React from \"react\";\nimport { CSSTransition, TransitionGroup } from \"react-transition-group\";\n\nimport { StyledVideo, StyledVideos } from \"./style.css\";\nimport { useDeleteVideo } from \"./service\";\nimport BeatLoader from \"react-spinners/BeatLoader\";\n\nconst Videos = ({ videos = [], query = \"\" }) => {\n const preloadVal = videos.length > 100 ? \"none\" : \"auto\";\n const filtered = videos.filter(fname => fname.includes(query));\n\n return (\n \n \n {filtered.length &&\n filtered.map(fname => {\n const src = `/video/${fname}`;\n const session = fname.match(/.*(?=\\.)/)[0];\n\n return (\n \n \n \n );\n })}\n \n\n \n
\n
\n
NO VIDEOS YET :'(
\n
\n \n \n );\n};\n\nconst RecordedVideo = ({ src, session, file, preload }) => {\n const [deleting, deleteVideo] = useDeleteVideo(file);\n\n return (\n \n
\n {session}\n
\n
\n
\n
\n \n \n \n
\n
\n {deleting ? (\n \n ) : (\n \n \n \n )}\n
\n
\n
\n \n
\n
\n
\n );\n};\n\nexport default Videos;\n","import { of } from \"rxjs\";\nimport { catchError, flatMap, mapTo, startWith } from \"rxjs/operators\";\nimport { ajax } from \"rxjs/ajax\";\nimport { useEventCallback } from \"rxjs-hooks\";\n\nexport function useDeleteVideo(name) {\n const [deleteVideo, deleted] = useEventCallback(\n event$ =>\n event$.pipe(\n flatMap(() =>\n ajax({\n url: `/video/${name}`,\n method: \"DELETE\",\n }).pipe(\n mapTo(true),\n catchError(e => {\n console.error(\"Can't delete video\", name, e);\n return of(false);\n }),\n startWith(true)\n )\n )\n ),\n false\n );\n\n return [deleted, () => deleteVideo(name)];\n}\n","import React from \"react\";\nimport styled from \"styled-components/macro\";\n\nimport { StatsElement } from \"./StatsElement\";\n\nconst StyledQuota = styled(StatsElement)`\n width: auto;\n min-width: 115px;\n\n .numbers {\n flex: 2;\n font-weight: 300;\n font-size: 2em;\n\n .pending {\n font-size: 0.7em;\n color: #ccc;\n }\n }\n`;\n\nconst Quota = ({ used = \"?\", pending = \"?\", total = \"?\" }) => {\n return (\n \n
QUOTA
\n
\n {used}{\" \"}\n \n + {pending}\n {\" \"}\n / {total}\n
\n
\n );\n};\n\nexport default Quota;\n","import React from \"react\";\nimport styled from \"styled-components/macro\";\nimport { StatsElement } from \"./StatsElement\";\n\nconst StyledQueue = styled(StatsElement)`\n width: auto;\n min-width: 45px;\n\n .queued {\n flex: 2;\n font-weight: 300;\n font-size: 2em;\n }\n`;\n\nconst Queue = ({ queued = \"?\" }) => {\n return (\n \n
QUEUED
\n
{queued}
\n
\n );\n};\n\nexport default Queue;\n","import React from \"react\";\nimport styled from \"styled-components/macro\";\nimport { StatsElement } from \"./StatsElement\";\n\nconst StyledQueue = styled(StatsElement)`\n width: auto;\n min-width: 45px;\n .used {\n flex: 2;\n font-weight: 300;\n font-size: 2em;\n\n .small {\n font-size: 0.5em;\n padding-left: 3px;\n }\n }\n`;\n\nconst Used = ({ used, pending, total }) => {\n const perc = total > 0 ? (((used + pending) / total) * 100).toFixed() : \"?\";\n\n return (\n \n
USED
\n
\n {perc}\n %\n
\n
\n );\n};\n\nexport default Used;\n","import styled from \"styled-components/macro\";\n\nconst Separator = styled.div`\n height: 60px;\n border-left: 1px dashed #555f6a;\n`;\n\nexport default Separator;\n","import React, { useRef, useState } from \"react\";\nimport { HashRouter as Router, Link, Route } from \"react-router-dom\";\nimport { merge, Observable, of, timer } from \"rxjs\";\nimport { catchError, delayWhen, flatMap, map, pluck, retryWhen, tap } from \"rxjs/operators\";\nimport { ajax } from \"rxjs/ajax\";\n\nimport AutosizeInput from \"react-input-autosize\";\n\nimport { useObservable } from \"rxjs-hooks\";\n\nimport styled from \"styled-components/macro\";\nimport { GlobalStyle, StyledTopBar, StyledViewport } from \"./styles.css\";\n\nimport \"event-source-polyfill\";\n\nimport Navigation from \"../../components/Navigation\";\nimport Stats from \"../../containers/Stats\";\nimport Capabilities from \"../../containers/Capabilities\";\nimport Status from \"../../components/Stats/Status\";\nimport Sessions from \"../../components/Sessions\";\nimport Session from \"../../components/Session\";\nimport Videos from \"../../components/Videos\";\nimport Quota from \"../../components/Stats/Quota\";\nimport Queue from \"../../components/Stats/Queue\";\nimport Used from \"../../components/Stats/Used\";\nimport Separator from \"../../components/Stats/Separator\";\n\nconst links = videos => {\n return [\n { href: \"/\", title: \"STATS\", exact: true },\n { href: \"/capabilities/\", title: \"CAPABILITIES\", exact: true },\n ...(videos ? [{ href: \"/videos\", title: \"VIDEOS\", exact: true }] : []),\n ];\n};\n\nconst Viewport = () => {\n const [{ status, sse }, onStatus] = useState({\n status: \"unknown\",\n sse: \"unknown\",\n });\n\n const [query, onQuery] = useState(\"\");\n\n const select = useRef(null);\n\n // can be checked offline with simple\n // const {origin, sse, status, state, browsers = {}, sessions = {}} = require(\"../../sse-example.json\");\n\n const { origin, state = {}, browsers = {}, sessions = {}, version = \"unknown\" } = useObservable(\n in$ => {\n return in$.pipe(\n flatMap(([pushStatus]) =>\n merge(\n ajax(\"/status\").pipe(\n pluck(\"response\"),\n tap(() => pushStatus({ status: \"ok\" })),\n catchError(e => {\n pushStatus({ status: \"error\" });\n return of();\n })\n ),\n\n new Observable(observer => {\n const sse = new EventSource(\"/events\");\n\n sse.onmessage = x => observer.next(x.data);\n sse.onerror = x => observer.error(x);\n sse.onopen = () => pushStatus({ sse: \"ok\" });\n\n return () => {\n sse.close();\n };\n }).pipe(\n map(event => JSON.parse(event)),\n map(event => {\n if (!event) {\n pushStatus({ status: \"error\" });\n return {};\n }\n\n if (event.errors && event.errors.length) {\n pushStatus({ status: \"error\", sse: \"ok\" });\n return event;\n }\n\n if (event.state) {\n pushStatus({ status: \"ok\", sse: \"ok\" });\n return event;\n } else {\n console.error(\"Wrong data from backend\", event);\n pushStatus({ status: \"error\" });\n return {\n ...event,\n errors: [],\n };\n }\n }),\n retryWhen(errs =>\n errs.pipe(\n tap(err => {\n console.error(\"Error connecting to SSE\", err.target ? err.target.url : err);\n pushStatus({\n sse: \"error\",\n status: \"unknown\",\n });\n }),\n delayWhen(() => timer(3000))\n )\n )\n )\n )\n )\n );\n },\n {\n state: {},\n },\n [onStatus]\n );\n\n return (\n <>\n \n \n \n \n  \n \n\n \n\n \n \n\n  \n\n \n  \n \n  \n \n \n \n \n \n \n\n {\n if (query) {\n return null;\n }\n return (\n \n );\n }}\n />\n\n } />\n\n }\n />\n\n }\n />\n\n (\n \n )}\n />\n \n \n \n );\n};\n\nconst PanelFilter = ({ select, query, onQuery }) => (\n {\n if (select.current) {\n select.current.focus();\n }\n }}\n >\n \n onQuery(\"\")}\n />\n \n);\n\nconst StyledPanelFilter = styled.div`\n flex: 1;\n display: flex;\n box-sizing: border-box;\n min-width: 190px;\n height: 100%;\n align-items: center;\n color: #fff;\n`;\n\nexport default Viewport;\n\nconst aerokubeColor = \"#4195d3\";\nconst aerokubeColorBright = \"#00c6f4\";\nconst statsBgColor = \"#272727\";\n\nconst StatsBar = styled.div`\n height: 80px;\n background-color: ${statsBgColor};\n box-shadow: inset 0 -5px 5px 0 rgba(0, 0, 0, 0.1);\n display: flex;\n align-items: center;\n overflow: auto;\n`;\n\nconst Logo = styled.div`\n line-height: 30px;\n transition: color 0.5s ease-out 0s;\n color: ${aerokubeColorBright};\n margin-left: 55px;\n position: relative;\n font-weight: 400;\n font-size: 16px;\n min-width: 40px;\n\n &:before {\n content: \"\";\n width: 20px;\n height: 20px;\n position: absolute;\n border-radius: 1px;\n left: -30px;\n top: 0;\n box-shadow: 0 0 10px 5px ${aerokubeColor};\n border: 5px solid #272727;\n background-color: ${aerokubeColorBright};\n }\n`;\n","import React from \"react\";\n\nimport Viewport from \"./containers/Viewport\";\n\nconst App = () => {\n return ;\n};\n\nexport default App;\n","// This optional code is used to register a service worker.\n// register() is not called by default.\n\n// This lets the app load faster on subsequent visits in production, and gives\n// it offline capabilities. However, it also means that developers (and users)\n// will only see deployed updates on subsequent visits to a page, after all the\n// existing tabs open on the page have been closed, since previously cached\n// resources are updated in the background.\n\n// To learn more about the benefits of this model and instructions on how to\n// opt-in, read http://bit.ly/CRA-PWA\n\nconst isLocalhost = Boolean(\n window.location.hostname === \"localhost\" ||\n // [::1] is the IPv6 localhost address.\n window.location.hostname === \"[::1]\" ||\n // 127.0.0.1/8 is considered localhost for IPv4.\n window.location.hostname.match(/^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/)\n);\n\nexport function register(config) {\n if (process.env.NODE_ENV === \"production\" && \"serviceWorker\" in navigator) {\n // The URL constructor is available in all browsers that support SW.\n const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);\n if (publicUrl.origin !== window.location.origin) {\n // Our service worker won't work if PUBLIC_URL is on a different origin\n // from what our page is served on. This might happen if a CDN is used to\n // serve assets; see https://github.com/facebook/create-react-app/issues/2374\n return;\n }\n\n window.addEventListener(\"load\", () => {\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\n\n if (isLocalhost) {\n // This is running on localhost. Let's check if a service worker still exists or not.\n checkValidServiceWorker(swUrl, config);\n\n // Add some additional logging to localhost, pointing developers to the\n // service worker/PWA documentation.\n navigator.serviceWorker.ready.then(() => {\n console.log(\n \"This web app is being served cache-first by a service \" +\n \"worker. To learn more, visit http://bit.ly/CRA-PWA\"\n );\n });\n } else {\n // Is not localhost. Just register service worker\n registerValidSW(swUrl, config);\n }\n });\n }\n}\n\nfunction registerValidSW(swUrl, config) {\n navigator.serviceWorker\n .register(swUrl)\n .then(registration => {\n registration.onupdatefound = () => {\n const installingWorker = registration.installing;\n if (installingWorker == null) {\n return;\n }\n installingWorker.onstatechange = () => {\n if (installingWorker.state === \"installed\") {\n if (navigator.serviceWorker.controller) {\n // At this point, the updated precached content has been fetched,\n // but the previous service worker will still serve the older\n // content until all client tabs are closed.\n console.log(\n \"New content is available and will be used when all \" +\n \"tabs for this page are closed. See http://bit.ly/CRA-PWA.\"\n );\n\n // Execute callback\n if (config && config.onUpdate) {\n config.onUpdate(registration);\n }\n } else {\n // At this point, everything has been precached.\n // It's the perfect time to display a\n // \"Content is cached for offline use.\" message.\n console.log(\"Content is cached for offline use.\");\n\n // Execute callback\n if (config && config.onSuccess) {\n config.onSuccess(registration);\n }\n }\n }\n };\n };\n })\n .catch(error => {\n console.error(\"Error during service worker registration:\", error);\n });\n}\n\nfunction checkValidServiceWorker(swUrl, config) {\n // Check if the service worker can be found. If it can't reload the page.\n fetch(swUrl)\n .then(response => {\n // Ensure service worker exists, and that we really are getting a JS file.\n const contentType = response.headers.get(\"content-type\");\n if (response.status === 404 || (contentType != null && contentType.indexOf(\"javascript\") === -1)) {\n // No service worker found. Probably a different app. Reload the page.\n navigator.serviceWorker.ready.then(registration => {\n registration.unregister().then(() => {\n window.location.reload();\n });\n });\n } else {\n // Service worker found. Proceed as normal.\n registerValidSW(swUrl, config);\n }\n })\n .catch(() => {\n console.log(\"No internet connection found. App is running in offline mode.\");\n });\n}\n\nexport function unregister() {\n if (\"serviceWorker\" in navigator) {\n navigator.serviceWorker.ready.then(registration => {\n registration.unregister();\n });\n }\n}\n","import React from \"react\";\nimport ReactDOM from \"react-dom\";\nimport \"./static/dripicons.css\";\nimport App from \"./App\";\nimport * as serviceWorker from \"./serviceWorker\";\n\nconst render = Component => {\n return ReactDOM.render(, document.getElementById(\"root\"));\n};\n\nrender(App);\n\nif (module.hot) {\n module.hot.accept(\"./App\", () => {\n const NextApp = require(\"./App\").default;\n render(NextApp);\n });\n}\n\n// If you want your app to work offline and load faster, you can change\n// unregister() to register() below. Note this comes with some pitfalls.\n// Learn more about service workers: http://bit.ly/CRA-PWA\nserviceWorker.unregister();\n"],"sourceRoot":""}