// --- BEGIN Global variables ----------------------------------- var rankedOnly = null; // Whether to adapt GUI to only show // information related to rankings var testCaseChecked = new Array(); // --- END Global variables ------------------------------------- function selectAllTestCases() { $("#testCasesTable input").attr("checked", true); updateActions(); } function clearAllTestCases() { $("#testCasesTable input").attr("checked", false); updateActions(); } function fetchTestCases() { updateStatus("fetching matching test cases ...", true); $("#div_matchingTestCases").css("display", "none"); context1_ = context1(); if (context1_ == null) { updateStatus("fetching matching test cases ... done", false); updateStatus("", false); return; } context2_ = context2(); // Save current selection ... $("#testCasesTable input").each(function() { testCaseChecked[this.name] = this.checked; }); query = "?db=" + $('#database').val(); if (context2_["host"] == "") { query += "&cmd=testcases1"; query += "&host=" + encodeURIComponent(context1_["host"]); query += "&platform=" + encodeURIComponent(context1_["platform"]); query += "&branch=" + encodeURIComponent(context1_["branch"]); query += "&sha1=" + context1_["sha1"]; } else { query += "&cmd=testcases2"; query += "&host1=" + encodeURIComponent(context1_["host"]); query += "&platform1=" + encodeURIComponent(context1_["platform"]); query += "&branch1=" + encodeURIComponent(context1_["branch"]); query += "&sha11=" + context1_["sha1"]; query += "&host2=" + encodeURIComponent(context2_["host"]); query += "&platform2=" + encodeURIComponent(context2_["platform"]); query += "&branch2=" + encodeURIComponent(context2_["branch"]); query += "&sha12=" + context2_["sha1"]; } url = "http://" + location.host + "/cgi-bin/getstatswrapper" + query; // alert("url: >" + url + "<"); $.ajax({ url: url, type: "GET", dataType: "json", success: function(data, textStatus, request) { if (request.readyState == 4) { if (request.status == 200) { if (data.error != null) { updateStatus( "fetching matching test cases ... failed: " + data.error, false); return } updateStatus( "fetching matching test cases ... done", false); updateStatus("", false); // Remove all rows ... $("#testCasesTable tr").remove(); // Insert new rows ... testCases = data.testcases; html = ""; for (i = 0; i < testCases.length; ++i) { testCase = testCases[i]; html += ""; html += ""; html += "" + testCase + ""; html += ""; } $("#testCasesTable > tbody:last").append(html); // Select all rows ... //$("#testCasesTable input").attr("checked", "true"); // Restore last selection as much as possible ... $("#testCasesTable input").each(function() { if (this.name in testCaseChecked) { this.checked = testCaseChecked[this.name]; } else { this.checked = true; } }); $("#div_matchingTestCases").css("display", "block"); updateActions(); } } }, error: function(request, textStatus, errorThrown) { descr = errorThrown; if (errorThrown == null) { descr = "undefined error - is the server down?"; } updateStatus( "fetching matching test cases ... error: " + descr, false); } // complete: function(request, textStatus) { // alert("complete; request.status: " + request.status) // } }); return false; } function setActionUrl(id, url) { sel = $("#" + id); if (url != "") { sel.removeAttr("onclick"); sel.attr("class", "actionButton"); sel.attr("href", url); } else { sel.attr("onclick", "return false"); sel.attr("class", "disabledActionButton"); sel.attr("href", "javascript::void(0)"); } } function updateActions() { context1_ = context1(); if (context1_ == null) { // special case: no contexts are available setActionUrl("action_stats1", ""); setActionUrl("action_rankings", ""); setActionUrl("action_stats2", ""); setActionUrl("action_tsstats", ""); return; } context2_ = context2(); testCaseFilter = ""; $("#testCasesTable input").each(function() { if (this.checked) { testCaseFilter += " " + this.name; } }); // --- stats1 --- url_stats1 = "stats1.html"; url_stats1 += "?db=" + $('#database').val(); url_stats1 += "&cmd=stats1"; url_stats1 += "&host=" + encodeURIComponent(context1_["host"]); url_stats1 += "&platform=" + encodeURIComponent(context1_["platform"]); url_stats1 += "&branch=" + encodeURIComponent(context1_["branch"]); url_stats1 += "&sha1=" + context1_["sha1"]; url_stats1 += "&testcasefilter=" + testCaseFilter; // --- rankings --- if (context1_["rankingsExist"]) { url_rankings = "rankings.shtml"; url_rankings += "?db=" + $('#database').val(); url_rankings += "&cmd=rankings"; url_rankings += "&host=" + encodeURIComponent(context1_["host"]); url_rankings += "&platform=" + encodeURIComponent(context1_["platform"]); url_rankings += "&branch=" + encodeURIComponent(context1_["branch"]); url_rankings += "&sha1=" + context1_["sha1"]; url_rankings += "&testcasefilter=" + testCaseFilter; url_rankings += "&maxsize=" + $("#max_rank_size option:selected").val(); } else { url_rankings = ""; } // --- stats2 --- if (context2_["host"] != "") { url_stats2 = "stats2.html"; url_stats2 += "?db=" + $('#database').val(); url_stats2 += "&cmd=stats2"; url_stats2 += "&host1=" + encodeURIComponent(context1_["host"]); url_stats2 += "&platform1=" + encodeURIComponent(context1_["platform"]); url_stats2 += "&branch1=" + encodeURIComponent(context1_["branch"]); url_stats2 += "&sha11=" + context1_["sha1"]; url_stats2 += "&host2=" + encodeURIComponent(context2_["host"]); url_stats2 += "&platform2=" + encodeURIComponent(context2_["platform"]); url_stats2 += "&branch2=" + encodeURIComponent(context2_["branch"]); url_stats2 += "&sha12=" + context2_["sha1"]; url_stats2 += "&testcasefilter=" + testCaseFilter; } else { url_stats2 = ""; } // --- tsstats --- if ((context1_["host"] == context2_["host"]) && (context1_["platform"] == context2_["platform"]) && (context1_["branch"] == context2_["branch"]) && (context1_["sha1"] != context2_["sha1"])) { url_tsstats = "tsstats.shtml"; url_tsstats += "?db=" + $('#database').val(); url_tsstats += "&cmd=timeseriesstats"; url_tsstats += "&host=" + encodeURIComponent(context1_["host"]); url_tsstats += "&platform=" + encodeURIComponent(context1_["platform"]); url_tsstats += "&branch=" + encodeURIComponent(context1_["branch"]); url_tsstats += "&sha11=" + context1_["sha1"]; url_tsstats += "&sha12=" + context2_["sha1"]; url_tsstats += "&difftol=" + $("#diff_tol option:selected").val(); url_tsstats += "&durtolmin=" + $("#dur_tol_min option:selected").val(); url_tsstats += "&durtolmax=" + $("#dur_tol_max option:selected").val(); url_tsstats += "&testcasefilter=" + testCaseFilter; var nsnapshots = Math.abs( parseInt(context1_["snapshotIndex"]) - parseInt(context2_["snapshotIndex"])) + 1; $("#tsstats_nsnapshots").text(nsnapshots); } else { url_tsstats = ""; $("#tsstats_nsnapshots").text(0); } setActionUrl("action_stats1", url_stats1); setActionUrl("action_rankings", url_rankings); setActionUrl("action_stats2", url_stats2); setActionUrl("action_tsstats", url_tsstats); } function updateSelectedSnapshotColor(select) { sha1 = select.attr("value"); option = select.find("option[value = '" + sha1 + "']"); bgColor = option.css("backgroundColor"); select.css("backgroundColor", bgColor); } // Handles selection of a new snapshot for a context. function selectContextSnapshot(contextIndex) { tr = $("#contextsTable tr:eq(" + (contextIndex + 1) + ")"); select = tr.find("select"); updateSelectedSnapshotColor(select); updateActions(); fetchTestCases(); } // Handles selection of a new snapshot from the duplicated list for context 2. function selectExtraContext2Snapshot(skipFetchTestCases) { select = $("#extra_context2_snapshots select"); updateSelectedSnapshotColor(select); updateActions(); if ((skipFetchTestCases == null) || (!skipFetchTestCases)) { fetchTestCases(); } } // Returns the currently selected Context 1. function context1() { context = []; tr = $("#contextsTable tr:has(input[name='context1'][checked='true'])"); if (tr.length == 0) return null; context["host"] = tr.find("td[name = 'host']").text(); context["platform"] = tr.find("td[name = 'platform']").text(); context["branch"] = tr.find("td[name = 'branch']").text(); var snapshot = tr.find("select[name = 'snapshot'] option:selected"); context["sha1"] = snapshot.attr("value"); context["snapshotIndex"] = snapshot.index(); context["rankingsExist"] = (snapshot.attr("text")[0] == 'R'); return context; } // Returns the currently selected Context 2 if any. function context2() { context = []; tr_hpb = tr_sha1 = null; trExtra = $("#extra_context2_row"); if (trExtra.length > 0) { mainIndex = trExtra.attr("name"); tr_hpb = $("#" + "context_row\\:" + mainIndex); tr_sha1 = trExtra; } else { tr_hpb = tr_sha1 = $("#contextsTable tr:has(input[name='context2'][checked='true'])"); } context["host"] = tr_hpb.find("td[name = 'host']").text(); context["platform"] = tr_hpb.find("td[name = 'platform']").text(); context["branch"] = tr_hpb.find("td[name = 'branch']").text(); var snapshot = tr_sha1.find("select[name = 'snapshot'] option:selected"); context["sha1"] = snapshot.attr("value"); context["snapshotIndex"] = snapshot.index(); return context; } function fetchContexts() { updateStatus("fetching available contexts ...", true); $("#div_noMatchingContexts").css("display", "none"); database = $('#database').val(); query = "?db=" + database; query += "&cmd=contexts"; query += "&rankedonly=" + (rankedOnly ? 1 : 0); url = "http://" + location.host + "/cgi-bin/getstatswrapper" + query; //alert("url: >" + url + "<"); $.ajax({ url: url, type: "GET", dataType: "json", success: function(data, textStatus, request) { if (request.readyState == 4) { if (request.status == 200) { if (data.error != null) { updateStatus( "fetching available contexts ... failed: " + data.error, false); return } updateStatus("loading contexts ... done", false); updateStatus("", false); // Remove all rows below the header ... $("#contextsTable tr:gt(0)").remove(); currTime = dateToTimestamp(new Date()); // Insert new rows ... contexts = data.contexts; html = ""; for (i = 0; i < contexts.length; ++i) { context = contexts[i]; html += ""; html += ""; html += ""; html += "" + context.host + ""; html += "" + context.platform + ""; html += "" + context.branch + ""; html += ""; snapshots = context.snapshots; firstUploadTime0 = snapshots[0][1]; secsAgo0 = currTime - firstUploadTime0; ageColor0 = ageColor(secsAgo0); html += ""; html +=""; html += ""; } $("#contextsTable > tbody:last").append(html); // Select the first context as Context 1 ... $("#contextsTable td:first input").attr("checked", "true"); if (context1() == null) $("#div_noMatchingContexts").css("display", "block"); highlightContextsTable(); updateActions(); $("#div_availableContexts").css("display", "block"); if (rankedOnly) { // In contexts table, disable the 'Context 2' column: $("#contextsTable th:eq(1)").remove(); $("#contextsTable td:nth-child(2)").remove(); } fetchTestCases(); } } }, error: function(request, textStatus, errorThrown) { descr = errorThrown; if (errorThrown == null) { descr = "undefined error - is the server down?"; } updateStatus( "fetching available contexts ... error: " + descr, false); } // complete: function(request, textStatus) { // alert("complete; request.status: " + request.status) // } }); return false; } // Handles selecting another database. function selectDatabase() { fetchContexts(); } function highlightContextsTable() { // Unhighlight all selectable rows: $("#contextsTable tr:has(input)").attr("class", "unselected"); // Highlight selected rows (prioritizing context 1): $.each(["context2", "context1"], function(index, value) { rows = $("#contextsTable tr:has(input[name='" + value + "'][checked='true'])"); rows.attr("class", value); }); // Highlight extra context 2 row (if any): $("#extra_context2_row").attr("class", "context2"); } // Handles clicking a context checkbox. Exactly one Context 1 and // zero or one Context 2 must be selected at any time. function clickContextCheckbox(cb, col) { // Enforce selection invariant: if (cb.checked) { // Deselect all other checkboxes in this column // (note: nth-child assumes 1-based indexes): $("#contextsTable td:nth-child(" + (col + 1) + ") input") .attr("checked", false); cb.checked = true; } else if ((col == 0)) { // Prevent deselection by reselecting: cb.checked = true; } // Check if the same host/platform/branch combination is selected for // both contexts. If so, add an extra row below the selected row to enable // selection of a different snapshot for the Context 2 // (unless such an extra row doesn't already exist): index = cb.id.split(":")[1]; tr = $("#" + "context_row\\:" + index); checked1 = tr.find("td:nth-child(1) input").attr("checked"); checked2 = tr.find("td:nth-child(2) input").attr("checked"); if (checked1 && checked2) { if ($("#extra_context2_row").length == 0) { // Get selected sha1: sha1 = tr.find("select option:selected").attr("value"); // Append extra row: tr.after( "" + " " + ""); // Clone snapshots: tr.find("#context_snapshots\\:" + index).clone().appendTo( "#extra_context2_snapshots"); extraSelect = $("#extra_context2_snapshots select"); extraSelect.find("option[value = '" + sha1 + "']").attr( "selected", true); extraSelect.attr("onchange", ""); // This is needed! extraSelect.change(function() { selectExtraContext2Snapshot(); }); // Initialize selected snapshot color: selectExtraContext2Snapshot(true); } } else { // Remove any extra row: trExtra = $("#extra_context2_row"); if (trExtra.length > 0) { mainIndex = trExtra.attr("name"); trMain = $("#" + "context_row\\:" + mainIndex); // If Context 2 is still selected for the main row, // select the current snapshot of the main row as the one // selected for the extra row before removing the latter: if (trMain.find("td:nth-child(2) input").attr("checked")) { // Get selected sha1 in extra row: sha1 = trExtra.find("select option:selected").attr("value"); // Select this sha1 in the main row: trMain.find("select option[value = '" + sha1 + "']").attr( "selected", true); // Initialize selected snapshot color: selectContextSnapshot(parseInt(mainIndex)); } trExtra.remove(); } } highlightContextsTable(); updateActions(); fetchTestCases(); } $(document).ready(function() { var args = queryStringArgs(); var rankedOnly_int = parseInt(extractArg(args, "rankedonly")); rankedOnly = ((!isNaN(rankedOnly_int)) && (rankedOnly_int != 0)) if (rankedOnly) { // In actions table, keep only header and rows related to // 'Show rankings...' action: $("#actionTable tr").css("display", "none"); $("#actionTable tr[id='actionTable_header']").css("display", ""); $("#actionTable tr[id*='rankings']").css("display", ""); } // Set default action arguments: $("#max_rank_size option[value='10']").attr("selected", true); $("#diff_tol option[value='1.1']").attr("selected", true); $("#dur_tol_min option[value='3']").attr("selected", true); $("#dur_tol_max option[value='50']").attr("selected", true); fetchContexts(); });