From bb1a12c76b938e5b2e10335cbab93dad83e82b3e Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Wed, 15 Jan 2014 14:49:56 +0100 Subject: [PATCH] Finished first version of Cluster Overview using fake data. User now gets a prominent overview over his cluster and can decide if coordinators or databases are effected by failures --- .../frontend/css/clusterDashboardView.css | 68 +++- .../js/templates/clusterOverviewView.ejs | 41 +- .../frontend/js/views/clusterOverviewView.js | 37 +- .../specs/views/clusterOverviewViewSpec.js | 361 ++++++++++++++---- 4 files changed, 415 insertions(+), 92 deletions(-) diff --git a/js/apps/system/aardvark/frontend/css/clusterDashboardView.css b/js/apps/system/aardvark/frontend/css/clusterDashboardView.css index fb62f9d025..1de6983ca3 100644 --- a/js/apps/system/aardvark/frontend/css/clusterDashboardView.css +++ b/js/apps/system/aardvark/frontend/css/clusterDashboardView.css @@ -1,13 +1,75 @@ div.clusterColumn { - width: 18%; - padding-left: 1%; - padding-right: 1%; + padding-right: 5px; float: left; } +div.clusterColumnMax { + float: none; + min-height: 255px; +} + div.clusterColumn li { background: none; } h3.clusterColumnHeader { text-align: center; } + +div.clusterAmounts { + position: absolute; + left: 0px; + right: 0px; + bottom: 0px; +} + +span.cluster_icon_large { + font-size: 120px; +} + +span.cluster_icon_small { + font-size: 25px; +} + +div.tile { + width: 200px; + height: 200px; + position: absolute; + text-align: center; + font-weight: 700; + font-size: 20px; + cursor: pointer; +} + +div.tile-left { + right: 50%; + margin-right: 20px; +} + +div.tile-right { + left: 50%; + margin-left: 20px; +} + +.btn-success { + background: #8AA051; +} + +.btn-success:hover { + background: #788F3D; +} + +.btn-danger { + background-color: #DA4F49; +} + +.btn-danger:hover { + background-color: #BE342E; +} + +.btn-warning { + background-color: #FAA732; +} + +.btn-warning:hover { + background-color: #F89406; +} diff --git a/js/apps/system/aardvark/frontend/js/templates/clusterOverviewView.ejs b/js/apps/system/aardvark/frontend/js/templates/clusterOverviewView.ejs index 678377f867..633c9dc265 100644 --- a/js/apps/system/aardvark/frontend/js/templates/clusterOverviewView.ejs +++ b/js/apps/system/aardvark/frontend/js/templates/clusterOverviewView.ejs @@ -1,14 +1,43 @@

Overview

-
+<% var statusClass = function(s) { + switch (s) { + case "ok": + return "success"; + case "warning": + return "warning"; + case "critical": + return "danger"; + } + }; +%> +<% if(minify) { %> +
  • - +
  • - -
  • -
  • - +
+<% } else { %> +
+ Data Servers +
+
+ +
+ <%=dbservers.having %>/<%=dbservers.plan %> +
+
+
+ Coordinators +
+
+ +
+ <%=coordinators.having %>/<%=coordinators.plan %> +
+
+<% } %> diff --git a/js/apps/system/aardvark/frontend/js/views/clusterOverviewView.js b/js/apps/system/aardvark/frontend/js/views/clusterOverviewView.js index 63ebe13ef2..8df5652fec 100644 --- a/js/apps/system/aardvark/frontend/js/views/clusterOverviewView.js +++ b/js/apps/system/aardvark/frontend/js/views/clusterOverviewView.js @@ -11,35 +11,48 @@ template: templateEngine.createTemplate("clusterOverviewView.ejs"), events: { - "click #primary": "loadPrimaries", - "click #secondary": "loadSecondaries", + "click #dbserver": "loadDBServers", "click #coordinator": "loadCoordinators" }, initialize: function() { + this.fakeData = { + dbservers: { + plan: 3, + having: 3, + status: "warning" + }, + coordinators: { + plan: 3, + having: 2, + status: "critical" + } + }; + this.serverView = new window.ClusterServerView(); }, - loadPrimaries: function() { + loadDBServers: function() { this.serverView.render({ - type: "primary" - }); - }, - - loadSecondaries: function() { - this.serverView.render({ - type: "secondary" + type: "dbservers" }); + this.render(true); }, loadCoordinators: function() { this.serverView.render({ type: "coordinator" }); + this.render(true); }, - render: function(info){ - $(this.el).html(this.template.render({})); + render: function(minify){ + $(this.el).html(this.template.render({ + minify: minify, + dbservers: this.fakeData.dbservers, + coordinators: this.fakeData.coordinators + })); + $(this.el).toggleClass("clusterColumnMax", !minify); return this; } diff --git a/js/apps/system/aardvark/test/specs/views/clusterOverviewViewSpec.js b/js/apps/system/aardvark/test/specs/views/clusterOverviewViewSpec.js index 04393e52b2..d748a1228f 100644 --- a/js/apps/system/aardvark/test/specs/views/clusterOverviewViewSpec.js +++ b/js/apps/system/aardvark/test/specs/views/clusterOverviewViewSpec.js @@ -1,7 +1,7 @@ /*jslint indent: 2, nomen: true, maxlen: 100, white: true plusplus: true, browser: true*/ /*global describe, beforeEach, afterEach, it, */ /*global spyOn, expect*/ -/*global templateEngine, $*/ +/*global templateEngine, $, _*/ (function() { "use strict"; @@ -16,6 +16,33 @@ render: function(){} }; spyOn(window, "ClusterServerView").andReturn(serverView); + this.addMatchers({ + + toBeTag: function(name) { + var el = this.actual; + this.message = function() { + return "Expected " + el.tagName.toLowerCase() + " to be a " + name; + }; + return el.tagName.toLowerCase() === name; + }, + + toBeOfClass: function(name) { + var el = $(this.actual); + this.message = function() { + return "Expected \"" + el.attr("class") + "\" to contain " + name; + }; + return el.hasClass(name); + }, + + toNotHaveClass: function(name) { + var el = $(this.actual); + this.message = function() { + return "Expected \"" + el.attr("class") + "\" to not contain " + name; + }; + return !el.hasClass(name); + } + + }); }); afterEach(function() { @@ -33,100 +60,292 @@ describe("rendering", function() { + var checkUserActions = function() { + describe("user actions", function() { + var info; + + beforeEach(function() { + serverView.render.reset(); + view.render(); + spyOn(view, "render"); + }); + + it("should be able to navigate to db servers", function() { + info = { + type: "dbservers" + }; + $("#dbserver").click(); + expect(serverView.render).toHaveBeenCalledWith(info); + expect(view.render).toHaveBeenCalledWith(true); + }); + + it("should be able to navigate to primary servers", function() { + info = { + type: "coordinator" + }; + $("#coordinator").click(); + expect(serverView.render).toHaveBeenCalledWith(info); + expect(view.render).toHaveBeenCalledWith(true); + }); + + }); + }, + + checkShowStatus = function (btn, status) { + var classNames = { + ok: "btn-success", + warning: "btn-warning", + critical: "btn-danger" + }; + expect(btn).toBeOfClass(classNames[status]); + delete classNames[status]; + _.each(classNames, function(v) { + expect(btn).toNotHaveClass(v); + }); + }; + beforeEach(function() { spyOn(serverView, "render"); view = new window.ClusterOverviewView(); // Fake Data Injection to be removed view.fakeData = { - primaries: { + dbservers: { plan: 3, - having: 2, + having: 3, status: "warning" }, - secondaries: { - plan: 3, - having: 1, - status: "critical" - }, coordinators: { plan: 3, - having: 3, - status: "ok" + having: 2, + status: "critical" } }; }); - it("should not render the Server view", function() { - view.render(); - expect(serverView.render).not.toHaveBeenCalled(); + describe("minified version", function() { + + beforeEach(function() { + view.render(true); + }); + + it("should not render the Server view", function() { + expect(serverView.render).not.toHaveBeenCalled(); + }); + + it("should render in minified version", function() { + expect($(div).hasClass("clusterColumnMax")).toBeFalsy(); + }); + + describe("dbservers" , function() { + + var getButton = function() { + return document.getElementById("dbserver"); + }; + + it("should render the amounts", function() { + view.fakeData.dbservers.plan = 5; + view.fakeData.dbservers.having = 4; + view.render(true); + var btn = getButton(), + span = btn.firstChild, + txt = $(span).text(); + expect(btn).toBeDefined(); + expect(span).toBeDefined(); + expect(span).toBeOfClass("arangoicon"); + expect(span).toBeOfClass("icon_arangodb_database1"); + expect(span).toBeOfClass("cluster_icon_small"); + expect(txt.trim()).toEqual("4/5"); + }); + + it("should render the status ok", function() { + var status = "ok"; + view.fakeData.dbservers.status = status; + view.render(true); + checkShowStatus(getButton(), status); + }); + + it("should render the status warning", function() { + var status = "warning"; + view.fakeData.dbservers.status = status; + view.render(true); + checkShowStatus(getButton(), status); + }); + + it("should render the status critical", function() { + var status = "critical"; + view.fakeData.dbservers.status = status; + view.render(true); + checkShowStatus(getButton(), status); + }); + + }); + + describe("coordinators" , function() { + + var getButton = function() { + return document.getElementById("coordinator"); + }; + + it("should render the amounts", function() { + view.fakeData.coordinators.plan = 5; + view.fakeData.coordinators.having = 4; + view.render(true); + var btn = getButton(), + span = btn.firstChild, + txt = $(span).text(); + expect(btn).toBeDefined(); + expect(span).toBeDefined(); + expect(span).toBeOfClass("arangoicon"); + expect(span).toBeOfClass("icon_arangodb_compass"); + expect(span).toBeOfClass("cluster_icon_small"); + expect(txt.trim()).toEqual("4/5"); + }); + + it("should render the status ok", function() { + var status = "ok"; + view.fakeData.coordinators.status = status; + view.render(true); + checkShowStatus(getButton(), status); + }); + + it("should render the status warning", function() { + var status = "warning"; + view.fakeData.coordinators.status = status; + view.render(true); + checkShowStatus(getButton(), status); + }); + + it("should render the status critical", function() { + var status = "critical"; + view.fakeData.coordinators.status = status; + view.render(true); + checkShowStatus(getButton(), status); + }); + + }); + + checkUserActions(); + }); - it("should render the amounts and status of primaries", function() { - view.render(); - var btn = document.getElementById("primary"), - txt = $(btn).text(); - expect(btn).toBeDefined(); - expect(txt.trim()).toEqual("Primaries 2/3"); - expect($(btn).hasClass("btn-success")).toBeFalsy(); - expect($(btn).hasClass("btn-warning")).toBeTruthy(); - expect($(btn).hasClass("btn-danger")).toBeFalsy(); - }); + describe("maximised version", function() { - it("should render the amounts and status of secondaries", function() { - view.render(); - var btn = document.getElementById("secondary"), - txt = $(btn).text(); - expect(btn).toBeDefined(); - expect(txt.trim()).toEqual("Secondaries 1/3"); - expect($(btn).hasClass("btn-success")).toBeFalsy(); - expect($(btn).hasClass("btn-warning")).toBeFalsy(); - expect($(btn).hasClass("btn-danger")).toBeTruthy(); - }); + beforeEach(function() { + view.render(); + }); - it("should render the amounts and status of coordinators", function() { - view.render(); - var btn = document.getElementById("coordinator"), - txt = $(btn).text(); - expect(btn).toBeDefined(); - expect(txt.trim()).toEqual("Coordinators 3/3"); - expect($(btn).hasClass("btn-success")).toBeTruthy(); - expect($(btn).hasClass("btn-warning")).toBeFalsy(); - expect($(btn).hasClass("btn-danger")).toBeFalsy(); - }); + it("should not render the Server view", function() { + expect(serverView.render).not.toHaveBeenCalled(); + }); - }); + it("should increase the size of the column to maximum", function() { + expect($(div).hasClass("clusterColumnMax")).toBeTruthy(); + }); - describe("user actions", function() { - var info; + describe("dbservers" , function() { - beforeEach(function() { - spyOn(serverView, "render"); - view = new window.ClusterOverviewView(); - view.render(); - }); + var getTile = function() { + return document.getElementById("dbserver"); + }; - it("should be able to navigate to primary servers", function() { - info = { - type: "primary" - }; - $("#primary").click(); - expect(serverView.render).toHaveBeenCalledWith(info); - }); + it("should render the tile", function() { + view.fakeData.dbservers.plan = 5; + view.fakeData.dbservers.having = 4; + view.render(); + var tile = getTile(), + spans = $("> span", $(tile)), + header = spans[0], + icon = spans[1], + footer = $("> div", $(tile)), + htxt = $(header).text(), + ftxt = $(footer).text(); + expect(tile).toBeDefined(); + expect(tile).toBeOfClass("tile"); + expect(tile).toBeOfClass("tile-left"); + expect(icon).toBeDefined(); + expect(icon).toBeOfClass("arangoicon"); + expect(icon).toBeOfClass("icon_arangodb_database1"); + expect(icon).toBeOfClass("cluster_icon_large"); + expect(htxt.trim()).toEqual("Data Servers"); + expect(ftxt.trim()).toEqual("4/5"); + }); - it("should be able to navigate to primary servers", function() { - info = { - type: "secondary" - }; - $("#secondary").click(); - expect(serverView.render).toHaveBeenCalledWith(info); - }); + it("should render the status ok", function() { + var status = "ok"; + view.fakeData.dbservers.status = status; + view.render(); + checkShowStatus(getTile(), status); + }); + + it("should render the status warning", function() { + var status = "warning"; + view.fakeData.dbservers.status = status; + view.render(); + checkShowStatus(getTile(), status); + }); + + it("should render the status critical", function() { + var status = "critical"; + view.fakeData.dbservers.status = status; + view.render(); + checkShowStatus(getTile(), status); + }); + + }); + + describe("coordinators" , function() { + + var getTile = function() { + return document.getElementById("coordinator"); + }; + + it("should render the tile", function() { + view.fakeData.coordinators.plan = 5; + view.fakeData.coordinators.having = 4; + view.render(); + var tile = getTile(), + spans = $("> span", $(tile)), + header = spans[0], + icon = spans[1], + footer = $("> div", $(tile)), + htxt = $(header).text(), + ftxt = $(footer).text(); + expect(tile).toBeDefined(); + expect(tile).toBeOfClass("tile"); + expect(tile).toBeOfClass("tile-right"); + expect(icon).toBeDefined(); + expect(icon).toBeOfClass("arangoicon"); + expect(icon).toBeOfClass("icon_arangodb_compass"); + expect(icon).toBeOfClass("cluster_icon_large"); + expect(htxt.trim()).toEqual("Coordinators"); + expect(ftxt.trim()).toEqual("4/5"); + }); + + it("should render the status ok", function() { + var status = "ok"; + view.fakeData.coordinators.status = status; + view.render(); + checkShowStatus(getTile(), status); + }); + + it("should render the status warning", function() { + var status = "warning"; + view.fakeData.coordinators.status = status; + view.render(); + checkShowStatus(getTile(), status); + }); + + it("should render the status critical", function() { + var status = "critical"; + view.fakeData.coordinators.status = status; + view.render(); + checkShowStatus(getTile(), status); + }); + + }); + + checkUserActions(); - it("should be able to navigate to primary servers", function() { - info = { - type: "coordinator" - }; - $("#coordinator").click(); - expect(serverView.render).toHaveBeenCalledWith(info); }); });