Browse Source

refactor(dashboard): Restructured front-end dashboard code.

Ed Rooth 12 years ago
parent
commit
06f990236c

+ 2 - 0
mod/dashboard/README.md

@@ -22,6 +22,8 @@ bower install
 
 
 ### View in Browser
 ### View in Browser
 
 
+run `export ETCD_DASHBOARD_DIR=/absolute/path/to/coreos/etcd/mod/dashboard/app`  
+
 Run etcd like you normally would and afterward browse to:
 Run etcd like you normally would and afterward browse to:
 
 
 http://localhost:4001/mod/dashboard/
 http://localhost:4001/mod/dashboard/

+ 0 - 1
mod/dashboard/app/.buildignore

@@ -1 +0,0 @@
-*.coffee

+ 0 - 50
mod/dashboard/app/browser.html

@@ -1,50 +0,0 @@
-<!doctype html>
-<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
-<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
-<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
-<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
-  <head>
-    <meta charset="utf-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge">
-    <title>etcd Browser</title>
-    <meta name="description" content="">
-    <meta name="viewport" content="width=device-width">
-    <!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
-
-        <!-- build:css(.tmp) styles/main.css -->
-        <link rel="stylesheet" href="styles/etcd-widgets.css">
-        <link href="http://fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400,400italic,600,700,900" rel="stylesheet" type="text/css">
-        <link href="http://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600,700" rel="stylesheet" type="text/css">
-        <!-- endbuild -->
-</head>
-  <body ng-app="etcdBrowser">
-    <!--[if lt IE 7]>
-      <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
-    <![endif]-->
-
-    <!--[if lt IE 9]>
-      <script src="bower_components/es5-shim/es5-shim.js"></script>
-      <script src="bower_components/json3/lib/json3.min.js"></script>
-    <![endif]-->
-
-    <!-- Add your site or application content here -->
-    <div id="etd_browser" ng-view="etcd">
-    </div>
-        <!-- build:js scripts/browser-modules.js -->
-        <script src="bower_components/jquery/jquery.js"></script>
-        <script src="bower_components/angular/angular.js"></script>
-        <script src="bower_components/angular-resource/angular-resource.js"></script>
-        <script src="bower_components/angular-route/angular-route.js"></script>
-        <script src="bower_components/angular-cookies/angular-cookies.js"></script>
-        <script src="bower_components/angular-sanitize/angular-sanitize.js"></script>
-        <script src="bower_components/underscore/underscore.js"></script>
-        <script src="bower_components/moment/moment.js"></script>
-        <!-- endbuild -->
-
-        <!-- build:js({.tmp,app}) scripts/browser-scripts.js -->
-        <script src="scripts/ng-time-relative.min.js"></script>
-        <script src="scripts/common/services/etcd.js"></script>
-        <script src="scripts/controllers/browser.js"></script>
-        <!-- endbuild -->
-</body>
-</html>

+ 7 - 0
mod/dashboard/app/img/add.svg

@@ -0,0 +1,7 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+  preserveAspectRatio="xMinYMin" viewBox="0 0 72.556 61" enable-background="new 0 0 72.556 61" xml:space="preserve">
+  <path d="M34.521,8v11.088v23v10.737c0,2.209,1.791,4,4,4c2.209,0,4-1.791,4-4V42.067V19.109V8c0-2.209-1.791-4-4-4
+  C36.312,4,34.521,5.791,34.521,8z"/>
+  <path d="M16.109,34.412h11.088h23h10.737c2.209,0,4-1.791,4-4c0-2.209-1.791-4-4-4H50.175H27.217H16.109c-2.209,0-4,1.791-4,4
+  C12.109,32.621,13.9,34.412,16.109,34.412z"/>
+</svg>

+ 6 - 0
mod/dashboard/app/img/back.svg

@@ -0,0 +1,6 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+  preserveAspectRatio="xMinYMin" viewBox="0 0 73.356 61" enable-background="new 0 0 73.356 61" xml:space="preserve">
+  <path d="M5.27,33.226l22.428,22.428c1.562,1.562,4.095,1.562,5.657,0c1.562-1.562,1.562-4.095,0-5.657L17.77,34.413h48.514
+  c2.209,0,4-1.791,4-4s-1.791-4-4-4H17.749l15.604-15.582c1.563-1.561,1.565-4.094,0.004-5.657C32.576,4.391,31.552,4,30.527,4
+  c-1.023,0-2.046,0.39-2.827,1.169L5.272,27.567c-0.751,0.75-1.173,1.768-1.173,2.829C4.098,31.458,4.52,32.476,5.27,33.226z"/>
+</svg>

+ 7 - 0
mod/dashboard/app/img/delete.svg

@@ -0,0 +1,7 @@
+<svg version="1.1" fill="#f00" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+  x="0px" y="0px" preserveAspectRatio="xMinYMin" viewBox="0 0 76.143 61" enable-background="new 0 0 76.143 61" xml:space="preserve">
+  <path d="M49.41,13.505l-6.035,6.035L27.112,35.803l-6.035,6.035c-1.562,1.562-1.562,4.095,0,5.657c1.562,1.562,4.095,1.562,5.657,0
+  l6.05-6.05l16.234-16.234l6.05-6.05c1.562-1.562,1.562-4.095,0-5.657C53.505,11.943,50.972,11.943,49.41,13.505z"/>
+  <path d="M21.077,19.162l6.035,6.035L43.375,41.46l6.035,6.035c1.562,1.562,4.095,1.562,5.657,0c1.562-1.562,1.562-4.095,0-5.657
+  l-6.05-6.05L32.783,19.555l-6.05-6.05c-1.562-1.562-4.095-1.562-5.657,0C19.515,15.067,19.515,17.6,21.077,19.162z"/>
+</svg>

+ 46 - 0
mod/dashboard/app/img/logo.svg

@@ -0,0 +1,46 @@
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+     preserveAspectRatio="xMinYMin" viewBox="0 0 792 306" enable-background="new 0 0 792 306" xml:space="preserve">
+  <g>
+    <g>
+      <path fill="#53A3DA" d="M136.168,45.527C76.898,45.527,28.689,93.739,28.689,153c0,59.265,48.209,107.474,107.479,107.474
+          c59.252,0,107.465-48.209,107.465-107.474C243.633,93.739,195.42,45.527,136.168,45.527z"/>
+      <path fill="#F1606D" d="M136.168,55.389c-17.283,0-31.941,27.645-37.235,66.069c-0.169,1.236-0.333,2.487-0.478,3.746
+          c-0.723,6.047-1.213,12.335-1.458,18.808c-0.117,2.962-0.175,5.956-0.175,8.988c0,3.029,0.058,6.029,0.175,8.985
+          c0.245,6.472,0.735,12.764,1.458,18.811c8.104,1.049,16.769,1.761,25.807,2.099c3.907,0.146,7.872,0.233,11.907,0.233
+          c4.023,0,8-0.088,11.895-0.233c9.049-0.338,17.708-1.05,25.819-2.099c0.892-0.114,1.77-0.239,2.659-0.368
+          c33.754-4.74,57.235-15.232,57.235-27.428C233.776,99.088,190.071,55.389,136.168,55.389z"/>
+      <path fill="#FFFFFF" d="M176.541,125.569c-0.979-1.428-2.029-2.796-3.148-4.11c-8.956-10.557-22.297-17.265-37.224-17.265
+          c-4.839,0-9.148,7.407-11.907,18.909c-1.096,4.586-1.947,9.819-2.495,15.498c-0.432,4.551-0.665,9.391-0.665,14.399
+          s0.233,9.849,0.665,14.396c4.554,0.432,9.387,0.664,14.402,0.664c5.009,0,9.842-0.232,14.396-0.664
+          c10.011-0.95,18.653-2.875,24.775-5.411c6.046-2.501,9.624-5.615,9.624-8.985C184.963,142.832,181.858,133.388,176.541,125.569z"
+          />
+    </g>
+    <g>
+      <path fill="#231F20" d="M344.891,100.053c12.585,0,22.816,6.138,29.262,13.062l-10.064,11.326
+          c-5.353-5.192-11.175-8.495-19.041-8.495c-16.839,0-28.953,14.16-28.953,37.291c0,23.448,11.169,37.608,28.32,37.608
+          c9.128,0,15.895-3.775,21.717-10.228l10.067,11.169c-8.335,9.598-19.038,14.95-32.099,14.95c-26.119,0-46.731-18.88-46.731-53.025
+          C297.37,120.036,318.454,100.053,344.891,100.053z"/>
+      <path fill="#231F20" d="M416.961,125.701c19.352,0,36.822,14.793,36.822,40.597c0,25.647-17.471,40.439-36.822,40.439
+          c-19.197,0-36.66-14.792-36.66-40.439C380.301,140.494,397.764,125.701,416.961,125.701z M416.961,191.945
+          c11.33,0,18.25-10.228,18.25-25.647c0-15.577-6.92-25.804-18.25-25.804s-18.094,10.227-18.094,25.804
+          C398.867,181.717,405.631,191.945,416.961,191.945z"/>
+      <path fill="#231F20" d="M459.771,127.589h14.943l1.26,13.688h0.629c5.506-10.07,13.691-15.577,21.871-15.577
+          c3.938,0,6.455,0.472,8.811,1.574l-3.148,15.734c-2.67-0.784-4.717-1.257-8.018-1.257c-6.139,0-13.539,4.245-18.256,15.893v47.203
+          h-18.092V127.589z"/>
+      <path fill="#231F20" d="M541.121,125.701c20.928,0,31.941,15.107,31.941,36.667c0,3.458-0.314,6.604-0.787,8.495h-49.09
+          c1.57,14.003,10.379,21.869,22.811,21.869c6.613,0,12.273-2.041,17.941-5.662l6.135,11.326
+          c-7.395,4.878-16.676,8.341-26.432,8.341c-21.404,0-38.08-14.95-38.08-40.439C505.561,141.12,523.023,125.701,541.121,125.701z
+           M557.326,159.376c0-12.277-5.189-19.671-15.732-19.671c-9.125,0-16.996,6.768-18.57,19.671H557.326z"/>
+      <path fill="#F1606D" d="M600.602,152.607c0-32.729,17.785-53.344,42.799-53.344c24.863,0,42.641,20.615,42.641,53.344
+          c0,32.889-17.777,54.13-42.641,54.13C618.387,206.737,600.602,185.496,600.602,152.607z M678.49,152.607
+          c0-28.639-14.158-46.731-35.09-46.731c-21.084,0-35.248,18.093-35.248,46.731c0,28.796,14.164,47.521,35.248,47.521
+          C664.332,200.128,678.49,181.403,678.49,152.607z"/>
+      <path fill="#53A4D9" d="M699.738,186.125c7.557,8.495,18.412,14.003,30.529,14.003c15.732,0,25.807-8.499,25.807-20.767
+          c0-12.904-8.494-17.154-18.723-21.717l-15.736-7.082c-8.969-3.936-20.934-10.385-20.934-25.808
+          c0-14.947,12.904-25.492,30.059-25.492c12.588,0,22.658,5.665,28.949,12.435l-4.244,4.878c-5.982-6.452-14.32-10.7-24.705-10.7
+          c-13.691,0-22.816,7.239-22.816,18.565c0,11.962,10.385,16.521,17.936,19.985l15.738,6.921
+          c11.486,5.195,21.713,11.647,21.713,27.539s-13.061,27.851-33.201,27.851c-15.107,0-26.75-6.451-34.932-15.576L699.738,186.125z"
+          />
+    </g>
+  </g>
+</svg>

