Просмотр исходного кода

Refactored drag/drop, moved header buttons around, disable drag on panels inside column panel, updated default panels with panel titles

Rashid Khan 12 лет назад
Родитель
Сommit
bd21266679

+ 3 - 2
src/app/dashboards/blank.json

@@ -1,5 +1,5 @@
 {
-  "title": "",
+  "title": "New Dashboard",
   "services": {
     "query": {
       "idQueue": [
@@ -33,9 +33,10 @@
   "rows": [
   ],
   "editable": true,
+  "failover": false,
   "index": {
     "interval": "none",
     "pattern": "[logstash-]YYYY.MM.DD",
-    "default": "NOT_CONFIGURED"
+    "default": "_all"
   }
 }

+ 4 - 17
src/app/dashboards/default.json

@@ -46,14 +46,14 @@
     {
       "title": "Intro",
       "height": "450px",
-      "editable": true,
+      "editable": false,
       "collapse": false,
       "collapsable": false,
       "panels": [
         {
           "error": false,
           "span": 4,
-          "editable": true,
+          "editable": false,
           "group": [
             "default"
           ],
@@ -66,26 +66,13 @@
         },
         {
           "error": false,
-          "span": 1,
+          "span": 8,
           "editable": false,
           "group": [
             "default"
           ],
           "type": "text",
           "mode": "markdown",
-          "content": "",
-          "style": {},
-          "status": "Stable"
-        },
-        {
-          "error": false,
-          "span": 7,
-          "editable": true,
-          "group": [
-            "default"
-          ],
-          "type": "text",
-          "mode": "markdown",
           "content": "### Welcome to Kibana. \nGlad you could make it. Happy to have you here! Lets get started, shall we?\n##### Requirements\n* **A good browser.**  \n    The latest version of Chrome or Firefox is recommended. Safari (latest version) and Internet Explorer 9 and above are also supported.\n* **A webserver.**  \n    Just somewhere to host the HTML and Javascript. Basically any webserver will work.\n* **Elasticsearch**  \n   0.20.5 or above. Kibana will soon move to requiring Elasticsearch 0.90 or above, so upgrading is recommended.\n\n##### Configuration\nIf Kibana and Elasticsearch are on the same host, and you're using the default Elasticsearch port, then you're all set. Kibana is configured to use that setup by default!  \n\nIf not, you need to edit *config.js* and set the *elasticsearch* parameter with the URL (including port, probably 9200) of your Elasticsearch server. The host part should be the entire, fully qualified domain name, or IP, **not localhost**.\n#### Are you a Logstash User?\n+ **YES** - Great! We have a prebuilt dashboard: [(Logstash Dashboard)](index.html#/dashboard/file/logstash.json). See the note to the right about making it your global default  \n\n+ **NO** - Hey, no problem, you just have a bit of setup to do. You have a few choices:  \n\n    1. [Sample Dashboard](index.html#/dashboard/file/guided.json) *I don't have much data yet, please extract some basics for me*  \n    2. [Unconfigured Dashboard](index.html#/dashboard/file/noted.json) *I have a lot of data and I don't want Kibana to query it at once*\n    3. [Blank Dashboard](index.html#/dashboard/file/blank.json) *I'm comfortable figuring it out on my own*",
           "style": {},
           "status": "Stable"
@@ -93,7 +80,7 @@
       ]
     }
   ],
-  "editable": true,
+  "editable": false,
   "index": {
     "interval": "none",
     "pattern": "[logstash-]YYYY.MM.DD",

+ 40 - 12
src/app/dashboards/guided.json

@@ -13,7 +13,9 @@
           "query": "*",
           "alias": "",
           "color": "#7EB26D",
-          "id": 0
+          "id": 0,
+          "pin": false,
+          "type": "lucene"
         }
       },
       "ids": [
@@ -40,7 +42,7 @@
       "panels": [
         {
           "error": false,
-          "span": 5,
+          "span": 8,
           "editable": true,
           "group": [
             "default"
@@ -48,7 +50,7 @@
           "type": "text",
           "status": "Stable",
           "mode": "markdown",
-          "content": "If you have a field with a timestamp in it, you might want to add a 'timepicker' panel here. Click the cog icon over to the left to do so. You can also remove these information text panels there",
+          "content": "If you have a field with a timestamp in it, you might want to add a 'timepicker' panel here. Click the plus sign over to the right to do so. You can also remove these information text panels there by clicking the 'x' icon above",
           "style": {},
           "title": "Have a timestamp somewhere?"
         }
@@ -75,7 +77,8 @@
           ],
           "remember": 10,
           "pinned": true,
-          "query": "*"
+          "query": "*",
+          "title": "Search"
         },
         {
           "error": false,
@@ -87,8 +90,9 @@
           "type": "text",
           "status": "Stable",
           "mode": "markdown",
-          "content": "#### Filtering\nSee the small *Filters* text to the left below? Click it to expand the filters row. Right now there are none. click on one of the icons in the document types list to filter down to only that document type",
-          "style": {}
+          "content": "See the *Filters* bar to the below? Click it to expand the filters row. Right now there are none. click on one of the icons in the document types list to filter down to only that document type",
+          "style": {},
+          "title": "About filters"
         }
       ]
     },
@@ -146,7 +150,8 @@
           "arrangement": "horizontal",
           "chart": "pie",
           "counter_pos": "none",
-          "title": "Document types"
+          "title": "Document types",
+          "spyable": true
         },
         {
           "error": false,
@@ -176,7 +181,9 @@
           "labels": true,
           "arrangement": "horizontal",
           "chart": "table",
-          "counter_pos": "above"
+          "counter_pos": "above",
+          "spyable": true,
+          "title": "Document Types"
         },
         {
           "error": false,
@@ -188,8 +195,9 @@
           "type": "text",
           "status": "Stable",
           "mode": "markdown",
-          "content": "### The most generic dashboard ever\nIt's the best I can do without knowing much about your data! I've tried to pick some sane defaults for you. The two *terms* panels to the left of this *text* panel show a breakdown of your document type. \n\nKibana is currently configured to point at the special Elasticsearch *_all* index. You can change that by clicking on the cog icon in the title bar. You can also add rows from that dialog. You can edit individual panels by click on the link that appears in their top right when yuo mouse over them\n\nThe *table* panel below has attempted to list your fields to the left, select a few to view them in the table. To add more panels, of different types, click the cog on the row label to the far left",
-          "style": {}
+          "content": "It's the best I can do without knowing much about your data! I've tried to pick some sane defaults for you. The two *terms* panels to the left of this *text* panel show a breakdown of your document type. \n\nKibana is currently configured to point at the special Elasticsearch *_all* index. You can change that by clicking on the cog icon in the navigation bar at the top. You can also add rows from that dialog. You can edit individual panels by click on the cog icon on the panel you want to edit\n\nThe *table* panel below has attempted to list your fields to the left, select a few to view them in the table. To add more panels, of different types, click the cog on the row label to the far left",
+          "style": {},
+          "title": "The most generic dashboard ever"
         }
       ]
     },
