summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/tools/wave/www/overview.html
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/tools/wave/www/overview.html
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/tools/wave/www/overview.html')
-rw-r--r--testing/web-platform/tests/tools/wave/www/overview.html1315
1 files changed, 1315 insertions, 0 deletions
diff --git a/testing/web-platform/tests/tools/wave/www/overview.html b/testing/web-platform/tests/tools/wave/www/overview.html
new file mode 100644
index 0000000000..48ec3a2514
--- /dev/null
+++ b/testing/web-platform/tests/tools/wave/www/overview.html
@@ -0,0 +1,1315 @@
+<!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>