+ 50 - 121
mod/dashboard/app/index.html

@@ -1,8 +1,6 @@
-<!doctype html>
-<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
-<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
-<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
-<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
+<!DOCTYPE html>
+
+<html class="no-js" ng-app="etcdControlPanel" ng-controller="RootCtrl">
   <head>
   <head>
     <meta charset="utf-8">
     <meta charset="utf-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
@@ -11,124 +9,55 @@
     <meta name="viewport" content="width=device-width">
     <meta name="viewport" content="width=device-width">
     <link href="http://fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400,400italic,600,700,900" rel="stylesheet" type="text/css">
     <link href="http://fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400,400italic,600,700,900" rel="stylesheet" type="text/css">
     <link href="http://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600,700" rel="stylesheet" type="text/css">
     <link href="http://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600,700" rel="stylesheet" type="text/css">
-    <style>
-        body {
-            padding: 30px;
-            margin: 0px;
-        }
-        h1 {
-            font-family: "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif;
-            font-weight: 400;
-            margin: 0px 0px 20px 0px;
-            padding: 0px;
-        }
-        iframe {
-            border: none;
-        }
-
-        a {
-            color: #1e6ec1;
-            text-decoration: none;
-        }
-
-        a:hover {
-            text-decoration: underline;
-        }
-
-        iframe {
-            margin-bottom: 30px;
-        }
-
-        iframe + iframe {
-            margin-bottom: 0px;
-        }
-
-        #footer {
-            width: 100%;
-            font-family: "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif;
-            margin-top: 20px;
-        }
-
-            #coreos-logo {
-                margin: 10px auto 0 auto;
-                height: 30px;
-                width: 80px;
-            }
+    <link rel="stylesheet" href="styles/bootstrap.css">
+    <link rel="stylesheet" href="styles/main.css">
+    <link rel="stylesheet" href="styles/browser.css">
+    <link rel="stylesheet" href="styles/stats.css">
+    <link rel="stylesheet" href="styles/etcd-widgets.css">
+  </head>
+
+  <body>
+    <h1>etcd Dashboard</h1>
 
 
-                #coreos-logo svg {
-                    fill: #999;
-                    max-width: 100px;
-                    display: inline-block;
-                    vertical-align: middle;
-                }
+    <div ng-view></div>
 
 
-            #powered-by {
-                font-size: 12px;
-                color: #333;
-                width: 100%;
-                display: inline-block;
-                vertical-align: middle;
-                line-height: 190%;
-                text-align: center;
-            }
-    </style>
-</head>
-<body>
-    <h1>etcd Dashboard</h1>
-    <iframe src="stats.html" style="width: 100%; height: 400px;"></iframe>
-    <iframe src="browser.html" style="width: 100%; height: 400px;"></iframe>
     <div id="footer">
     <div id="footer">
-        <div id="powered-by">Powered by <a href="https://github.com/coreos/etcd">etcd</a></div>
-        <div id="coreos-logo">
-            <a href="http://coreos.com">
-                <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-                     preserveAspectRatio="xMinYMin" viewBox="0 0 792 306" enable-background="new 0 0 792 306" xml:space="preserve">
-                <g>
-                    <g>
-                        <path fill="#53A3DA" d="M136.168,45.527C76.898,45.527,28.689,93.739,28.689,153c0,59.265,48.209,107.474,107.479,107.474
-                            c59.252,0,107.465-48.209,107.465-107.474C243.633,93.739,195.42,45.527,136.168,45.527z"/>
-                        <path fill="#F1606D" d="M136.168,55.389c-17.283,0-31.941,27.645-37.235,66.069c-0.169,1.236-0.333,2.487-0.478,3.746
-                            c-0.723,6.047-1.213,12.335-1.458,18.808c-0.117,2.962-0.175,5.956-0.175,8.988c0,3.029,0.058,6.029,0.175,8.985
-                            c0.245,6.472,0.735,12.764,1.458,18.811c8.104,1.049,16.769,1.761,25.807,2.099c3.907,0.146,7.872,0.233,11.907,0.233
-                            c4.023,0,8-0.088,11.895-0.233c9.049-0.338,17.708-1.05,25.819-2.099c0.892-0.114,1.77-0.239,2.659-0.368
-                            c33.754-4.74,57.235-15.232,57.235-27.428C233.776,99.088,190.071,55.389,136.168,55.389z"/>
-                        <path fill="#FFFFFF" d="M176.541,125.569c-0.979-1.428-2.029-2.796-3.148-4.11c-8.956-10.557-22.297-17.265-37.224-17.265
-                            c-4.839,0-9.148,7.407-11.907,18.909c-1.096,4.586-1.947,9.819-2.495,15.498c-0.432,4.551-0.665,9.391-0.665,14.399
-                            s0.233,9.849,0.665,14.396c4.554,0.432,9.387,0.664,14.402,0.664c5.009,0,9.842-0.232,14.396-0.664
-                            c10.011-0.95,18.653-2.875,24.775-5.411c6.046-2.501,9.624-5.615,9.624-8.985C184.963,142.832,181.858,133.388,176.541,125.569z"
-                            />
-                    </g>
-                    <g>
-                        <path fill="#231F20" d="M344.891,100.053c12.585,0,22.816,6.138,29.262,13.062l-10.064,11.326
-                            c-5.353-5.192-11.175-8.495-19.041-8.495c-16.839,0-28.953,14.16-28.953,37.291c0,23.448,11.169,37.608,28.32,37.608
-                            c9.128,0,15.895-3.775,21.717-10.228l10.067,11.169c-8.335,9.598-19.038,14.95-32.099,14.95c-26.119,0-46.731-18.88-46.731-53.025
-                            C297.37,120.036,318.454,100.053,344.891,100.053z"/>
-                        <path fill="#231F20" d="M416.961,125.701c19.352,0,36.822,14.793,36.822,40.597c0,25.647-17.471,40.439-36.822,40.439
-                            c-19.197,0-36.66-14.792-36.66-40.439C380.301,140.494,397.764,125.701,416.961,125.701z M416.961,191.945
-                            c11.33,0,18.25-10.228,18.25-25.647c0-15.577-6.92-25.804-18.25-25.804s-18.094,10.227-18.094,25.804
-                            C398.867,181.717,405.631,191.945,416.961,191.945z"/>
-                        <path fill="#231F20" d="M459.771,127.589h14.943l1.26,13.688h0.629c5.506-10.07,13.691-15.577,21.871-15.577
-                            c3.938,0,6.455,0.472,8.811,1.574l-3.148,15.734c-2.67-0.784-4.717-1.257-8.018-1.257c-6.139,0-13.539,4.245-18.256,15.893v47.203
-                            h-18.092V127.589z"/>
-                        <path fill="#231F20" d="M541.121,125.701c20.928,0,31.941,15.107,31.941,36.667c0,3.458-0.314,6.604-0.787,8.495h-49.09
-                            c1.57,14.003,10.379,21.869,22.811,21.869c6.613,0,12.273-2.041,17.941-5.662l6.135,11.326
-                            c-7.395,4.878-16.676,8.341-26.432,8.341c-21.404,0-38.08-14.95-38.08-40.439C505.561,141.12,523.023,125.701,541.121,125.701z
-                             M557.326,159.376c0-12.277-5.189-19.671-15.732-19.671c-9.125,0-16.996,6.768-18.57,19.671H557.326z"/>
-                        <path fill="#F1606D" d="M600.602,152.607c0-32.729,17.785-53.344,42.799-53.344c24.863,0,42.641,20.615,42.641,53.344
-                            c0,32.889-17.777,54.13-42.641,54.13C618.387,206.737,600.602,185.496,600.602,152.607z M678.49,152.607
-                            c0-28.639-14.158-46.731-35.09-46.731c-21.084,0-35.248,18.093-35.248,46.731c0,28.796,14.164,47.521,35.248,47.521
-                            C664.332,200.128,678.49,181.403,678.49,152.607z"/>
-                        <path fill="#53A4D9" d="M699.738,186.125c7.557,8.495,18.412,14.003,30.529,14.003c15.732,0,25.807-8.499,25.807-20.767
-                            c0-12.904-8.494-17.154-18.723-21.717l-15.736-7.082c-8.969-3.936-20.934-10.385-20.934-25.808
-                            c0-14.947,12.904-25.492,30.059-25.492c12.588,0,22.658,5.665,28.949,12.435l-4.244,4.878c-5.982-6.452-14.32-10.7-24.705-10.7
-                            c-13.691,0-22.816,7.239-22.816,18.565c0,11.962,10.385,16.521,17.936,19.985l15.738,6.921
-                            c11.486,5.195,21.713,11.647,21.713,27.539s-13.061,27.851-33.201,27.851c-15.107,0-26.75-6.451-34.932-15.576L699.738,186.125z"
-                            />
-                    </g>
-                </g>
-                </svg>
-            </a>
-        </div>
+      <div id="powered-by">Powered by <a href="https://github.com/coreos/etcd">etcd</a></div>
+      <div id="coreos-logo">
+        <a href="http://coreos.com"><img src="img/logo.svg"/></a>
+      </div>
     </div>
     </div>
-</body>
+
+    <!-- build:js scripts/stats-modules.js -->
+    <script src="bower_components/jquery/jquery.js"></script>
+    <script src="bower_components/angular/angular.js"></script>
+    <script src="bower_components/angular-resource/angular-resource.js"></script>
+    <script src="bower_components/angular-route/angular-route.js"></script>
+    <script src="bower_components/angular-cookies/angular-cookies.js"></script>
+    <script src="bower_components/angular-sanitize/angular-sanitize.js"></script>
+    <script src="bower_components/d3/d3.js"></script>
+    <script src="bower_components/underscore/underscore.js"></script>
+    <script src="bower_components/underscore.string/lib/underscore.string.js"></script>
+    <script src="bower_components/moment/moment.js"></script>
+    <!-- endbuild -->
+
+    <script src="scripts/app.js"></script>
+    <script src="scripts/controllers/root.js"></script>
+    <script src="scripts/directives.js"></script>
+    <script src="scripts/shims.js"></script>
+    <script src="scripts/controllers/home.js"></script>
+    <script src="scripts/controllers/browser.js"></script>
+    <script src="scripts/ng-time-relative.min.js"></script>
+    <script src="scripts/common/services/etcd.js"></script>
+    <script src="scripts/common/services/prefix-url.js"></script>
+    <script src="scripts/common/directives/highlight.js"></script>
+    <script src="scripts/common/directives/enter.js"></script>
+
+    <!-- build:js({.tmp,app}) scripts/stats-scripts.js -->
+    <script src="scripts/vega.js"></script>
+    <script src="scripts/common/services/etcd.js"></script>
+    <!--<script src="scripts/controllers/stats.js"></script>-->
+    <!-- endbuild -->
+
+  </body>
 </html>
 </html>

