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, "<").replace(/\>/g, ">") %></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 – 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