{"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","useState","loading","onLoading","error","onError","useMoreCaps","toggleMoreCaps","moreCapsError","onMoreCapsError","JSON","stringify","moreCaps","setMoreCaps","useEventCallback","event$","inputs$","combineLatest","pipe","tap","flatMap","_","rootCaps","moonOptions","enableVNC","sessionTimeout","labels","manual","additionalFonts","parse","hasOwnProperty","capabilities","alwaysMatch","browserName","browserVersion","desiredCapabilities","ajax","url","method","headers","timeout","body","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","window","location","protocol","hostname","port","optionsClass","curl","java","go","python","javascript","PHP","ruby","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","indexOf","screenResolution","Actions","Capabilities","Sessions","sessions","query","ids","includes","toLowerCase","withQuery","TransitionGroup","CSSTransition","classNames","unmountOnExit","in","exit","SessionInfo","urlTo","lnk","document","createElement","setAttribute","isSecure","VncScreen","Component","onVNCDisconnect","this","connection","onVNCConnect","rfb","resizeSession","scaleViewport","props","onUpdateState","componentDidMount","defaultPort","disconnect","createRFB","componentDidUpdate","prevProps","prevOrigin","componentWillUnmount","removeEventListener","secure","RFB","canvas","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","host","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.e69d4411.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: 250px;\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 origin = window.location.protocol + \"//\" + window.location.hostname + (window.location.port == \"\" ? \"\" : \":4444\");\n let optionsClass = \"SpecificBrowserOptions\";\n switch (browser) {\n case \"UNKNOWN\":\n case \"chrome\":\n case \"opera\":\n optionsClass = \"ChromeOptions\";\n break;\n case \"firefox\":\n optionsClass = \"FirefoxOptions\";\n break;\n case \"safari\":\n optionsClass = \"SafariOptions\";\n break;\n case \"MicrosoftEdge\":\n optionsClass = \"EdgeOptions\";\n break;\n }\n return {\n curl: `curl -H'Content-Type: application/json' ${origin}/wd/hub/session -d'{\n \"capabilities\": {\n \"alwaysMatch\": {\n \"browserName\": \"${browser != \"UNKNOWN\" ? browser : \"chrome\"}\",\n ${version == \"\" ? \"\" : \"\\\"browserVersion\\\": \\\"\" + version + \"\\\",\"}\n \"moon:options\": {\n \"name\": \"Session started using curl command...\",\n \"sessionTimeout\": \"1m\"\n }\n }\n }\n}'\n`,\n java: `${optionsClass} options = new ${optionsClass}();\n${browser == \"opera\" ? \"options.setCapability(\\\"browserName\\\", \\\"opera\\\");\" : \"\"}\n${version != \"\" ? \"options.setCapability(\\\"browserVersion\\\", \\\"\" + version + \"\\\");\" : \"\"}\noptions.setCapability(\"moon:options\", new HashMap() {{\n /* How to add test badge */\n put(\"name\", \"Test badge...\");\n\n /* How to set session timeout */\n put(\"sessionTimeout\", \"15m\");\n\n /* How to set timezone */\n put(\"env\", new ArrayList() {{\n add(\"TZ=UTC\");\n }});\n\n /* How to add \"trash\" button */\n put(\"labels\", new HashMap() {{\n put(\"manual\", \"true\");\n }});\n\n /* How to enable video recording */\n put(\"enableVideo\", true);\n}});\nRemoteWebDriver driver = new RemoteWebDriver(new URL(\"${origin}/wd/hub\"), options);\n`,\n go: `// import \"github.com/tebeka/selenium\"\n\ncaps := selenium.Capabilities{\n \"browserName\": \"${browser != \"UNKNOWN\" ? browser : \"chrome\"}\",\n\t\t\"browserVersion\": \"${version}\",\n\t\t\"moon:options\": map[string]interface{}{\n /* How to add test badge */\n \"name\": \"Test badge...\",\n\n /* How to set session timeout */\n \"sessionTimeout\": \"5m\",\n\n /* How to set timezone */\n \"env\": []string{\n \"TZ=UTC\",\n },\n\n /* How to add \"trash\" button */\n \"labels\": map[string]interface{}{\n \"manual\": \"true\",\n },\n\n /* How to enable video recording */\n \"enableVideo\": true,\n },\n}\n\ndriver, err := selenium.NewRemote(caps, \"http://moon.aerokube.local/wd/hub\")\nif err != nil {\n t.Errorf(\"starting browser: %v\", err)\n}\ndefer driver.Quit()\n`,\n \"C#\": `${optionsClass} options = new ${optionsClass}();\n${version != \"\" ? \"options.BrowserVersion = \\\"\" + version + \"\\\";\" : \"\"}\noptions.AddAdditionalOption(\"moon:options\", new Dictionary {\n /* How to add test badge */\n [\"name\"] = \"Test badge...\",\n\n /* How to set session timeout */\n [\"sessionTimeout\"] = \"15m\",\n\n /* How to set timezone */\n [\"env\"] = new List() {\n \"TZ=UTC\"\n },\n\n /* How to add \"trash\" button */\n [\"labels\"] = new Dictionary {\n [\"manual\"] = \"true\"\n },\n\n /* How to enable video recording */\n [\"enableVideo\"] = true\n});\nIWebDriver driver = new RemoteWebDriver(new Uri(\"http://moon.aerokube.local/wd/hub\"), options);\n`,\n python: `from selenium import webdriver\n \ncapabilities = {\n \"browserName\": \"${browser != \"UNKNOWN\" ? browser : \"chrome\"}\",\n \"browserVersion\": \"${version}\",\n \"moon:options\": {\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: '${window.location.hostname}',\n port: 4444,\n protocol: '${window.location.protocol == \"https:\" ? \"https\" : \"http\"}',\n capabilities: { \n browserName: '${browser != \"UNKNOWN\" ? browser : \"chrome\"}',\n browserVersion: '${version}',\n 'moon:options': {\n enableVideo: false \n } \n } \n};\nvar client = webdriverio.remote(options);\n`,\n PHP: `$web_driver = RemoteWebDriver::create(\"${origin}/wd/hub\",\narray(\"browserName\"=>\"${browser != \"UNKNOWN\" ? browser : \"chrome\"}\", \"browserVersion\"=>\"${version}\")\n);\n`,\n ruby: `caps = Selenium::WebDriver::Remote::Capabilities.new\nbrowserName: '${browser != \"UNKNOWN\" ? browser : \"chrome\"}',\ncaps[\"browserVersion\"] = \"${version}\"\n\ndriver = Selenium::WebDriver.for(:remote,\n :url => \"${origin}/wd/hub\",\n :desired_capabilities => caps)\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(\"curl\");\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 = { \"capabilities\": { \"alwaysMatch\": { \"goog:chromeOptions\":{ \"excludeSwitches\": [\"enable-automation\"] }}} };\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 rootCaps;\n let moonOptions = {\n enableVNC: true,\n sessionTimeout: \"60m\",\n labels: { manual: \"true\" },\n name: \"Manual session\",\n additionalFonts: true\n };\n\n if (useMoreCaps && !moreCapsError) {\n rootCaps = JSON.parse(moreCaps);\n const alwaysMatch = {};\n if (rootCaps.hasOwnProperty('capabilities')) {\n if (rootCaps.capabilities.hasOwnProperty('alwaysMatch')) {\n if (!rootCaps.capabilities.alwaysMatch.hasOwnProperty('browserName')) {\n rootCaps.capabilities.alwaysMatch.browserName = `${name}`\n }\n if (!rootCaps.capabilities.alwaysMatch.hasOwnProperty('browserVersion')) {\n rootCaps.capabilities.alwaysMatch.browserVersion = `${version}`\n }\n if (!rootCaps.capabilities.alwaysMatch.hasOwnProperty('moon:options')) {\n rootCaps.capabilities.alwaysMatch['moon:options'] = moonOptions\n }\n } else {\n rootCaps.capabilities.alwaysMatch = {\n browserName: `${name}`,\n browserVersion: `${version}`,\n \"moon:options\": moonOptions,\n }\n }\n } else {\n rootCaps.capabilities = {\n alwaysMatch: {\n browserName: `${name}`,\n browserVersion: `${version}`,\n \"moon:options\": moonOptions,\n }\n }\n }\n } else {\n rootCaps = {\n capabilities: {\n alwaysMatch: {\n browserName: `${name}`,\n browserVersion: `${version}`,\n \"moon:options\": moonOptions,\n }\n }\n }\n }\n\n rootCaps.desiredCapabilities = rootCaps.capabilities.alwaysMatch\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: rootCaps\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, id.indexOf(\"-\"))}\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":""}