+ 42 - 0
mod/dashboard/app/scripts/app.js

@@ -0,0 +1,42 @@
+'use strict';
+
+var app = angular.module('etcdControlPanel', [
+  'ngRoute',
+  'ngResource',
+  'etcd',
+  'etcdDirectives',
+  'timeRelative',
+  'underscore',
+  'jquery',
+  'moment'
+]);
+
+app.constant('urlPrefix', '/mod/dashboard');
+app.constant('keyPrefix', '/v2/keys/');
+
+app.config(function($routeProvider, $locationProvider, urlPrefix) {
+
+  function prefixUrl(url) {
+    return urlPrefix + url;
+  }
+
+  $locationProvider.html5Mode(true);
+
+  $routeProvider
+    .when(prefixUrl('/'), {
+      controller: 'HomeCtrl',
+      templateUrl: prefixUrl('/views/home.html')
+    })
+    //.when(prefixUrl('/stats'), {
+      //controller: 'StatsCtrl',
+      //templateUrl: prefixUrl('/views/stats.html')
+    //})
+    .when(prefixUrl('/browser'), {
+      controller: 'BrowserCtrl',
+      templateUrl: prefixUrl('/views/browser.html')
+    })
+    .otherwise({
+      templateUrl: prefixUrl('/404.html')
+    });
+
+});

+ 16 - 0
mod/dashboard/app/scripts/common/directives/enter.js

@@ -0,0 +1,16 @@
+'use strict';
+
+angular.module('etcdControlPanel')
+.directive('ngEnter', function() {
+  return function(scope, element, attrs) {
+    element.bind('keydown keypress', function(event) {
+      if(event.which === 13) {
+        scope.$apply(function(){
+          scope.$eval(attrs.ngEnter);
+        });
+
+        event.preventDefault();
+      }
+    });
+  };
+});

+ 13 - 0
mod/dashboard/app/scripts/common/directives/highlight.js

@@ -0,0 +1,13 @@
+'use strict';
+
+angular.module('etcdControlPanel')
+.directive('highlight', function() {
+  return {
+    restrict: 'A',
+    link: function(scope, element, attrs) {
+      if('#' + scope.etcdPath === attrs.href) {
+        element.parent().parent().addClass('etcd-selected');
+      }
+    }
+  };
+});

+ 10 - 0
mod/dashboard/app/scripts/common/services/prefix-url.js

@@ -0,0 +1,10 @@
+'use strict';
+
+angular.module('etcdControlPanel')
+.factory('prefixUrl', function(urlPrefix) {
+
+  return function(url) {
+    return urlPrefix + url;
+  }
+
+});

+ 19 - 71
mod/dashboard/app/scripts/controllers/browser.js

@@ -1,31 +1,20 @@
 'use strict';
 'use strict';
 
 
