1. Federico Silva Armas
  2. ccnet-dashboard

Commits

Federico Silva Armas  committed 2424484

Move files to src directory in preparation for build script.

  • Participants
  • Parent commits c7338a1
  • Branches master

Comments (0)

Files changed (10)

File ajax-loader.gif

  • Ignore whitespace
Removed
Old image

File ccnet-dashboard.sln

View file
  • Ignore whitespace
 # Visual Studio 2012
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{955FA299-60FA-4D51-B540-95B9EC22E269}"
 	ProjectSection(SolutionItems) = preProject
-		dashboard.css = dashboard.css
-		dashboard.html = dashboard.html
-		dashboard.js = dashboard.js
+		src\dashboard.css = src\dashboard.css
+		src\dashboard.html = src\dashboard.html
+		src\dashboard.js = src\dashboard.js
 	EndProjectSection
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{004168C9-4B5E-439A-9976-5F619F546820}"

File dashboard.css

  • Ignore whitespace
-body {
-    background-color: #262526;
-}
-
-ul.ccnet-project-list {
-    list-style: none;
-    padding-left: 0;
-    width: 80%;
-    margin-left: auto;
-    margin-right: auto;
-}
-
-.ccnet-project {
-    border: 1px solid black;
-    background-color: green;
-    height: 150px;
-    border-radius: 15px;
-    margin: 30px;
-    padding: 15px;
-}
-
-.ccnet-project-success {
-    box-shadow: inset 0 0 20px #2A732D, inset 0 0 20px #2A732D, inset 0 0 20px #2A732D;
-    background-color: #4AB53E;
-}
-
-.ccnet-project-building {
-    box-shadow: inset 0 0 20px #7A8707, inset 0 0 20px #7A8707, inset 0 0 20px #7A8707;
-    background-color: #D6D140;
-    background-repeat: no-repeat;
-    background-position: center;
-    background-image: url('data:image/gif;base64,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');
-}
-
-.ccnet-project-fail {
-    box-shadow: inset 0 0 20px #800612, inset 0 0 20px #800612, inset 0 0 20px #800612;
-    background-color: #ED3E49;
-}
-
-.ccnet-project-stopped {
-    box-shadow: inset 0 0 20px #878486, inset 0 0 20px #878486, inset 0 0 20px #878486;
-    background-color: #C4C0C2;
-}
-
-.ccnet-project-name {
-    font-family: sans-serif;
-    font-size: 30px;
-}
-
-.ccnet-project-lastBuildDate {
-    position: relative;
-    top: 95px;
-    white-space: nowrap;
-    overflow: hidden;
-}
-
-@media all and (max-width: 999px) {
-    ul.ccnet-project-list li {
-        width: 100%;
-    }
-
-    ul.ccnet-project-list li > div {
-        margin: 30px;
-    }
-}
-
-@media all and (min-width: 1000px) {
-    ul.ccnet-project-list li {
-        float: left;
-        width: 50%;
-    }
-
-    ul.ccnet-project-list li > div {
-        margin: 20px 20px;
-    }
-}

File dashboard.html

  • Ignore whitespace
-<!DOCTYPE html>
-
-<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
-<head>
-    <meta charset="utf-8" />
-    <title></title>
-    <link rel="stylesheet" type="text/css" href="dashboard.css" />
-</head>
-<body>
-    <div id="dashboardContainer"></div>
-
-    <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.3.min.js"></script>
-    <script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.1.0.js"></script>
-    <script>
-        window.jQuery || document.write('<script src="lib/jquery-1.8.3.min.js")><\/script>');
-        window.ko || document.write('<script src="lib/knockout-2.2.0.js")><\/script>');
-    </script>
-
-    <script type="text/javascript" src="lib/jquery.xml2json.js"></script>
-    <script type="text/javascript" src="dashboard.js"></script>
-    <script>
-        var dashboard;
-        $(function() {
-            dashboard = new Farmas.Dashboard({
-                selector: "#dashboardContainer",
-                server: new Farmas.TestServer(),
-                enableAnimation: true
-            });
-
-            window.setInterval(function() {
-                dashboard.update();
-            }, 5000);
-        });
-    </script>
-</body>
-</html>

File dashboard.js

  • Ignore whitespace