@@ -232,7 +240,10 @@
             ]
           },
           "field_list": true,
-          "status": "Stable"
+          "status": "Stable",
+          "trimFactor": 300,
+          "normTimes": true,
+          "title": "Documents"
         }
       ]
     }
@@ -242,5 +253,22 @@
     "interval": "none",
     "pattern": "[logstash-]YYYY.MM.DD",
     "default": "_all"
+  },
+  "style": "dark",
+  "failover": false,
+  "panel_hints": true,
+  "loader": {
+    "save_gist": false,
+    "save_elasticsearch": true,
+    "save_local": true,
+    "save_default": true,
+    "save_temp": true,
+    "save_temp_ttl_enable": true,
+    "save_temp_ttl": "30d",
+    "load_gist": true,
+    "load_elasticsearch": true,
+    "load_elasticsearch_size": 20,
+    "load_local": true,
+    "hide": false
   }
-}
+}

+ 6 - 1
src/app/dashboards/logstash.js

@@ -103,7 +103,7 @@ dashboard.services.filter = {
 // Ok, lets make some rows. The Filters row is collapsed by default
 dashboard.rows = [
   {
-    title: "Options",
+    title: "Time span",
     height: "30px"
   },
   {
@@ -128,6 +128,7 @@ dashboard.rows = [
 // Setup some panels. A query panel and a filter panel on the same row
 dashboard.rows[0].panels = [
   {
+    title: "Set time filter",
     type: 'timepicker',
     span: 6,
     timespan: ARGS.from||_d_timespan
@@ -137,6 +138,7 @@ dashboard.rows[0].panels = [
 // Add a filtering panel to the 3rd row
 dashboard.rows[1].panels = [
   {
+    title: 'search',
     type: 'query',
     span: 12
   }
@@ -146,6 +148,7 @@ dashboard.rows[1].panels = [
 // Add a filtering panel to the 3rd row
 dashboard.rows[2].panels = [
   {
+    title: 'filters (applied globally)',
     type: 'filtering',
     span: 12
   }
@@ -154,6 +157,7 @@ dashboard.rows[2].panels = [
 // And a histogram that allows the user to specify the interval and time field
 dashboard.rows[3].panels = [
   {
+    title: 'events over time',
     type: 'histogram',
     time_field: ARGS.timefield||"@timestamp",
     auto_int: true,
@@ -164,6 +168,7 @@ dashboard.rows[3].panels = [
 // And a table row where you can specify field and sort order
 dashboard.rows[4].panels = [
   {
+    title: 'all events',
     type: 'table',
     fields: !_.isUndefined(ARGS.fields) ? ARGS.fields.split(',') : [],
     sort: !_.isUndefined(ARGS.sort) ? ARGS.sort.split(',') : [ARGS.timefield||'@timestamp','desc'],

+ 5 - 0
src/app/dashboards/logstash.json

@@ -47,6 +47,7 @@
       "collapsable": true,
       "panels": [
         {
+          "title": "Set time span",
           "error": "",
           "span": 6,
           "editable": true,
@@ -87,6 +88,7 @@
       "collapsable": true,
       "panels": [
         {
+          "title": "Search",
           "error": false,
           "span": 12,
           "editable": true,
@@ -110,6 +112,7 @@
       "collapsable": true,
       "panels": [
         {
+          "title": "dashboard filters",
           "error": false,
           "span": 12,
           "editable": true,
@@ -172,6 +175,7 @@
       "collapsable": true,
       "panels": [
         {
+          "title": "All events",
           "error": false,
           "span": 12,
           "editable": true,
@@ -209,6 +213,7 @@
     }
   ],
   "editable": true,
+  "failover": false,
   "index": {
     "interval": "day",
     "pattern": "[logstash-]YYYY.MM.DD",

+ 35 - 11
src/app/dashboards/noted.json

@@ -1,5 +1,5 @@
 {
-  "title": "Your Basic Dashboard",
+  "title": "A few notes",
   "services": {
     "query": {
       "idQueue": [
@@ -13,7 +13,9 @@
           "query": "*",
           "alias": "",
           "color": "#7EB26D",
-          "id": 0
+          "id": 0,
+          "pin": false,
+          "type": "lucene"
         }
       },
       "ids": [
@@ -40,7 +42,7 @@
       "panels": [
         {
           "error": false,
-          "span": 5,
+          "span": 8,
           "editable": true,
           "group": [
             "default"
@@ -75,7 +77,8 @@
           ],
           "remember": 10,
           "pinned": true,
-          "query": "*"
+          "query": "*",
+          "title": "Search"
         }
       ]
     },
@@ -88,7 +91,7 @@
       "panels": [
         {
           "error": false,
-          "span": 3,
+          "span": 5,
           "editable": true,
           "group": [
             "default"
@@ -97,16 +100,18 @@
           "status": "Stable",
           "mode": "markdown",
           "content": "You found the filter row! This row has a 'filtering' panel in it that lists any active filters. You usually want one of these on any dashboard.",
-          "style": {}
+          "style": {},
+          "title": "Found me!"
         },
         {
           "error": false,
-          "span": 9,
+          "span": 7,
           "editable": true,
           "group": [
             "default"
           ],
-          "type": "filtering"
+          "type": "filtering",
+          "title": "Filters (applied globally)"
         }
       ]
     },
@@ -127,7 +132,7 @@
           "type": "text",
           "status": "Stable",
           "mode": "markdown",
-          "content": "See the small Filters text above this? Click it to expand the filters row. Right now there are none, but if you were to add a Table panel, you could click on event fields to drill down and add some. Or if you had timestamped data and used a time picker, your time filter would appear there",
+          "content": "See the small Filters bar above this? Click it to expand the filters row. Right now there are none, but if you were to add a Table panel, you could click on event fields to drill down and add some. Or if you had timestamped data and used a time picker, your time filter would appear there",
           "style": {},
           "title": "Filtering"
         },
@@ -142,7 +147,8 @@
           "status": "Stable",
           "mode": "markdown",
           "content": "### Start here\nThis dashboard doesn't run any queries, but it's the best I can do without knowing much about your data!\n\n##### Kibana is currently configured to point at the special Elasticsearch *_all* index. You can change that by clicking on the cog icon in the title bar of this dashboard\nIf you have several indices and a lot of data, you should probably do that before you add any new panels. You can also add rows from that dialog. You can edit individual panels by click on the link that appears in their top right when you mouse over them",
-          "style": {}
+          "style": {},
+          "title": "Welcome!"
         }
       ]
     },
@@ -164,7 +170,8 @@
           "status": "Stable",
           "mode": "markdown",
           "content": "## A good place for a table\nThis is a good place for a table panel. Table panels present your data in a tabular format and allow you pick the fields you want to see, sort on them, and drill down.",
-          "style": {}
+          "style": {},
+          "title": "Put a table here maybe?"
         }
       ]
     }
@@ -174,5 +181,22 @@
     "interval": "none",
     "pattern": "[logstash-]YYYY.MM.DD",
     "default": "_all"
+  },
+  "style": "dark",
+  "failover": false,
+  "panel_hints": true,
+  "loader": {
+    "save_gist": false,
+    "save_elasticsearch": true,
+    "save_local": true,
+    "save_default": true,
+    "save_temp": true,
+    "save_temp_ttl_enable": true,
+    "save_temp_ttl": "30d",
+    "load_gist": true,
+    "load_elasticsearch": true,
+    "load_elasticsearch_size": 20,
+    "load_local": true,
+    "hide": false
   }
 }

+ 14 - 6
src/app/directives/kibanaPanel.js

@@ -13,17 +13,21 @@ function (angular) {
 
         '<div class="row-fluid panel-extra"><div class="panel-extra-container">' +
 
-          '<span class="extra row-button " ng-show="panel.editable != false">' +
-            '<span class="row-text pointer" bs-tooltip="\'Drag title to move\'" data-drag=true '+
-            'data-jqyoui-options="{revert: \'invalid\',helper:\'clone\'}"'+
+          '<span class="extra row-button" ng-hide="panel.draggable == false">' +
+            '<span class="row-text pointer" bs-tooltip="\'Drag here to move\'"' +
+            'data-drag=true data-jqyoui-options="{revert: \'invalid\',helper:\'clone\'}"'+
             ' jqyoui-draggable="'+
             '{'+
               'animate:false,'+
+              'mutate:false,'+
               'index:{{$index}},'+
               'onStart:\'panelMoveStart\','+
               'onStop:\'panelMoveStop\''+
               '}"  ng-model="row.panels">{{panel.type}}</span>'+
           '</span>' +
+          '<span class="extra row-button" ng-show="panel.draggable == false">' +
+            '<span class="row-text">{{panel.type}}</span>'+
+          '</span>' +
 
           '<span class="extra row-button" ng-show="panel.editable != false">' +
             '<span confirm-click="row.panels = _.without(row.panels,panel)" '+
@@ -41,10 +45,14 @@ function (angular) {
               'bs-tooltip="task.description" ng-class="task.icon" class="pointer"></i></span>'+
           '</span>' +
 
+          '<span class="row-button extra" ng-show="panelMeta.loading == true">' +
+            '<span>'+
+              '<i class="icon-spinner smaller icon-spin icon-large"></i>' +
+            '</span>'+
+          '</span>' +
+
           '<span class="row-button row-text panel-title" ng-show="panel.title">' +
-            '{{panel.title}}&nbsp' +
-            '<i class="icon-spinner smaller icon-spin icon-large"' +
-              'ng-show="panelMeta.loading == true && panel.title"></i>' +
+            '{{panel.title}}' +
           '</span>'+
 
         '</div></div>';

+ 1 - 0
src/app/panels/column/module.js

@@ -62,6 +62,7 @@ function (angular, app, _, config) {
         height: "150px",
         editable: true,
         type: type,
+        draggable: false
       };
     };
 

+ 7 - 8
src/app/panels/histogram/editor.html

@@ -45,21 +45,20 @@
     <div class="span1"> <label class="small">Selectable</label><input type="checkbox" ng-model="panel.interactive" ng-checked="panel.interactive"></div>
     <div class="span2">
       <label class="small">Zoom Links</label><input type="checkbox" ng-model="panel.zoomlinks" ng-checked="panel.zoomlinks" />
+    </div>
+        <div class="span2">
+      <label class="small">View Options</label><input type="checkbox" ng-model="panel.options" ng-checked="panel.options" />
     </div>
     <div class="span2">
       <label class="small">Auto-interval</label><input type="checkbox" ng-model="panel.auto_int" ng-checked="panel.auto_int" />
     </div>
     <div class="span2" ng-show='panel.auto_int'>
-      <label class="small">Resolution</label><input type="number" class='input-mini' ng-model="panel.resolution" ng-change='set_refresh(true)'/>
-    </div>
-    <div class="span3" ng-show='panel.auto_int'>
-      <label class="small">Shoot for this many data points, rounding to sane intervals</label>
+      <label class="small">Resolution <tip>Shoot for this many data points, rounding to sane intervals</tip></label>
+      <input type="number" class='input-mini' ng-model="panel.resolution" ng-change='set_refresh(true)'/>
     </div>
     <div class="span2" ng-hide='panel.auto_int'>
-      <label class="small">Interval</label><input type="text" class='input-mini' ng-model="panel.interval" ng-change='set_refresh(true)'/>
-    </div>
-    <div class="span3" ng-hide='panel.auto_int'>
-      <label class="small">Use Elasticsearch date math format (eg 1m, 5m, 1d, 2w, 1y)</label>
+      <label class="small">Interval <tip>Use Elasticsearch date math format (eg 1m, 5m, 1d, 2w, 1y)</tip></label>
+      <input type="text" class='input-mini' ng-model="panel.interval" ng-change='set_refresh(true)'/>
     </div>
   </div>
   <h5>Tooltip Settings</h5>

+ 6 - 1
src/app/partials/dashLoader.html

@@ -1,3 +1,6 @@
+
+<li><a bs-tooltip="'Goto saved default'" data-placement="bottom" href='#/dashboard'><i class='icon-home'></i></a></li>
+
 <li class="dropdown" bs-tooltip="'Load'" data-placement="bottom" ng-show="showDropdown('load')" >
   <a href="#" class="dropdown-toggle" data-toggle="dropdown" ng-click="elasticsearch_dblist('title:'+elasticsearch.query+'*')">
     <i class='icon-folder-open'></i>
@@ -70,4 +73,6 @@
     </li>
   </ul>
 </li>
-<li ng-show="showDropdown('share')"><a bs-tooltip="'Share'" data-placement="bottom" ng-click="elasticsearch_save('temp',loader.save_temp_ttl)" bs-modal="'app/partials/dashLoaderShare.html'"><i class='icon-share'></i></a></li>
+<li ng-show="showDropdown('share')"><a bs-tooltip="'Share'" data-placement="bottom" ng-click="elasticsearch_save('temp',loader.save_temp_ttl)" bs-modal="'app/partials/dashLoaderShare.html'"><i class='icon-share'></i></a></li>
+
+<li ng-show="dashboard.current.editable "bs-tooltip="'Configure dashboard'" data-placement="bottom"><a href='#' bs-modal="'app/partials/dasheditor.html'"><i class='icon-cog pointer'></i></a></li>

+ 34 - 14
src/app/partials/dashboard.html

@@ -6,24 +6,27 @@
       <div class="row-fluid" style="padding:0px;margin:0px;position:relative;">
 
         <div class="row-close span12" ng-show="row.collapse" data-placement="bottom" >
-          <span class="row-button" ng-click="toggle_row(row)" ng-show="row.collapsable}">
-            <i bs-tooltip="'Expand row'" data-placement="right" ng-show="row.editable" class="icon-expand pointer" ></i>
-          </span>
           <span class="row-button" bs-modal="'app/partials/roweditor.html'" class="pointer">
             <i bs-tooltip="'Configure row'" data-placement="right" ng-show="row.editable" class="icon-cog pointer"></i>
           </span>
-          <span class="row-button row-text">{{row.title || 'Row '+$index}}</span>
+          <span class="row-button" ng-click="toggle_row(row)" ng-show="row.collapsable">
+            <i bs-tooltip="'Expand row'" data-placement="right" ng-show="row.editable" class="icon-expand pointer" ></i>
+          </span>
+          <span class="row-button row-text" ng-click="toggle_row(row)" ng-class="{'pointer':row.collapsable}">{{row.title || 'Row '+$index}}</span>
         </div>
 
         <div style="text-align:left" class="row-open" ng-show="!row.collapse">
-          <span>
-            <i bs-tooltip="'Hide row'" data-placement="right" ng-show="row.collapsable" class="icon-collapse-top" ng-click="toggle_row(row)"></i>
-          </span><br>
-          <span bs-modal="'app/partials/roweditor.html'">
-            <i bs-tooltip="'Configure row'" data-placement="right" ng-show="row.editable" class="icon-cog pointer"></i>
-          </span><br>
-          <span bs-modal="'app/partials/roweditor.html'">
-            <i ng-click="editor.index = 2" bs-tooltip="'Add panel'" data-placement="right" ng-show="row.editable" class="icon-plus pointer"></i>
+          <span ng-show="row.collapsable">
+            <i bs-tooltip="'Hide row'" data-placement="right"  class="icon-collapse-top" ng-click="toggle_row(row)"></i>
+            <br>
+          </span>
+          <span bs-modal="'app/partials/roweditor.html'" ng-show="row.editable">
+            <i bs-tooltip="'Configure row'" data-placement="right"  class="icon-cog pointer"></i>
+            <br>
+          </span>
+          <span ng-show="rowSpan(row) > 11 && row.editable">
+            <i bs-tooltip="'Row full. Create a new row to add more panels'" data-placement="right" class="icon-trello"></i>
+            <br>
           </span>
         </div>
 
@@ -31,7 +34,7 @@
       <div class="row-fluid" style="padding-top:0px" ng-hide="row.collapse">
 
         <!-- Panels -->
-        <div ng-repeat="(name, panel) in row.panels|filter:isPanel" ng-hide="panel.span == 0 || panel.hide" class="span{{panel.span}} panel nospace" style="min-height:{{row.height}}; position:relative" data-drop="true" ng-model="row.panels" data-jqyoui-options jqyoui-droppable="{index:$index,onDrop:'panelMoveDrop',onOver:'panelMoveOver(true)',onOut:'panelMoveOut'}">
+        <div ng-repeat="(name, panel) in row.panels|filter:isPanel" ng-hide="panel.span == 0 || panel.hide" class="span{{panel.span}} panel nospace" style="min-height:{{row.height}}; position:relative" data-drop="true" ng-model="row.panels" data-jqyoui-options jqyoui-droppable="{index:$index,mutate:false,onDrop:'panelMoveDrop',onOver:'panelMoveOver(true)',onOut:'panelMoveOut'}">
           <!-- Error Panel -->
           <div class="row-fluid">
             <div class="span12 alert alert-error panel-error" ng-hide="!panel.error">
@@ -45,9 +48,26 @@
           </div>
         </div>
 
-        <div ng-hide="(12-rowSpan(row)) < 1 || !dashboard.current.panel_hints" class="panel span{{(12-rowSpan(row))}}" ng-class="{'dragInProgress':dashboard.panelDragging}" style="height:{{row.height}};" data-drop="true" ng-model="row.panels" data-jqyoui-options jqyoui-droppable="{index:row.panels.length,onDrop:'panelMoveDrop({{(12-rowSpan(row))}})',onOver:'panelMoveOver(false)',onOut:'panelMoveOut'}"></div>
+        <div ng-hide="(12-rowSpan(row)) < 1 || !dashboard.current.panel_hints" class="panel span{{(12-rowSpan(row))}}" ng-class="{'dragInProgress':dashboard.panelDragging}" style="height:{{row.height}};" data-drop="true" ng-model="row.panels" data-jqyoui-options jqyoui-droppable="{index:row.panels.length,onDrop:'panelMoveDrop({{(12-rowSpan(row))}})',onOver:'panelMoveOver(false)',onOut:'panelMoveOut'}">
+
+          <span bs-modal="'app/partials/roweditor.html'" ng-show="row.editable && !dashboard.panelDragging">
+            <i ng-hide="rowSpan(row) == 0" class="pointer icon-plus-sign" ng-click="editor.index = 2" bs-tooltip="'Add a panel to this row'" data-placement="right"></i>
+            <span ng-click="editor.index = 2" style="margin-top: 8px; margin-left: 3px" ng-show="rowSpan(row) == 0" class="btn btn-mini">Add panel to empty row</btn>
+          </span>
+
+        </div>
 
       </div>
     </div>
   </div>
+
+  <div class="row-fluid" ng-show='dashboard.current.editable'>
+    <div class="span12" style="text-align:right;">
+      <span style="margin-left: 0px;" class="pointer btn btn-mini" bs-modal="'app/partials/dasheditor.html'">
+        <span ng-click="editor.index = 2"><i class="icon-plus-sign"></i> ADD A ROW</span>
+      </span>
+    </div>
+  </div>
+
+
 </div>

+ 23 - 10
src/app/services/panelMove.js

@@ -15,18 +15,13 @@ function (angular, _) {
 
     this.onStart = function() {
       dashboard.panelDragging =  true;
-      notices.push(alertSrv.set('Moving','Drop this panel into an empty space, or on top of another panel','info'));
+      notices.push(alertSrv.set('Moving','Drop this panel into an available space, or on top of another panel','info'));
       $rootScope.$apply();
     };
 
-    this.onOver = function(event,ui,data,replace) {
-      if(replace) {
-        notices.push(alertSrv.set('Swap panel',
-          'Drop to swap these panels. Panels will use row height, but retain their span','success'));
-      } else {
-        notices.push(alertSrv.set('Add panel',
-          'Drop to add to this row. Panel will use row height, but retain their span','success'));
-      }
+    this.onOver = function() {
+      notices.push(alertSrv.set('Add panel',
+          'Drop to add panel to this row. Panel will use row height, but retain their span','success'));
       $rootScope.$apply();
     };
 
@@ -35,7 +30,25 @@ function (angular, _) {
       $rootScope.$apply();
     };
 
-    this.onDrop = function() {
+    /*
+      Use our own drop logic. the $parent.$parent this is ugly.
+    */
+    this.onDrop = function(event,ui,data) {
+      var
+        dragRow = data.draggableScope.$parent.$parent.row.panels,
+        dropRow =  data.droppableScope.$parent.$parent.row.panels,
+        dragIndex = data.dragSettings.index,
+        dropIndex =  data.dropSettings.index;
+
+
+      // Remove panel from source row
+      dragRow.splice(dragIndex,1);
+
+      // Add to destination row
+      if(!_.isUndefined(dropRow)) {
+        dropRow.splice(dropIndex,0,data.dragItem);
+      }
+
       dashboard.panelDragging = false;
       // Cleanup nulls/undefined left behind
       cleanup();

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
src/css/bootstrap.dark.min.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
src/css/bootstrap.light.min.css


+ 0 - 5
src/index.html

@@ -34,11 +34,6 @@
       <div class="navbar-inner">
         <div class="container-fluid">
           <span class="brand">{{dashboard.current.title}}</span>
-          <ul class="nav" ng-show='dashboard.current.editable'>
-            <li>
-              <a href='#' bs-modal="'app/partials/dasheditor.html'"><i class='icon-cog pointer'></i></a>
-            </li>
-          </ul>
           <ul class="nav pull-right" ng-controller='dashLoader' ng-init="init()" ng-include="'app/partials/dashLoader.html'">
           </ul>
         </div>

+ 15 - 4
src/vendor/angular/angular-dragdrop.js

@@ -86,16 +86,27 @@ var jqyoui = angular.module('ngDragDrop', []).service('ngDragDropService', ['$ti
             $draggable.css({'position': 'relative', 'left': '', 'top': ''});
             $droppableDraggable.css({'position': 'relative', 'left': '', 'top': ''});
 
-            this.mutateDraggable(draggableScope, dropSettings, dragSettings, dragModel, dropModel, dropItem, $draggable);
-            this.mutateDroppable(droppableScope, dropSettings, dragSettings, dropModel, dragItem, jqyoui_pos);
+            if(dragSettings.mutate !== false) {
+              this.mutateDraggable(draggableScope, dropSettings, dragSettings, dragModel, dropModel, dropItem, $draggable);
+            }
+
+            if(dropSettings.mutate !== false) {
+              this.mutateDroppable(droppableScope, dropSettings, dragSettings, dropModel, dragItem, jqyoui_pos);
+            }
 
             this.callEventCallback(droppableScope, dropSettings.onDrop, event, ui, data);
           }.bind(this));
         }.bind(this));
       } else {
         $timeout(function() {
-          this.mutateDraggable(draggableScope, dropSettings, dragSettings, dragModel, dropModel, dropItem, $draggable);
-          this.mutateDroppable(droppableScope, dropSettings, dragSettings, dropModel, dragItem, jqyoui_pos);
+
+          if(dragSettings.mutate !== false) {
+            this.mutateDraggable(draggableScope, dropSettings, dragSettings, dragModel, dropModel, dropItem, $draggable);
+          }
+
+          if(dropSettings.mutate !== false) {
+            this.mutateDroppable(droppableScope, dropSettings, dragSettings, dropModel, dragItem, jqyoui_pos);
+          }
 
           this.callEventCallback(droppableScope, dropSettings.onDrop, event, ui, data);
         }.bind(this));

+ 1 - 0
src/vendor/bootstrap/less/bootstrap.light.less

@@ -1,3 +1,4 @@
 @import "bootstrap.less";
+@import "bootswatch.light.less";
 @import "overrides.less";
 @import "variables.light.less";

+ 10 - 1
src/vendor/bootstrap/less/bootswatch.dark.less

@@ -2,6 +2,15 @@
 // Bootswatch
 // -----------------------------------------------------
 
+// KIBANA
+.panelCont {
+    outline: 1px solid darken(@bodyBackground, 10%);
+    border-top: 1px solid lighten(@bodyBackground, 10%);
+    padding: 0px 10px 10px 10px;
+    background: darken(@bodyBackground, 3%);
+    margin: 0px;
+}
+
 
 // TYPOGRAPHY
 // -----------------------------------------------------
@@ -33,7 +42,7 @@ hr {
 .navbar {
 
 	.navbar-inner {
-		#gradient > .vertical-three-colors(@gray, @grayDark, 70%, @grayDark);
+		#gradient > .vertical-three-colors(@grayDark, darken(@bodyBackground,3%), 70%, darken(@bodyBackground,3%));
 	}
 
 	.brand {

+ 9 - 0
src/vendor/bootstrap/less/bootswatch.light.less

@@ -0,0 +1,9 @@
+
+// KIBANA
+.panelCont {
+    outline: 1px solid darken(@bodyBackground, 10%);
+    border-top: 1px solid lighten(@bodyBackground, 10%);
+    padding: 0px 10px 10px 10px;
+    background: darken(@bodyBackground, 5%);
+    margin: 0px;
+}

+ 0 - 8
src/vendor/bootstrap/less/overrides.less

@@ -115,14 +115,6 @@
   z-index: 9999;
 }
 
-.panelCont {
-    outline: 1px solid darken(@bodyBackground, 10%);
-    border-top: 1px solid lighten(@bodyBackground, 10%);
-    padding: 0px 10px 10px 10px;
-    background: darken(@bodyBackground, 3%);
-    margin: 0px;
-}
-
 .panel-title {
   border: 0px;
   margin-left: -11px;

+ 1 - 0
src/vendor/bootstrap/less/variables.dark.less

@@ -177,6 +177,7 @@
 
 // Navbar
 // -------------------------
+
 @navbarCollapseWidth:             979px;
 @navbarCollapseDesktopWidth:      @navbarCollapseWidth + 1;
 @navbarHeight:                    40px;

Некоторые файлы не были показаны из-за большого количества измененных файлов