Source code

Revision control

Copy as Markdown

Other Tools

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Overview - Web Platform Test</title>
<link rel="stylesheet" href="css/bulma-0.7.5/bulma.min.css" />
<link rel="stylesheet" href="css/fontawesome-5.7.2.min.css" />
<script src="lib/utils.js"></script>
<script src="lib/wave-service.js"></script>
<script src="lib/ui.js"></script>
<style>
.site-logo {
max-width: 300px;
margin: 0 0 30px -15px;
}
.disabled-row {
color: gray;
background: lightgray;
}
</style>
</head>
<body>
<script>
window.onload = () => {
const query = utils.parseQuery(location.search);
if (query.token) {
location.href = WEB_ROOT + "results.html" + location.search;
}
resultsUi.render();
resultsUi.loadData();
};
var sortDetail = {};
const defaultSortDetail = { sortColumn: "dateStarted", ascending: true };
sortDetail["recentSessions"] = defaultSortDetail;
sortDetail["pinnedSessions"] = defaultSortDetail;
sortDetail["publicSessions"] = defaultSortDetail;
const resultsUi = {
state: {
comparison: [],
recentSessions: null,
importResultsEnabled: false,
filterLabels: []
},
loadData() {
const pinnedSessions = WaveService.getPinnedSessions().filter(
token => !!token
);
const recentSessions = WaveService.getRecentSessions().filter(
token => !!token
);
pinnedSessions.forEach(token => {
const index = recentSessions.indexOf(token);
if (index !== -1) recentSessions.splice(index, 1);
});
WaveService.setRecentSessions(recentSessions);
let allSessions = [];
allSessions = allSessions.concat(pinnedSessions);
allSessions = allSessions.concat(recentSessions);
WaveService.readPublicSessions(publicSessions => {
publicSessions.forEach(token => {
const index = recentSessions.indexOf(token);
if (index !== -1) recentSessions.splice(index, 1);
});
WaveService.setRecentSessions(recentSessions);
allSessions = allSessions.concat(publicSessions);
WaveService.readMultipleSessions(allSessions, configurations =>
WaveService.readMultipleSessionStatuses(allSessions, statuses => {
configurations.forEach(configuration => {
const status = statuses.find(
status => status.token === configuration.token
);
configuration.dateStarted = status.dateStarted;
configuration.dateFinished = status.dateFinished;
configuration.status = status.status;
});
configurations = configurations.filter(
configuration => !!configuration
);
allSessions
.filter(
token =>
!configurations.some(
configuration => configuration.token === token
)
)
.forEach(token => {
WaveService.removePinnedSession(token);
WaveService.removeRecentSession(token);
});
resultsUi.state.publicSessions = publicSessions;
resultsUi.state.pinnedSessions = WaveService.getPinnedSessions();
resultsUi.state.recentSessions = WaveService.getRecentSessions();
const sessions = {};
configurations.forEach(
configuration =>
(sessions[configuration.token] = configuration)
);
resultsUi.state.sessions = sessions;
const referenceTokens = [];
const loadedSessionsTokens = Object.keys(sessions);
configurations.forEach(configuration =>
configuration.referenceTokens
.filter(token => loadedSessionsTokens.indexOf(token) === -1)
.forEach(token => referenceTokens.push(token))
);
WaveService.readMultipleSessions(
referenceTokens,
configurations => {
const { sessions } = resultsUi.state;
configurations.forEach(
configuration =>
(sessions[configuration.token] = configuration)
);
resultsUi.renderPublicSessions();
resultsUi.renderPinnedSessions();
resultsUi.renderRecentSessions();
}
);
})
);
});
WaveService.readStatus(function(config) {
resultsUi.state.importResultsEnabled = config.importResultsEnabled;
resultsUi.state.reportsEnabled = config.reportsEnabled;
resultsUi.renderManageSessions();
});
},
findSession(fragment, callback) {
if (!fragment || fragment.length < 8) return;
WaveService.findToken(
fragment,
token => {
WaveService.readSession(token, session => {
WaveService.readSessionStatus(token, status => {
session.status = status.status;
session.dateStarted = status.dateStarted;
session.dateFinished = status.dateFinished;
callback(session);
});
});
},
() => callback(null)
);
},
addSession(session) {
const token = session.token;
if (resultsUi.state.sessions[token]) return;
resultsUi.state.sessions[token] = session;
resultsUi.pinSession(token);
},
removeSession(token) {
delete resultsUi.state.sessions[token];
WaveService.removeRecentSession(token);
WaveService.removePinnedSession(token);
resultsUi.updateSessionState();
},
showAddSessionError() {
const errorBox = UI.getElement("find-error");
errorBox.setAttribute("style", "display: block");
},
hideAddSessionError() {
const errorBox = UI.getElement("find-error");
errorBox.setAttribute("style", "display: none");
},
pinSession(token) {
WaveService.addPinnedSession(token);
WaveService.removeRecentSession(token);
resultsUi.updateSessionState();
},
unpinSession(token) {
WaveService.removePinnedSession(token);
WaveService.addRecentSession(token);
resultsUi.updateSessionState();
},
updateSessionState() {
resultsUi.state.pinnedSessions = WaveService.getPinnedSessions();
resultsUi.state.recentSessions = WaveService.getRecentSessions();
resultsUi.renderPinnedSessions();
resultsUi.renderRecentSessions();
},
openSessionResult(token) {
location.href = `${WEB_ROOT}results.html?token=${token}`;
},
sortSessions(tableType, column) {
if (tableType in sortDetail) {
if (sortDetail[tableType].sortColumn == column) {
sortDetail[tableType].ascending = !sortDetail[tableType]
.ascending;
} else {
sortDetail[tableType].sortColumn = column;
sortDetail[tableType].ascending = true;
}
switch (tableType) {
case "recentSessions":
resultsUi.renderRecentSessions();
break;
case "pinnedSessions":
resultsUi.renderPinnedSessions();
break;
case "publicSessions":
resultsUi.renderPublicSessions();
break;
}
}
},
sortSessionsByColumn(sessions, recentSessions, column, ascending) {
var resultArray = recentSessions
.map(token => sessions[token])
.sort(function(sessionA, sessionB) {
let columnA = sessionA[column];
if (column === "browser")
columnA = sessionA[column].name + sessionA[column].version;
if (column === "dateStarted" && !columnA) {
columnA = Date.now();
}
let columnB = sessionB[column];
if (column === "browser")
columnB = sessionB[column].name + sessionA[column].version;
if (column === "dateStarted" && !columnB) {
columnB = Date.now();
}
if (columnA < columnB) {
return -1;
}
if (columnA > columnB) {
return 1;
}
return 0;
});
if (ascending) {
resultArray.reverse();
}
return resultArray;
},
compareSessions(reftokens) {
if (!resultsUi.isComparisonValid()) return;
const tokens = resultsUi.state.comparison;
if (!tokens || tokens.length === 0) return;
const refQuery = reftokens ? `&reftokens=${reftokens}` : "";
location.href = `${WEB_ROOT}comparison.html?tokens=${tokens.join(
","
)}${refQuery}`;
},
isComparisonValid() {
const { comparison, sessions } = resultsUi.state;
if (!comparison) return false;
if (comparison.length <= 1) return false;
const comparingSessions = comparison.map(token => sessions[token]);
const referenceTokens = comparingSessions[0].referenceTokens;
for (let comparingSession of comparingSessions) {
const comparingReferenceTokens = comparingSession.referenceTokens;
if (referenceTokens.length !== comparingReferenceTokens.length)
return false;
for (let token of comparingReferenceTokens) {
if (referenceTokens.indexOf(token) === -1) return false;
}
}
return true;
},
isSessionValidForComparison(session) {
if (!session) return false;
if (session.status !== "completed" && session.status !== "aborted")
return false;
const sessionRefTokens = session.reference_tokens;
const comparisonSession =
resultsUi.state.sessions[resultsUi.state.comparison[0]];
if (!comparisonSession) return true;
const comparisonRefTokens = comparisonSession.reference_tokens;
if (!comparisonRefTokens) return true;
if (sessionRefTokens.length !== comparisonRefTokens.length)
return false;
if (
sessionRefTokens.some(
token => comparisonRefTokens.indexOf(token) === -1
)
)
return false;
return true;
},
isSessionSelectedForComparison(session) {
return resultsUi.state.comparison.indexOf(session.token) !== -1;
},
isSessionDisabled(session) {
return (
resultsUi.state.comparison.length > 0 &&
!resultsUi.isSessionValidForComparison(session)
);
},
addSessionToComparison(token) {
if (resultsUi.state.comparison.indexOf(token) !== -1) return;
resultsUi.state.comparison.push(token);
resultsUi.updateCompareButton();
resultsUi.renderSessions();
},
removeSessionFromComparison(token) {
const index = resultsUi.state.comparison.indexOf(token);
if (index === -1) return;
resultsUi.state.comparison.splice(index, 1);
resultsUi.updateCompareButton();
resultsUi.renderSessions();
},
handleAddSession() {
const tokenFragmentInput = UI.getElement("token-fragment");
const fragment = tokenFragmentInput.value;
resultsUi.findSession(fragment, session => {
if (!session) {
resultsUi.showAddSessionError();
return;
}
tokenFragmentInput.value = "";
resultsUi.hideAddSessionError();
resultsUi.addSession(session);
});
},
handleImportSession() {
resultsUi.state.importError = null;
resultsUi.state.importInProgress = true;
resultsUi.renderManageSessions();
const { importSessionFile: file } = resultsUi.state;
const reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = () => {
const data = reader.result;
WaveService.importResults(
data,
function(token) {
location.href = WEB_ROOT + "results.html?token=" + token;
},
function(error) {
resultsUi.state.importError = error;
resultsUi.state.importInProgress = false;
resultsUi.renderManageSessions();
}
);
};
},
handleImportSessionSelection() {
const file = UI.getElement("import-session-file").files[0];
resultsUi.state.importSessionFile = file;
resultsUi.renderManageSessions();
},
addFilterLabel() {
const label = UI.getElement("filter-label-input").value;
if (!label) return;
const { filterLabels } = resultsUi.state;
if (filterLabels.indexOf(label) !== -1) return;
filterLabels.push(label);
resultsUi.renderSessions();
UI.getElement("filter-label-input").focus();
},
removeFilterLabel(index) {
resultsUi.state.filterLabels.splice(index, 1);
resultsUi.renderSessions();
},
showAddFilterLabel() {
resultsUi.state.addFilterLabelVisible = true;
resultsUi.renderSessions();
UI.getElement("filter-label-input").focus();
},
hideAddFilterLabel() {
resultsUi.state.addFilterLabelVisible = false;
resultsUi.renderSessions();
},
render() {
const { getRoot, createElement, getElement } = UI;
const resultsView = UI.createElement({
className: "section",
children: [
{
className: "container",
style: "margin-bottom: 2em",
children: [
{
element: "img",
src: "res/wavelogo_2016.jpg",
className: "site-logo"
},
{ text: "Results Overview", className: "title" }
]
},
{
id: "manage-sessions",
className: "container",
style: "margin-bottom: 2em"
},
{ id: "sessions", className: "container" }
]
});
const root = UI.getRoot();
root.innerHTML = "";
root.appendChild(resultsView);
resultsUi.renderManageSessions();
resultsUi.renderSessions();
},
renderManageSessions() {
const manageSessionsView = UI.getElement("manage-sessions");
manageSessionsView.innerHTML = "";
const heading = { text: "Manage Sessions", className: "title is-4" };
const addCompareSessions = {
className: "columns",
children: [
{
className: "column",
children: [
{ text: "Add Sessions", className: "title is-5" },
{
element: "article",
className: "message is-danger",
id: "find-error",
children: [
{
text:
"Could not find any sessions! Try adding more characters of the token.",
className: "message-body"
}
],
style: "display: none"
},
{
className: "field",
children: [
{
className: "label has-text-weight-normal",
text: "Session token:"
},
{
className: "field-body",
children: {
className: "field",
children: {
className: "control",
children: {
style: "display: flex; margin-bottom: 10px;",
children: [
{
element: "input",
inputType: "text",
className: "input is-family-monospace",
id: "token-fragment",
placeholder:
"First 8 characters or more of session token",
onKeyDown: event =>
event.key === "Enter"
? resultsUi.handleAddSession()
: null
}
]
}
}
}
},
{
className: "field is-grouped is-grouped-right",
children: {
className: "control",
children: {
className: "button is-dark is-outlined",
children: [
{
element: "span",
className: "icon",
children: [
{
element: "i",
className: "fas fa-plus"
}
]
},
{ text: "Add Session", element: "span" }
],
onclick: resultsUi.handleAddSession
}
}
}
]
}
]
},
{
className: "column",
children: [
{ text: "Compare Sessions", className: "title is-5" },
{
element: "label",
text:
"Compare sessions by selecting them in the list below. " +
"Only sessions with the same set of reference sessions can be compared. " +
"Sessions have to be finished."
},
{
style: "text-align: right",
children: [
{
className: "button is-dark is-outlined",
disabled: true,
id: "compare-button",
children: [
{
element: "span",
className: "icon",
children: [
{
element: "i",
className: "fas fa-balance-scale"
}
]
},
{ text: "Compare Selected", element: "span" }
],
onClick: () => resultsUi.compareSessions()
}
]
}
]
}
]
};
const {
importSessionFile,
importError,
importInProgress
} = resultsUi.state;
const importSessions = {
className: "columns",
style: "margin-bottom: 2em",
children: [
{
className: "column is-half",
children: [
{ text: "Import Sessions", className: "title is-5" },
{
element: "article",
className: "message is-danger",
children: [
{
className: "message-body",
text: "Could not import session: " + importError
}
],
style: importError ? "" : "display: none"
},
{
className: "field file has-name",
children: [
{
element: "label",
className: "file-label",
style: "width: 100%",
children: [
{
element: "input",
className: "file-input",
type: "file",
accept: ".zip",
id: "import-session-file",
onChange: resultsUi.handleImportSessionSelection
},
{
element: "span",
className: "file-cta",
children: [
{
element: "span",
className: "file-icon",
children: [
{
element: "i",
className: "fas fa-upload"
}
]
},
{
element: "span",
className: "file-label",
text: "Choose ZIP file"
}
]
},
{
element: "span",
className: "file-name",
style: "width: 100%; max-width: unset",
text: importSessionFile
? importSessionFile.name
: ""
}
]
}
]
},
{
className: "field is-grouped is-grouped-right",
children: {
className: "control",
children: {
className: "button is-dark is-outlined",
disabled: !importSessionFile,
children: [
{
element: "span",
className: "icon",
children: [
{
element: "i",
className: importInProgress
? "fas fa-spinner fa-pulse"
: "fas fa-plus"
}
]
},
{ text: "Import Session", element: "span" }
],
onclick: resultsUi.handleImportSession
}
}
}
]
},
{
className: "column",
children: []
}
]
};
const { importResultsEnabled } = resultsUi.state;
manageSessionsView.appendChild(UI.createElement(heading));
manageSessionsView.appendChild(UI.createElement(addCompareSessions));
if (!importResultsEnabled) return;
manageSessionsView.appendChild(UI.createElement(importSessions));
},
renderSessions() {
const sessionsView = UI.getElement("sessions");
sessionsView.innerHTML = "";
sessionsView.appendChild(
UI.createElement({ text: "Sessions", className: "title is-4" })
);
const sessionFilters = resultsUi.createSessionFilters();
sessionsView.appendChild(sessionFilters);
sessionsView.appendChild(UI.createElement({ id: "public-sessions" }));
sessionsView.appendChild(UI.createElement({ id: "pinned-sessions" }));
sessionsView.appendChild(UI.createElement({ id: "recent-sessions" }));
sessionsView.appendChild(UI.createElement({ id: "session-status" }));
resultsUi.renderPublicSessions();
resultsUi.renderPinnedSessions();
resultsUi.renderRecentSessions();
},
renderPublicSessions() {
resultsUi.renderSessionStatus();
const { sessions, publicSessions, filterLabels } = resultsUi.state;
UI.saveScrollPosition("public-sessions-overflow");
const publicSessionsView = UI.getElement("public-sessions");
publicSessionsView.innerHTML = "";
if (!publicSessions || publicSessions.length === 0) return;
const sortedPublicSessions = resultsUi.sortSessionsByColumn(
sessions,
publicSessions,
sortDetail["publicSessions"].sortColumn,
sortDetail["publicSessions"].ascending
);
const filteredPublicSessions = sortedPublicSessions.filter(
session =>
filterLabels.length === 0 ||
filterLabels.reduce(
(match, label) =>
match &&
session.labels
.map(label => label.toLowerCase())
.indexOf(label.toLowerCase()) !== -1,
true
)
);
if (filteredPublicSessions.length === 0) return;
publicSessionsView.appendChild(
UI.createElement({
text: "Reference Browsers",
className: "title is-5"
})
);
const sessionsTable = UI.createElement({
style: "overflow-x: auto",
id: "public-sessions-overflow",
children: resultsUi.createSessionsTable(
"publicSessions",
filteredPublicSessions,
{ static: true }
)
});
publicSessionsView.appendChild(sessionsTable);
publicSessionsView.appendChild(
UI.createElement({ style: "content: ''; margin-bottom: 40px" })
);
UI.loadScrollPosition("public-sessions-overflow")
},
renderPinnedSessions() {
resultsUi.renderSessionStatus();
const { sessions, pinnedSessions, filterLabels } = resultsUi.state;
UI.saveScrollPosition("pinned-sessions-overflow");
const pinnedSessionsView = UI.getElement("pinned-sessions");
pinnedSessionsView.innerHTML = "";
if (!pinnedSessions || pinnedSessions.length === 0) return;
const sortedPinnedSessions = resultsUi.sortSessionsByColumn(
sessions,
pinnedSessions,
sortDetail["pinnedSessions"].sortColumn,
sortDetail["pinnedSessions"].ascending
);
const filteredPinnedSessions = sortedPinnedSessions.filter(
session =>
filterLabels.length === 0 ||
filterLabels.reduce(
(match, label) =>
match &&
session.labels
.map(label => label.toLowerCase())
.indexOf(label.toLowerCase()) !== -1,
true
)
);
if (filteredPinnedSessions.length === 0) return;
pinnedSessionsView.appendChild(
UI.createElement({ text: "Pinned", className: "title is-5" })
);
const sessionsTable = UI.createElement({
style: "overflow-x: auto",
id: "pinned-sessions-overflow",
children: resultsUi.createSessionsTable(
"pinnedSessions",
filteredPinnedSessions,
{ pinned: true }
)
});
pinnedSessionsView.appendChild(sessionsTable);
pinnedSessionsView.appendChild(
UI.createElement({ style: "content: ''; margin-bottom: 40px" })
);
UI.loadScrollPosition("pinned-sessions-overflow");
},
renderRecentSessions() {
resultsUi.renderSessionStatus();
const {
sessions,
recentSessions,
pinnedSessions,
filterLabels
} = resultsUi.state;
UI.saveScrollPosition("recent-sessions-overflow");
const recentSessionsView = UI.getElement("recent-sessions");
recentSessionsView.innerHTML = "";
if (!recentSessions || recentSessions.length === 0) return;
const sortedRecentSessions = resultsUi.sortSessionsByColumn(
sessions,
recentSessions,
sortDetail["recentSessions"].sortColumn,
sortDetail["recentSessions"].ascending
);
const filteredRecentSessions = sortedRecentSessions.filter(
session =>
filterLabels.length === 0 ||
filterLabels.reduce(
(match, label) =>
match &&
session.labels
.map(label => label.toLowerCase())
.indexOf(label.toLowerCase()) !== -1,
true
)
);
if (filteredRecentSessions.length === 0) return;
recentSessionsView.appendChild(
UI.createElement({ text: "Recent", className: "title is-5" })
);
const sessionsTable = UI.createElement({
style: "overflow-x: auto",
id: "recent-sessions-overflow",
children: resultsUi.createSessionsTable(
"recentSessions",
filteredRecentSessions,
{ pinned: false }
)
});
recentSessionsView.appendChild(sessionsTable);
recentSessionsView.appendChild(
UI.createElement({ style: "content: ''; margin-bottom: 40px" })
);
UI.loadScrollPosition("recent-sessions-overflow");
},
renderSessionStatus() {
const {
recentSessions,
pinnedSessions,
publicSessions
} = resultsUi.state;
const sessionStatusView = UI.getElement("session-status");
sessionStatusView.innerHTML = "";
if (!recentSessions && !pinnedSessions && !publicSessions) {
sessionStatusView.appendChild(
UI.createElement({
className: "level",
children: {
element: "span",
className: "level-item",
children: [
{
element: "i",
className: "fas fa-spinner fa-pulse"
},
{
style: "margin-left: 0.4em;",
text: "Loading sessions ..."
}
]
}
})
);
return;
} else if (
(!recentSessions || recentSessions.length === 0) &&
(!pinnedSessions || pinnedSessions.length === 0) &&
(!publicSessions || publicSessions.length === 0)
) {
sessionStatusView.appendChild(
UI.createElement({
className: "level",
children: {
element: "span",
className: "level-item",
text: "No sessions available."
}
})
);
return;
}
},
createSessionFilters() {
const { filterLabels, addFilterLabelVisible } = resultsUi.state;
const filters = UI.createElement({
className: "field is-horizontal",
style: "margin-bottom: 2em",
children: [
{
className: "field-label",
style: "flex: unset",
children: {
className: "label has-text-weight-normal",
text: "Filter by labels:"
}
},
{
className: "field-body",
children: {
className: "control",
children: {
className: "field is-grouped is-grouped-multiline",
children: filterLabels
.map((label, index) => ({
className: "control",
children: {
className: "tags has-addons",
children: [
{
element: "span",
className: "tag is-info",
text: label
},
{
element: "a",
className: "tag is-delete",
onClick: () => resultsUi.removeFilterLabel(index)
}
]
}
}))
.concat(
addFilterLabelVisible
? [
{
className: "control field is-grouped",
children: [
{
element: "input",
className: "input is-small control",
style: "width: 10rem",
id: "filter-label-input",
type: "text",
onKeyUp: event =>
event.keyCode === 13
? resultsUi.addFilterLabel()
: null
},
{
className:
"button is-dark is-outlined is-small is-rounded control",
text: "save",
onClick: resultsUi.addFilterLabel
},
{
className:
"button is-dark is-outlined is-small is-rounded control",
text: "cancel",
onClick: resultsUi.hideAddFilterLabel
}
]
}
]
: [
{
className: "button is-rounded is-small",
text: "Add",
onClick: resultsUi.showAddFilterLabel
}
]
)
}
}
}
]
});
return filters;
},
createSessionsTable(
tableType,
sessions,
{ pinned = false, static = false } = {}
) {
const getTagStyle = status => {
switch (status) {
case "completed":
return "is-success";
case "running":
return "is-info";
case "aborted":
return "is-danger";
case "paused":
return "is-warning";
case "pending":
return "is-primary";
}
};
var sortIcon = null;
if (tableType in sortDetail) {
sortIcon = sortDetail[tableType].ascending
? "fas fa-sort-down"
: "fas fa-sort-up";
}
return UI.createElement({
element: "table",
className: "table is-bordered is-hoverable is-fullwidth",
children: [
{
element: "thead",
children: {
element: "tr",
children: [
{
element: "td",
style: "text-decoration: underline dotted;",
text: "Cp",
className: "is-narrow",
title: "Select for comparison"
},
{
element: "td",
text: "Token",
className: "is-narrow",
onclick: () => resultsUi.sortSessions(tableType, "token"),
style: "cursor: pointer;",
children: [
{
element: "i",
className: sortIcon,
style:
"padding-left: 20px; visibility:" +
(sortIcon &&
sortDetail[tableType].sortColumn == "token"
? "visible;"
: "hidden;")
}
]
},
{
element: "td",
text: "Browser",
onclick: () =>
resultsUi.sortSessions(tableType, "browser"),
style: "cursor: pointer;",
className: "is-narrow",
children: [
{
element: "i",
className: sortIcon,
style:
"padding-left: 20px; visibility:" +
(sortIcon &&
sortDetail[tableType].sortColumn == "browser"
? "visible;"
: "hidden;")
}
]
},
{
element: "td",
text: "Status",
onclick: () =>
resultsUi.sortSessions(tableType, "status"),
style: "cursor: pointer",
className: "is-narrow",
children: [
{
element: "i",
className: sortIcon,
style:
"padding-left: 20px; visibility:" +
(sortIcon &&
sortDetail[tableType].sortColumn == "status"
? "visible;"
: "hidden;")
}
]
},
{
element: "td",
text: "Date Started",
onclick: () =>
resultsUi.sortSessions(tableType, "dateStarted"),
style: "cursor: pointer;",
className: "is-narrow",
children: [
{
element: "i",
className: sortIcon,
style:
"padding-left: 20px; visibility:" +
(sortIcon &&
sortDetail[tableType].sortColumn == "dateStarted"
? "visible;"
: "hidden;")
}
]
},
{
element: "td",
text: "Labels",
style: "cursor: pointer; width: 18rem"
},
static
? null
: {
element: "td",
text: "RefS",
title: "Reference Sessions",
style: "text-decoration: underline dotted;",
className: "is-narrow"
},
static
? null
: {
element: "td",
colspan: 2,
text: "Options",
className: "is-narrow"
}
]
}
},
{
element: "tbody",
children: sessions.map(session => ({
element: "tr",
className: resultsUi.isSessionDisabled(session)
? "disabled-row"
: "",
style: "cursor: pointer",
onclick: () => resultsUi.openSessionResult(session.token),
children: [
{
element: "td",
onclick: event => event.stopPropagation(),
style: "vertical-align: middle;",
children: [
{
element: "input",
className: "checkbox",
style:
"width: 18px; height: 18px; margin-top: 0.55em",
type: "checkbox",
disabled: !resultsUi.isSessionValidForComparison(
session
),
checked: resultsUi.isSessionSelectedForComparison(
session
),
onchange: event =>
event.target.checked
? resultsUi.addSessionToComparison(session.token)
: resultsUi.removeSessionFromComparison(
session.token
)
}
]
},
{
element: "td",
className: "is-family-monospace",
style: "vertical-align: middle;",
text: session.token.split("-").shift()
},
{
element: "td",
style: "vertical-align: middle; white-space: nowrap",
text: session.browser.name + " " + session.browser.version
},
{
element: "td",
style: "vertical-align: middle; text-align: center",
children: [
{
className: `tag ${getTagStyle(session.status)}`,
text: session.status
}
]
},
{
element: "td",
style: "vertical-align: middle; white-space: nowrap",
text: session.dateStarted
? new Date(session.dateStarted).toLocaleString()
: "not started"
},
{
element: "td",
children: {
className: "tags field is-grouped isgrouped-multiline",
style: "min-width: 10em",
children: session.labels.map(label => ({
className: "control",
children: {
element: "span",
className: "tag is-info",
text: label
}
}))
}
},
static
? null
: {
element: "td",
title: session.referenceTokens
.map(token => token.split("-").shift())
.sort((tokenA, tokenB) => tokenA - tokenB)
.join("\n"),
style: "white-space:nowrap",
children: (() => {
const tokens = session.referenceTokens.slice();
let overflow = 0;
if (tokens.length > 3) {
overflow = tokens.length - 2;
}
if (overflow > 0) tokens.splice(2, overflow + 2);
const children = tokens.map(token => {
let icon = "";
const session = resultsUi.state.sessions[token];
switch (session.browser.name.toLowerCase()) {
case "firefox":
icon = "fab fa-firefox";
break;
case "edge":
icon = "fab fa-edge";
break;
case "chrome":
case "chromium":
icon = "fab fa-chrome";
break;
case "safari":
case "webkit":
icon = "fab fa-safari";
break;
}
return {
element: "span",
style:
"margin-right: 5px; vertical-align: middle;",
children: { element: "i", className: icon }
};
});
if (overflow > 0)
children.push({
element: "span",
style: "vertical-align: middle",
className: "is-size-7",
text: `+${overflow}`
});
return children;
})()
},
static
? null
: {
element: "td",
style: "vertical-align: middle; text-align: center",
className: "is-paddingless",
children: [
{
className: "button is-dark is-outlined is-small",
title: pinned ? "Unpin session" : "Pin session",
style: "margin: 5px",
children: [
{
element: "span",
className: "icon",
children: [
{
element: "i",
className: "fas fa-thumbtack",
style: pinned
? ""
: "transform: rotate(45deg)"
}
]
}
],
onclick: event => {
event.stopPropagation();
if (pinned) {
resultsUi.unpinSession(session.token);
} else {
resultsUi.pinSession(session.token);
}
}
}
]
},
static
? null
: {
element: "td",
style: "vertical-align: middle; text-align: center",
className: "is-paddingless",
children: [
{
className: "button is-dark is-outlined is-small",
title: "Remove session from list",
style: "margin: 5px",
children: [
{
element: "span",
className: "icon",
children: [
{
element: "i",
className: "fas fa-trash-alt"
}
]
}
],
onclick: event => {
event.stopPropagation();
resultsUi.removeSession(session.token);
}
}
]
}
]
}))
}
]
});
},
updateCompareButton: () => {
const compareButton = UI.getElement("compare-button");
if (resultsUi.isComparisonValid()) {
compareButton.removeAttribute("disabled");
} else {
compareButton.setAttribute("disabled", true);
}
}
};
</script>
</body>
</html>