yellow team mailing list archive
-
yellow team
-
Mailing list archive
-
Message #01157
[Merge] lp:~tveronezi/juju-gui/service-header into lp:juju-gui
Thiago Veronezi has proposed merging lp:~tveronezi/juju-gui/service-header into lp:juju-gui.
Requested reviews:
Juju GUI Hackers (juju-gui)
For more details, see:
https://code.launchpad.net/~tveronezi/juju-gui/service-header/+merge/130243
Service view header should match design doc
The service view header should match visual design document.
(https://docs.google.com/a/canonical.com/file/d/0B6l8lFdCRvtqS19SYWQ2MzU3cFU/edit)
--
https://code.launchpad.net/~tveronezi/juju-gui/service-header/+merge/130243
Your team Juju GUI Hackers is requested to review the proposed merge of lp:~tveronezi/juju-gui/service-header into lp:juju-gui.
=== added file 'app/assets/images/slider_off.png'
Binary files app/assets/images/slider_off.png 1970-01-01 00:00:00 +0000 and app/assets/images/slider_off.png 2012-10-17 22:10:34 +0000 differ
=== added file 'app/assets/images/slider_on.png'
Binary files app/assets/images/slider_on.png 1970-01-01 00:00:00 +0000 and app/assets/images/slider_on.png 2012-10-17 22:10:34 +0000 differ
=== added file 'app/assets/images/tab_div.png'
Binary files app/assets/images/tab_div.png 1970-01-01 00:00:00 +0000 and app/assets/images/tab_div.png 2012-10-17 22:10:34 +0000 differ
=== added file 'app/assets/images/tab_marker.png'
Binary files app/assets/images/tab_marker.png 1970-01-01 00:00:00 +0000 and app/assets/images/tab_marker.png 2012-10-17 22:10:34 +0000 differ
=== removed file 'app/assets/images/white-triangle-16X8.png'
Binary files app/assets/images/white-triangle-16X8.png 2012-10-11 18:06:58 +0000 and app/assets/images/white-triangle-16X8.png 1970-01-01 00:00:00 +0000 differ
=== added file 'app/templates/service-footer-common-controls.partial'
--- app/templates/service-footer-common-controls.partial 1970-01-01 00:00:00 +0000
+++ app/templates/service-footer-common-controls.partial 2012-10-17 22:10:34 +0000
@@ -0,0 +1,26 @@
+<div class="inline service-common-controls">
+ {{#unless charm.is_subordinate}}
+ <div class="control-unit-count">
+ <div class="inline"><span>Unit count</span></div>
+ <div class="inline">
+ <input type="text" id="num-service-units" value="{{service.unit_count}}">
+ </div>
+ </div>
+ {{/unless}}
+ <div class="control-expose">
+ <div class="inline"><span>Expose</span></div>
+ <div class="inline">
+ {{#if service.exposed}}
+ <img class="unexposeService"
+ alt="Exposed"
+ src="/juju-ui/assets/images/slider_on.png" />
+ <span class="on">On</span>
+ {{else}}
+ <img class="exposeService"
+ alt="Not exposed"
+ src="/juju-ui/assets/images/slider_off.png" />
+ <span class="off">Off</span>
+ {{/if}}
+ </div>
+ </div>
+</div>
\ No newline at end of file
=== modified file 'app/templates/service-footer.partial'
--- app/templates/service-footer.partial 2012-10-12 18:27:58 +0000
+++ app/templates/service-footer.partial 2012-10-17 22:10:34 +0000
@@ -1,8 +1,14 @@
-<div class="juju-service-info-container-bottom-menu">
- <div class="juju-service-info-container-bottom-menu-wrapper">
- <div class="inline">
- <a class="btn" id="destroy-service" data-toggle="modal"
- href="#destroy-service-modal">Destroy Service</a>
+<div class="service-view">
+ <div class="juju-service-info-container-bottom-menu">
+ <div class="destroy-control">
+ <a id="destroy-service" data-toggle="modal"
+ href="#destroy-service-modal">
+ <img src="/juju-ui/assets/images/destroy_icon.png" />Destroy
+ </a>
+ <img class="divider"
+ src="/juju-ui/assets/images/bottom_bar_big_div.png" />
</div>
+
+ {{> service-footer-common-controls}}
</div>
-</div>
\ No newline at end of file
+</div>
\ No newline at end of file
=== modified file 'app/templates/service-header.partial'
--- app/templates/service-header.partial 2012-10-12 18:27:36 +0000
+++ app/templates/service-header.partial 2012-10-17 22:10:34 +0000
@@ -1,66 +1,26 @@
-<div class="service-header-partial">
-<div class="hero-unit juju-service-info-container">
- <div class="inline juju-service-info-container-big">
- <div class="juju-service-container-header-name">
- <div class="juju-sevice-container-name">
- <span><strong>{{service.id}}</strong></span>
- </div>
- <div>
- <span><strong>{{charm.id}}</strong></span>
- <span> </span>
- <a class="juju-service-charm-link"
- href="{{charm.app_url}}">Show Charm</a>
- </div>
- </div>
- </div>
- <div class="inline juju-service-info-container-separator"></div>
- <div class="inline juju-service-info-container-separator"></div>
- <div class="inline juju-service-info-container-small">
- <div class="juju-service-container-header-expose">
- {{#if service.exposed}}
- <button class="btn unexposeService">
- <i class="icon-play-circle"></i>Unexpose
- </button>
- {{else}}
- <button class="btn exposeService">
- <i class="icon-ban-circle"></i>Expose
- </button>
- {{/if}}
- </div>
- </div>
- <div class="inline juju-service-info-container-separator"></div>
- <div class="inline juju-service-info-container-separator"></div>
- <div class="inline juju-service-info-container-small">
- <div class="juju-service-container-header-unit-count">
- {{#unless charm.is_subordinate}}
- <form class="unit-count-form">
- <label class="control-label" for="num-service-units">Unit count</label>
- <input type="text" id="num-service-units"
- value="{{service.unit_count}}">
- </form>
- {{/unless}}
- </div>
- </div>
-
-
-</div>
-<div class="juju-service-info-container-menu">
- <div class="juju-service-info-container-menu-wrapper">
- {{#tabs}}
- <div class="inline juju-menu-item">
- <div>
- <a href="{{href}}"><strong>{{title}}</strong></a>
- </div>
- <div>
- {{#if active}}
- <img src="/juju-ui/assets/images/white-triangle-16X8.png" />
- {{/if}}
- </div>
- </div>
- {{/tabs}}
- </div>
-</div>
-<div class="row">
- <div id="message-area" class="span10"></div>
-</div>
+<div class="service-view">
+ <div class="service-header-partial">
+ <div class="name crosshatch-background">
+ <div>
+ <span>{{service.id}}</span>
+ </div>
+ <div>
+ <span>{{charm.id}}</span>
+ </div>
+ </div>
+ <div class="menu-items">
+ {{#tabs}}
+ <div class="inline item">
+ <div>
+ <a href="{{href}}">{{title}}</a>
+ </div>
+ <div {{#if active}}class="active"{{/if}}>
+ </div>
+ </div>
+ {{/tabs}}
+ </div>
+ <div class="row">
+ <div id="message-area" class="span10"></div>
+ </div>
+ </div>
</div>
\ No newline at end of file
=== modified file 'app/templates/service.handlebars'
--- app/templates/service.handlebars 2012-10-12 23:43:24 +0000
+++ app/templates/service.handlebars 2012-10-17 22:10:34 +0000
@@ -7,22 +7,24 @@
</div>
<div id="destroy-modal-panel"></div>
</div>
-<div class="juju-service-info-container-bottom-menu">
- <div>
- <div class="inline">
- <a class="btn" id="destroy-service" data-toggle="modal"
- href="#destroy-service-modal">Destroy Service</a>
- </div>
- <div class="inline juju-service-info-container-separator-footer"></div>
- <div class="inline">
- <div class="juju-service-info-container-bottom-menu-wrapper-service">
- <span class="state-filter-label"><strong>Filter</strong> </span>
- {{#states}}
- <a class="state-btn btn {{#if active}}btn-primary{{/if}}"
- data-toggle="modal" href="{{link}}">
- <span class="state-title">{{title}}</span> ({{count}})</a>
- {{/states}}
- </div>
- </div>
- </div>
-</div>
\ No newline at end of file
+<div class="service-view">
+ <div class="juju-service-info-container-bottom-menu">
+ <div class="destroy-control">
+ <a id="destroy-service" data-toggle="modal"
+ href="#destroy-service-modal">
+ <img src="/juju-ui/assets/images/destroy_icon.png" />Destroy
+ </a>
+ <img class="divider"
+ src="/juju-ui/assets/images/bottom_bar_big_div.png" />
+ </div>
+ <div class="filter-control">
+ <span>Filter</span>
+ {{#states}}
+ <a class="state-btn btn {{#if active}}btn-primary{{/if}}"
+ data-toggle="modal" href="{{link}}">
+ <span class="state-title">{{title}}</span> ({{count}})</a>
+ {{/states}}
+ </div>
+ {{> service-footer-common-controls}}
+ </div>
+</div>
=== modified file 'app/views/environment.js'
--- app/views/environment.js 2012-10-15 19:22:40 +0000
+++ app/views/environment.js 2012-10-17 22:10:34 +0000
@@ -84,6 +84,21 @@
self.set('potential_drop_point_service', d);
self.set('potential_drop_point_rect', rect);
self.addSVGClass(rect, 'hover');
+
+ // If we have an active dragline, stop redrawing it on mousemove
+ // and draw the line between the two nearest connector points of
+ // the two services.
+ if (self.dragline) {
+ var connectors = d.getConnectorPair(
+ self.get('addRelationStart_service')),
+ s = connectors[0],
+ t = connectors[1];
+ self.dragline.attr('x1', t[0])
+ .attr('y1', t[1])
+ .attr('x2', s[0])
+ .attr('y2', s[1])
+ .attr('class', 'relation pending-relation dragline');
+ }
},
mouseleave: function(d, self) {
// Do not fire if we aren't looking for a relation endpoint.
@@ -101,6 +116,11 @@
self.set('potential_drop_point_service', null);
self.set('potential_drop_point_rect', null);
self.removeSVGClass(rect, 'hover');
+
+ if (self.dragline) {
+ self.dragline.attr('class',
+ 'relation pending-relation dragline dragging');
+ }
}
},
'.sub-rel-block': {
@@ -254,6 +274,8 @@
.attr('height', height)
.append('svg:g')
.call(zoom)
+ // Disable zoom on double click.
+ .on('dblclick.zoom', null)
.append('g');
vis.append('svg:rect')
@@ -386,7 +408,7 @@
},
/*
- * Sync view models with curent db.models.
+ * Sync view models with current db.models.
*/
updateData: function() {
//model data
@@ -775,7 +797,13 @@
});
var status_chart_layout = d3.layout.pie()
- .value(function(d) { return (d.value ? d.value : 1); });
+ .value(function(d) { return (d.value ? d.value : 1); })
+ .sort(function(a, b) {
+ // Ensure that the service health graphs will be renders in
+ // the correct order: error - pending - running.
+ var states = {error: 0, pending: 1, running: 2};
+ return states[a.name] - states[b.name];
+ });
// Append to status charts to non-subordinate services
var status_chart = node.append('g')
@@ -872,14 +900,17 @@
});
},
renderSlider: function() {
- var self = this;
+ var self = this,
+ value = 100,
+ currentScale = this.get('scale');
// Build a slider to control zoom level
- // TODO once we have a stored value in view models, use that
- // for the value property, but for now, zoom to 100%
+ if (currentScale) {
+ value = currentScale * 100;
+ }
var slider = new Y.Slider({
min: 25,
max: 200,
- value: 100
+ value: value
});
slider.render('#slider-parent');
slider.after('valueChange', function(evt) {
@@ -949,6 +980,22 @@
.setAttribute('x', -width / 2);
});
+ // Preserve zoom when the scene is updated.
+ var changed = false,
+ currentScale = this.get('scale'),
+ currentTranslate = this.get('translate');
+ if (currentTranslate && currentTranslate !== this.zoom.translate()) {
+ this.zoom.translate(currentTranslate);
+ changed = true;
+ }
+ if (currentScale && currentScale !== this.zoom.scale()) {
+ this.zoom.scale(currentScale);
+ changed = true;
+ }
+ if (changed) {
+ this._fire_zoom(0);
+ }
+
// Render the slider after the view is attached.
// Although there is a .syncUI() method on sliders, it does not
// seem to play well with the app framework: the slider will render
@@ -977,7 +1024,7 @@
addRelationDragStart: function(d, context) {
// Create a pending drag-line behind services.
var dragline = this.vis.insert('line', '.service')
- .attr('class', 'relation pending-relation dragline'),
+ .attr('class', 'relation pending-relation dragline dragging'),
self = this;
// Start the line in the middle of the service.
@@ -987,6 +1034,7 @@
.attr('x2', point[0])
.attr('y2', point[1]);
self.dragline = dragline;
+ self.cursorBox = views.BoundingBox();
// Start the add-relation process.
self.service_click_actions
@@ -994,9 +1042,21 @@
},
addRelationDrag: function(d, context) {
- // Rubberband our potential relation line.
- this.dragline.attr('x2', d3.event.x)
+ // Rubberband our potential relation line if we're not currently
+ // hovering over a potential drop-point.
+ if (!this.get('potential_drop_point_service')) {
+ // Create a BoundingBox for our cursor.
+ this.cursorBox.pos = {x: d3.event.x, y: d3.event.y, w: 0, h: 0};
+
+ // Draw the relation line from the connector point nearest the
+ // cursor to the cursor itself.
+ var connectors = this.cursorBox.getConnectorPair(d),
+ s = connectors[1];
+ this.dragline.attr('x1', s[0])
+ .attr('y1', s[1])
+ .attr('x2', d3.event.x)
.attr('y2', d3.event.y);
+ }
},
addRelationDragEnd: function(d, context) {
@@ -1006,8 +1066,9 @@
var endpoint = self.get('potential_drop_point_service');
// Get rid of our drag line
- this.dragline.remove();
- this.buildingRelation = false;
+ self.dragline.remove();
+ self.buildingRelation = false;
+ self.cursorBox = null;
// If we landed on a rect, add relation, otherwise, cancel.
if (rect) {
@@ -1133,7 +1194,11 @@
if (new_scale < 25 || new_scale > 200) {
evt.scale = this.get('scale');
}
+ // Store the current value of scale so that it can be restored later.
this.set('scale', evt.scale);
+ // Store the current value of translate as well, by copying the event
+ // array in order to avoid reference sharing.
+ this.set('translate', evt.translate.slice(0));
vis.attr('transform', 'translate(' + evt.translate + ')' +
' scale(' + evt.scale + ')');
this.updateServiceMenuLocation();
=== modified file 'app/views/service.js'
--- app/views/service.js 2012-10-14 00:51:02 +0000
+++ app/views/service.js 2012-10-17 22:10:34 +0000
@@ -223,8 +223,8 @@
var exposeButtonMixin = {
events: {
- '.unexposeService': {click: 'unexposeService'},
- '.exposeService': {click: 'exposeService'}
+ '.unexposeService': {mousedown: 'unexposeService'},
+ '.exposeService': {mousedown: 'exposeService'}
},
unexposeService: function() {
@@ -297,7 +297,7 @@
}, this));
},
- getServiceTabs: function(href) {
+ getServiceTabs: function(href, charm) {
var tabs = [{
href: '.',
title: 'Units',
@@ -311,6 +311,10 @@
title: 'Settings',
active: false
}, {
+ href: (charm ? charm.app_url : '#'),
+ title: 'Charm',
+ active: false
+ }, {
href: 'constraints',
title: 'Constraints',
active: false
@@ -379,7 +383,8 @@
container.setHTML(this.template(
{ viewName: 'relations',
- tabs: this.getServiceTabs('relations'),
+ tabs: this.getServiceTabs('relations',
+ this.renderable_charm(service.get('charm'), app)),
service: service.getAttrs(),
relations: relation_data,
charm: this.renderable_charm(service.get('charm'), app)}
@@ -560,7 +565,8 @@
console.log('service constraints', display_constraints);
container.setHTML(this.template({
viewName: 'constraints',
- tabs: this.getServiceTabs('constraints'),
+ tabs: this.getServiceTabs('constraints',
+ this.renderable_charm(service.get('charm'), app)),
service: service.getAttrs(),
constraints: display_constraints,
readOnlyConstraints: (function() {
@@ -638,7 +644,8 @@
container.setHTML(this.template(
{ viewName: 'config',
- tabs: this.getServiceTabs('config'),
+ tabs: this.getServiceTabs('config',
+ this.renderable_charm(service.get('charm'), app)),
service: service.getAttrs(),
settings: settings,
charm: this.renderable_charm(service.get('charm'), app)}
@@ -809,7 +816,8 @@
}, this);
container.setHTML(this.template({
viewName: 'units',
- tabs: this.getServiceTabs('.'),
+ tabs: this.getServiceTabs('.',
+ this.renderable_charm(service.get('charm'), app)),
service: service.getAttrs(),
charm: this.renderable_charm(service.get('charm'), app),
state: filter_state,
=== modified file 'lib/views/stylesheet.less'
--- lib/views/stylesheet.less 2012-10-15 23:49:23 +0000
+++ lib/views/stylesheet.less 2012-10-17 22:10:34 +0000
@@ -234,6 +234,10 @@
&.pending-relation {
stroke: #faaf40;
+
+ &.dragging {
+ stroke: #fa6a40
+ }
}
&.unused {
@@ -830,136 +834,142 @@
background: pink;
}
-.juju-service-info-container {
- padding: 0px;
- margin-bottom: 0px;
- background-color: #515151;
- color: white;
- height: 70px;
- -webkit-border-radius: 0px;
- -moz-border-radius: 0px;
- border-radius: 0px;
- -webkit-border-top-left-radius: 6px;
- -moz-border-top-left-radius: 6px;
- border-top-left-radius: 6px;
- -webkit-border-top-right-radius: 6px;
- -moz-border-top-right-radius: 6px;
- border-top-right-radius: 6px;
-
- .juju-service-info-container-big {
- width: 58%;
-
- .juju-service-container-header-name {
- padding-top: 15px;
- padding-left: 10px;
-
- .juju-sevice-container-name {
- padding-bottom: 5px;
-
- span {
- font-size: 3em;
- }
- }
- }
- }
-
- .juju-service-info-container-small {
- width: 20%;
-
- .juju-service-container-header-expose {
- padding: 20px;
- }
-
- .juju-service-container-header-unit-count {
- padding: 5px;
-
- input {
- width: 95%
- }
- }
- }
-}
-
-.juju-service-info-container-menu {
- border-top: 1px solid #737373;
- background-color: black;
- height: 40px;
- text-align: center;
-}
-
-.juju-service-info-container-menu-wrapper {
- display: inline-block;
-}
-
-.juju-menu-item {
- color: white;
- padding: 10px;
- padding-bottom: 0px;
- padding-top: 10px;
- text-align: center;
-
- a {
- color: white;
- text-decoration: none;
- }
-
- a:HOVER {
- color: white;
- text-decoration: none;
- }
-}
-
-.unit-count-form {
- margin-bottom: 0px;
-}
-
-.juju-service-charm-link,.juju-service-charm-link:HOVER {
- color: #919191;
- text-decoration: underline;
-}
-
-.juju-service-info-container-separator {
- width: 0px;
- height: 68px;
- border: 1px solid #737373;
- margin-left: 1px;
-}
-
-.juju-service-info-container-separator-footer {
- height: 48px;
-}
-
-.juju-service-info-container-bottom-menu {
- border-top: 1px solid #737373;
- background-color: black;
- height: 50px;
-
- .juju-service-info-container-bottom-menu-wrapper {
- margin-left: 10px;
-
- div {
- width: 200px
- }
- }
-
- .juju-service-info-container-bottom-menu-wrapper-service {
- margin-top: 10px;
- margin-left: 10px;
-
- div {
- width: 200px
- }
- }
-
- #destroy-service {
+#destroy-service {
margin-top: 10px;
margin-left: 10px;
margin-right: 10px;
- }
}
-.state-filter-label {
- color: white
+.service-view {
+ .juju-service-info-container-bottom-menu {
+ background: url(/juju-ui/assets/images/bottom_bar.png) repeat-x;
+ height: 50px;
+ position: relative;
+ color: #2d2d2d!important;
+
+ .destroy-control {
+ position: absolute;
+ top: 1px;
+ left: 10px;
+
+ a {
+ color: #2D2D2D!important;
+ }
+
+ a:link, a:visited, a:active, a:hover {
+ text-decoration: none
+ }
+ }
+ }
+
+ .filter-control {
+ position: absolute;
+ left: 120px;
+ top: 10px;
+
+ span:first-child {
+ padding-right: 5px;
+ }
+
+ }
+
+.service-header-partial {
+ .name {
+ padding-top: 38px;
+ padding-left: 46px;
+ height: 111px;
+
+ div:nth-child(1) {
+ font-family: @font-family;
+ font-style: regular;
+ font-size: 22px; fill: #292929;
+ }
+
+ div:nth-child(2) {
+ padding-top: 18px;
+ font-family: @font-family;
+ font-style: italic;
+ font-size: 16px; fill: #6a737b;
+ }
+ }
+
+ .menu-items {
+ height: 26px;
+ padding-top: 2px;
+ padding-left: 38px;
+ background: url(/juju-ui/assets/images/tab_div.png) repeat;
+
+ .item {
+ a {
+ font-family: @font-family;
+ font-style: medium;
+ font-size: 12px; fill: #dd4814;
+ padding-left: 10px;
+ padding-right: 10px;
+ color: #2D2D2D!important;
+ }
+ a:link, a:visited, a:active, a:hover {
+ text-decoration: none
+ }
+ a:first-child {
+ color: #2D2D2D!important;
+ }
+ .active {
+ margin-top: 3px;
+ height: 4px;
+ background: url(/juju-ui/assets/images/tab_marker.png) repeat;
+ }
+ }
+ }
+ }
+
+ .service-common-controls {
+ position: absolute;
+ right: 10px;
+ top: 10px;
+
+ .control-unit-count {
+ position: absolute;
+ right: 130px;
+ top: 0px;
+ width: 290px;
+
+ div {
+ padding-left: 5px;
+ }
+
+ div:first-child {
+ padding-top: 4px;
+ }
+ }
+
+ .control-expose {
+ position: absolute;
+ right: 0px;
+ top: 4px;
+ width: 120px;
+
+ div {
+ padding-left: 5px;
+ }
+
+ .on {
+ font-family: @font-family;
+ font-size: 12px; fill: #ffffff;
+ position: absolute;
+ right: 20px;
+ top: 3px;
+ }
+
+ .off {
+ font-family: @font-family;
+ font-size: 12px; fill: #292929;
+ position: absolute;
+ right: 40px;
+ top: 3px;
+ }
+ }
+ }
}
div.inline {
Follow ups
-
[Merge] lp:~tveronezi/juju-gui/service-header into lp:juju-gui
From: Kapil Thangavelu, 2012-10-19
-
Re: Service view header should match design doc (issue 6724059)
From: Kapil Thangavelu, 2012-10-19
-
Re: Service view header should match design doc (issue 6724059)
From: Thiago Veronezi, 2012-10-19
-
Re: Service view header should match design doc (issue 6724059)
From: Thiago Veronezi, 2012-10-19
-
Re: Service view header should match design doc (issue 6724059)
From: Kapil Thangavelu, 2012-10-19
-
Re: Service view header should match design doc (issue 6724059)
From: Thiago Veronezi, 2012-10-19
-
Re: Service view header should match design doc (issue 6724059)
From: Thiago Veronezi, 2012-10-19
-
Re: Service view header should match design doc (issue 6724059)
From: Gary Poster, 2012-10-18
-
Service view header should match design doc (issue 6724059)
From: Thiago Veronezi, 2012-10-17
-
[Merge] lp:~tveronezi/juju-gui/service-header into lp:juju-gui
From: Thiago Veronezi, 2012-10-17