-(function(global, $, ko, undefined) {
-    var dashboardTemplate =
-        "<ul class='ccnet-project-list' data-bind='foreach: projects'>" +
-            "<li data-bind='fadeWhileUpdate: isUpdating'>" +
-                "<div class='ccnet-project' data-bind='css: { " +
-                    "\"ccnet-project-success\": status() === 1, " +
-                    "\"ccnet-project-building\": status() === 2, " +
-                    "\"ccnet-project-fail\": status() === 3, " +
-                    "\"ccnet-project-stopped\": status() === 4 " +
-               "}'>" +
-                    "<div class='ccnet-project-name' data-bind='text: projectName'></div>" +
-                    "<div class='ccnet-project-lastBuildDate' data-bind='text: lastBuildDate'></div>" +
-                "</div>" +
-            "</li>"+
-        "</ul>";
-
-    function Dashboard(options) {
-        var dashboard = new DashboardViewModel(),
-            projectsRequestOptions = buildProjectsRequest(),
-            settings = $.extend({
-                selector: "#dashboardContainer",
-                enableAnimation: false,
-                server: new Server()
-            }, options);
-        
-        function init() {
-            var $container = $(settings.selector);
-
-            dashboard.isAnimationEnabled = settings.enableAnimation;
-
-            settings.server.makeRequest(projectsRequestOptions).done(function(data) {
-                $.each(data.projects, function(index, project) {
-                    dashboard.projects.push(new ProjectViewModel(dashboard, project));
-                });
-            });
-
-            $container.html(dashboardTemplate);
-            ko.applyBindings(dashboard, $container[0]);
-        }
-
-        function buildProjectsRequest() {
-            return {
-                url: "server/feanor/RawXmlMessage.aspx",
-                dataType: "xml",
-                type: "POST",
-                data: "action=GetProjectStatus&message=" +
-                    "%3cserverMessage+" +
-                        "xmlns%3axsi%3d%22http%3a%2f%2fwww.w3.org%2f2001%2fXMLSchema-instance%22+" +
-                        "xmlns%3axsd%3d%22http%3a%2f%2fwww.w3.org%2f2001%2fXMLSchema%22+" +
-                        "timestamp%3d%22" + global.Farmas.getCurrentDate() + "%22+" +
-                        "identifier%3d%22ccnet-dashboard%22+" +
-                        "server%3d%22" + global.Farmas.getHostName() + "%22+" +
-                        "source%3d%22CCNET-DASHBOARD%22+" +
-                   "%2f%3e"
-            };
-        }
-
-        function findProject(projectName){
-            var matches = $.grep(dashboard.projects(), function(project) { return project.projectName === projectName; });
-
-            return (matches.length >= 0) ? matches[0] : null;
-        }
-
-        function updateProject(localProject, remoteProject) {
-            localProject.isAnimationEnabled = dashboard.isAnimationEnabled
-                 && (localProject.activity() !== remoteProject.activity.type
-                     || localProject.buildStatus() !== remoteProject.buildStatus);
-
-            localProject.beginUpdate(
-                function() {
-                    this.buildStatus(remoteProject.buildStatus);
-                    this.lastBuildDate(remoteProject.lastBuildDate);
-                    this.projectStatus(remoteProject.status);
-                    if (remoteProject.activity) {
-                        this.activity(remoteProject.activity.type);
-                    }
-                });
-        }
-
-        this.update = function() {
-            settings.server.makeRequest(projectsRequestOptions).done(function(data) {
-                $.each(data.projects, function(index, remoteProject) {
-                    var localProject = findProject(remoteProject.name);
-
-                    if (localProject) {
-                        updateProject(localProject, remoteProject);
-                    }
-                });
-            });
-        }
-
-        init();
-    }
-
-    function DashboardViewModel() {
-        this.projects = ko.observableArray();
-        this.isAnimationEnabled = false;
-    }
-
-    function ProjectViewModel(dashboard, project) {
-        var buildingActivity = "Building",
-            stoppedProjectStatus = "Stopped",
-            successBuildStatus = "Success";
-
-        this.projectName = project.name;
-        this.serverName = project.serverName;
-        this.description = project.description;
-        this.projectStatus = ko.observable(project.status);
-        this.buildStatus = ko.observable(project.buildStatus);
-        this.lastBuildDate = ko.observable(project.lastBuildDate);
-        this.activity = ko.observable((project.activity) ? project.activity.type : "");
-
-        this.isAnimationEnabled = dashboard.isAnimationEnabled;
-        this.isUpdating = ko.observable(false);
-        this.endUpdate = null;
-        this.beginUpdate = function(endUpdateCallback) {
-            this.endUpdate = function(){
-                endUpdateCallback.call(this);
-                this.isUpdating(false); 
-            };
-
-            if (this.isAnimationEnabled) {
-                this.isUpdating(true);
-            }
-            else {
-                this.endUpdate();
-            }
-        };
-
-        this.status = ko.computed(function() {
-            /* Will return one of 3 status codes:
-                - 1: Success
-                - 2: Building
-                - 3: Error
-                - 4: Stopped
-            */
-
-            if (this.projectStatus() === stoppedProjectStatus) {
-                return 4;
-            }
-            else if (this.activity() === buildingActivity) {
-                return 2;
-            }
-            else if (this.buildStatus() === successBuildStatus) {
-                return 1;
-            }
-            else {
-                return 3;
-            }
-        }, this);
-    }
-
-    function Server() {
-        this.makeRequest = function (requestOptions) {
-            return $.ajax(requestOptions).pipe(function(xml) {
-                var json = $.xml2json(xml);
-                return {
-                    projects: $.isArray(json.project) ? json.project : [json.project]
-                };
-            });
-        };
-    }
-
-    function TestServer(makeRequestFunc) {
-
-        function random(num) {
-            return Math.floor((Math.random() * num) + 1);
-        }
-
-        function generateProject(suffix) {
-            return {
-                name: "Project " + suffix,
-                buildStatus: random(2) === 1 ? "Success" : "Fail",
-                status: random(3) === 1 ? "Stopped" : "Running",
-                lastBuildDate: new Date(),
-                activity: {
-                    type: random(2) === 1 ? "Sleeping" : "Building",
-                }
-            };
-        };
-
-        function testMakeRequest(requestOptions) {
-            var deferred = $.Deferred();
-            deferred.resolve({
-                projects: [
-                    generateProject("One"),
-                    generateProject("Two"),
-                    generateProject("Three"),
-                    generateProject("Four"),
-                    generateProject("Five"),
-                    generateProject("Six"),
-                    generateProject("Seven"),
-                    generateProject("Eight")
-               ]
-            });
-            return deferred.promise();
-        };
-
-        this.makeRequest = makeRequestFunc || testMakeRequest;
-    }
-
-    ko.bindingHandlers.fadeWhileUpdate = {
-        update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
-            var isUpdating = ko.utils.unwrapObservable(valueAccessor());
-
-            if (isUpdating) {
-                $(element).fadeOut("slow", viewModel.endUpdate.bind(viewModel));
-            }
-            else {
-                $(element).fadeIn();
-            }
-        }
-    }
-
-    global.Farmas = {
-        Dashboard: Dashboard,
-        TestServer: TestServer,
-        getCurrentDate: function() {
-            return new Date().toISOString();
-        },
-        getHostName: function() {
-            return window.location.hostname;
-        }
-    }
-})(this, jQuery, ko);

