ui: more work on loading data for /services
This commit is contained in:
parent
a65ec76738
commit
bcdce24314
|
@ -29,11 +29,13 @@
|
|||
</div>
|
||||
|
||||
<div class="col-md-2 col-sm-3">
|
||||
<a class="btn btn-primary" href="#">Services</a>
|
||||
{{#link-to 'services' controllers.application.getDc class='btn btn-default'}}Services{{/link-to}}
|
||||
</div>
|
||||
|
||||
<div class="col-md-2 col-sm-3">
|
||||
<a class="btn btn-default" href="#">Nodes</a>
|
||||
{{#link-to 'nodes' controllers.application.getDc class='btn btn-default'}}Nodes{{/link-to}}
|
||||
</div>
|
||||
|
||||
<div class="col-md-2 col-sm-3">
|
||||
<a class="btn btn-default" href="#">Key/Value</a>
|
||||
</div>
|
||||
|
@ -55,29 +57,60 @@
|
|||
</script>
|
||||
|
||||
<script type="text/x-handlebars" id="services">
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-5">
|
||||
|
||||
{{#each service in services}}
|
||||
|
||||
{{#each item in model}}
|
||||
<div class="list-group-item">
|
||||
<div {{bind-attr class="item.hasFailingChecks:bg-orange:bg-green :list-bar"}}></div>
|
||||
<div {{bind-attr class="service.hasFailingChecks:bg-orange:bg-green :list-bar"}}></div>
|
||||
<h4 class="list-group-item-heading">
|
||||
<a href="#" class="subtle">{{item.Name}}</a>
|
||||
<small>{{item.Name}}</small>
|
||||
{{#link-to 'service' controllers.application.getDc service.Name class='subtle'}}{{service.Name}}{{/link-to}}
|
||||
<small>{{service.Name}}</small>
|
||||
<div class="heading-helper">
|
||||
<a class="subtle" href="#">{{item.checkMessage}}</a>
|
||||
<a class="subtle" href="#">{{service.checkMessage}}</a>
|
||||
</div>
|
||||
</h4>
|
||||
<ul class="list-inline">
|
||||
{{#each node in item.Nodes }}
|
||||
{{#each node in service.Nodes }}
|
||||
<li>{{#link-to 'node' controllers.application.getDc node class='subtle'}}{{node}}{{/link-to}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{{/each}}
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-6 col-md-offset-1">
|
||||
<div class="row">
|
||||
{{#if model}}
|
||||
<h2 class="no-margin">{{ model.1.ServiceName }}</h2>
|
||||
<hr>
|
||||
<h5>Nodes</h5>
|
||||
|
||||
{{#each node in model }}
|
||||
|
||||
<div {{bind-attr class=":panel node.hasFailingChecks:panel-warning:panel-success"}}>
|
||||
<div class="panel-bar"></div>
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
{{node.Node}}
|
||||
<small>{{node.Address}}</small>
|
||||
<span class="panel-note">{{node.checkMessage}}</span>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
{{#each check in node.Checks }}
|
||||
<h4>{{ check.Name }} <small>{{ check.CheckID }}</small> <span class="pull-right"><small>{{check.Status}}</small></h4>
|
||||
<hr>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ window.App = Ember.Application.create({
|
|||
App.Router.map(function() {
|
||||
this.route("index", { path: "/" });
|
||||
this.route("services", { path: "/:dc/services" });
|
||||
this.route("service", { path: "/:dc/services/:name" });
|
||||
this.route("nodes", { path: "/:dc/nodes" });
|
||||
this.route("node", { path: "/:dc/nodes/:name" });
|
||||
this.route("kv", { path: "/:dc/kv" });
|
||||
|
@ -36,13 +37,6 @@ App.ApplicationController = Ember.Controller.extend({
|
|||
}.property("getDc")
|
||||
});
|
||||
|
||||
//
|
||||
// path: /:dc/services
|
||||
//
|
||||
App.ServicesController = Ember.Controller.extend({
|
||||
needs: ['application']
|
||||
})
|
||||
|
||||
//
|
||||
// Superclass to be used by all of the main routes below. All routes
|
||||
// but the IndexRoute share the need to have a datacenter set.
|
||||
|
@ -140,12 +134,84 @@ App.Service = Ember.Object.extend({
|
|||
}.property('hasFailingChecks')
|
||||
});
|
||||
|
||||
//
|
||||
// A Consul Node
|
||||
//
|
||||
App.Node = Ember.Object.extend({
|
||||
//
|
||||
// The number of failing checks within the service.
|
||||
//
|
||||
failingChecks: function() {
|
||||
return this.get('Checks').filterBy('Status', 'critical').get('length');
|
||||
}.property('failingChecks'),
|
||||
|
||||
//
|
||||
// The number of passing checks within the service.
|
||||
//
|
||||
passingChecks: function() {
|
||||
return this.get('Checks').filterBy('Status', 'passing').get('length');
|
||||
}.property('passingChecks'),
|
||||
|
||||
//
|
||||
// The formatted message returned for the user which represents the
|
||||
// number of checks failing or passing. Returns `1 passing` or `2 failing`
|
||||
//
|
||||
checkMessage: function() {
|
||||
if (this.get('hasFailingChecks') === false) {
|
||||
return this.get('passingChecks') + ' passing';
|
||||
} else {
|
||||
return this.get('failingChecks') + ' failing';
|
||||
}
|
||||
}.property('checkMessage'),
|
||||
|
||||
//
|
||||
// Boolean of whether or not there are failing checks in the service.
|
||||
// This is used to set color backgrounds and so on.
|
||||
//
|
||||
hasFailingChecks: function() {
|
||||
return (this.get('failingChecks') > 0);
|
||||
}.property('hasFailingChecks')
|
||||
});
|
||||
|
||||
//
|
||||
// Display all the services, allow to drill down into the specific services.
|
||||
//
|
||||
App.ServicesRoute = App.BaseRoute.extend({
|
||||
model: function() {
|
||||
return [App.Service.create(window.fixtures.services[0]), App.Service.create(window.fixtures.services[1])];
|
||||
//
|
||||
// Set the services as the routes default model to be called in
|
||||
// the template as {{model}}
|
||||
//
|
||||
setupController: function(controller, model) {
|
||||
//
|
||||
// Since we have 2 column layout, we need to also display the
|
||||
// list of services on the left. Hence setting the attribute
|
||||
// {{services}} on the controller.
|
||||
//
|
||||
controller.set('services', [App.Service.create(window.fixtures.services[0]), App.Service.create(window.fixtures.services[1])]);
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Display an individual service, as well as the global services in the left
|
||||
// column.
|
||||
//
|
||||
App.ServiceRoute = App.BaseRoute.extend({
|
||||
//
|
||||
// Set the model on the route. We look up the specific service
|
||||
// by it's identifier passed via the route
|
||||
//
|
||||
model: function(params) {
|
||||
return [App.Node.create(window.fixtures.services_full[params.name][0]), App.Node.create(window.fixtures.services_full[params.name][1])];
|
||||
},
|
||||
|
||||
setupController: function(controller, model) {
|
||||
controller.set('content', model);
|
||||
//
|
||||
// Since we have 2 column layout, we need to also display the
|
||||
// list of services on the left. Hence setting the attribute
|
||||
// {{services}} on the controller.
|
||||
//
|
||||
controller.set('services', [App.Service.create(window.fixtures.services[0]), App.Service.create(window.fixtures.services[1])]);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -153,6 +219,33 @@ App.ServicesRoute = App.BaseRoute.extend({
|
|||
// Services
|
||||
//
|
||||
App.ServicesView = Ember.View.extend({
|
||||
templateName: 'services',
|
||||
layoutName: 'default_layout'
|
||||
})
|
||||
|
||||
//
|
||||
// Services
|
||||
//
|
||||
App.ServiceView = Ember.View.extend({
|
||||
templateName: 'services',
|
||||
layoutName: 'default_layout'
|
||||
})
|
||||
|
||||
//
|
||||
// path: /:dc/services
|
||||
//
|
||||
App.ServicesController = Ember.Controller.extend({
|
||||
needs: ['application']
|
||||
})
|
||||
|
||||
//
|
||||
// path: /:dc/services/:name
|
||||
//
|
||||
App.ServiceController = Ember.Controller.extend({
|
||||
//
|
||||
// We use the same template as we do for the services
|
||||
// array and have a simple conditional to display the nested
|
||||
// individual service resource.
|
||||
//
|
||||
needs: ['application']
|
||||
})
|
||||
|
|
|
@ -27,8 +27,7 @@ fixtures.services = [
|
|||
],
|
||||
"Nodes": [
|
||||
"node-10-0-1-109",
|
||||
"node-10-0-1-102",
|
||||
"node-10-0-1-103"
|
||||
"node-10-0-3-84"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -48,13 +47,114 @@ fixtures.services = [
|
|||
}
|
||||
],
|
||||
"Nodes": [
|
||||
"node-10-0-1-109",
|
||||
"node-10-0-1-102",
|
||||
"node-10-0-1-103"
|
||||
"node-10-0-1-103",
|
||||
"node-10-0-1-104"
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
// This is both of the fixture services full response. We
|
||||
// would just expect one of these, inside of the top level
|
||||
// key. We require that key just for the fixture lookup.
|
||||
fixtures.services_full = {
|
||||
"vagrant-cloud-http": [
|
||||
// A node
|
||||
{
|
||||
"ServicePort": 80,
|
||||
"ServiceTags": null,
|
||||
"ServiceName": "vagrant-cloud-http",
|
||||
"ServiceID": "vagrant-cloud-http",
|
||||
"Address": "10.0.1.109",
|
||||
"Node": "node-10-0-1-109",
|
||||
"Checks": [
|
||||
{
|
||||
"ServiceName": "",
|
||||
"ServiceID": "",
|
||||
"Notes": "",
|
||||
"Status": "critical",
|
||||
"Name": "Serf Health Status",
|
||||
"CheckID": "serfHealth",
|
||||
"Node": "node-10-0-3-83"
|
||||
}
|
||||
]
|
||||
},
|
||||
// A node
|
||||
{
|
||||
"ServicePort": 80,
|
||||
"ServiceTags": null,
|
||||
"ServiceName": "vagrant-cloud-http",
|
||||
"ServiceID": "vagrant-cloud-http",
|
||||
"Address": "10.0.3.83",
|
||||
"Node": "node-10-0-3-84",
|
||||
"Checks": [
|
||||
{
|
||||
"ServiceName": "",
|
||||
"ServiceID": "",
|
||||
"Notes": "",
|
||||
"Status": "passing",
|
||||
"Name": "Serf Health Status",
|
||||
"CheckID": "serfHealth",
|
||||
"Node": "node-10-0-3-84"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"vagrant-share-mux": [
|
||||
// A node
|
||||
{
|
||||
"ServicePort": 80,
|
||||
"ServiceTags": null,
|
||||
"ServiceName": "vagrant-share-mux",
|
||||
"ServiceID": "vagrant-share-mux",
|
||||
"Address": "10.0.1.104",
|
||||
"Node": "node-10-0-1-104",
|
||||
"Checks": [
|
||||
{
|
||||
"ServiceName": "vagrant-share-mux",
|
||||
"ServiceID": "vagrant-share-mux",
|
||||
"Notes": "",
|
||||
"Output": "200 ok",
|
||||
"Status": "passing",
|
||||
"Name": "Foo Heathly",
|
||||
"CheckID": "fooHealth",
|
||||
"Node": "node-10-0-1-104"
|
||||
}
|
||||
]
|
||||
},
|
||||
// A node
|
||||
{
|
||||
"ServicePort": 80,
|
||||
"ServiceTags": null,
|
||||
"ServiceName": "vagrant-share-mux",
|
||||
"ServiceID": "vagrant-share-mux",
|
||||
"Address": "10.0.1.103",
|
||||
"Node": "node-10-0-1-103",
|
||||
"Checks": [
|
||||
{
|
||||
"ServiceName": "",
|
||||
"ServiceID": "",
|
||||
"Notes": "",
|
||||
"Output": "foobar baz",
|
||||
"Status": "passing",
|
||||
"Name": "Baz Status",
|
||||
"CheckID": "bazHealth",
|
||||
"Node": "node-10-0-1-103"
|
||||
},
|
||||
{
|
||||
"ServiceName": "",
|
||||
"ServiceID": "",
|
||||
"Notes": "",
|
||||
"Output": "foobar baz",
|
||||
"Status": "passing",
|
||||
"Name": "Serf Health Status",
|
||||
"CheckID": "serfHealth",
|
||||
"Node": "node-10-0-1-103"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
fixtures.dcs = ['nyc1', 'sf1', 'sg1']
|
||||
|
||||
localStorage.setItem("current_dc", fixtures.dcs[0]);
|
||||
|
|
|
@ -13,7 +13,12 @@
|
|||
.btn-default {
|
||||
}
|
||||
|
||||
&.btn-primary {
|
||||
&.active {
|
||||
box-shadow: none;
|
||||
-webkit-box-shadow: none;
|
||||
}
|
||||
|
||||
&.btn-primary, &.active {
|
||||
color: $purple;
|
||||
background-color: transparent;
|
||||
border: 2px solid $purple;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
.topbar {
|
||||
padding: 30px;
|
||||
margin-bottom: 20px;
|
||||
min-height: 100px;
|
||||
border-bottom: 1px #eee solid;
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
}
|
||||
|
||||
&.panel-link:hover {
|
||||
cursor: pointer;
|
||||
background-color: lighten($gray-background, 8%);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,26 @@
|
|||
@import "buttons";
|
||||
@import "lists";
|
||||
|
||||
@media (min-width: 768px) { // + 18
|
||||
.container {
|
||||
width: 750px;
|
||||
}
|
||||
}
|
||||
@media (min-width: 992px) { // + 22
|
||||
.container {
|
||||
width: 970px;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1200px) { // + 30
|
||||
.container {
|
||||
width: 1400px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.no-margin {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.vertical-center {
|
||||
margin-top: 200px;
|
||||
|
@ -17,6 +37,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
.bordered {
|
||||
border-left: 2px solid $gray-background;
|
||||
}
|
||||
|
||||
|
||||
.bg-purple {
|
||||
background-color: $purple;
|
||||
|
|
Loading…
Reference in a new issue