lib/crazy_ivan/templates/index.html in crazy_ivan-1.1.1 vs lib/crazy_ivan/templates/index.html in crazy_ivan-1.2.0

- old
+ new

@@ -1,183 +1,229 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" - "http://www.w3.org/TR/html4/loose.dtd"> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <title>Crazy Ivan: CI straight up.</title> - <link rel="stylesheet" href="css/ci.css" type="text/css" charset="utf-8"> - <script type="text/javascript" src="javascript/prototype.js"></script> - <script type="text/javascript" src="javascript/scriptaculous.js"></script> - <script type="text/javascript" src="javascript/date.js"></script> - <script type="text/javascript" src="javascript/json-template.js"></script> + <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script> + <script type="text/javascript" charset="utf-8" src="javascript/date.js"></script> <script type="text/javascript"> - var init = function() { - render('index.jsont', projects()); + // Simple JavaScript Templating + // John Resig - http://ejohn.org/ - MIT Licensed + (function(){ + var cache = {}; + + this.tmpl = function tmpl(str, data){ + // Figure out if we're getting a template, or if we need to + // load the template - and be sure to cache the result. + var fn = !/\W/.test(str) ? + cache[str] = cache[str] || + tmpl(document.getElementById(str).innerHTML) : + + // Generate a reusable function that will serve as a template + // generator (and which will be cached). + new Function("obj", + "var p=[],print=function(){p.push.apply(p,arguments);};" + + + // Introduce the data as local variables using with(){} + "with(obj){p.push('" + + + // Convert the template into pure JavaScript + str + .replace(/[\r\t\n]/g, " ") + .split("<%").join("\t") + .replace(/((^|%>)[^\t]*)'/g, "$1\r") + .replace(/\t=(.*?)%>/g, "',$1,'") + .split("\t").join("');") + .split("%>").join("p.push('") + .split("\r").join("\\'") + + "');}return p.join('');"); + + // Provide some basic currying to the user + return data ? fn( data ) : fn; + }; + })(); + </script> + <style type="text/css" media="screen"> + body { + margin: 2.5em 3em; + padding: 0; + background: #fff; + color: #333; + font: 100%/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; } - - var projects = function() { - var projects = []; - var project_names = []; + + h1 { margin: 0;} + + pre { margin: 0;} + + .error { + color: red; + } + + .project h2 { margin: 12px 0 0 0;} + + .tests { margin: 0 0 0 18px;} + .tests .test { font-size: 80%; margin-right: 8px} + .tests a.test:hover { text-decoration: underline;} + .tests .test:first-child { font-size: 100%;} + .tests .test.active { font-weight: bold;} + + .result .timestamp { margin-right: 12px;} + .result .version { margin: 6px 0 6px 12px } + .result .output { padding: 5px; color: silver; background: black; margin: 12px 18px 8px 18px; overflow: auto } + .result .output .update { margin: 6px 0 6px 12px } + .result .output .test { margin: 6px 0 6px 12px} + + .footer { + margin: 24px 0 0 0; + font-size: 60%; + width: 100%; + text-align: center; + } + </style> + </head> + <body> + <h1>Projects</h1> + <div id="projects"></div> + + <div class="footer"> + <a href="http://github.com/edward/crazy_ivan">Crazy Ivan on Github</a> + </div> + + <!-- templates --> + + <!-- project template --> + <script type="text/html" id="projectTemplate"> + <div id="<%= projectId %>" class="project"> + <h2><%= projectName %></h2> - new Ajax.Request('projects.json', { - asynchronous: false, - onSuccess: function(transport) { - project_names = transport.responseText.evalJSON().projects; - } - }); + <div class="tests"></div> + <div class="results"></div> + <div> + </script> + + <!-- test link template --> + <script type="text/html" id="resultLinkTemplate"> + <a id="<%= projectDomId %>-<%= version.output %>" class="test"><%= shortTimeStamp %></a> + </script> + + <!-- build result holder --> + <script type="text/html" id="resultTemplate"> + <div class="result <%= projectDomId %>-<%= version.output %>" style="display: none"> + <div> + <span class="timestamp"><%= timestamp.finish %></span> + <span class="version"><%= version.output %></span> + </div> - project_names.each(function(project_name) { - var reports = []; + <div class="output"> + <div class="version" style="display: none"><pre class="error"><%= version.error %></pre></div> - reports = recent_versions(project_name).map(function(version) { - return version_test_report(project_name, version); - }) + <div class="update" style="display: none"> + <pre><%= update.output %></pre> + <pre class="error"><%= update.error %></pre> + </div> - project = {name: project_name, reports: reports.reverse(), build_in_progress: build_in_progress(project_name)}; - projects.push(project); - }) - - return {"projects": projects}; - } + <div class="test"> + <pre><%= test.output.replace(/\</g, "&lt;").replace(/\>/g, "&gt;") %></pre> + <pre class="error"><%= test.error %></pre> + </div> + </div> + </div> + </script> + + <script type="text/javascript" charset="utf-8"> + var json = {projects: []}; - var recent_versions = function(project) { - var recent_versions = []; - new Ajax.Request(project + '/recent.json', { - asynchronous: false, - onSuccess: function(transport) { - recent_versions = transport.responseText.evalJSON().recent_versions; - } + jQuery(document).ready(function($) { + $.getJSON("projects.json", function(data) { + jQuery.each(data.projects, function(i, projectName) { + addProjectToJson(projectName); + }); }); - return recent_versions; - } + }); - var version_test_report = function(project, version) { - var report = {}; - url = project + '/' + version + '.json'; + function addProjectToJson(name) { + var project = {'name': name, reports: []}; + var recentVersionsJsonPath = name + "/recent.json"; - new Ajax.Request(url, { - asynchronous: false, - onSuccess: function(transport) { - report = transport.responseText.evalJSON(); - } + jQuery.getJSON(recentVersionsJsonPath, function(data) { + jQuery.each(data.recent_versions, function(i, version) { + addReportToProject(project, version); + }); }); - return report; + + json.projects.push(project); } - var build_in_progress = function(project) { - var build_in_progress = {}; - - new Ajax.Request(project + '/currently_building.json', { - asynchronous: false, - onSuccess: function(transport) { - build_in_progress = transport.responseText.evalJSON(); - } + function addReportToProject(project, version) { + var name = project.name; + var resultJsonPath = name + "/" + version + ".json"; + jQuery.getJSON(resultJsonPath, function(data) { + project.reports.push(data); + trigger_render(); }); - return build_in_progress; } - var expand = function(element) { - element.siblings().invoke('show'); - element.remove(); + function sortReports(reports) { + return reports.sort(function(report_a, report_b) { + // Not sure why providing a 3-letter day trips up Date.js sometimes + a = Date.parse(report_a.timestamp.finish.substring(4)); + b = Date.parse(report_b.timestamp.finish.substring(4)); + + return Date.compare(a, b); + }); } - var render = function(template_name, json) { - var template = jsontemplate.Template(" \ - <h1>Projects</h1> \ - <div class='projects'> \ - {.section projects} \ - {.repeated section @} \ - <div class='project'> \ - <h2>{name}</h2> \ - {.section build_in_progress} \ - {.section timestamp} \ - <div>[build in progress &ndash; started at {start}]</div> \ - {.end} \ - {.end} \ - <div class='tests'> \ - {.section reports} \ - {.repeated section @} \ - <a class='test {.section test} {.section exit_status} error {.end} {.end} {.section update} {.section exit_status} error {.end} {.end}' href='#'>{timestamp.finish}</a> \ - {.end} \ - {.end} \ - </div> \ - <div class='results'> \ - {.section reports} \ - {.repeated section @} \ - <div class='result'> \ - <div> \ - <span class='timestamp'>{timestamp.finish}</span> \ - <span class='version'>{version.output}</span> \ - </div> \ - \ - <div class='output'> \ - {.section version} \ - {.section exit_status} \ - <div class='version'> \ - <pre class='error'>{error}</pre> \ - </div> \ - {.end} \ - {.end} \ - \ - <div class='update'> \ - <pre>{update.output}</pre> \ - {.section update} \ - {.section exit_status} \ - <pre class='error'>{update.error}</pre> \ - {.end} \ - {.end} \ - </div> \ - \ - <div class='test'> \ - <pre>{test.output}</pre> \ - {.section test} \ - {.section exit_status} \ - <pre class='error'>{test.error}</pre> \ - {.end} \ - {.end} \ - </div> \ - </div> \ - </div> \ - {.end} \ - {.or} \ - <p>No test reports found. Please run crazy_ivan.</p> \ - {.end} \ - </div> \ - </div> \ - {.end} \ - {.or} \ - <p>No projects found.</p> \ - {.end} \ - </div> \ - "); + var timeout = null; + function trigger_render() { + if (timeout) { clearTimeout(timeout) } + timeout = setTimeout(render, 50); + } + + var render = function() { + $('#projects').empty(); - var html = template.expand(json); - $("replace").update(html); - - - $$('.project .tests').each(function(t) { - t.down('.test').addClassName('latest') - }); - - // Reformat the test timestamps to be less enormous - $$('.project .tests .test').each(function(t) { - t.update(Date.parse(t.innerHTML).toString("HH:mm")); - t.observe('click', function(e) { - console.debug("hallo"); - $$('.results').invoke('show') - return false; + jQuery.each(json.projects, function(i, project) { + var name = project.name; + var domId = name.replace(/\./g, ""); // remove . from id name + + // create project holder div + $('#projects').append(tmpl("projectTemplate", {projectName: name, projectId: domId})); + + project.reports = sortReports(project.reports); + + jQuery.each(project.reports, function(i, report) { + var version = report.version.output; + var resultJsonPath = name + "/" + version + ".json"; + var domId = name.replace(/\./g, ""); // remove . from id name + + // Not sure why providing a 3-letter day trips up Date.js sometimes + report["shortTimeStamp"] = Date.parse(report.timestamp.finish.substring(4)).toString("HH:mm"); + report["projectDomId"] = domId; + + $("#" + domId + " .results").append(tmpl("resultTemplate", report)); + $("#" + domId + " .tests").prepend(tmpl("resultLinkTemplate", report)); + + // add failed/success indication to link - inlining in the template screws up + if (report.test.exit_status) { + $("#" + domId + '-' + version).addClass('error'); + } }); }); - - $$('.results').invoke('hide') } - </script> - </head> - <body onload="init();"> - <div id="replace"></div> - - <div class="footer"> - <a href="http://github.com/edward/crazy_ivan">Crazy Ivan on Github</a> - </div> + + // listen to clicking of test result links + $('#projects .project .tests a.test').live('click', function(e) { + $('.result:visible').hide(); + + if($(e.target).hasClass('active')) { + $('.test').removeClass('active'); + } else { + $('.test').removeClass('active'); + $('.result.' + e.target.id).show(); + $(e.target).addClass('active'); + } + }); + </script> </body> </html> \ No newline at end of file