File src/ajax-loader.gif

  • Ignore whitespace
Added
New image

File src/dashboard.css

View file
  • Ignore whitespace
+body {
+    background-color: #262526;
+}
+
+ul.ccnet-project-list {
+    list-style: none;
+    padding-left: 0;
+    width: 80%;
+    margin-left: auto;
+    margin-right: auto;
+}
+
+.ccnet-project {
+    border: 1px solid black;
+    background-color: green;
+    height: 150px;
+    border-radius: 15px;
+    margin: 30px;
+    padding: 15px;
+}
+
+.ccnet-project-success {
+    box-shadow: inset 0 0 20px #2A732D, inset 0 0 20px #2A732D, inset 0 0 20px #2A732D;
+    background-color: #4AB53E;
+}
+
+.ccnet-project-building {
+    box-shadow: inset 0 0 20px #7A8707, inset 0 0 20px #7A8707, inset 0 0 20px #7A8707;
+    background-color: #D6D140;
+    background-repeat: no-repeat;
+    background-position: center;
+    background-image: url('data:image/gif;base64,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');
+}
+
+.ccnet-project-fail {
+    box-shadow: inset 0 0 20px #800612, inset 0 0 20px #800612, inset 0 0 20px #800612;
+    background-color: #ED3E49;
+}
+
+.ccnet-project-stopped {
+    box-shadow: inset 0 0 20px #878486, inset 0 0 20px #878486, inset 0 0 20px #878486;
+    background-color: #C4C0C2;
+}
+
+.ccnet-project-name {
+    font-family: sans-serif;
+    font-size: 30px;
+}
+
+.ccnet-project-lastBuildDate {
+    position: relative;
+    top: 95px;
+    white-space: nowrap;
+    overflow: hidden;
+}
+
+@media all and (max-width: 999px) {
+    ul.ccnet-project-list li {
+        width: 100%;
+    }
+
+    ul.ccnet-project-list li > div {
+        margin: 30px;
+    }
+}
+
+@media all and (min-width: 1000px) {
+    ul.ccnet-project-list li {
+        float: left;
+        width: 50%;
+    }
+
+    ul.ccnet-project-list li > div {
+        margin: 20px 20px;
+    }
+}

