comparison.html (14819B)
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8" /> 5 <title>Compare Results - Web Platform Test</title> 6 <link rel="stylesheet" href="css/bulma-0.7.5/bulma.min.css" /> 7 <link rel="stylesheet" href="css/fontawesome-5.7.2.min.css" /> 8 <script src="lib/utils.js"></script> 9 <script src="lib/wave-service.js"></script> 10 <script src="lib/ui.js"></script> 11 <style> 12 body { 13 margin: 0; 14 padding: 0; 15 width: 100vw; 16 height: 100vh; 17 display: flex; 18 justify-content: center; 19 font-family: "Noto Sans", sans-serif; 20 overflow-y: auto; 21 overflow-x: hidden; 22 background-color: white; 23 color: #000; 24 } 25 26 .site-logo { 27 max-width: 300px; 28 margin-left: -15px; 29 } 30 31 .content { 32 width: 1000px; 33 } 34 35 .header { 36 display: flex; 37 margin: 50px 0 30px 0; 38 } 39 40 .header :first-child { 41 flex: 1; 42 } 43 44 .session-header { 45 display: flex; 46 justify-content: center; 47 align-items: center; 48 cursor: pointer; 49 } 50 51 .session-header div { 52 padding: 5px; 53 font-weight: bold; 54 } 55 56 .session-header:hover div { 57 text-decoration: underline; 58 } 59 </style> 60 </head> 61 <body> 62 <script> 63 window.onload = () => { 64 let { tokens, reftokens } = utils.parseQuery(location.search); 65 tokens = tokens ? tokens.split(",") : []; 66 const refTokens = reftokens ? reftokens.split(",") : []; 67 if (tokens) { 68 WaveService.readStatus(function(config) { 69 comparisonUi.state.reportsEnabled = config.reportsEnabled; 70 comparisonUi.render(); 71 }); 72 WaveService.addRecentSessions(tokens); 73 WaveService.addRecentSessions(refTokens); 74 comparisonUi.state.tokens = tokens; 75 comparisonUi.state.refTokens = refTokens; 76 comparisonUi.render(); 77 comparisonUi.refreshData(); 78 } 79 }; 80 81 const comparisonUi = { 82 state: { 83 tokens: [], 84 refTokens: [], 85 sessions: {} 86 }, 87 refreshData: () => { 88 const { tokens, refTokens } = comparisonUi.state; 89 const allTokens = tokens.slice(); 90 refTokens 91 .filter(token => allTokens.indexOf(token) === -1) 92 .forEach(token => allTokens.push(token)); 93 94 WaveService.readMultipleSessions(allTokens, configurations => { 95 const sessions = {}; 96 configurations.forEach( 97 details => (sessions[details.token] = details) 98 ); 99 comparisonUi.state.sessions = sessions; 100 101 WaveService.readResultComparison(tokens, results => { 102 comparisonUi.state.results = results; 103 comparisonUi.renderApiResults(); 104 }); 105 106 const sessionsReferenceTokens = []; 107 configurations.forEach(({ referenceTokens }) => 108 referenceTokens 109 .filter(token => refTokens.indexOf(token) === -1) 110 .filter(token => sessionsReferenceTokens.indexOf(token) === -1) 111 .forEach(token => sessionsReferenceTokens.push(token)) 112 ); 113 114 sessionsReferenceTokens.forEach(token => 115 comparisonUi.state.refTokens.push(token) 116 ); 117 118 WaveService.readMultipleSessions( 119 sessionsReferenceTokens, 120 configurations => { 121 const { sessions } = comparisonUi.state; 122 configurations.forEach( 123 details => (sessions[details.token] = details) 124 ); 125 comparisonUi.renderDetails(); 126 } 127 ); 128 }); 129 }, 130 openResultsOverview() { 131 location.href = WEB_ROOT + "overview.html"; 132 }, 133 render() { 134 const comparisonView = UI.createElement({ 135 className: "content", 136 style: "margin-bottom: 40px;", 137 children: [ 138 { 139 className: "header", 140 children: [ 141 { 142 children: [ 143 { 144 element: "img", 145 src: "res/wavelogo_2016.jpg", 146 className: "site-logo" 147 } 148 ] 149 }, 150 { 151 className: "button is-dark is-outlined", 152 onClick: comparisonUi.openResultsOverview, 153 children: [ 154 { 155 element: "span", 156 className: "icon", 157 children: [ 158 { 159 element: "i", 160 className: "fas fa-arrow-left" 161 } 162 ] 163 }, 164 { 165 text: "Results Overview", 166 element: "span" 167 } 168 ] 169 } 170 ] 171 }, 172 { 173 id: "header", 174 children: [ 175 { className: "title", text: "Comparison" }, 176 { id: "controls" } 177 ] 178 }, 179 { id: "details" }, 180 { id: "api-results" } 181 ] 182 }); 183 184 const root = UI.getRoot(); 185 root.innerHTML = ""; 186 root.appendChild(comparisonView); 187 comparisonUi.renderDetails(); 188 comparisonUi.renderApiResults(); 189 }, 190 renderDetails() { 191 const detailsView = UI.createElement({ 192 style: "margin-bottom: 20px" 193 }); 194 195 const { refTokens } = comparisonUi.state; 196 const detailsTable = UI.createElement({ 197 element: "table", 198 children: { 199 element: "tbody", 200 children: [ 201 { 202 element: "tr", 203 id: "reference-sessions" 204 } 205 ] 206 } 207 }); 208 detailsView.appendChild(detailsTable); 209 210 const details = UI.getElement("details"); 211 details.innerHTML = ""; 212 details.appendChild(detailsView); 213 comparisonUi.renderReferenceSessions(); 214 }, 215 renderReferenceSessions() { 216 const { sessions, refTokens } = comparisonUi.state; 217 if (!refTokens || refTokens.length === 0) return; 218 if (!Object.keys(sessions) || Object.keys(sessions).length === 0) 219 return; 220 const referenceSessions = refTokens.map(token => sessions[token]); 221 const referenceSessionsTarget = UI.getElement("reference-sessions"); 222 referenceSessionsTarget.innerHTML = ""; 223 224 const referenceSessionsLabel = UI.createElement({ 225 element: "td", 226 text: "Reference Sessions:", 227 style: "width: 175px" 228 }); 229 referenceSessionsTarget.appendChild(referenceSessionsLabel); 230 231 const referenceSessionsList = UI.createElement({ element: "td" }); 232 referenceSessions.forEach(session => { 233 const { token, browser } = session; 234 const referenceSessionItem = UI.createElement({ 235 style: "margin-right: 10px", 236 className: "button is-dark is-small is-rounded is-outlined", 237 onClick: () => WaveService.openSession(token), 238 children: [ 239 { 240 element: "span", 241 className: "icon", 242 children: { 243 element: "i", 244 className: utils.getBrowserIcon(browser.name) 245 } 246 }, 247 { 248 element: "span", 249 className: "is-family-monospace", 250 text: token.split("-").shift() 251 } 252 ] 253 }); 254 referenceSessionsList.appendChild(referenceSessionItem); 255 }); 256 referenceSessionsTarget.appendChild(referenceSessionsList); 257 }, 258 renderApiResults() { 259 const apiResultsView = UI.createElement({ 260 style: "margin-bottom: 20px" 261 }); 262 263 const heading = UI.createElement({ 264 className: "title is-4", 265 text: "Results" 266 }); 267 apiResultsView.appendChild(heading); 268 269 const { results, tokens, sessions } = comparisonUi.state; 270 271 if (!results) { 272 const loadingIndicator = UI.createElement({ 273 className: "level", 274 children: { 275 element: "span", 276 className: "level-item icon", 277 children: [ 278 { 279 element: "i", 280 className: "fas fa-spinner fa-pulse" 281 }, 282 { 283 style: "margin-left: 0.4em;", 284 text: "Loading comparison ..." 285 } 286 ] 287 } 288 }); 289 apiResultsView.appendChild(loadingIndicator); 290 291 const apiResults = UI.getElement("api-results"); 292 apiResults.innerHTML = ""; 293 apiResults.appendChild(apiResultsView); 294 return; 295 } 296 297 const resultsTable = UI.createElement({ 298 element: "table" 299 }); 300 apiResultsView.appendChild(resultsTable); 301 302 const getColor = percent => { 303 const tRed = 28; 304 const tGreen = 166; 305 const tBlue = 76; 306 const mRed = 204; 307 const mGreen = 163; 308 const mBlue = 0; 309 const bRed = 255; 310 const bGreen = 56; 311 const bBlue = 96; 312 if (percent > 50) { 313 const red = mRed + ((percent - 50) / 50) * (tRed - mRed); 314 const green = mGreen + ((percent - 50) / 50) * (tGreen - mGreen); 315 const blue = mBlue + ((percent - 50) / 50) * (tBlue - mBlue); 316 return `rgb(${red}, ${green}, ${blue})`; 317 } else { 318 const red = bRed + (percent / 50) * (mRed - bRed); 319 const green = bGreen + (percent / 50) * (mGreen - bGreen); 320 const blue = bBlue + (percent / 50) * (mBlue - bBlue); 321 return `rgb(${red}, ${green}, ${blue})`; 322 } 323 }; 324 325 const resultsTableHeader = UI.createElement({ 326 element: "thead", 327 children: { 328 element: "tr", 329 children: [ 330 { 331 element: "td", 332 text: "API", 333 style: "vertical-align: bottom; width: 200px" 334 } 335 ] 336 .concat( 337 tokens.map(token => ({ 338 element: "td", 339 children: { 340 onClick: () => WaveService.openSession(token), 341 className: "session-header", 342 children: [ 343 { 344 element: "i", 345 style: "font-size: 1.5em; margin-right: 0.1em", 346 className: utils.getBrowserIcon( 347 sessions[token].browser.name 348 ) 349 }, 350 { 351 children: [ 352 { 353 style: "margin: 0; padding: 0;", 354 className: "is-family-monospace", 355 text: `${token.split("-").shift()}` 356 }, 357 { 358 style: "margin: 0; padding: 0;", 359 text: `${sessions[token].browser.name} ${ 360 sessions[token].browser.version 361 }` 362 } 363 ] 364 } 365 ] 366 } 367 })) 368 ) 369 .concat([{ element: "td", style: "width: 80px" }]) 370 } 371 }); 372 resultsTable.appendChild(resultsTableHeader); 373 374 let apis = []; 375 tokens.forEach(token => 376 Object.keys(results[token]) 377 .filter(api => apis.indexOf(api) === -1) 378 .forEach(api => apis.push(api)) 379 ); 380 apis = apis.sort((apiA, apiB) => 381 apiA.toLowerCase() > apiB.toLowerCase() ? 1 : -1 382 ); 383 384 const resultsTableBody = UI.createElement({ 385 element: "tbody", 386 children: apis.map(api => ({ 387 element: "tr", 388 children: [{ element: "td", text: api }] 389 .concat( 390 tokens.map(token => 391 results[token][api] 392 ? { 393 element: "td", 394 style: 395 "text-align: center; font-weight: bold;" + 396 `color: ${getColor( 397 utils.percent( 398 results[token][api], 399 results["total"][api] 400 ) 401 )}`, 402 text: `${utils.percent( 403 results[token][api], 404 results["total"][api] 405 )}%` 406 } 407 : { 408 element: "td", 409 text: "Not Tested", 410 style: "text-align: center;" 411 } 412 ) 413 ) 414 .concat([ 415 comparisonUi.state.reportsEnabled ? 416 { 417 element: "td", 418 children: { 419 className: 420 "html-report button is-dark is-outlined is-small", 421 onclick: () => 422 WaveService.readMultiReportUri( 423 comparisonUi.state.tokens, 424 api, 425 function(uri) { 426 window.open(uri, "_blank"); 427 } 428 ), 429 text: "report" 430 } 431 } : null 432 ]) 433 })) 434 }); 435 resultsTable.appendChild(resultsTableBody); 436 437 const apiResults = UI.getElement("api-results"); 438 apiResults.innerHTML = ""; 439 apiResults.appendChild(apiResultsView); 440 } 441 }; 442 </script> 443 </body> 444 </html>