Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Add cluster management. #71

Merged
merged 6 commits into from

2 participants

@cmeiklejohn
Collaborator

Add new cluster management page.

There are some final things that are not completely idiomatic Ember, but we're going to revise those after this release cycle so we can focus on testing for the remainder of this cycle.

@cmeiklejohn
Collaborator

Another card I tried moving to working and vanished from the kanban. @seancribbs @joedevivo @jgnewman can I get a final review here?

@seancribbs
Owner

@cmeiklejohn I'll look over it again, yes.

priv/admin/js/cluster.js
((123 lines not shown))
+ } else {
+ return common + 'pct-static';
+ }
+ }.property('ring_pct', 'pending_pct'),
+
+ /**
+ * In order for labels to be clickable, they need to be bound to checks/radios
+ * by ID. However, since these nodes are cloned by Ember, we need a way to make
+ * sure all of those elements get id's that don't override each other. This
+ * function gives us an ID string we can use as a prefix for id's on these other
+ * elements.
+ *
+ * @returns {String}
+ */
+ node_id: function() {
+ return Ember.generateGuid();
@seancribbs Owner

This object will already have a guid, though, right? Why not Ember.guidFor(this)?

@cmeiklejohn Collaborator

Good call, fixed in [805d0b8].

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@seancribbs seancribbs commented on the diff
priv/admin/js/legacy/gui.js
((73 lines not shown))
} else {
- parent.css('background-position', 'left top');
+ parent.css('background-position', 'left top');
+ }
+ });
+
+ // MAKE RADIO BUTTONS WORK WHEN YOU CLICK THEM
+ $(document).on('change', '.gui-radio', function(e) {
@seancribbs Owner

I suppose this is working around a legacy design, but it feels like an arraycontroller/view/template combo would cover this problem.

@cmeiklejohn Collaborator

Agreed. We will refactor this later, but agreed. We have ton of legacy code that needs to be killed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@seancribbs
Owner

There are a few problems with the UI, and it's unclear whether this is a riak_core issue or just control.

If I stage adding a bunch of nodes, and then clear the plan, the staged plan clears, but the nodes in the cluster (on the left side) do not clear. If I then try to re-add the first node of my crazy plan, ALL the nodes reappear in the plan. Additionally, the node being added suddenly becomes the owner of all partitions (at least in the UI). When I went to check the CLI version, all but the node that claimed to own 100% of the partitions were down, including the one running control.

Here's some sample errors from the logs that may help:

2013-04-11 11:01:34.805 [error] <0.3435.0> CRASH REPORT Process <0.3435.0> with 0 neighbours exited with reason: no match of right hand value {'EXIT',{badarg,[{erlang,hd,[[]],[]},{riak_core_ring_handler,startable_vnodes,2,[{file,"src/riak_core_ring_handler.erl"},{line,154}]},{riak_core_ring_handler,ensure_vnodes_started,2,[{file,"src/riak_core_ring_handler.erl"},{line,106}]},{riak_core_ring_handler,ensure_vnodes_started,3,[{file,"src/riak_core_ring_handler.erl"},{line,103}]},{riak_core_ring_handler,ensure_vnodes_started,1,[{file,"src/riak_core_ring_handler.erl"},{line,66}]},{riak_core_ring_handler,init,1,[{file,"src/riak_core_rin..."},...]},...]}} in riak_core_eventhandler_guard:init/1 line 36 in gen_server:init_it/6 line 328
2013-04-11 11:01:34.782 [error] <0.139.0> gen_server riak_core_ring_manager terminated with reason: no function clause matching random:uniform(0) line 111

It seems that if you clear a plan with nodes being added, they get stopped.

2013-04-11 11:01:48.068 [notice] <0.139.0>@riak_core:stop:51 "node removal completed, exiting."

I believe this is a bug/problem in core, based on the errors, but the UI is problematic in its display of the problem.

@cmeiklejohn
Collaborator

@seancribbs Yes, this is riak_core. There is no "staged addition" in riak_core's claimant. If you perform these actions via the CLI, you should see the same behaviour. I'll try to verify this myself shortly.

@cmeiklejohn
Collaborator

@seancribbs Can we chat more about the potential problem in core and how to handle the proper display in the user interface?

@cmeiklejohn
Collaborator

@seancribbs good to merge?

@seancribbs
Owner

1+

@cmeiklejohn
Collaborator

lol, merging dat.

@cmeiklejohn cmeiklejohn merged commit c42c1b1 into from
@cmeiklejohn cmeiklejohn was assigned
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
Showing with 2,768 additions and 1,645 deletions.
  1. +5 −4 Makefile
  2. +24 −1 include/riak_control.hrl
  3. +386 −121 priv/admin/css/cluster.styl
  4. +553 −196 priv/admin/css/compiled/style.css
  5. +82 −29 priv/admin/css/general.styl
  6. +17 −1 priv/admin/css/reusable.styl
  7. +12 −3 priv/admin/css/snapshot.styl
  8. BIN  priv/admin/images/actions-toggle-slider.png
  9. BIN  priv/admin/images/actions-toggle-text.png
  10. BIN  priv/admin/images/nav-icons-small.png
  11. BIN  priv/admin/images/pointbutton-right-sprite.png
  12. BIN  priv/admin/images/pointer.png
  13. BIN  priv/admin/images/radio-sprite.png
  14. BIN  priv/admin/images/riak-control-logo-small.png
  15. BIN  priv/admin/images/right-angle-arrow.png
  16. BIN  priv/admin/images/stagebutton-sprite.png
  17. +24 −0 priv/admin/js/app.js
  18. +742 −1 priv/admin/js/cluster.js
  19. +4 −2 priv/admin/js/generated/templates.js
  20. +0 −71 priv/admin/js/legacy/actions.js
  21. +0 −630 priv/admin/js/legacy/cluster.js
  22. +64 −52 priv/admin/js/legacy/gui.js
  23. +5 −2 priv/admin/js/ring.js
  24. +11 −3 priv/admin/js/router.js
  25. +0 −7 priv/admin/js/templates/application.hbs
  26. +96 −113 priv/admin/js/templates/cluster.hbs
  27. +107 −0 priv/admin/js/templates/current_cluster_item.hbs
  28. +29 −0 priv/admin/js/templates/staged_cluster_item.hbs
  29. +1 −1  rebar.config
  30. +381 −0 src/admin_cluster.erl
  31. +0 −67 src/admin_cluster_down.erl
  32. +0 −79 src/admin_cluster_join.erl
  33. +26 −0 src/admin_gui.erl
  34. +0 −90 src/admin_node.erl
  35. +0 −63 src/admin_node_leave.erl
  36. +0 −63 src/admin_node_stop.erl
  37. +24 −0 src/admin_nodes.erl
  38. +14 −0 src/admin_partitions.erl
  39. +16 −15 src/admin_routes.erl
  40. +37 −17 src/riak_control_security.erl
  41. +107 −8 src/riak_control_session.erl
  42. +1 −5 src/riak_control_sup.erl
  43. +0 −1  templates/index.dtl
View
9 Makefile
@@ -31,12 +31,10 @@ APPS = kernel stdlib sasl erts ssl tools os_mon runtime_tools crypto inets \
PLT = $(HOME)/.riak_control_dialyzer_plt
check_plt: compile
- dialyzer --check_plt --plt $(PLT) --apps $(APPS) \
- deps/*/ebin
+ dialyzer --check_plt --plt $(PLT) --apps $(APPS)
build_plt: compile
- dialyzer --build_plt --output_plt $(PLT) --apps $(APPS) \
- deps/*/ebin
+ dialyzer --build_plt --output_plt $(PLT) --apps $(APPS)
dialyzer: compile
@echo
@@ -53,3 +51,6 @@ cleanplt:
@echo
sleep 5
rm $(PLT)
+
+typer:
+ typer --annotate -I ../ --plt $(PLT) -r src
View
25 include/riak_control.hrl
@@ -31,6 +31,27 @@
-type ring() :: riak_core_ring:riak_core_ring().
-type handoffs() :: [handoff()].
-type vnodes() :: [vnode()].
+-type plan() :: [] | legacy | ring_not_ready | unavailable.
+
+-type stage_error() :: nodedown
+ | already_leaving
+ | not_member
+ | only_member
+ | is_claimant
+ | invalid_replacement
+ | already_replacement
+ | not_reachable
+ | not_single_node
+ | self_join.
+
+-type action() :: leave
+ | remove
+ | {replace, node()}
+ | {force_replace, node()}.
+
+-type claim_percentage() :: number().
+
+-type change() :: {node(), action()}.
-record(partition_info,
{ index :: index(),
@@ -50,7 +71,9 @@
pending_pct :: float(),
mem_total :: integer(),
mem_used :: integer(),
- mem_erlang :: integer()
+ mem_erlang :: integer(),
+ action :: action(),
+ replacement :: node()
}).
-type partitions() :: [#partition_info{}].
View
507 priv/admin/css/cluster.styl
@@ -4,52 +4,206 @@ CSS to be applied ONLY on the cluster page
*/
@import reusable
+
#cluster-page
-
+
+ .warning
+ display : block
+ padding : 10px 0 0
+ color : riakred
+
+ #current-area, #planned-area
+ float : left
+ width : 47%
+
+ #current-area
+ margin : 0 0 45px 0
+
+
+ #area-separator
+ width : 6%
+ height : 450px
+ float : left
+ text-align : center
+
+ div
+ margin : 0 auto
+ width : 1px
+ height : 100%
+ background : lightWhite
+
+ span.gui-text-flat
+ line-height : 1.5
+
h3
copy-font()
+ .spinner-box
+ corners()
+ text-align : center
+ background : rgba(255, 255, 255, .05)
+ padding : 25px
+
+ img, h4
+ vertical-align : middle
+
+ h4
+ opaque(.8)
+ display : inline-block
+ padding-top : 6px
+ padding-left : 10px
+ line-height : 1.2
+
+ .actions-container
+ css-transition(height .4s ease, margin-bottom .4s ease)
+ overflow : hidden
+ height : 0
+ margin-bottom : 0
+
+ .open .actions-container
+ css-transition(height .4s ease, margin-bottom .4s ease)
+ height : 375px
+ margin-bottom : 25px
+
+ .gui-light
+ vertical-align : middle
+ padding : 9px 5px 9px 14px
+ margin-left : -6px
+ margin-top : -7px
+
+ .field-container
+ width : 75%
+ vertical-align : middle
+
+ .gui-field
+ margin-right : 0
+ overflow : hidden
+
#add-node
padding-top : 40px
- margin-bottom : 25px
+ margin-bottom : 45px
.add-node-table tr td
padding-top : 25px
-
- .more-node-actions
- display : none
- vendor('box-shadow', 0 3px 5px darkened)
- .more-node-actions td
- padding : 0 5px
-
- .button-column
- text-align : right
+ .list-header
+ min-height : 18px
- .switch-box
- dimensions(125px, auto)
- vertical-align : top
-
- div
- width : 88px
- padding-left : 4px
-
- &.on > div
- vendor('box-shadow', inset 0 1px 3px darkened)
- singleCorner(top, left, 4px)
- singleCorner(top, right, 4px)
- background : darkened
+ li
+ float : left
+ margin-bottom : 30px
+ h4
+ display : inline-block
- .status-box
- dimensions(170px, auto)
-
- .actions-header
- padding-left : 6px
+ #node-list, #planned-list
+ margin-top : 20px
+
+ #node-list
+ .item1
+ width : 18%
+ .item2
+ width : 42%
+ .item3
+ width : 18%
+ .item4
+ width : 22%
+
+ .node
+ margin-bottom : 10px
+ position : relative
+
+ .node > div
+ float : left
+
+ .node > div.clear
+ float : none
+
+ .toggle-container
+ overflow : visible
+ padding : 0
+
+ .actions-toggle
+ dimensions(82px, 30px)
+ position : relative
+ overflow : visible
+ padding : 0
+ background : url('/admin/ui/images/actions-toggle-text.png') -5px top no-repeat rgba(0, 0, 0, .3)
+ margin-top : 3px
+
+ a
+ dimensions(48px, 34px)
+ css-transition(left .2s ease)
+ position : absolute
+ display : inline-block
+ background : url('/admin/ui/images/actions-toggle-slider.png') left top no-repeat transparent
+ top : 0
+ left : -5px
+
+ .open .actions-toggle a
+ css-transition(left .2s ease)
+ left : 38px
+
+ .name-box
+ overflow : visible
+
+ .ring-pct, .used-memory, .action-name
+ monospace();
+
+ .used-memory
+ display : inline-block
+ padding : 0 0 0 5px
+ vertical-align : middle
+
+ .action-name
+ display : inline-block
+ padding-top : 8px
+
+ .replacing-box .field-container
+ width : 100%
+ #planned-list
+ .item1
+ width : 40%
+ .item2
+ width : 17%
+ .item3
+ width : 17%
+ .item4
+ width : 26%
+ .plan-details-header
+ margin-top : 30px
+ padding : 10px 0
+
+ .accept-plan
+ position : relative
+ padding : 15px 0
+ margin-top : 15px
+
+ .clear-plan-box
+ border-top : 1px solid lightWhite
+ margin-top : 25px
+ padding-top : 25px
+
+ a
+ display : block
+ margin-top : 15px
+ margin-left : -5px
+
+ .plan-details
+ @extend .gui-text-flat
+ copy-font()
+ line-height : 1.5
+
+ #commit-button
+ absoluteRight(0, 12px)
+
+ .button-column
+ text-align : right
+
.pct-box
margin-top : 8px
display : inline-block
@@ -77,11 +231,14 @@ CSS to be applied ONLY on the cluster page
margin : 0 5px 0 0
display : none
- #node-error
- headline-font()
+ .error-message
+ copy-font()
vendor('box-shadow', 0 2px 3px darkened)
corners()
- padding : 8px 10px 8px 12px
+ font-size : 14px
+ font-style : italic
+ color : mediumGray
+ padding : 8px 10px 9px 12px
background : rgba(232, 78, 78, .5)
border : 1px solid lighten(rgba(232, 78, 78, .5), 15%)
@@ -104,8 +261,6 @@ CSS to be applied ONLY on the cluster page
&:hover
opaque(1)
- .ring_pct-box
- width : 150px
.memory-box
width : 175px
@@ -160,121 +315,231 @@ CSS to be applied ONLY on the cluster page
background-color : #404040
width : 100%
- .action-button
- dimensions(45px, 45px)
- gradient(#616161, #434343)
- corners()
- vendor('box-shadow', 0 2px 3px darkened)
- display : block
- margin-bottom : 5px
-
- &:hover
- gradient(lighten(#616161, 10%), #434343)
-
- &:active, &.pressed
- gradient(#434343, #515151)
-
- .disabled.action-button
- gradient(#434343, #515151) !important
-
- .action-icon
- dimensions(45px, 45px)
- vendor('box-shadow', inset 0 1px 2px lightWhite)
- corners()
- display : block
- background : url('/admin/ui/images/action-button-sprite.png') left top no-repeat transparent
+ .actions-pointer
+ dimensions(72px, 13px)
+ background : url('/admin/ui/images/pointer.png') center top no-repeat transparent
+ margin-top : 8px
.actions-box
- singleCorner(bottom, left, 10px)
- singleCorner(bottom, right, 10px)
- singleCorner(top, left, 4px)
+ corners()
+ width : 92%
background : darkened
- margin-top : -6px
margin-bottom : 15px
border-bottom : 1px solid lightWhite
- padding : 15px
+ padding : 18px
margin-right : 33px
- display : none
+ position : relative
+
+ & > h4
+ display : block
+ border-bottom : 1px solid lightWhite
+ padding : 0 0 12px
+
.actions-box > div > span
- headline-bold()
+ copy-font()
color : lightGray
padding-left : 3px
-
- .markdown-box, .shutdown-box, .leave-cluster-box
- margin-bottom : 10px
- margin-right : 15px
- .shutdown-button .action-icon
- background-position : left bottom
-
- .markdown-button .action-icon
- background-position : 1px 1px
+ .extra-actions
+ opaque(.32)
+ padding-bottom : 25px
+ height : 35px
+ position : relative
+
+ & > div
+ float : left
+
+ .gui-checkbox-wrapper
+ margin-left : 15px
- .leave-cluster-button .action-icon
- background-position : 1px -44px
+ &.active
+ opaque(1)
.replacement-controls
- float : left
- width : auto
+ width : auto
+ margin-top : 18px
+ border-bottom : 1px solid lightWhite
+ margin-bottom : 10px
+
+ div
+ margin-bottom : 8px
+
+ select
+ margin-top : -38px
.replacement-node-dropdown
- width : 100%
- float : left
margin-bottom : 5px
+ .right-angle-arrow
+ dimensions(15px, 18px)
+ background : url('/admin/ui/images/right-angle-arrow.png') left top no-repeat transparent
+ margin : 0 10px 0 10px
+
+ .disabler
+ background : red
+ opaque(.2)
+ absoluteLeft(0, 0)
+ dimensions(100%, 100%)
+ background : transparent
+
+ .stage-button
+ float : right
+
+ .stage-instructions
+ float : left
+ display : block
+ width : 50%
+
+ .no-joining-nodes
+ padding-top : 6px
+
+ .slide-up
+ margin-top : -35px
+
+ .semi-transparent
+ opaque(.32)
+
+
/* RESPONSIVE MEDIA QUERIES */
- @media screen and (min-width : 1100px)
+ @media screen and (max-width : 1200px)
+
+ #area-separator
+ display : none
+
+ #current-area, #planned-area
+ width : 100%
+
+ #planned-area
+ padding-top : 30px
+ border-top : 1px solid lightWhite
+
+ .field-container
+ width : 90%
+
+ #node-list
+ .item1
+ width : 100px
+ .item2
+ width : 500px
+ .item3
+ width : 100px
+ .item4
+ width : 150px
+
+ #planned-list
+ .item1
+ width : 300px
+ .item2
+ width : 100px
+ margin-left : 25px
+ .item3
+ width : 100px
+ .item4
+ width : 350px
+
+ @media screen and (max-width : 950px)
+
+ #node-list
+ .item1
+ width : 100px
+ .item2
+ width : 400px
+ .item3
+ width : 100px
+ .item4
+ width : 150px
+
+ #planned-list
+ .item1
+ width : 275px
+ .item2
+ width : 100px
+ .item3
+ width : 100px
+ .item4
+ width : 225px
+
+ @media screen and (max-width : 850px)
+
+ #node-list
+ .item1
+ width : 100px
+ .item2
+ width : 300px
+
+ .field-container
+ width : 75%
- .replacement-controls
- width : 250px
+ .item3
+ width : 100px
+ .item4
+ width : 150px
- @media screen and (max-width : 959px)
+ #planned-list
+ .item3
+ display : none
- .free-memory
+ .used-memory
display : none
-
- .actions-box
- margin-right : 0
-
- .switch-box
- width : 100px
-
- .switch-box div
- width : 78px
- padding-left : 0
-
- .switch-box > div
- width : auto
- padding : 0
- text-align : center
-
- .actions-header
- padding-left : 0
- text-align : center
- @media screen and (max-width : 699px)
+ @media screen and (max-width : 700px)
- .status-box, .ring_pct-box, .memory-box
- width : auto
+ #node-list
+ .item1
+ width : 100px
+ .item2
+ width : 200px
+
+ .field-container
+ width : 75%
+
+ .item3
+ width : 100px
+ .item4
+ width : 150px
+
+ #planned-list
+ .item1
+ width : 200px
+ .item2
+ width : 100px
+ margin-left : 0
+ .item4
+ width : 200px
+
+ .gui-light
+ display : none
+
+ @media screen and (max-width : 600px)
+
+ #node-list
+ .item1
+ display : none
+ .item2
+ width : 40%
+ .field-container
+ width : 95%
+ .item4
+ width : 100px
+
+ #planned-list
+ .item1
+ width : 40%
+ .field-container
+ width : 95%
+ .item2
+ width : 20%
+ margin-right : 2%
+ .item4
+ width : 38%
+ .field-container
+ width : 95%
- .status-box
- text-align : center
-
- .gui-light span
+ .actions-container
display : none
-
- .markdown-box, .shutdown-box, .leave-cluster-box
- margin-right : 10px
- .replacement-controls
- margin-right : 0
-
- @media screen and (max-width : 499px)
- .switch-box div
- padding: 0 7px 0 0
- margin : 0 0 0 5px
- /* END RESPONSIVE MEDIA QUERIES */
+
View
749 priv/admin/css/compiled/style.css
@@ -412,6 +412,7 @@ footer {
}
footer {
padding: 0 25px 0;
+ margin-bottom: 25px;
}
footer .title-box {
width: 16%;
@@ -484,7 +485,8 @@ footer .side-line {
margin-top: -30px;
}
.gui-point-button,
-.gui-rect-button {
+.gui-rect-button,
+.gui-point-button-right {
width: 137px;
height: 40px;
display: inline-block;
@@ -495,6 +497,9 @@ footer .side-line {
.gui-point-button {
background: url("/admin/ui/images/pointbutton-sprite.png") left top no-repeat transparent;
}
+.gui-point-button-right {
+ background: url("/admin/ui/images/pointbutton-right-sprite.png") left top no-repeat transparent;
+}
.gui-rect-button {
background: url("/admin/ui/images/rectbutton-sprite.png") left top no-repeat transparent;
}
@@ -506,28 +511,38 @@ footer .side-line {
padding-top: 8px;
text-align: center;
}
+.gui-point-button-right .gui-button-msg {
+ padding-right: 11px;
+}
.gui-point-button:hover,
-.gui-rect-button:hover {
+.gui-rect-button:hover,
+.gui-point-button-right:hover {
background-position: left -40px;
}
.gui-point-button:active,
.gui-point-button.pressed,
.gui-rect-button:active,
-.gui-rect-button.pressed {
+.gui-rect-button.pressed,
+.gui-point-button-right:active,
+.gui-point-button-right.pressed {
background-position: left -80px !important;
}
-.gui-point-button:active .gui-button-msg,
-.gui-point-button.pressed .gui-button-msg,
-.gui-rect-button:active .gui-button-msg,
-.gui-rect-button.pressed .gui-button-msg {
+.gui-point-button:active .gui-button-msg,
+.gui-point-button.pressed .gui-button-msg,
+.gui-rect-button:active .gui-button-msg,
+.gui-rect-button.pressed .gui-button-msg,
+.gui-point-button-right:active .gui-button-msg,
+.gui-point-button-right.pressed .gui-button-msg {
padding-top: 9px;
}
input.gui-point-button,
-input.gui-rect-button {
+input.gui-rect-button,
+input.gui-point-button-right {
padding-bottom: 12px;
}
input.gui-point-button:active,
-input.gui-rect-button:active {
+input.gui-rect-button:active,
+input.gui-point-button-right:active {
padding-bottom: 9px;
}
.button-column {
@@ -547,21 +562,42 @@ input.gui-rect-button:active {
.gui-switch.off {
background-position: left bottom;
}
-.gui-checkbox-wrapper {
+.gui-checkbox-wrapper,
+.gui-radio-wrapper {
width: auto;
height: 24px;
background: url("/admin/ui/images/checkbox-sprite.png") left top no-repeat transparent;
vertical-align: middle;
margin-top: 5px;
}
-.gui-checkbox-wrapper span {
+.gui-checkbox-wrapper.default,
+.gui-radio-wrapper.default {
+ background-position: left bottom;
+}
+.gui-checkbox-wrapper span,
+.gui-radio-wrapper span,
+.gui-checkbox-wrapper label,
+.gui-radio-wrapper label {
font-family: 'titillium', helvetica, arial, sans-serif;
font-weight: bold;
display: inline-block;
margin: 5px 0 0 8px;
color: #efefef;
}
-.gui-checkbox {
+.gui-checkbox-wrapper span.serif,
+.gui-radio-wrapper span.serif,
+.gui-checkbox-wrapper label.serif,
+.gui-radio-wrapper label.serif {
+ font-family: 'noticia', georgia, serif;
+ font-weight: normal;
+ color: #ccc;
+ font-style: italic;
+}
+.gui-radio-wrapper {
+ background: url("/admin/ui/images/radio-sprite.png") left top no-repeat transparent;
+}
+.gui-checkbox,
+.gui-radio {
width: 25px;
height: 24px;
opacity: 0;
@@ -570,8 +606,8 @@ input.gui-rect-button:active {
float: left;
margin: 0;
}
-.gui-checkbox[checked=checked],
-.gui-checkbox-wrapper .gui-text {
+.gui-checkbox-wrapper .gui-text,
+.gui-radio-wrapper .gui-text {
width: auto;
height: 24px;
display: block;
@@ -661,7 +697,8 @@ input.gui-rect-button:active {
}
.gui-text-flat,
.gui-text,
-.gui-text-bold {
+.gui-text-bold,
+#cluster-page .plan-details {
text-shadow: none;
color: #ccc;
font-size: 14px;
@@ -693,18 +730,18 @@ input.gui-rect-button:active {
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
- -webkit-box-shadow: inset 0 1px 3px rgba(0,0,0,0.3);
- -moz-box-shadow: inset 0 1px 3px rgba(0,0,0,0.3);
- box-shadow: inset 0 1px 3px rgba(0,0,0,0.3);
- background: rgba(0,0,0,0.3);
- padding: 8px;
+ -webkit-box-shadow: inset 0 1px 3px rgba(0,0,0,0.35);
+ -moz-box-shadow: inset 0 1px 3px rgba(0,0,0,0.35);
+ box-shadow: inset 0 1px 3px rgba(0,0,0,0.35);
+ background: rgba(0,0,0,0.35);
+ padding: 10px;
border-bottom: 1px solid rgba(255,255,255,0.18);
margin-right: 2em;
}
.gui-input {
width: 100%;
height: auto;
- padding: 6px 8px;
+ padding: 8px;
border-left: 0;
border-right: 0;
border-top: 0;
@@ -714,7 +751,7 @@ input.gui-rect-button:active {
}
.gui-light {
background: url("/admin/ui/images/light-sprite.png") left top no-repeat transparent;
- padding: 9px 0 9px 33px;
+ padding: 11px 0 9px 33px;
min-height: 14px;
min-width: 14px;
display: inline-block;
@@ -756,6 +793,9 @@ input.gui-rect-button:active {
font-family: 'noticia', georgia, serif;
font-style: italic;
}
+.serif {
+ font-family: 'noticia', georgia, serif;
+}
.left {
float: left;
}
@@ -766,9 +806,12 @@ input.gui-rect-button:active {
.unreachable {
color: #f05f5f;
}
+.inline-block {
+ display: inline-block;
+}
@media screen and (min-width : 1100px) {
#wrapper {
- width: 1100px;
+ max-width: 1500px;
}
}
@media screen and (max-width : 699px) {
@@ -813,6 +856,41 @@ input.gui-rect-button:active {
}
}
@media screen and (max-width : 499px) {
+ #header {
+ height: 44px;
+ }
+ #navbar,
+ #nav-ul {
+ height: 41px;
+ }
+ .nav-li {
+ width: 45px;
+ height: 41px;
+ }
+ .nav-li .nav-item {
+ width: 45px;
+ height: 41px;
+ background: url("/admin/ui/images/nav-icons-small.png") center bottom no-repeat transparent;
+ }
+ .nav-li .indicator {
+ width: 45px;
+ height: 2px;
+ }
+ #riak-control-logo {
+ width: 123px;
+ height: 32px;
+ background: url("/admin/ui/images/riak-control-logo-small.png") right bottom no-repeat transparent;
+ margin: 6px 0 0 10px;
+ }
+ #nav-snapshot a {
+ background-position: 8px -237px;
+ }
+ #nav-cluster a {
+ background-position: 8px 11px;
+ }
+ #nav-ring a {
+ background-position: 8px -24px;
+ }
h1 {
font-size: 30px;
letter-spacing: 0;
@@ -841,21 +919,32 @@ input.gui-rect-button:active {
}
#snapshot-page #healthy-cluster li,
#snapshot-page #unhealthy-cluster li {
- font-family: 'menlo', 'consolas', 'monaco', monospace;
+ font-family: 'titillium', helvetica, arial, sans-serif;
line-height: 1.5;
+ font-size: 15px;
}
#snapshot-page #healthy-cluster li a,
#snapshot-page #unhealthy-cluster li a {
color: #efefef;
}
#snapshot-page #health-indicator {
- width: 311px;
- height: 309px;
float: left;
margin-right: 25px;
}
+#snapshot-page #healthy-cluster #health-indicator {
+ width: 337px;
+ height: 310px;
+}
+#snapshot-page #unhealthy-cluster #health-indicator {
+ width: 311px;
+ height: 309px;
+}
@media screen and (max-width : 899px) {
- #snapshot-page #health-indicator {
+ #snapshot-page #healthy-cluster #health-indicator {
+ width: 279px;
+ height: 249px;
+ }
+ #snapshot-page #unhealthy-cluster #health-indicator {
width: 250px;
height: 249px;
}
@@ -880,55 +969,238 @@ input.gui-rect-button:active {
text-align: left;
}
}
+#cluster-page .warning {
+ display: block;
+ padding: 10px 0 0;
+ color: #f05f5f;
+}
+#cluster-page #current-area,
+#cluster-page #planned-area {
+ float: left;
+ width: 47%;
+}
+#cluster-page #current-area {
+ margin: 0 0 45px 0;
+}
+#cluster-page #area-separator {
+ width: 6%;
+ height: 450px;
+ float: left;
+ text-align: center;
+}
+#cluster-page #area-separator div {
+ margin: 0 auto;
+ width: 1px;
+ height: 100%;
+ background: rgba(255,255,255,0.18);
+}
+#cluster-page span.gui-text-flat {
+ line-height: 1.5;
+}
#cluster-page h3 {
font-family: 'noticia', georgia, serif;
}
+#cluster-page .spinner-box {
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ text-align: center;
+ background: rgba(255,255,255,0.05);
+ padding: 25px;
+}
+#cluster-page .spinner-box img,
+#cluster-page .spinner-box h4 {
+ vertical-align: middle;
+}
+#cluster-page .spinner-box h4 {
+ opacity: 0.8;
+ filter: alpha(opacity=80);
+ display: inline-block;
+ padding-top: 6px;
+ padding-left: 10px;
+ line-height: 1.2;
+}
+#cluster-page .actions-container {
+ -webkit-transition: height 0.4s ease;
+ -moz-transition: height 0.4s ease;
+ -ms-transition: height 0.4s ease;
+ -webkit-transition: height 0.4s ease;
+ -moz-transition: height 0.4s ease;
+ -o-transition: height 0.4s ease;
+ transition: height 0.4s ease;
+ overflow: hidden;
+ height: 0;
+ margin-bottom: 0;
+}
+#cluster-page .open .actions-container {
+ -webkit-transition: height 0.4s ease;
+ -moz-transition: height 0.4s ease;
+ -ms-transition: height 0.4s ease;
+ -webkit-transition: height 0.4s ease;
+ -moz-transition: height 0.4s ease;
+ -o-transition: height 0.4s ease;
+ transition: height 0.4s ease;
+ height: 375px;
+ margin-bottom: 25px;
+}
+#cluster-page .gui-light {
+ vertical-align: middle;
+ padding: 9px 5px 9px 14px;
+ margin-left: -6px;
+ margin-top: -7px;
+}
+#cluster-page .field-container {
+ width: 75%;
+ vertical-align: middle;
+}
+#cluster-page .gui-field {
+ margin-right: 0;
+ overflow: hidden;
+}
#cluster-page #add-node {
padding-top: 40px;
- margin-bottom: 25px;
+ margin-bottom: 45px;
}
#cluster-page .add-node-table tr td {
padding-top: 25px;
}
-#cluster-page .more-node-actions {
- display: none;
- -webkit-box-shadow: 0 3px 5px rgba(0,0,0,0.3);
- -moz-box-shadow: 0 3px 5px rgba(0,0,0,0.3);
- box-shadow: 0 3px 5px rgba(0,0,0,0.3);
+#cluster-page .list-header {
+ min-height: 18px;
}
-#cluster-page .more-node-actions td {
- padding: 0 5px;
+#cluster-page .list-header li {
+ float: left;
+ margin-bottom: 30px;
}
-#cluster-page .button-column {
- text-align: right;
+#cluster-page .list-header li h4 {
+ display: inline-block;
}
-#cluster-page .switch-box {
- width: 125px;
- height: auto;
- vertical-align: top;
+#cluster-page #node-list,
+#cluster-page #planned-list {
+ margin-top: 20px;
}
-#cluster-page .switch-box div {
- width: 88px;
- padding-left: 4px;
-}
-#cluster-page .switch-box.on > div {
- -webkit-box-shadow: inset 0 1px 3px rgba(0,0,0,0.3);
- -moz-box-shadow: inset 0 1px 3px rgba(0,0,0,0.3);
- box-shadow: inset 0 1px 3px rgba(0,0,0,0.3);
- -webkit-border-top-left-radius: 4px;
- -moz-border-radius-topleft: 4px;
- border-top-left-radius: 4px;
- -webkit-border-top-right-radius: 4px;
- -moz-border-radius-topright: 4px;
- border-top-right-radius: 4px;
- background: rgba(0,0,0,0.3);
-}
-#cluster-page .status-box {
- width: 170px;
- height: auto;
+#cluster-page #node-list .item1 {
+ width: 18%;
+}
+#cluster-page #node-list .item2 {
+ width: 42%;
+}
+#cluster-page #node-list .item3 {
+ width: 18%;
+}
+#cluster-page #node-list .item4 {
+ width: 22%;
+}
+#cluster-page .node {
+ margin-bottom: 10px;
+ position: relative;
+}
+#cluster-page .node > div {
+ float: left;
+}
+#cluster-page .node > div.clear {
+ float: none;
+}
+#cluster-page .toggle-container {
+ overflow: visible;
+ padding: 0;
+}
+#cluster-page .toggle-container .actions-toggle {
+ width: 82px;
+ height: 30px;
+ position: relative;
+ overflow: visible;
+ padding: 0;
+ background: url("/admin/ui/images/actions-toggle-text.png") -5px top no-repeat rgba(0,0,0,0.3);
+ margin-top: 3px;
+}
+#cluster-page .toggle-container .actions-toggle a {
+ width: 48px;
+ height: 34px;
+ -webkit-transition: left 0.2s ease;
+ -moz-transition: left 0.2s ease;
+ -ms-transition: left 0.2s ease;
+ -webkit-transition: left 0.2s ease;
+ -moz-transition: left 0.2s ease;
+ -o-transition: left 0.2s ease;
+ transition: left 0.2s ease;
+ position: absolute;
+ display: inline-block;
+ background: url("/admin/ui/images/actions-toggle-slider.png") left top no-repeat transparent;
+ top: 0;
+ left: -5px;
+}
+#cluster-page .open .actions-toggle a {
+ -webkit-transition: left 0.2s ease;
+ -moz-transition: left 0.2s ease;
+ -ms-transition: left 0.2s ease;
+ -webkit-transition: left 0.2s ease;
+ -moz-transition: left 0.2s ease;
+ -o-transition: left 0.2s ease;
+ transition: left 0.2s ease;
+ left: 38px;
+}
+#cluster-page .name-box {
+ overflow: visible;
+}
+#cluster-page .ring-pct,
+#cluster-page .used-memory,
+#cluster-page .action-name {
+ font-family: 'menlo', 'consolas', 'monaco', monospace;
+}
+#cluster-page .used-memory {
+ display: inline-block;
+ padding: 0 0 0 5px;
+ vertical-align: middle;
+}
+#cluster-page .action-name {
+ display: inline-block;
+ padding-top: 8px;
+}
+#cluster-page .replacing-box .field-container {
+ width: 100%;
+}
+#cluster-page #planned-list .item1 {
+ width: 40%;
+}
+#cluster-page #planned-list .item2 {
+ width: 17%;
+}
+#cluster-page #planned-list .item3 {
+ width: 17%;
+}
+#cluster-page #planned-list .item4 {
+ width: 26%;
+}
+#cluster-page .plan-details-header {
+ margin-top: 30px;
+ padding: 10px 0;
+}
+#cluster-page .accept-plan {
+ position: relative;
+ padding: 15px 0;
+ margin-top: 15px;
+}
+#cluster-page .clear-plan-box {
+ border-top: 1px solid rgba(255,255,255,0.18);
+ margin-top: 25px;
+ padding-top: 25px;
+}
+#cluster-page .clear-plan-box a {
+ display: block;
+ margin-top: 15px;
+ margin-left: -5px;
+}
+#cluster-page .plan-details {
+ font-family: 'noticia', georgia, serif;
+ line-height: 1.5;
}
-#cluster-page .actions-header {
- padding-left: 6px;
+#cluster-page #commit-button {
+ position: absolute;
+ right: 0;
+ top: 12px;
+}
+#cluster-page .button-column {
+ text-align: right;
}
#cluster-page .pct-box {
margin-top: 8px;
@@ -959,27 +1231,30 @@ input.gui-rect-button:active {
margin: 0 5px 0 0;
display: none;
}
-#cluster-page #node-error {
- font-family: 'titillium', helvetica, arial, sans-serif;
- -webkit-box-shadow: 0 2px 3px rgba(0,0,0,0.3);
- -moz-box-shadow: 0 2px 3px rgba(0,0,0,0.3);
- box-shadow: 0 2px 3px rgba(0,0,0,0.3);
+#cluster-page .error-message {
+ font-family: 'noticia', georgia, serif;
+ -webkit-box-shadow: 0 2px 3px rgba(0,0,0,0.35);
+ -moz-box-shadow: 0 2px 3px rgba(0,0,0,0.35);
+ box-shadow: 0 2px 3px rgba(0,0,0,0.35);
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
- padding: 8px 10px 8px 12px;
+ font-size: 14px;
+ font-style: italic;
+ color: #ccc;
+ padding: 8px 10px 9px 12px;
background: rgba(232,78,78,0.5);
border: 1px solid rgba(235,105,105,0.5);
}
-#cluster-page #node-error .error-link {
+#cluster-page .error-message .error-link {
font-family: 'titillium', helvetica, arial, sans-serif;
font-weight: bold;
padding-left: 5px;
}
-#cluster-page #node-error .error-link:hover {
+#cluster-page .error-message .error-link:hover {
text-decoration: underline;
}
-#cluster-page #node-error .close-error {
+#cluster-page .error-message .close-error {
width: 16px;
height: 16px;
opacity: 0.6;
@@ -990,13 +1265,10 @@ input.gui-rect-button:active {
vertical-align: middle;
background: url("/admin/ui/images/close-error.png") left top no-repeat transparent;
}
-#cluster-page #node-error .close-error:hover {
+#cluster-page .error-message .close-error:hover {
opacity: 1;
filter: alpha(opacity=100);
}
-#cluster-page .ring_pct-box {
- width: 150px;
-}
#cluster-page .memory-box {
width: 175px;
}
@@ -1071,167 +1343,252 @@ input.gui-rect-button:active {
background-color: #404040;
width: 100%;
}
-#cluster-page .action-button {
- width: 45px;
- height: 45px;
- background: #434343;
- background: -moz-linear-gradient(top, #616161 0%, #434343 100%);
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #616161), color-stop(100%, #434343));
- background: -webkit-linear-gradient(top, #616161 0%, #434343 100%);
- background: -o-linear-gradient(top, #616161 0%, #434343 100%);
- background: -ms-linear-gradient(top, #616161 0%, #434343 100%);
- background: linear-gradient(top bottom, #616161 0%, #434343 100%);
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- -webkit-box-shadow: 0 2px 3px rgba(0,0,0,0.3);
- -moz-box-shadow: 0 2px 3px rgba(0,0,0,0.3);
- box-shadow: 0 2px 3px rgba(0,0,0,0.3);
- display: block;
- margin-bottom: 5px;
+#cluster-page .actions-pointer {
+ width: 72px;
+ height: 13px;
+ background: url("/admin/ui/images/pointer.png") center top no-repeat transparent;
+ margin-top: 8px;
}
-#cluster-page .action-button:hover {
- background: #434343;
- background: -moz-linear-gradient(top, #717171 0%, #434343 100%);
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #717171), color-stop(100%, #434343));
- background: -webkit-linear-gradient(top, #717171 0%, #434343 100%);
- background: -o-linear-gradient(top, #717171 0%, #434343 100%);
- background: -ms-linear-gradient(top, #717171 0%, #434343 100%);
- background: linear-gradient(top bottom, #717171 0%, #434343 100%);
-}
-#cluster-page .action-button:active,
-#cluster-page .action-button.pressed {
- background: #515151;
- background: -moz-linear-gradient(top, #434343 0%, #515151 100%);
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #434343), color-stop(100%, #515151));
- background: -webkit-linear-gradient(top, #434343 0%, #515151 100%);
- background: -o-linear-gradient(top, #434343 0%, #515151 100%);
- background: -ms-linear-gradient(top, #434343 0%, #515151 100%);
- background: linear-gradient(top bottom, #434343 0%, #515151 100%);
-}
-#cluster-page .disabled.action-button {
- background: #515151;
- background: -moz-linear-gradient(top, #434343 0%, #515151 100%);
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #434343), color-stop(100%, #515151));
- background: -webkit-linear-gradient(top, #434343 0%, #515151 100%);
- background: -o-linear-gradient(top, #434343 0%, #515151 100%);
- background: -ms-linear-gradient(top, #434343 0%, #515151 100%);
- background: linear-gradient(top bottom, #434343 0%, #515151 100%);
-}
-#cluster-page .action-icon {
- width: 45px;
- height: 45px;
- -webkit-box-shadow: inset 0 1px 2px rgba(255,255,255,0.18);
- -moz-box-shadow: inset 0 1px 2px rgba(255,255,255,0.18);
- box-shadow: inset 0 1px 2px rgba(255,255,255,0.18);
+#cluster-page .actions-box {
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
- display: block;
- background: url("/admin/ui/images/action-button-sprite.png") left top no-repeat transparent;
-}
-#cluster-page .actions-box {
- -webkit-border-bottom-left-radius: 10px;
- -moz-border-radius-bottomleft: 10px;
- border-bottom-left-radius: 10px;
- -webkit-border-bottom-right-radius: 10px;
- -moz-border-radius-bottomright: 10px;
- border-bottom-right-radius: 10px;
- -webkit-border-top-left-radius: 4px;
- -moz-border-radius-topleft: 4px;
- border-top-left-radius: 4px;
- background: rgba(0,0,0,0.3);
- margin-top: -6px;
+ width: 92%;
+ background: rgba(0,0,0,0.35);
margin-bottom: 15px;
border-bottom: 1px solid rgba(255,255,255,0.18);
- padding: 15px;
+ padding: 18px;
margin-right: 33px;
- display: none;
+ position: relative;
+}
+#cluster-page .actions-box > h4 {
+ display: block;
+ border-bottom: 1px solid rgba(255,255,255,0.18);
+ padding: 0 0 12px;
}
#cluster-page .actions-box > div > span {
- font-family: 'titillium', helvetica, arial, sans-serif;
- font-weight: bold;
+ font-family: 'noticia', georgia, serif;
color: #efefef;
padding-left: 3px;
}
-#cluster-page .markdown-box,
-#cluster-page .shutdown-box,
-#cluster-page .leave-cluster-box {
- margin-bottom: 10px;
- margin-right: 15px;
+#cluster-page .extra-actions {
+ opacity: 0.32;
+ filter: alpha(opacity=32);
+ padding-bottom: 25px;
+ height: 35px;
+ position: relative;
}
-#cluster-page .shutdown-button .action-icon {
- background-position: left bottom;
+#cluster-page .extra-actions > div {
+ float: left;
}
-#cluster-page .markdown-button .action-icon {
- background-position: 1px 1px;
+#cluster-page .extra-actions .gui-checkbox-wrapper {
+ margin-left: 15px;
}
-#cluster-page .leave-cluster-button .action-icon {
- background-position: 1px -44px;
+#cluster-page .extra-actions.active {
+ opacity: 1;
+ filter: alpha(opacity=100);
}
#cluster-page .replacement-controls {
- float: left;
width: auto;
+ margin-top: 18px;
+ border-bottom: 1px solid rgba(255,255,255,0.18);
+ margin-bottom: 10px;
+}
+#cluster-page .replacement-controls div {
+ margin-bottom: 8px;
+}
+#cluster-page .replacement-controls select {
+ margin-top: -38px;
}
#cluster-page .replacement-node-dropdown {
+ margin-bottom: 5px;
+}
+#cluster-page .right-angle-arrow {
+ width: 15px;
+ height: 18px;
+ background: url("/admin/ui/images/right-angle-arrow.png") left top no-repeat transparent;
+ margin: 0 10px 0 10px;
+}
+#cluster-page .disabler {
+ background: #f00;
+ opacity: 0.2;
+ filter: alpha(opacity=20);
+ position: absolute;
+ left: 0;
+ top: 0;
width: 100%;
+ height: 100%;
+ background: transparent;
+}
+#cluster-page .stage-button {
+ float: right;
+}
+#cluster-page .stage-instructions {
float: left;
- margin-bottom: 5px;
+ display: block;
+ width: 50%;
}
-@media screen and (min-width : 1100px) {
- #cluster-page .replacement-controls {
- width: 250px;
- }
+#cluster-page .no-joining-nodes {
+ padding-top: 6px;
+}
+#cluster-page .slide-up {
+ margin-top: -35px;
}
-@media screen and (max-width : 959px) {
- #cluster-page .free-memory {
+#cluster-page .semi-transparent {
+ opacity: 0.32;
+ filter: alpha(opacity=32);
+}
+@media screen and (max-width : 1200px) {
+ #cluster-page #area-separator {
display: none;
}
- #cluster-page .actions-box {
- margin-right: 0;
+ #cluster-page #current-area,
+ #cluster-page #planned-area {
+ width: 100%;
}
- #cluster-page .switch-box {
+ #cluster-page #planned-area {
+ padding-top: 30px;
+ border-top: 1px solid rgba(255,255,255,0.18);
+ }
+ #cluster-page .field-container {
+ width: 90%;
+ }
+ #cluster-page #node-list .item1 {
width: 100px;
}
- #cluster-page .switch-box div {
- width: 78px;
- padding-left: 0;
+ #cluster-page #node-list .item2 {
+ width: 500px;
}
- #cluster-page .switch-box > div {
- width: auto;
- padding: 0;
- text-align: center;
+ #cluster-page #node-list .item3 {
+ width: 100px;
}
- #cluster-page .actions-header {
- padding-left: 0;
- text-align: center;
+ #cluster-page #node-list .item4 {
+ width: 150px;
+ }
+ #cluster-page #planned-list .item1 {
+ width: 300px;
+ }
+ #cluster-page #planned-list .item2 {
+ width: 100px;
+ margin-left: 25px;
+ }
+ #cluster-page #planned-list .item3 {
+ width: 100px;
+ }
+ #cluster-page #planned-list .item4 {
+ width: 350px;
}
}
-@media screen and (max-width : 699px) {
- #cluster-page .status-box,
- #cluster-page .ring_pct-box,
- #cluster-page .memory-box {
- width: auto;
+@media screen and (max-width : 950px) {
+ #cluster-page #node-list .item1 {
+ width: 100px;
}
- #cluster-page .status-box {
- text-align: center;
+ #cluster-page #node-list .item2 {
+ width: 400px;
+ }
+ #cluster-page #node-list .item3 {
+ width: 100px;
+ }
+ #cluster-page #node-list .item4 {
+ width: 150px;
+ }
+ #cluster-page #planned-list .item1 {
+ width: 275px;
+ }
+ #cluster-page #planned-list .item2 {
+ width: 100px;
+ }
+ #cluster-page #planned-list .item3 {
+ width: 100px;
+ }
+ #cluster-page #planned-list .item4 {
+ width: 225px;
+ }
+}
+@media screen and (max-width : 850px) {
+ #cluster-page #node-list .item1 {
+ width: 100px;
}
- #cluster-page .gui-light span {
+ #cluster-page #node-list .item2 {
+ width: 300px;
+ }
+ #cluster-page #node-list .item2 .field-container {
+ width: 75%;
+ }
+ #cluster-page #node-list .item3 {
+ width: 100px;
+ }
+ #cluster-page #node-list .item4 {
+ width: 150px;
+ }
+ #cluster-page #planned-list .item3 {
display: none;
}
- #cluster-page .markdown-box,
- #cluster-page .shutdown-box,
- #cluster-page .leave-cluster-box {
- margin-right: 10px;
+ #cluster-page .used-memory {
+ display: none;
}
- #cluster-page .replacement-controls {
- margin-right: 0;
+}
+@media screen and (max-width : 700px) {
+ #cluster-page #node-list .item1 {
+ width: 100px;
+ }
+ #cluster-page #node-list .item2 {
+ width: 200px;
+ }
+ #cluster-page #node-list .item2 .field-container {
+ width: 75%;
+ }
+ #cluster-page #node-list .item3 {
+ width: 100px;
+ }
+ #cluster-page #node-list .item4 {
+ width: 150px;
+ }
+ #cluster-page #planned-list .item1 {
+ width: 200px;
+ }
+ #cluster-page #planned-list .item2 {
+ width: 100px;
+ margin-left: 0;
+ }
+ #cluster-page #planned-list .item4 {
+ width: 200px;
+ }
+ #cluster-page .gui-light {
+ display: none;
}
}
-@media screen and (max-width : 499px) {
- #cluster-page .switch-box div {
- padding: 0 7px 0 0;
- margin: 0 0 0 5px;
+@media screen and (max-width : 600px) {
+ #cluster-page #node-list .item1 {
+ display: none;
+ }
+ #cluster-page #node-list .item2 {
+ width: 40%;
+ }
+ #cluster-page #node-list .item2 .field-container {
+ width: 95%;
+ }
+ #cluster-page #node-list .item4 {
+ width: 100px;
+ }
+ #cluster-page #planned-list .item1 {
+ width: 40%;
+ }
+ #cluster-page #planned-list .item1 .field-container {
+ width: 95%;
+ }
+ #cluster-page #planned-list .item2 {
+ width: 20%;
+ margin-right: 2%;
+ }
+ #cluster-page #planned-list .item4 {
+ width: 38%;
+ }
+ #cluster-page #planned-list .item4 .field-container {
+ width: 95%;
+ }
+ #cluster-page .actions-container {
+ display: none;
}
}
#ring-page #ring-filter {
View
111 priv/admin/css/general.styl
@@ -190,7 +190,8 @@ th
right : 0
footer
- padding : 0 25px 0
+ padding : 0 25px 0
+ margin-bottom : 25px
.title-box
dimensions(16%, auto)
@@ -259,15 +260,16 @@ footer
/* CODE FOR POINT BUTTONS */
-.gui-point-button, .gui-rect-button
+.gui-point-button, .gui-rect-button, .gui-point-button-right
dimensions(137px, 40px)
display : inline-block
cursor : pointer
border : 0
margin-top : 3px
-.gui-point-button { background: url('/admin/ui/images/pointbutton-sprite.png') left top no-repeat transparent; }
-.gui-rect-button { background: url('/admin/ui/images/rectbutton-sprite.png') left top no-repeat transparent; }
+.gui-point-button { background: url('/admin/ui/images/pointbutton-sprite.png') left top no-repeat transparent; }
+.gui-point-button-right { background: url('/admin/ui/images/pointbutton-right-sprite.png') left top no-repeat transparent; }
+.gui-rect-button { background: url('/admin/ui/images/rectbutton-sprite.png') left top no-repeat transparent; }
.gui-button-msg
headline-bold()
@@ -276,21 +278,28 @@ footer
padding-top : 8px
text-align : center
-.gui-point-button:hover, .gui-rect-button:hover
+.gui-point-button-right .gui-button-msg
+ padding-right : 11px
+
+.gui-point-button:hover, .gui-rect-button:hover, .gui-point-button-right:hover
background-position : left -40px
-.gui-point-button:active, .gui-point-button.pressed, .gui-rect-button:active, .gui-rect-button.pressed
+.gui-point-button:active, .gui-point-button.pressed,
+.gui-rect-button:active, .gui-rect-button.pressed,
+.gui-point-button-right:active, .gui-point-button-right.pressed
background-position : left -80px !important
-.gui-point-button:active .gui-button-msg,
-.gui-point-button.pressed .gui-button-msg,
-.gui-rect-button:active .gui-button-msg,
-.gui-rect-button.pressed .gui-button-msg { padding-top : 9px; }
+.gui-point-button:active .gui-button-msg,
+.gui-point-button.pressed .gui-button-msg,
+.gui-rect-button:active .gui-button-msg,
+.gui-rect-button.pressed .gui-button-msg,
+.gui-point-button-right:active .gui-button-msg,
+.gui-point-button-right.pressed .gui-button-msg { padding-top : 9px; }
-input.gui-point-button, input.gui-rect-button
+input.gui-point-button, input.gui-rect-button, input.gui-point-button-right
padding-bottom : 12px
-input.gui-point-button:active, input.gui-rect-button:active
+input.gui-point-button:active, input.gui-rect-button:active, input.gui-point-button-right:active
padding-bottom : 9px
.button-column
@@ -314,39 +323,47 @@ input.gui-point-button:active, input.gui-rect-button:active
/* END CODE FOR TOGGLE SWITCHES */
-/* CODE FOR CHECKBOXES */
+/* CODE FOR CHECKBOXES AND RADIO BUTTONS */
-.gui-checkbox-wrapper
+.gui-checkbox-wrapper, .gui-radio-wrapper
dimensions(auto, 24px)
background : url('/admin/ui/images/checkbox-sprite.png') left top no-repeat transparent
vertical-align : middle
margin-top : 5px
+
+ &.default
+ background-position : left bottom
- span
+ span, label
headline-bold()
display : inline-block
margin : 5px 0 0 8px
color : lightGray
-.gui-checkbox
+ &.serif
+ copy-font()
+ font-weight : normal
+ color : mediumGray
+ font-style : italic
+
+.gui-radio-wrapper
+ background : url('/admin/ui/images/radio-sprite.png') left top no-repeat transparent
+
+.gui-checkbox, .gui-radio
dimensions(25px, 24px)
opaque(0)
display : inline-block
float : left
- margin : 0
-
-.gui-checkbox[checked=checked]
-
-
+ margin : 0
-.gui-checkbox-wrapper .gui-text
+.gui-checkbox-wrapper .gui-text, .gui-radio-wrapper .gui-text
dimensions(auto, 24px)
display : block
float : left
padding-left : 5px
font-size : 15px
-/* END CODE FOR CHECKBOXES */
+/* END CODE FOR CHECKBOXES AND RADIO BUTTONS */
/* CODE FOR PAGINATION */
.pagination
@@ -434,14 +451,14 @@ input.gui-point-button:active, input.gui-rect-button:active
corners()
vendor('box-shadow', inset 0 1px 3px darkened)
background : darkened
- padding : 8px
+ padding : 10px
border-bottom : 1px solid lightWhite
margin-right : 2em
.gui-input
@extend .gui-field
dimensions(100%, auto)
- padding : 6px 8px
+ padding : 8px
border-left : 0
border-right : 0
border-top : 0
@@ -452,7 +469,7 @@ input.gui-point-button:active, input.gui-rect-button:active
.gui-light
background : url('/admin/ui/images/light-sprite.png') left top no-repeat transparent
- padding : 9px 0 9px 33px
+ padding : 11px 0 9px 33px
min-height : 14px
min-width : 14px
display : inline-block
@@ -495,6 +512,9 @@ input.gui-point-button:active, input.gui-rect-button:active
copy-font()
font-style : italic
+.serif
+ copy-font()
+
.left
float : left
@@ -504,13 +524,16 @@ input.gui-point-button:active, input.gui-rect-button:active
.unreachable
color : riakred
+.inline-block
+ display : inline-block
+
/* RESPONSIVE MEDIA QUERIES */
@media screen and (min-width : 1100px)
#wrapper
- width : 1100px
+ max-width : 1500px
@media screen and (max-width : 699px)
@@ -547,8 +570,38 @@ input.gui-point-button:active, input.gui-rect-button:active
width : 212px
@media screen and (max-width : 499px)
+
+ #header
+ height : 44px
+
+ #navbar, #nav-ul
+ height : 41px
+
+ .nav-li
+ dimensions(45px, 41px)
+
+ .nav-item
+ dimensions(45px, 41px)
+ background : url('/admin/ui/images/nav-icons-small.png') center bottom no-repeat transparent
+
+ .indicator
+ dimensions(45px, 2px)
+
+ #riak-control-logo
+ dimensions(123px, 32px)
+ background : url('/admin/ui/images/riak-control-logo-small.png') right bottom no-repeat transparent
+ margin : 6px 0 0 10px
+
+ #nav-snapshot a
+ background-position : 8px -237px
+
+ #nav-cluster a
+ background-position : 8px 11px
+
+ #nav-ring a
+ background-position : 8px -24px
- h1
- hSize(30px, 0, 5px)
+ h1
+ hSize(30px, 0, 5px)
/* END RESPONSIVE MEDIA QUERIES */
View
18 priv/admin/css/reusable.styl
@@ -1,7 +1,7 @@
/* Variables */
coverup = rgba(0, 0, 0, .85)
-darkened = rgba(0, 0, 0, .3)
+darkened = rgba(0, 0, 0, .35)
darkGray = #2d2d2d
mediumGray = #cccccc
lightGray = #efefef
@@ -92,4 +92,20 @@ headline-bold()
headline-font()
font-weight : bold
+// Applies a css transition
+css-transition(args) {
+ -webkit-transition : args
+ -moz-transition : args
+ -ms-transition : args
+ transition : args
+}
+
+// Applies a css transform
+css-transform(args) {
+ -webkit-transform : rotate(args)
+ -moz-transform : rotate(args)
+ -o-transform : rotate(args)
+ transform : rotate(args)
+}
+
/* End Functions */
View
15 priv/admin/css/snapshot.styl
@@ -23,22 +23,31 @@ CSS to be applied ONLY on the snapshot page
margin : 10px 0 0 20px
li
- monospace()
+ headline-font()
line-height : 1.5
+ font-size : 15px
a
color : lightGray
#health-indicator
- dimensions(311px, 309px)
float : left
margin-right : 25px
+ #healthy-cluster #health-indicator
+ dimensions(337px, 310px)
+
+ #unhealthy-cluster #health-indicator
+ dimensions(311px, 309px)
+
/* RESPONSIVE MEDIA QUERIES */
@media screen and (max-width : 899px)
- #health-indicator
+ #healthy-cluster #health-indicator
+ dimensions(279px, 249px)
+
+ #unhealthy-cluster #health-indicator
dimensions(250px, 249px)
#healthy-cluster section, #unhealthy-cluster section
View
BIN  priv/admin/images/actions-toggle-slider.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  priv/admin/images/actions-toggle-text.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  priv/admin/images/nav-icons-small.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  priv/admin/images/pointbutton-right-sprite.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  priv/admin/images/pointer.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  priv/admin/images/radio-sprite.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  priv/admin/images/riak-control-logo-small.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  priv/admin/images/right-angle-arrow.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  priv/admin/images/stagebutton-sprite.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
24 priv/admin/js/app.js
@@ -41,6 +41,30 @@ minispade.register('app', function() {
RiakControl.store = RiakControl.Store.create();
+ // Automatically add CSRF tokens to AJAX requests.
+ $("body").bind("ajaxSend", function(elm, xhr, s){
+ var csrf_token = $('meta[name=csrf_token]').attr('content');
+
+ if(s.type === 'POST' || s.type === 'PUT') {
+ xhr.setRequestHeader('X-CSRF-Token', csrf_token);
+ }
+ });
+
+ // Set default content-type for AJAX requests.
+ // From: http://stackoverflow.com/questions/1749272/jquery-how-to-put-json-via-ajax
+ $.ajaxSetup({
+ contentType: 'application/json',
+ processData: false
+ });
+
+ // Prefilter for stringifying.
+ // From: http://stackoverflow.com/questions/1749272/jquery-how-to-put-json-via-ajax
+ $.ajaxPrefilter(function(options, originalOptions, jqXHR) {
+ if(options.data) {
+ options.data = JSON.stringify(options.data);
+ }
+ });
+
minispade.require('core');
minispade.require('router');
minispade.require('snapshot');
View
743 priv/admin/js/cluster.js
@@ -3,11 +3,410 @@ minispade.register('cluster', function() {
/**
* @class
*
+ * Responsible for modeling one specific cluster node.
+ */
+ RiakControl.CurrentClusterNode = Ember.Object.extend(
+ /** @scope RiakControl.CurrentClusterNode.prototype */ {});
+
+ /**
+ * @class
+ *
+ * Responsible for modeling one specific cluster node.
+ */
+ RiakControl.StagedClusterNode = Ember.Object.extend(
+ /** @scope RiakControl.StagedClusterNode.prototype */ {
+
+ /**
+ * Does the node have a replacement?
+ *
+ * @returns {boolean}
+ */
+ isReplaced: function() {
+ return this.get('replacement') !== "undefined" ? true : false;
+ }.property('replacement'),
+
+ /**
+ * Is the node taking an action?
+ *
+ * @returns {boolean}
+ */
+ isAction: function() {
+ return this.get('action') !== "undefined" ? true : false;
+ }.property('action')
+
+ });
+
+ /**
+ * @class
+ *
+ * Responsible for modeling the current and staged cluster.
+ */
+ RiakControl.CurrentAndPlannedCluster = Ember.Object.extend(
+ /** @scope RiakControl.CurrentAndPlannedCluster.prototype */ {});
+
+ /**
+ * @class
+ *
* ClusterController is responsible for display the list of nodes
* in the cluster. This controller is basically a placeholder and
* wrapper around the legacy cluster page until we rewrite it.
*/
- RiakControl.ClusterController = Ember.ArrayController.extend();
+ RiakControl.ClusterController = Ember.ObjectController.extend(
+ /** @scope RiakControl.ClusterController.prototype */ {
+
+ /**
+ * Refresh a particular cluster, giving a cluster returned as JSON,
+ * and a cluster modeled in Ember.
+ *
+ * Not computationally efficient at all, but explicit for debugging
+ * the Ember bindings and propagation.
+ *
+ * @returns {void}
+ */
+ refresh: function(newCluster, existingCluster, nodeFactory) {
+ newCluster.forEach(function(node) {
+ var exists = existingCluster.findProperty('name', node.name);
+
+ // If it doesn't exist yet, add it. If it does, update it.
+ if(exists !== undefined) {
+ exists.setProperties(node);
+ } else {
+ existingCluster.pushObject(nodeFactory.create(node));
+ }
+ });
+
+ // Iterate the cluster removing nodes that shouldn't
+ // be there.
+ var changesOccurred = false;
+ var replacementCluster = [];
+
+ existingCluster.forEach(function(node, i) {
+ var exists = newCluster.findProperty('name', node.name);
+
+ if(exists === undefined) {
+ node.destroy();
+ changesOccurred = true;
+ } else {
+ replacementCluster.pushObject(node);
+ }
+ });
+
+ if(changesOccurred) {
+ existingCluster.set('[]', replacementCluster.get('[]'));
+ }
+ },
+
+ /**
+ * Load data from server.
+ *
+ * @returns {void}
+ */
+ load: function() {
+ var self = this;
+
+ $.ajax({
+ type: 'GET',
+ url: '/admin/cluster',
+ dataType: 'json',
+
+ success: function(d) {
+ var updatedCurrentCluster = d.cluster.current;
+ var currentCurrentCluster = self.get('content.currentCluster');
+
+ self.refresh(updatedCurrentCluster,
+ currentCurrentCluster, RiakControl.CurrentClusterNode);
+
+ var updatedStagedCluster = d.cluster.staged;
+
+ if(updatedStagedCluster === 'ring_not_ready') {
+ self.set('ringNotReady', true);
+ } else {
+ self.set('ringNotReady', false);
+ }
+
+ if(updatedStagedCluster === 'legacy') {
+ self.set('legacyRing', true);
+ } else {
+ self.set('legacyRing', false);
+ }
+
+ if($.isArray(updatedStagedCluster)) {
+ var currentStagedCluster = self.get('content.stagedCluster');
+
+ self.refresh(updatedStagedCluster,
+ currentStagedCluster, RiakControl.StagedClusterNode);
+ }
+ },
+
+ error: function (jqXHR, textStatus, errorThrown) {
+ if(jqXHR.status === 404 || jqXHR.status === 0) {
+ self.get('displayError').call(self, undefined, undefined, "The node hosting Riak Control is unavailable.");
+ } else {
+ self.get('displayError').call(self, jqXHR, textStatus, errorThrown);
+ }
+ }
+ });
+ },
+