File src/dashboard.html

View file
  • Ignore whitespace
+<!DOCTYPE html>
+
+<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
+<head>
+    <meta charset="utf-8" />
+    <title></title>
+    <link rel="stylesheet" type="text/css" href="dashboard.css" />
+</head>
+<body>
+    <div id="dashboardContainer"></div>
+
+    <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.3.min.js"></script>
+    <script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.1.0.js"></script>
+    <script>
+        window.jQuery || document.write('<script src="../lib/jquery-1.8.3.min.js")><\/script>');
+        window.ko || document.write('<script src="../lib/knockout-2.2.0.js")><\/script>');
+    </script>
+
+    <script type="text/javascript" src="../lib/jquery.xml2json.js"></script>
+    <script type="text/javascript" src="dashboard.js"></script>
+    <script>
+        var dashboard;
+        $(function() {
+            dashboard = new Farmas.Dashboard({
+                selector: "#dashboardContainer",
+                server: new Farmas.TestServer(),
+                enableAnimation: true
+            });
+
+            window.setInterval(function() {
+                dashboard.update();
+            }, 5000);
+        });
+    </script>
+</body>
+</html>

File src/dashboard.js

View file
  • Ignore whitespace
+(function(global, $, ko, undefined) {
+    var dashboardTemplate =
+        "<ul class='ccnet-project-list' data-bind='foreach: projects'>" +
+            "<li data-bind='fadeWhileUpdate: isUpdating'>" +
+                "<div class='ccnet-project' data-bind='css: { " +
+                    "\"ccnet-project-success\": status() === 1, " +
+                    "\"ccnet-project-building\": status() === 2, " +
+                    "\"ccnet-project-fail\": status() === 3, " +
+                    "\"ccnet-project-stopped\": status() === 4 " +
+               "}'>" +
+                    "<div class='ccnet-project-name' data-bind='text: projectName'></div>" +
+                    "<div class='ccnet-project-lastBuildDate' data-bind='text: lastBuildDate'></div>" +
+                "</div>" +
+            "</li>"+
+        "</ul>";
+
+    function Dashboard(options) {
+        var dashboard = new DashboardViewModel(),
+            projectsRequestOptions = buildProjectsRequest(),
+            settings = $.extend({
+                selector: "#dashboardContainer",
+                enableAnimation: false,
+                server: new Server()
+            }, options);
+        
+        function init() {
+            var $container = $(settings.selector);
+
+            dashboard.isAnimationEnabled = settings.enableAnimation;
+
+            settings.server.makeRequest(projectsRequestOptions).done(function(data) {
+                $.each(data.projects, function(index, project) {
+                    dashboard.projects.push(new ProjectViewModel(dashboard, project));
+                });
+            });
+
+            $container.html(dashboardTemplate);
+            ko.applyBindings(dashboard, $container[0]);
+        }
+
+        function buildProjectsRequest() {
+            return {
+                url: "server/feanor/RawXmlMessage.aspx",
+                dataType: "xml",
+                type: "POST",
+                data: "action=GetProjectStatus&message=" +
+                    "%3cserverMessage+" +
+                        "xmlns%3axsi%3d%22http%3a%2f%2fwww.w3.org%2f2001%2fXMLSchema-instance%22+" +
+                        "xmlns%3axsd%3d%22http%3a%2f%2fwww.w3.org%2f2001%2fXMLSchema%22+" +
+                        "timestamp%3d%22" + global.Farmas.getCurrentDate() + "%22+" +
+                        "identifier%3d%22ccnet-dashboard%22+" +
+                        "server%3d%22" + global.Farmas.getHostName() + "%22+" +
+                        "source%3d%22CCNET-DASHBOARD%22+" +
+                   "%2f%3e"
+            };
+        }
+
+        function findProject(projectName){
+            var matches = $.grep(dashboard.projects(), function(project) { return project.projectName === projectName; });
+
+            return (matches.length >= 0) ? matches[0] : null;
+        }
+
+        function updateProject(localProject, remoteProject) {
+            localProject.isAnimationEnabled = dashboard.isAnimationEnabled
+                 && (localProject.activity() !== remoteProject.activity.type
+                     || localProject.buildStatus() !== remoteProject.buildStatus);
+
+            localProject.beginUpdate(
+                function() {
+                    this.buildStatus(remoteProject.buildStatus);
+                    this.lastBuildDate(remoteProject.lastBuildDate);
+                    this.projectStatus(remoteProject.status);
+                    if (remoteProject.activity) {
+                        this.activity(remoteProject.activity.type);
+                    }
+                });
+        }
+
+        this.update = function() {
+            settings.server.makeRequest(projectsRequestOptions).done(function(data) {
+                $.each(data.projects, function(index, remoteProject) {
+                    var localProject = findProject(remoteProject.name);
+
+                    if (localProject) {
+                        updateProject(localProject, remoteProject);
+                    }
+                });
+            });
+        }
+
+        init();
+    }
+
+    function DashboardViewModel() {
+        this.projects = ko.observableArray();
+        this.isAnimationEnabled = false;
+    }
+
+    function ProjectViewModel(dashboard, project) {
+        var buildingActivity = "Building",
+            stoppedProjectStatus = "Stopped",
+            successBuildStatus = "Success";
+
+        this.projectName = project.name;
+        this.serverName = project.serverName;
+        this.description = project.description;
+        this.projectStatus = ko.observable(project.status);
+        this.buildStatus = ko.observable(project.buildStatus);
+        this.lastBuildDate = ko.observable(project.lastBuildDate);
+        this.activity = ko.observable((project.activity) ? project.activity.type : "");
+
+        this.isAnimationEnabled = dashboard.isAnimationEnabled;
+        this.isUpdating = ko.observable(false);
+        this.endUpdate = null;
+        this.beginUpdate = function(endUpdateCallback) {
+            this.endUpdate = function(){
+                endUpdateCallback.call(this);
+                this.isUpdating(false); 
+            };
+
+            if (this.isAnimationEnabled) {
+                this.isUpdating(true);
+            }
+            else {
+                this.endUpdate();
+            }
+        };
+
+        this.status = ko.computed(function() {
+            /* Will return one of 3 status codes:
+                - 1: Success
+                - 2: Building
+                - 3: Error
+                - 4: Stopped
+            */
+
+            if (this.projectStatus() === stoppedProjectStatus) {
+                return 4;
+            }
+            else if (this.activity() === buildingActivity) {
+                return 2;
+            }
+            else if (this.buildStatus() === successBuildStatus) {
+                return 1;
+            }
+            else {
+                return 3;
+            }
+        }, this);
+    }
+
+    function Server() {
+        this.makeRequest = function (requestOptions) {
+            return $.ajax(requestOptions).pipe(function(xml) {
+                var json = $.xml2json(xml);
+                return {
+                    projects: $.isArray(json.project) ? json.project : [json.project]
+                };
+            });
+        };
+    }
+
+    function TestServer(makeRequestFunc) {
+
+        function random(num) {
+            return Math.floor((Math.random() * num) + 1);
+        }
+
+        function generateProject(suffix) {
+            return {
+                name: "Project " + suffix,
+                buildStatus: random(2) === 1 ? "Success" : "Fail",
+                status: random(3) === 1 ? "Stopped" : "Running",
+                lastBuildDate: new Date(),
+                activity: {
+                    type: random(2) === 1 ? "Sleeping" : "Building",
+                }
+            };
+        };
+
+        function testMakeRequest(requestOptions) {
+            var deferred = $.Deferred();
+            deferred.resolve({
+                projects: [
+                    generateProject("One"),
+                    generateProject("Two"),
+                    generateProject("Three"),
+                    generateProject("Four"),
+                    generateProject("Five"),
+                    generateProject("Six"),
+                    generateProject("Seven"),
+                    generateProject("Eight")
+               ]
+            });
+            return deferred.promise();
+        };
+
+        this.makeRequest = makeRequestFunc || testMakeRequest;
+    }
+
+    ko.bindingHandlers.fadeWhileUpdate = {
+        update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
+            var isUpdating = ko.utils.unwrapObservable(valueAccessor());
+
+            if (isUpdating) {
+                $(element).fadeOut("slow", viewModel.endUpdate.bind(viewModel));
+            }
+            else {
+                $(element).fadeIn();
+            }
+        }
+    }
+
+    global.Farmas = {
+        Dashboard: Dashboard,
+        TestServer: TestServer,
+        getCurrentDate: function() {
+            return new Date().toISOString();
+        },
+        getHostName: function() {
+            return window.location.hostname;
+        }
+    }
+})(this, jQuery, ko);

File test/SpecRunner.html

View file
  • Ignore whitespace
   <script type="text/javascript" src="../lib/jasmine-jquery-1.3.1.js"></script>
 
   <!-- include source files here... -->
-  <script type="text/javascript" src="../dashboard.js"></script>
+  <script type="text/javascript" src="../src/dashboard.js"></script>
 
   <!-- include spec files here... -->
   <script type="text/javascript" src="dashboardSpec.js"></script>