-angular.module('etcdBrowser', ['ngRoute', 'etcd', 'timeRelative'])
-
-.constant('keyPrefix', '/v2/keys/')
-
-.config(['$routeProvider', 'keyPrefix', function ($routeProvider, keyPrefix) {
-  //read localstorage
-  var previousPath = localStorage.getItem('etcd_path');
-
-  $routeProvider
-    .when('/', {
-      redirectTo: keyPrefix
-    })
-    .otherwise({
-      templateUrl: 'views/browser.html',
-      controller: 'MainCtrl'
-    });
-}])
-
-.controller('MainCtrl', ['$scope', '$location', 'EtcdV2', 'keyPrefix', function ($scope, $location, EtcdV2, keyPrefix) {
+angular.module('etcdControlPanel')
+.controller('BrowserCtrl', function ($scope, $location, $window, EtcdV2, keyPrefix, $, _, moment) {
   $scope.save = 'etcd-save-hide';
   $scope.save = 'etcd-save-hide';
   $scope.preview = 'etcd-preview-hide';
   $scope.preview = 'etcd-preview-hide';
   $scope.enableBack = true;
   $scope.enableBack = true;
   $scope.writingNew = false;
   $scope.writingNew = false;
+  $scope.key = '';
+  $scope.list = [];
 
 
   // etcdPath is the path to the key that is currenly being looked at.
   // etcdPath is the path to the key that is currenly being looked at.
-  $scope.etcdPath = $location.path();
+  $scope.etcdPath = keyPrefix;
+
+  $scope.setActiveKey = function(key) {
+    $scope.etcdPath = keyPrefix + _.str.trim(key, '/');
+  };
 
 
   $scope.$watch('etcdPath', function() {
   $scope.$watch('etcdPath', function() {
     function etcdPathKey() {
     function etcdPathKey() {
@@ -44,7 +33,7 @@ angular.module('etcdBrowser', ['ngRoute', 'etcd', 'timeRelative'])
     localStorage.setItem('etcdPath', $scope.etcdPath);
     localStorage.setItem('etcdPath', $scope.etcdPath);
     $scope.enableBack = true;
     $scope.enableBack = true;
     //disable back button if at root (/v2/keys/)
     //disable back button if at root (/v2/keys/)
-    if($scope.etcdPath === keyPrefix) {
+    if ($scope.etcdPath === keyPrefix) {
       $scope.enableBack = false;
       $scope.enableBack = false;
     }
     }
 
 
@@ -63,7 +52,7 @@ angular.module('etcdBrowser', ['ngRoute', 'etcd', 'timeRelative'])
         $scope.list = data.node.nodes;
         $scope.list = data.node.nodes;
         $scope.preview = 'etcd-preview-hide';
         $scope.preview = 'etcd-preview-hide';
       } else {
       } else {
-        $scope.singleValue = data.value;
+        $scope.singleValue = data.node.value;
         $scope.preview = 'etcd-preview-reveal';
         $scope.preview = 'etcd-preview-reveal';
         $scope.key.getParent().get().success(function(data) {
         $scope.key.getParent().get().success(function(data) {
           $scope.list = data.node.nodes;
           $scope.list = data.node.nodes;
@@ -79,14 +68,14 @@ angular.module('etcdBrowser', ['ngRoute', 'etcd', 'timeRelative'])
   //back button click
   //back button click
   $scope.back = function() {
   $scope.back = function() {
     $scope.etcdPath = $scope.key.getParent().path();
     $scope.etcdPath = $scope.key.getParent().path();
-    $scope.syncLocation();
+    //$scope.syncLocation();
     $scope.preview = 'etcd-preview-hide';
     $scope.preview = 'etcd-preview-hide';
     $scope.writingNew = false;
     $scope.writingNew = false;
   };
   };
 
 
-  $scope.syncLocation = function() {
-    $location.path($scope.etcdPath);
-  };
+  //$scope.syncLocation = function() {
+    //$location.path($scope.etcdPath);
+  //};
 
 
   $scope.showSave = function() {
   $scope.showSave = function() {
     $scope.save = 'etcd-save-reveal';
     $scope.save = 'etcd-save-reveal';
@@ -136,56 +125,15 @@ angular.module('etcdBrowser', ['ngRoute', 'etcd', 'timeRelative'])
   };
   };
 
 
   $scope.getHeight = function() {
   $scope.getHeight = function() {
-    return $(window).height();
+    return $($window).height();
   };
   };
+
   $scope.$watch($scope.getHeight, function() {
   $scope.$watch($scope.getHeight, function() {
     $('.etcd-body').css('height', $scope.getHeight()-45);
     $('.etcd-body').css('height', $scope.getHeight()-45);
   });
   });
-  window.onresize = function(){
-    $scope.$apply();
-  };
 
 
-}])
-
-.directive('ngEnter', function() {
-  return function(scope, element, attrs) {
-    element.bind('keydown keypress', function(event) {
-      if(event.which === 13) {
-        scope.$apply(function(){
-          scope.$eval(attrs.ngEnter);
-        });
-
-        event.preventDefault();
-      }
-    });
-  };
-})
-
-.directive('highlight', function() {
-  return {
-    restrict: 'A',
-    link: function(scope, element, attrs) {
-      if('#' + scope.etcdPath === attrs.href) {
-        element.parent().parent().addClass('etcd-selected');
-      }
-    }
+  $window.onresize = function(){
+    $scope.$apply();
   };
   };
-});
 
 
-moment.lang('en', {
-  relativeTime : {
-    future: 'Expires in %s',
-    past:   'Expired %s ago',
-    s:  'seconds',
-    m:  'a minute',
-    mm: '%d minutes',
-    h:  'an hour',
-    hh: '%d hours',
-    d:  'a day',
-    dd: '%d days',
-    M:  'a month',
-    MM: '%d months',
-    y:  'a year',
-    yy: '%d years'
-  }
 });
 });

+ 3 - 0
mod/dashboard/app/scripts/controllers/home.js

@@ -0,0 +1,3 @@
+angular.module('etcdControlPanel')
+.controller('HomeCtrl', function($scope) {
+});

+ 7 - 0
mod/dashboard/app/scripts/controllers/root.js

@@ -0,0 +1,7 @@
+angular.module('etcdControlPanel')
+.controller('RootCtrl', function($rootScope, prefixUrl) {
+
+  // Expose prefixUrl() function to all.
+  $rootScope.prefixUrl = prefixUrl;
+
+});

+ 1 - 13
mod/dashboard/app/scripts/controllers/stats.js

@@ -1,19 +1,7 @@
 'use strict';
 'use strict';
 
 
-angular.module('etcdStats', ['ngRoute', 'etcd'])
-
-.config(['$routeProvider', function ($routeProvider) {
-  $routeProvider
-    .when('/', {
-      templateUrl: 'views/stats.html',
-      controller: 'StatsCtrl'
-    })
-    .otherwise({
-      templateUrl: 'views/stats.html',
-      controller: 'StatsCtrl'
-    });
-}])
 
 
+angular.module('etcdControlPanel')
 .controller('StatsCtrl', ['$scope', 'EtcdV2', 'statsVega', function ($scope, EtcdV2, statsVega) {
 .controller('StatsCtrl', ['$scope', 'EtcdV2', 'statsVega', function ($scope, EtcdV2, statsVega) {
   $scope.graphContainer = '#latency';
   $scope.graphContainer = '#latency';
   $scope.graphVisibility = 'etcd-graph-show';
   $scope.graphVisibility = 'etcd-graph-show';

+ 3 - 0
mod/dashboard/app/scripts/directives.js

@@ -0,0 +1,3 @@
+'use strict';
+
+angular.module('etcdDirectives', []);

+ 32 - 0
mod/dashboard/app/scripts/shims.js

@@ -0,0 +1,32 @@
+'use strict';
+
+angular.module('underscore', []).factory('_', function($window) {
+  return $window._;
+});
+
+angular.module('jquery', []).factory('$', function($window) {
+  return $window.$;
+});
+
+angular.module('moment', []).factory('moment', function($window) {
+
+  $window.moment.lang('en', {
+    relativeTime : {
+      future: 'Expires in %s',
+      past:   'Expired %s ago',
+      s:  'seconds',
+      m:  'a minute',
+      mm: '%d minutes',
+      h:  'an hour',
+      hh: '%d hours',
+      d:  'a day',
+      dd: '%d days',
+      M:  'a month',
+      MM: '%d months',
+      y:  'a year',
+      yy: '%d years'
+    }
+  });
+
+  return $window.moment;
+});

+ 0 - 50
mod/dashboard/app/stats.html

@@ -1,50 +0,0 @@
-<!doctype html>
-<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
-<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
-<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
-<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
-  <head>
-    <meta charset="utf-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge">
-    <title>etcd Browser</title>
-    <meta name="description" content="">
-    <meta name="viewport" content="width=device-width">
-    <!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
-
-        <!-- build:css(.tmp) styles/main.css -->
-        <link rel="stylesheet" href="styles/etcd-widgets.css">
-        <link href="http://fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400,400italic,600,700,900" rel="stylesheet" type="text/css">
-        <link href="http://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600,700" rel="stylesheet" type="text/css">
-        <!-- endbuild -->
-</head>
-  <body ng-app="etcdStats">
-    <!--[if lt IE 7]>
-      <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
-    <![endif]-->
-
-    <!--[if lt IE 9]>
-      <script src="bower_components/es5-shim/es5-shim.js"></script>
-      <script src="bower_components/json3/lib/json3.min.js"></script>
-    <![endif]-->
-
-    <!-- Add your site or application content here -->
-    <div id="etd_stats" ng-view="etcd">
-    </div>
-        <!-- build:js scripts/stats-modules.js -->
-        <script src="bower_components/jquery/jquery.js"></script>
-        <script src="bower_components/angular/angular.js"></script>
-        <script src="bower_components/angular-resource/angular-resource.js"></script>
-        <script src="bower_components/angular-route/angular-route.js"></script>
-        <script src="bower_components/angular-cookies/angular-cookies.js"></script>
-        <script src="bower_components/angular-sanitize/angular-sanitize.js"></script>
-        <script src="bower_components/d3/d3.js"></script>
-        <script src="bower_components/underscore/underscore.js"></script>
-        <!-- endbuild -->
-
-        <!-- build:js({.tmp,app}) scripts/stats-scripts.js -->
-        <script src="scripts/vega.js"></script>
-        <script src="scripts/common/services/etcd.js"></script>
-        <script src="scripts/controllers/stats.js"></script>
-        <!-- endbuild -->
-</body>
-</html>

+ 180 - 0
mod/dashboard/app/styles/browser.css

@@ -0,0 +1,180 @@
+.etcd-container.etcd-browser {
+}
+
+.etcd-container.etcd-browser .etcd-header {
+  height: 37px;
+}
+
+.etcd-container.etcd-browser.etcd-preview-reveal .etcd-back {
+  display: block;
+}
+
+.etcd-container.etcd-browser.etcd-preview-hide .etcd-back {
+  display: block;
+}
+
+.etcd-container.etcd-browser.etcd-preview-reveal .etcd-add {
+}
+
+.etcd-container.etcd-browser.etcd-preview-hide .etcd-add {
+}
+
+.etcd-container.etcd-browser .etcd-header .etcd-browser-path {
+  position: absolute;
+  left: 72px;
+  right: 0px;
+  top: 0;
+  margin: 6px 5px 6px 5px;
+}
+
+.etcd-container.etcd-browser .etcd-header .etcd-browser-path input {
+  width: 100%;
+  box-sizing: border-box;
+    -moz-box-sizing: border-box;
+    -webkit-box-sizing: border-box;
+}
+
+.etcd-container.etcd-browser .etcd-header .etcd-save {
+  position: absolute;
+  width: 54px;
+  right: -55px;
+  margin: 6px 0;
+}
+
+.etcd-container.etcd-browser.etcd-save-reveal .etcd-header .etcd-save {
+  right: 7px;
+}
+
+.etcd-container.etcd-browser.etcd-save-reveal .etcd-header .etcd-browser-path {
+  right: 62px;
+}
+
+.etcd-container.etcd-browser.etcd-save-hide .etcd-header .etcd-save {
+  right: -55px;
+}
+
+.etcd-container.etcd-browser.etcd-save-hide .etcd-header .etcd-browser-path {
+  right: 0px;
+}
+
+.etcd-container.etcd-browser .etcd-preview {
+  position: absolute;
+  left: 100%;
+  min-height: 100%;
+  overflow-y: auto;
+  overflow-x: hidden;
+  top: 0px;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  background-color: #fff;
+  width: 100%;
+  border-left: 1px solid #ddd;
+}
+
+.etcd-container.etcd-browser .etcd-preview pre, .etcd-container.etcd-browser .etcd-preview textarea {
+  padding: 20px 20px 20px 20px;
+  margin: 0px;
+  font-family: Consolas, "Liberation Mono", Courier, monospace;
+  height: 100%;
+  width: 100%;
+  white-space: pre-wrap;
+  position: absolute;
+  font-size: 13px;
+  border: 1px;
+  outline: none;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+}
+
+.etcd-container.etcd-browser.etcd-preview-reveal .etcd-preview pre, .etcd-container.etcd-browser.etcd-preview-reveal .etcd-preview textarea {
+  display: block;
+}
+
+.etcd-container.etcd-browser .etcd-preview .etcd-empty {
+  top: 0px;
+  bottom: 0px;
+  width: 100%;
+  text-align: center;
+  position: absolute;
+}
+
+.etcd-container.etcd-browser.etcd-preview-reveal .etcd-empty {
+  display: none;
+}
+
+.etcd-container.etcd-browser .etcd-preview .etcd-empty-message {
+  margin-top: 25%;
+  color: #999;
+}
+
+/* Single Column Positioning */
+@media (max-width: 700px) {
+  .etcd-container.etcd-browser .etcd-list {
+    width: 100%;
+  }
+
+  .etcd-container.etcd-browser.etcd-preview-reveal .etcd-list {
+    left: -100%;
+    transition-property: all;
+      transition-duration: 250ms;
+      transition-timing-function: ease-in-out;
+  }
+
+  .etcd-container.etcd-browser.etcd-preview-hide .etcd-list {
+    left: 0%;
+    transition-property: all;
+      transition-duration: 250ms;
+      transition-timing-function: ease-in-out;
+  }
+
+  .etcd-container.etcd-browser .etcd-preview {
+    left: 100%;
+  }
+
+  .etcd-container.etcd-browser.etcd-preview-reveal .etcd-preview { left: -1px;
+    transition-property: all;
+      transition-duration: 250ms;
+      transition-timing-function: ease-in-out;
+  }
+
+  .etcd-container.etcd-browser.etcd-preview-hide .etcd-preview {
+    left: 100%;
+    transition-property: all;
+      transition-duration: 250ms;
+      transition-timing-function: ease-in-out;
+  }
+}
+
+
+/* Double Column Positioning */
+@media (min-width: 700px) {
+  .etcd-container.etcd-browser .etcd-list {
+      width: 50%;
+  }
+
+  .etcd-container.etcd-browser .etcd-preview {
+    left: 50%;
+    width: 50%;
+  }
+
+  .etcd-container.etcd-browser.etcd-preview-reveal .etcd-preview {
+    left: 50%; /* does nothing */
+  }
+
+  .etcd-container.etcd-browser.etcd-preview-reveal .etcd-preview .etcd-empty {
+    display: none;
+  }
+
+  .etcd-container.etcd-browser.etcd-preview-hide .etcd-preview {
+    left: 50%; /* does nothing */
+  }
+
+  .etcd-container.etcd-browser.etcd-preview-hide .etcd-preview .etcd-empty {
+    display: block;
+  }
+
+  .etcd-container.etcd-browser.etcd-preview-hide .etcd-preview pre, .etcd-container.etcd-browser.etcd-preview-hide .etcd-preview textarea {
+    display: none;
+  }
+}
+

+ 377 - 710
mod/dashboard/app/styles/etcd-widgets.css

@@ -1,713 +1,380 @@
 body {
 body {
-	margin: 0px;
+  margin: 0px;
 }
 }
+
 .etcd-container {
 .etcd-container {
-	background-color: #fff;
-	border: 1px solid #ddd;
-	border-radius: 5px;
-	box-shadow: rgba(0, 0, 0, 0.14902) 0px 1px 3px;
-	font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
-	overflow: hidden;
-	box-sizing: border-box;
-	-moz-box-sizing: border-box;
-	position: relative;
-	user-select: none;
-	-webkit-user-select: none;
-	-moz-user-select: none;
-	-ms-user-select: none;
-}
-
-	a {
-		color: #2176AC;
-		text-decoration: none;
-	}
-
-	a:hover, a:active {
-		text-decoration: underline;
-	}
-
-	input[type=text] {
-		box-shadow: inset 0 1px 2px rgba(0,0,0,.5);
-		border: none;
-		border-radius: 3px;
-		font-size: 13px;
-		padding-left: 5px;
-		padding-right: 5px;
-		height: 25px;
-	}
-
-	input[type=text]:focus {
-		
-	}
-
-	h2 {
-		font-size: 22px;
-		font-family: "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif;
-		font-weight: 500;
-		margin: 0 0 20px 0;
-		padding: 0;
-	}
-
-	.etcd-button {
-		display:inline-block;
-		padding:6px 12px;
-		margin-bottom:0;
-		font-size:14px;
-		font-weight:normal;
-		line-height:1.428571429;
-		text-align:center;
-		white-space:nowrap;
-		vertical-align:middle;
-		cursor:pointer;
-		border:1px solid transparent;
-		border-radius:4px;
-		-webkit-user-select:none;
-		-moz-user-select:none;
-		-ms-user-select:none;
-		-o-user-select:none;
-		user-select:none;
-		margin: 0px;
-		border: none;
-		box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.25);
-	}
-
-	.etcd-button.etcd-button-small {
-		height: 25px;
-		padding: 0 10px;
-		font-size: 13px;
-	}
-
-	.etcd-button-primary {
-		background-color: #428BCA;
-		color: #fff;
-		text-shadow: 0 0 3px rgba(0,0,0,0.25);
-	}
-
-	.etcd-button-primary:active {
-		background-color: #2276ad;
-	}
-
-	.etcd-popover {
-		background: #333;
-		border-radius: 3px;
-		padding: 15px;
-		position: absolute;
-		top: 39px;
-		z-index: 9999;
-		color: #fff;
-		font-size: 13px;
-		box-shadow: 0px 2px 10px rgba(0,0,0,.5);
-		display: none;
-	}
-
-		.etcd-popover-error .etcd-popover-content {
-			color: #FF3C43;
-			font-weight: bold;
-			user-select: text;
-			-webkit-user-select: text;
-			-moz-user-select: text;
-			-ms-user-select: text;
-		}
-
-		.etcd-popover-notch {
-			width: 14px;
-			height: 14px;
-			-webkit-transform: rotate(45deg);
-			-moz-transform: rotate(45deg);
-			-ms-transform: rotate(45deg);
-			position: absolute;
-			margin-top: -5px;
-			margin-left: 3px;
-			background: #333;
-			top: 0px;
-			right: 15px;
-		}
-
-	.etcd-popover.etcd-popover-right {
-		left: 77px;
-	}
-
-		.etcd-popover-right .etcd-popover-notch {
-			left: 15px;
-		}
-
-	.etcd-popover.etcd-popover-left {
-		right: 10px;
-	}
-
-		.etcd-popover-left .etcd-popover-notch {
-			right: 15px;
-		}
-
-		.etcd-popover-confirm {
-			margin-top: 10px;
-		}
-
-		.etcd-popover-confirm button {
-
-		}
-
-	.etcd-header {
-		width: 100%;
-		position: relative;
-		box-sizing: border-box;
-		-moz-box-sizing: border-box;
-	}
-	.etcd-header.solid {
-		background: #eeeeee;
-		background: -moz-linear-gradient(top,  #eeeeee 0%, #dddddd 100%);
-		background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#eeeeee), color-stop(100%,#dddddd));
-		background: -webkit-linear-gradient(top,  #eeeeee 0%,#dddddd 100%);
-		background: -o-linear-gradient(top,  #eeeeee 0%,#dddddd 100%);
-		background: -ms-linear-gradient(top,  #eeeeee 0%,#dddddd 100%);
-		background: linear-gradient(to bottom,  #eeeeee 0%,#dddddd 100%);
-		filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#dddddd',GradientType=0 );
-	}
-
-	.etcd-body {
-		top: 0px;
-		left: 0px;
-		position: relative;
-		overflow-y: auto;
-		overflow-x: hidden;
-		height: 100%;
-		width: 100%;
-		box-sizing: border-box;
-		-moz-box-sizing: border-box;
-	}
-
-		.etcd-body table {
-			width: 100%;
-			box-sizing: border-box;
-			-moz-box-sizing: border-box;
-		}
-
-			.etcd-body table thead td {
-				text-transform: uppercase;
-				font-size: 11px;
-				line-height: 20px;
-				border-bottom: 1px solid #ddd;
-				padding-top: 0px;
-				padding-right: 10px;
-				padding-bottom: 0px;
-				padding-left: 0px;
-				color: #666;
-			}
-
-			.etcd-body table tbody td {
-				line-height: 18px;
-				border-bottom: 1px solid #ddd;
-				padding-top: 6px;
-				padding-right: 10px;
-				padding-bottom: 6px;
-				padding-left: 0px;
-				vertical-align: text-top;
-				user-select: text;
-				-webkit-user-select: text;
-				-moz-user-select: text;
-				-ms-user-select: text;
-			}
-
-			.etcd-body table .etcd-ttl-header {
-				width: 33%;
-			}
-
-			.etcd-body table tbody .etcd-ttl {
-				font-size: 13px;
-			}
-
-			.etcd-body table tbody .etcd-ttl .etcd-ttl-none {
-				color: #999;
-				font-weight: 100;
-			}
-
-			.etcd-body table .etcd-actions-header {
-				width: 30px;
-			}
-
-		.etcd-body table thead td:first-child, .etcd-body table tbody td:first-child {
-			padding-left: 10px;
-		}
-
-		.etcd-body table thead td:last-child, .etcd-body table tbody td:last-child {
-			padding-right: 10px;
-		}
-
-		.etcd-container .etcd-preview .etcd-dialog {
-			background: #333;
-			position: absolute;
-			right: 0px;
-			left: 0px;
-			padding: 20px;
-			color: #fff;
-			font-size: 14px;
-			font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
-			bottom: 0px;
-			opacity: 0;
-			min-height: 110px; /* REMOVE ME! */
-			transition-property: all;
-			transition-duration: 150ms;
-			transition-timing-function: ease-in-out;
-		}
-
-			.etcd-container .etcd-preview .etcd-dialog .etcd-dialog-message {
-				margin-bottom: 20px;
-			}
-
-			.etcd-container .etcd-preview .etcd-dialog .etcd-dialog-buttons a {
-				line-height: 34px;
-				color: #fff;
-				vertical-align: middle;
-				margin-left: 10px;
-			}
-
-		/*.etcd-container .etcd-preview .etcd-dialog.etcd-reveal {
-			opacity: 1;
-		}
-
-		.etcd-container .etcd-preview .etcd-dialog.etcd-hide {
-			opacity: 0;
-		}*/
-
-		.etcd-body .etcd-list {
-			padding: 20px;
-			box-sizing: border-box;
-			-moz-box-sizing: border-box;
-			overflow: auto;
-			height: 100%;
-			position: absolute;
-		}
-
-			.etcd-body .etcd-list .etcd-selected {
-				background-color: #EAF3FF;
-			}
-
-			.etcd-body .etcd-list a.directory {
-				font-weight: bold;
-			}
-
-			.etcd-body .etcd-list tr:hover .etcd-delete svg {
-				1visibility: visible;
-				fill: #ff0000;
-			}
-
-			.etcd-body .etcd-list .etcd-delete {
-				height: 20px;
-				width: 25px;
-				vertical-align: middle;
-				margin: 0px;
-				display: inline-block;
-			}
-
-				.etcd-body .etcd-list .etcd-delete svg {
-					height: 20px;
-					fill: #eee;
-				}
-
-				.etcd-body .etcd-list .etcd-selected .etcd-delete svg {
-					height: 20px;
-					fill: #ddd;
-				}
-
-				.etcd-body .etcd-list .etcd-delete:hover svg {
-					cursor: pointer;
-					fill: #ff0000;
-				}
-
-
-.etcd-container.etcd-browser {
-
-}
-
-	.etcd-container.etcd-browser .etcd-header {
-		height: 37px;
-	}
-
-		.etcd-back {
-			height: 37px;
-			width: 37px;
-			vertical-align: middle;
-			margin: 0px;
-			position: absolute;
-			top: 0px;
-			left: 3px;
-			display: none;
-		}
-
-		.etcd-container.etcd-browser.etcd-preview-reveal .etcd-back {
-			display: block;
-		}
-
-		.etcd-container.etcd-browser.etcd-preview-hide .etcd-back {
-			display: block;
-		}
-
-			.etcd-back svg {
-				height: 20px;
-				padding: 8px 6px;
-			}
-
-			.etcd-back:hover svg {
-				cursor: pointer;
-				fill: #428bca;
-			}
-
-			.etcd-back.etcd-disabled svg {
-				fill: #bbb;
-			}
-
-		.etcd-add {
-			height: 37px;
-			width: 37px;
-			vertical-align: middle;
-			margin: 0px;
-			position: absolute;
-			top: 0px;
-			left: 36px;
-		}
-
-		.etcd-container.etcd-browser.etcd-preview-reveal .etcd-add {
-
-		}
-
-		.etcd-container.etcd-browser.etcd-preview-hide .etcd-add {
-
-		}
-
-			.etcd-add svg {
-				height: 22px;
-				padding: 7px 6px;
-			}
-
-			.etcd-add:hover svg {
-				cursor: pointer;
-				fill: #428bca;
-			}
-
-			.etcd-add.etcd-disabled svg {
-				fill: #bbb;
-			}
-
-		.etcd-container.etcd-browser .etcd-header .etcd-browser-path {
-			position: absolute;
-			left: 72px;
-			right: 0px;
-			top: 0;
-			margin: 6px 5px 6px 5px;
-		}
-
-		.etcd-container.etcd-browser .etcd-header .etcd-browser-path input {
-			width: 100%;
-			box-sizing: border-box;
-   			-moz-box-sizing: border-box;
-   			-webkit-box-sizing: border-box;
-		}
-
-		.etcd-container.etcd-browser .etcd-header .etcd-save {
-			position: absolute;
-			width: 54px;
-			right: -55px;
-			margin: 6px 0;
-		}
-
-		.etcd-container.etcd-browser.etcd-save-reveal .etcd-header .etcd-save {
-			right: 7px;
-		}
-
-		.etcd-container.etcd-browser.etcd-save-reveal .etcd-header .etcd-browser-path {
-			right: 62px;
-		}
-
-		.etcd-container.etcd-browser.etcd-save-hide .etcd-header .etcd-save {
-			right: -55px;
-		}
-
-		.etcd-container.etcd-browser.etcd-save-hide .etcd-header .etcd-browser-path {
-			right: 0px;
-		}
-
-	.etcd-container.etcd-browser .etcd-preview {
-		position: absolute;
-		left: 100%;
-		min-height: 100%;
-		overflow-y: auto;
-		overflow-x: hidden;
-		top: 0px;
-		box-sizing: border-box;
-		-moz-box-sizing: border-box;
-		background-color: #fff;
-		width: 100%;
-		border-left: 1px solid #ddd;
-	}
-
-	.etcd-container.etcd-browser .etcd-preview pre, .etcd-container.etcd-browser .etcd-preview textarea {
-		padding: 20px 20px 20px 20px;
-		margin: 0px;
-		font-family: Consolas, "Liberation Mono", Courier, monospace;
-		height: 100%;
-		width: 100%;
-		white-space: pre-wrap;
-		position: absolute;
-		font-size: 13px;
-		border: 1px;
-		outline: none;
-		box-sizing: border-box;
-		-moz-box-sizing: border-box;
-	}
-
-		.etcd-container.etcd-browser.etcd-preview-reveal .etcd-preview pre, .etcd-container.etcd-browser.etcd-preview-reveal .etcd-preview textarea {
-			display: block;
-		}
-
-	.etcd-container.etcd-browser .etcd-preview .etcd-empty {
-		top: 0px;
-		bottom: 0px;
-		width: 100%;
-		text-align: center;
-		position: absolute;
-	}
-
-		.etcd-container.etcd-browser.etcd-preview-reveal .etcd-empty {
-			display: none;
-		}
-
-	.etcd-container.etcd-browser .etcd-preview .etcd-empty-message {
-		margin-top: 25%;
-		color: #999;
-	}
-
-	/* Single Column Positioning */
-	@media (max-width: 700px) {
-		.etcd-container.etcd-browser .etcd-list {
-			width: 100%;
-		}
-
-			.etcd-container.etcd-browser.etcd-preview-reveal .etcd-list {
-				left: -100%;
-				transition-property: all;
-  				transition-duration: 250ms;
-  				transition-timing-function: ease-in-out;
-			}
-
-			.etcd-container.etcd-browser.etcd-preview-hide .etcd-list {
-				left: 0%;
-				transition-property: all;
-  				transition-duration: 250ms;
-  				transition-timing-function: ease-in-out;
-			}
-
-		.etcd-container.etcd-browser .etcd-preview {
-			left: 100%;
-		}
-
-			.etcd-container.etcd-browser.etcd-preview-reveal .etcd-preview {
-				left: -1px;
-				transition-property: all;
-  				transition-duration: 250ms;
-  				transition-timing-function: ease-in-out;
-			}
-
-			.etcd-container.etcd-browser.etcd-preview-hide .etcd-preview {
-				left: 100%;
-				transition-property: all;
-  				transition-duration: 250ms;
-  				transition-timing-function: ease-in-out;
-			}
-	}
-	
-
-	/* Double Column Positioning */
-	@media (min-width: 700px) {
-	.etcd-container.etcd-browser .etcd-list {
-			width: 50%;
-		}
-
-		.etcd-container.etcd-browser .etcd-preview {
-			left: 50%;
-			width: 50%;
-		}
-
-			.etcd-container.etcd-browser.etcd-preview-reveal .etcd-preview {
-				left: 50%; /* does nothing */
-			}
-
-			.etcd-container.etcd-browser.etcd-preview-reveal .etcd-preview .etcd-empty {
-				display: none;
-			}
-
-			.etcd-container.etcd-browser.etcd-preview-hide .etcd-preview {
-				left: 50%; /* does nothing */
-			}
-
-			.etcd-container.etcd-browser.etcd-preview-hide .etcd-preview .etcd-empty {
-				display: block;
-			}
-
-			.etcd-container.etcd-browser.etcd-preview-hide .etcd-preview pre, .etcd-container.etcd-browser.etcd-preview-hide .etcd-preview textarea {
-				display: none;
-			}
-	}
-
-.etcd-container.etcd-stats {
-
-}
-
-	.etcd-container.etcd-stats h2 {
-		margin-top: -7px;
-	}
-
-	.etcd-format-selector {
-		position: absolute;
-		top: 12px;
-		right: 16px;
-		z-index: 999;
-	}
-
-	.etcd-format-selector .etcd-selector-item {
-		display: inline-block;
-		height: 12px;
-		width: 12px;
-		padding: 8px 4px;
-	}
-
-	.etcd-format-selector .etcd-selector-item:hover {
-		cursor: pointer;
-	}
-
-		.etcd-format-selector .etcd-selector-item svg {
-			fill: #333;
-		}
-
-	.etcd-container.etcd-stats .etcd-graph {
-		box-sizing: border-box;
-		-moz-box-sizing: border-box;
-		position: absolute;
-		top: 0px;
-		bottom: 0px;
-		left: 0px;
-		right: 0px;
-		padding: 20px;
-	}
-
-		.etcd-container.etcd-stats .etcd-graph .etcd-graph-container {
-			position: absolute;
-			top: 60px;
-			bottom: 20px;
-			left: 20px;
-			right: 20px;
-			box-sizing: border-box;
-			-moz-box-sizing: border-box;
-		}
-
-	.etcd-container.etcd-stats table .etcd-latency {
-		width: 50%;
-	}
-
-	.etcd-container.etcd-stats .etcd-list {
-		position: absolute;
-		left: 100%;
-		min-height: 100%;
-		overflow-y: auto;
-		overflow-x: hidden;
-		top: 0px;
-		box-sizing: border-box;
-		-moz-box-sizing: border-box;
-		background-color: #fff;
-		width: 100%;
-		border-left: 1px solid #ddd;
-	}
-
-	.etcd-container.etcd-stats .etcd-list .etcd-square {
-		height: 10px;
-		width: 10px;
-		display: inline-block;
-		margin-right: 5px;
-	}
-
-		.etcd-container.etcd-stats .etcd-list .etcd-square-red {
-			background-color: #c40022;
-		}
-
-		.etcd-container.etcd-stats .etcd-list .etcd-square-orange {
-			background-color: #FFC000;
-		}
-
-		.etcd-container.etcd-stats .etcd-list .etcd-square-green {
-			background-color: #00DB24;
-		}
-
-	.etcd-container.etcd-stats .etcd-list .etcd-peer-type {
-		color: #999;
-		padding-left: 3px;
-		font-size: 13px;
-		line-height: 100%;
-	}
-
-	.etcd-container.etcd-stats .etcd-list .etcd-latency-value {
-		display: inline-block;
-	}
-
-	/* Single Column Positioning */
-	@media (max-width: 700px) {
-		.etcd-container.etcd-stats .etcd-list {
-			width: 100%;
-			left: 100%;
-		}
-
-		.etcd-container.etcd-stats .etcd-graph {
-			left: 0%;
-		}
-
-		.etcd-container.etcd-stats.etcd-table-reveal .etcd-graph {
-			left: -100%;
-			transition-property: all;
-  			transition-duration: 250ms;
-  			transition-timing-function: ease-in-out;
-		}
-		.etcd-container.etcd-stats.etcd-table-hide .etcd-graph {
-			left: 0%;
-			transition-property: all;
-  			transition-duration: 250ms;
-  			transition-timing-function: ease-in-out;
-
-		}
-		.etcd-container.etcd-stats.etcd-table-hide .etcd-format-selector .etcd-selector-graph svg * {
-			fill: #428bca;
-		}
-
-		.etcd-container.etcd-stats.etcd-table-hide .etcd-list {
-			left: 100%;
-			transition-property: all;
-  			transition-duration: 250ms;
-  			transition-timing-function: ease-in-out;
-		}
-		.etcd-container.etcd-stats.etcd-table-reveal .etcd-list {
-			left: 0%;
-			transition-property: all;
-  			transition-duration: 250ms;
-  			transition-timing-function: ease-in-out;
-		}
-		.etcd-container.etcd-stats.etcd-table-reveal .etcd-format-selector .etcd-selector-table svg * {
-			fill: #428bca;
-		}
-
-	}
-	
-
-	/* Double Column Positioning */
-	@media (min-width: 700px) {
-		.etcd-container.etcd-stats .etcd-list {
-			width: 50%;
-			left: 50%;
-		}
-
-		.etcd-container.etcd-stats .etcd-graph {
-			left: 0%;
-			width: 50%;
-		}
-
-		.etcd-container.etcd-stats .etcd-format-selector {
-			display: none;
-		}
-
-	}
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-radius: 5px;
+  box-shadow: rgba(0, 0, 0, 0.14902) 0px 1px 3px;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  overflow: hidden;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  position: relative;
+  user-select: none;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+}
+
+a {
+  color: #2176AC;
+  text-decoration: none;
+}
+
+a:hover, a:active {
+  text-decoration: underline;
+}
+
+input[type=text] {
+  box-shadow: inset 0 1px 2px rgba(0,0,0,.5);
+  border: none;
+  border-radius: 3px;
+  font-size: 13px;
+  padding-left: 5px;
+  padding-right: 5px;
+  height: 25px;
+}
+
+input[type=text]:focus {
+}
+
+h2 {
+  font-size: 22px;
+  font-family: "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-weight: 500;
+  margin: 0 0 20px 0;
+  padding: 0;
+}
+
+.etcd-button {
+  display:inline-block;
+  padding:6px 12px;
+  margin-bottom:0;
+  font-size:14px;
+  font-weight:normal;
+  line-height:1.428571429;
+  text-align:center;
+  white-space:nowrap;
+  vertical-align:middle;
+  cursor:pointer;
+  border:1px solid transparent;
+  border-radius:4px;
+  -webkit-user-select:none;
+  -moz-user-select:none;
+  -ms-user-select:none;
+  -o-user-select:none;
+  user-select:none;
+  margin: 0px;
+  border: none;
+  box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.25);
+}
+
+.etcd-button.etcd-button-small {
+  height: 25px;
+  padding: 0 10px;
+  font-size: 13px;
+}
+
+.etcd-button-primary {
+  background-color: #428BCA;
+  color: #fff;
+  text-shadow: 0 0 3px rgba(0,0,0,0.25);
+}
+
+.etcd-button-primary:active {
+  background-color: #2276ad;
+}
+
+.etcd-popover {
+  background: #333;
+  border-radius: 3px;
+  padding: 15px;
+  position: absolute;
+  top: 39px;
+  z-index: 9999;
+  color: #fff;
+  font-size: 13px;
+  box-shadow: 0px 2px 10px rgba(0,0,0,.5);
+  display: none;
+}
+
+.etcd-popover-error .etcd-popover-content {
+  color: #FF3C43;
+  font-weight: bold;
+  user-select: text;
+  -webkit-user-select: text;
+  -moz-user-select: text;
+  -ms-user-select: text;
+}
+
+.etcd-popover-notch {
+  width: 14px;
+  height: 14px;
+  -webkit-transform: rotate(45deg);
+  -moz-transform: rotate(45deg);
+  -ms-transform: rotate(45deg);
+  position: absolute;
+  margin-top: -5px;
+  margin-left: 3px;
+  background: #333;
+  top: 0px;
+  right: 15px;
+}
+
+.etcd-popover.etcd-popover-right {
+  left: 77px;
+}
+
+.etcd-popover-right .etcd-popover-notch {
+  left: 15px;
+}
+
+.etcd-popover.etcd-popover-left {
+  right: 10px;
+}
+
+.etcd-popover-left .etcd-popover-notch {
+  right: 15px;
+}
+
+.etcd-popover-confirm {
+  margin-top: 10px;
+}
+
+.etcd-popover-confirm button {
+}
+
+.etcd-header {
+  width: 100%;
+  position: relative;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+}
+.etcd-header.solid {
+  background: #eeeeee;
+  background: -moz-linear-gradient(top,  #eeeeee 0%, #dddddd 100%);
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#eeeeee), color-stop(100%,#dddddd));
+  background: -webkit-linear-gradient(top,  #eeeeee 0%,#dddddd 100%);
+  background: -o-linear-gradient(top,  #eeeeee 0%,#dddddd 100%);
+  background: -ms-linear-gradient(top,  #eeeeee 0%,#dddddd 100%);
+  background: linear-gradient(to bottom,  #eeeeee 0%,#dddddd 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#dddddd',GradientType=0 );
+}
+
+.etcd-body {
+  top: 0px;
+  left: 0px;
+  position: relative;
+  overflow-y: auto;
+  overflow-x: hidden;
+  height: 100%;
+  width: 100%;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+}
+
+.etcd-body table {
+  width: 100%;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+}
+
+.etcd-body table thead td {
+  text-transform: uppercase;
+  font-size: 11px;
+  line-height: 20px;
+  border-bottom: 1px solid #ddd;
+  padding-top: 0px;
+  padding-right: 10px;
+  padding-bottom: 0px;
+  padding-left: 0px;
+  color: #666;
+}
+
+.etcd-body table tbody td {
+  line-height: 18px;
+  border-bottom: 1px solid #ddd;
+  padding-top: 6px;
+  padding-right: 10px;
+  padding-bottom: 6px;
+  padding-left: 0px;
+  vertical-align: text-top;
+  user-select: text;
+  -webkit-user-select: text;
+  -moz-user-select: text;
+  -ms-user-select: text;
+}
+
+.etcd-body table .etcd-ttl-header {
+  width: 33%;
+}
+
+.etcd-body table tbody .etcd-ttl {
+  font-size: 13px;
+}
+
+.etcd-body table tbody .etcd-ttl .etcd-ttl-none {
+  color: #999;
+  font-weight: 100;
+}
+
+.etcd-body table .etcd-actions-header {
+  width: 30px;
+}
+
+.etcd-body table thead td:first-child, .etcd-body table tbody td:first-child {
+  padding-left: 10px;
+}
+
+.etcd-body table thead td:last-child, .etcd-body table tbody td:last-child {
+  padding-right: 10px;
+}
+
+.etcd-container .etcd-preview .etcd-dialog {
+  background: #333;
+  position: absolute;
+  right: 0px;
+  left: 0px;
+  padding: 20px;
+  color: #fff;
+  font-size: 14px;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  bottom: 0px;
+  opacity: 0;
+  min-height: 110px; /* REMOVE ME! */
+  transition-property: all;
+  transition-duration: 150ms;
+  transition-timing-function: ease-in-out;
+}
+
+.etcd-container .etcd-preview .etcd-dialog .etcd-dialog-message {
+  margin-bottom: 20px;
+}
+
+.etcd-container .etcd-preview .etcd-dialog .etcd-dialog-buttons a {
+  line-height: 34px;
+  color: #fff;
+  vertical-align: middle;
+  margin-left: 10px;
+}
+
+.etcd-body .etcd-list {
+  padding: 20px;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  overflow: auto;
+  height: 100%;
+  position: absolute;
+}
+
+.etcd-body .etcd-list .etcd-selected {
+  background-color: #EAF3FF;
+}
+
+.etcd-body .etcd-list a.directory {
+  font-weight: bold;
+}
+
+.etcd-list tr:hover .etcd-delete {
+  visibility: visible;
+  fill: #ff0000;
+}
+
+.etcd-delete {
+  height: 20px;
+  width: 25px;
+  vertical-align: middle;
+  margin: 0px;
+  display: inline-block;
+}
+
+.etcd-delete {
+  height: 20px;
+  fill: #eee;
+}
+
+.etcd-selected .etcd-delete {
+  height: 20px;
+  fill: #ddd;
+}
+
+.etcd-delete:hover {
+  cursor: pointer;
+  fill: #ff0000;
+}
+
+.etcd-back {
+  height: 37px;
+  width: 37px;
+  vertical-align: middle;
+  margin: 0px;
+  position: absolute;
+  top: 0px;
+  left: 3px;
+  display: none;
+}
+
+
+.etcd-back svg {
+  height: 20px;
+  padding: 8px 6px;
+}
+
+.etcd-back:hover svg {
+  cursor: pointer;
+  fill: #428bca;
+}
+
+.etcd-back.etcd-disabled svg {
+  fill: #bbb;
+}
+
+.etcd-add {
+  height: 37px;
+  width: 37px;
+  vertical-align: middle;
+  margin: 0px;
+  position: absolute;
+  top: 0px;
+  left: 36px;
+}
+
+
+.etcd-add svg {
+  height: 22px;
+  padding: 7px 6px;
+}
+
+.etcd-add:hover svg {
+  cursor: pointer;
+  fill: #428bca;
+}
+
+.etcd-add.etcd-disabled svg {
+  fill: #bbb;
+}
+
+.etcd-format-selector {
+  position: absolute;
+  top: 12px;
+  right: 16px;
+  z-index: 999;
+}
+
+.etcd-format-selector .etcd-selector-item {
+  display: inline-block;
+  height: 12px;
+  width: 12px;
+  padding: 8px 4px;
+}
+
+.etcd-format-selector .etcd-selector-item:hover {
+  cursor: pointer;
+}
+
+.etcd-format-selector .etcd-selector-item svg {
+  fill: #333;
+}
+

+ 45 - 16
mod/dashboard/app/styles/main.css

@@ -1,22 +1,51 @@
 body {
 body {
-    background: #fafafa;
-    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
-    color: #333;
+  background: #fafafa;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  color: #333;
+  padding: 30px;
+  margin: 0px;
+}
+h1 {
+    font-family: "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif;
+    font-weight: 400;
+    margin: 0px 0px 20px 0px;
+    padding: 0px;
+}
+
+a {
+    color: #1e6ec1;
+    text-decoration: none;
+}
+
+a:hover {
+    text-decoration: underline;
+}
+
+#footer {
+    width: 100%;
+    font-family: "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif;
+    margin-top: 20px;
+}
+
+#coreos-logo {
+    margin: 10px auto 0 auto;
+    height: 30px;
+    width: 80px;
 }
 }
 
 
-.hero-unit {
-    margin: 50px auto 0 auto;
-    width: 300px;
-    font-size: 18px;
-    font-weight: 200;
-    line-height: 30px;
-    background-color: #eee;
-    border-radius: 6px;
-    padding: 60px;
+#coreos-logo svg {
+    fill: #999;
+    MAX-WIDTH: 100PX;
+    DISPLAY: INLINE-BLOCK;
+    VERTICAL-ALIGN: MIDDLE;
 }
 }
 
 
-.hero-unit h1 {
-    font-size: 60px;
-    line-height: 1;
-    letter-spacing: -1px;
+#POWERED-BY {
+    FONT-SIZE: 12PX;
+    COLOR: #333;
+    WIDTH: 100%;
+    DISPLAY: INLINE-BLOCK;
+    VERTICAL-ALIGN: MIDDLE;
+    LINE-HEIGHT: 190%;
+    TEXT-ALIGN: CENTER;
 }
 }

+ 142 - 0
mod/dashboard/app/styles/stats.css

@@ -0,0 +1,142 @@
+.etcd-stats {
+  width: 100%; height: 400px;
+}
+
+.etcd-container.etcd-stats {
+}
+
+.etcd-container.etcd-stats h2 {
+  margin-top: -7px;
+}
+
+.etcd-container.etcd-stats table .etcd-latency {
+  width: 50%;
+}
+
+.etcd-container.etcd-stats .etcd-list {
+  position: absolute;
+  left: 100%;
+  min-height: 100%;
+  overflow-y: auto;
+  overflow-x: hidden;
+  top: 0px;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  background-color: #fff;
+  width: 100%;
+  border-left: 1px solid #ddd;
+}
+
+.etcd-container.etcd-stats .etcd-list .etcd-square {
+  height: 10px;
+  width: 10px;
+  display: inline-block;
+  margin-right: 5px;
+}
+
+.etcd-container.etcd-stats .etcd-list .etcd-square-red {
+  background-color: #c40022;
+}
+
+.etcd-container.etcd-stats .etcd-list .etcd-square-orange {
+  background-color: #FFC000;
+}
+
+.etcd-container.etcd-stats .etcd-list .etcd-square-green {
+  background-color: #00DB24;
+}
+
+.etcd-container.etcd-stats .etcd-list .etcd-peer-type {
+  color: #999;
+  padding-left: 3px;
+  font-size: 13px;
+  line-height: 100%;
+}
+
+.etcd-container.etcd-stats .etcd-list .etcd-latency-value {
+  display: inline-block;
+}
+
+.etcd-container.etcd-stats .etcd-graph {
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  position: absolute;
+  top: 0px;
+  bottom: 0px;
+  left: 0px;
+  right: 0px;
+  padding: 20px;
+}
+
+.etcd-container.etcd-stats .etcd-graph .etcd-graph-container {
+  position: absolute;
+  top: 60px;
+  bottom: 20px;
+  left: 20px;
+  right: 20px;
+  box-sizing: border-box;
+  -moz-box-sizing: border-box;
+}
+
+
+/* Single Column Positioning */
+@media (max-width: 700px) {
+  .etcd-container.etcd-stats .etcd-list {
+    width: 100%;
+    left: 100%;
+  }
+
+  .etcd-container.etcd-stats .etcd-graph {
+    left: 0%;
+  }
+
+  .etcd-container.etcd-stats.etcd-table-reveal .etcd-graph {
+    left: -100%;
+    transition-property: all;
+      transition-duration: 250ms;
+      transition-timing-function: ease-in-out;
+  }
+  .etcd-container.etcd-stats.etcd-table-hide .etcd-graph {
+    left: 0%;
+    transition-property: all;
+      transition-duration: 250ms;
+      transition-timing-function: ease-in-out;
+
+  }
+  .etcd-container.etcd-stats.etcd-table-hide .etcd-format-selector .etcd-selector-graph svg * {
+    fill: #428bca;
+  }
+
+  .etcd-container.etcd-stats.etcd-table-hide .etcd-list {
+    left: 100%;
+    transition-property: all;
+      transition-duration: 250ms;
+      transition-timing-function: ease-in-out;
+  }
+  .etcd-container.etcd-stats.etcd-table-reveal .etcd-list {
+    left: 0%;
+    transition-property: all;
+      transition-duration: 250ms;
+      transition-timing-function: ease-in-out;
+  }
+  .etcd-container.etcd-stats.etcd-table-reveal .etcd-format-selector .etcd-selector-table svg * {
+    fill: #428bca;
+  }
+}
+
+/* Double Column Positioning */
+@media (min-width: 700px) {
+  .etcd-container.etcd-stats .etcd-list {
+    width: 50%;
+    left: 50%;
+  }
+
+  .etcd-container.etcd-stats .etcd-graph {
+    left: 0%;
+    width: 50%;
+  }
+
+  .etcd-container.etcd-stats .etcd-format-selector {
+    display: none;
+  }
+}

+ 65 - 93
mod/dashboard/app/views/browser.html

@@ -1,99 +1,71 @@
-<div class="etcd-container etcd-browser {{columns}} {{preview}} {{save}}">
-    <!--
-    <div class="etcd-popover etcd-popover-error">
-        <div class="etcd-popover-notch"></div>
-        <div class="etcd-popover-content">
-            Overwrite this value?
-        </div>
-        <div class="etcd-popover-confirm">
-            <button class="etcd-button etcd-button-small etcd-button-primary etcd-confirm">Overwrite</button>
-        </div>
-    </div>
-    -->
-    <div class="etcd-popover etcd-popover-error" id="etcd-save-error">
-        <div class="etcd-popover-notch"></div>
-        <div class="etcd-popover-content">
-            Error:
-        </div>
-    </div>
-    <div class="etcd-popover etcd-popover-error" id="etcd-browse-error">
-        <div class="etcd-popover-notch"></div>
-        <div class="etcd-popover-content">
-            Error: 
-        </div>
-    </div>
-    <div class="etcd-header solid">
-        <a class="etcd-back" ng-click="back()" ng-class="{false:'etcd-disabled'}[enableBack]">
-            <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-            preserveAspectRatio="xMinYMin" viewBox="0 0 73.356 61" enable-background="new 0 0 73.356 61" xml:space="preserve">
-            <path d="M5.27,33.226l22.428,22.428c1.562,1.562,4.095,1.562,5.657,0c1.562-1.562,1.562-4.095,0-5.657L17.77,34.413h48.514
-            c2.209,0,4-1.791,4-4s-1.791-4-4-4H17.749l15.604-15.582c1.563-1.561,1.565-4.094,0.004-5.657C32.576,4.391,31.552,4,30.527,4
-            c-1.023,0-2.046,0.39-2.827,1.169L5.272,27.567c-0.751,0.75-1.173,1.768-1.173,2.829C4.098,31.458,4.52,32.476,5.27,33.226z"/>
-            </svg>
-        </a>
-        <a class="etcd-add">
+<div ng-controller="BrowserCtrl" class="etcd-container etcd-browser {{columns}} {{preview}} {{save}}">
 
 
-            <svg version="1.1" ng-click="add()" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-			preserveAspectRatio="xMinYMin" viewBox="0 0 72.556 61" enable-background="new 0 0 72.556 61" xml:space="preserve">
-			<path d="M34.521,8v11.088v23v10.737c0,2.209,1.791,4,4,4c2.209,0,4-1.791,4-4V42.067V19.109V8c0-2.209-1.791-4-4-4
-			C36.312,4,34.521,5.791,34.521,8z"/>
-			<path d="M16.109,34.412h11.088h23h10.737c2.209,0,4-1.791,4-4c0-2.209-1.791-4-4-4H50.175H27.217H16.109c-2.209,0-4,1.791-4,4
-			C12.109,32.621,13.9,34.412,16.109,34.412z"/>
-			</svg>
-        </a>
-        <div class="etcd-browser-path">
-            <input type="text" ng-model="etcdPath" ng-enter="syncLocation()" tabindex="888" />
-        </div>
-        <button class="etcd-button etcd-button-small etcd-button-primary etcd-save" ng-click="saveData()">Save</button>
+  <div class="etcd-popover etcd-popover-error" id="etcd-save-error">
+    <div class="etcd-popover-notch"></div>
+    <div class="etcd-popover-content">Error:</div>
+  </div>
+
+  <div class="etcd-popover etcd-popover-error" id="etcd-browse-error">
+    <div class="etcd-popover-notch"></div>
+    <div class="etcd-popover-content">Error:</div>
+  </div>
+
+  <div class="etcd-header solid">
+    <a class="etcd-back" ng-click="back()" ng-class="{false:'etcd-disabled'}[enableBack]">
+      <img src="img/back.svg"/>
+    </a>
+    <a class="etcd-add" ng-click="add()"><img src="img/add.svg"/></a>
+    <div class="etcd-browser-path">
+      <input type="text" ng-model="etcdPath" ng-enter="syncLocation()" tabindex="888" />
     </div>
     </div>
-    <div class="etcd-body">
-        <div class="etcd-list">
-            <table cellpadding="0" cellspacing="0">
-			<thead>
-			    <td class="etcd-name-header">Name</td>
-			    <td class="etcd-ttl-header">TTL</td>
-			    <td class="etcd-actions-header">&nbsp</td>
-			</thead>
-			<tbody>
-			    <tr ng-repeat="key in list | orderBy:'key'">
-			        <td><a ng-class="{true:'directory'}[key.dir]" href="#/v2/keys{{key.key}}" highlight>{{key.key}}</a></td>
-			        <td ng-switch on="!!key.expiration" class="etcd-ttl">
-					    <div ng-switch-when="true"><time relative datetime="{{key.expiration.substring(0, key.expiration.lastIndexOf('-'))}}"></time></div>
-					    <div ng-switch-default class="etcd-ttl-none">&mdash;</div>
-					</td>
-			        <td>
-			            <div class="etcd-actions">
-			                <div class="etcd-delete" ng-switch on="!!key.dir">
-			                    <svg ng-switch-when="false" ng-click="deleteKey()" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
-			                    x="0px" y="0px" preserveAspectRatio="xMinYMin" viewBox="0 0 76.143 61" enable-background="new 0 0 76.143 61" xml:space="preserve">
-			                    <path d="M49.41,13.505l-6.035,6.035L27.112,35.803l-6.035,6.035c-1.562,1.562-1.562,4.095,0,5.657c1.562,1.562,4.095,1.562,5.657,0
-			                    l6.05-6.05l16.234-16.234l6.05-6.05c1.562-1.562,1.562-4.095,0-5.657C53.505,11.943,50.972,11.943,49.41,13.505z"/>
-			                    <path d="M21.077,19.162l6.035,6.035L43.375,41.46l6.035,6.035c1.562,1.562,4.095,1.562,5.657,0c1.562-1.562,1.562-4.095,0-5.657
-			                    l-6.05-6.05L32.783,19.555l-6.05-6.05c-1.562-1.562-4.095-1.562-5.657,0C19.515,15.067,19.515,17.6,21.077,19.162z"/>
-			                    </svg>
-			                    <div ng-switch-when="true"></div>
-			                </div>
-			            </div>
-			        </td>
-			    </tr>
-			</tbody>
-			</table>
-        </div>
-        <div class="etcd-preview">
-            <textarea placeholder="Enter a key name above and the value here" ng-model="singleValue" tabindex="888" ng-change="showSave()">
-            </textarea>
-            <div class="etcd-empty">
-                <div class="etcd-empty-message">{{preview_message}}</div>
-            </div>
-            <div class="etcd-dialog">
-                <div class="etcd-dialog-message">
-                    Save and replicate this change?
-                </div>
-                <div class="etcd-dialog-buttons">
-                    <button class="etcd-button etcd-button-primary">Save Changes</button>
-                    <a href="javascript:void(0);">Cancel</a>
-                </div>
+    <button class="etcd-button etcd-button-small etcd-button-primary etcd-save" ng-click="saveData()">Save</button>
+  </div>
+
+
+  <div class="etcd-body">
+
+    <div class="etcd-list">
+      <table cellpadding="0" cellspacing="0">
+      <thead>
+        <td class="etcd-name-header">Name</td>
+        <td class="etcd-ttl-header">TTL</td>
+        <td class="etcd-actions-header">&nbsp;</td>
+      </thead>
+      <tbody>
+        <tr ng-repeat="key in list | orderBy:'key'">
+          <td><a ng-class="{true:'directory'}[key.dir]" ng-click="setActiveKey(key.key)" highlight>{{key.key}}</a></td>
+          <td ng-switch on="!!key.expiration" class="etcd-ttl">
+            <div ng-switch-when="true"><time relative datetime="{{key.expiration.substring(0, key.expiration.lastIndexOf('-'))}}"></time></div>
+            <div ng-switch-default class="etcd-ttl-none">&mdash;</div>
+          </td>
+          <td>
+            <div class="etcd-actions">
+              <div ng-switch on="!!key.dir">
+                <img class="etcd-delete" src="img/delete.svg" ng-switch-when="false" ng-click="deleteKey()" />
+                <div ng-switch-when="true"></div>
+              </div>
             </div>
             </div>
+          </td>
+        </tr>
+      </tbody>
+      </table>
+    </div>
+
+    <div class="etcd-preview">
+      <textarea placeholder="Enter a key name above and the value here" ng-model="singleValue" tabindex="888" ng-change="showSave()"></textarea>
+      <div class="etcd-empty">
+        <div class="etcd-empty-message">{{preview_message}}</div>
+      </div>
+      <div class="etcd-dialog">
+        <div class="etcd-dialog-message">Save and replicate this change?</div>
+          <div class="etcd-dialog-buttons">
+            <button class="etcd-button etcd-button-primary">Save Changes</button>
+            <a href="javascript:void(0);">Cancel</a>
+          </div>
         </div>
         </div>
+      </div>
     </div>
     </div>
+
+  </div>
+
 </div>
 </div>

+ 2 - 0
mod/dashboard/app/views/home.html

@@ -0,0 +1,2 @@
+<!--<div ng-include="prefixUrl('/views/stats.html')" style="width: 100%; height: 400px;"></div>-->
+<div ng-include="prefixUrl('/views/browser.html')" style="width: 100%; height: 400px;"></div>

+ 2 - 2
mod/dashboard/bower.json

@@ -12,11 +12,11 @@
     "angular-cookies": "~1.2.0-rc.2",
     "angular-cookies": "~1.2.0-rc.2",
     "angular-sanitize": "~1.2.0-rc.2",
     "angular-sanitize": "~1.2.0-rc.2",
     "d3": "~3.3.6",
     "d3": "~3.3.6",
-    "moment": "~2.3.0"
+    "moment": "~2.3.0",
+    "underscore.string": "~2.3.3"
   },
   },
   "devDependencies": {
   "devDependencies": {
     "angular-mocks": "~1.2.0-rc.2",
     "angular-mocks": "~1.2.0-rc.2",
-    "angular-scenario": "~1.2.0-rc.2",
     "underscore": "~1.5.2"
     "underscore": "~1.5.2"
   }
   }
 }
 }

+ 0 - 2
mod/dashboard/package.json

@@ -11,7 +11,6 @@
     "grunt-contrib-compass": "~0.5.0",
     "grunt-contrib-compass": "~0.5.0",
     "grunt-contrib-jshint": "~0.6.0",
     "grunt-contrib-jshint": "~0.6.0",
     "grunt-contrib-cssmin": "~0.6.0",
     "grunt-contrib-cssmin": "~0.6.0",
-    "grunt-contrib-connect": "~0.3.0",
     "grunt-contrib-clean": "~0.5.0",
     "grunt-contrib-clean": "~0.5.0",
     "grunt-contrib-htmlmin": "~0.1.3",
     "grunt-contrib-htmlmin": "~0.1.3",
     "grunt-contrib-imagemin": "~0.2.0",
     "grunt-contrib-imagemin": "~0.2.0",
@@ -23,7 +22,6 @@
     "grunt-open": "~0.2.0",
     "grunt-open": "~0.2.0",
     "grunt-concurrent": "~0.3.0",
     "grunt-concurrent": "~0.3.0",
     "load-grunt-tasks": "~0.1.0",
     "load-grunt-tasks": "~0.1.0",
-    "connect-livereload": "~0.2.0",
     "grunt-google-cdn": "~0.2.0",
     "grunt-google-cdn": "~0.2.0",
     "grunt-ngmin": "~0.0.2",
     "grunt-ngmin": "~0.0.2",
     "time-grunt": "~0.1.0",
     "time-grunt": "~0.1.0",