mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Merge branch 'develop' into vislib/refactor
Conflicts: .gitignore
This commit is contained in:
commit
bbbd971810
117 changed files with 2431 additions and 492 deletions
4
.bowerrc
4
.bowerrc
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"directory": "./src/bower_components"
|
||||
}
|
||||
"directory": "./src/kibana/bower_components"
|
||||
}
|
||||
|
|
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -1,7 +1,8 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
src/bower_components
|
||||
bower_components
|
||||
**/*.css
|
||||
trash
|
||||
build
|
||||
target
|
||||
target
|
||||
.jruby
|
||||
|
|
1
.ruby-version
Normal file
1
.ruby-version
Normal file
|
@ -0,0 +1 @@
|
|||
1.9.3-p547
|
|
@ -12,9 +12,12 @@ module.exports = function (grunt) {
|
|||
target: __dirname + '/target', // location of the compressed build targets
|
||||
buildApp: __dirname + '/build/kibana', // build directory for the app
|
||||
|
||||
jrubyVersion: '1.7.14',
|
||||
jrubyPath: __dirname + '/.jruby',
|
||||
|
||||
unitTestDir: __dirname + '/test/unit',
|
||||
testUtilsDir: __dirname + '/test/utils',
|
||||
bowerComponentsDir: __dirname + '/src/bower_components',
|
||||
bowerComponentsDir: __dirname + '/src/kibana/bower_components',
|
||||
|
||||
meta: {
|
||||
banner: '/*! <%= package.name %> - v<%= package.version %> - ' +
|
||||
|
@ -36,4 +39,4 @@ module.exports = function (grunt) {
|
|||
|
||||
// load task definitions
|
||||
grunt.loadTasks('tasks');
|
||||
};
|
||||
};
|
||||
|
|
7
LICENSE.md
Normal file
7
LICENSE.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
Copyright 2012-2014 Elasticsearch BV
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
431
TODOS.md
431
TODOS.md
File diff suppressed because one or more lines are too long
42
bower.json
42
bower.json
|
@ -20,32 +20,32 @@
|
|||
"tests"
|
||||
],
|
||||
"dependencies": {
|
||||
"requirejs": "~2.1.10",
|
||||
"angular": "~1.2.14",
|
||||
"lodash": "~2.4.1",
|
||||
"d3": "~3.4.8",
|
||||
"angular-route": "~1.2.14",
|
||||
"gridster": "~0.5.0",
|
||||
"angular-mocks": "~1.2.14",
|
||||
"font-awesome": "~4.0.3",
|
||||
"requirejs-text": "~2.0.10",
|
||||
"async": "~0.2.10",
|
||||
"bootstrap": "~3.1.1",
|
||||
"jquery": "~2.1.0",
|
||||
"moment": "~2.5.1",
|
||||
"require-css": "~0.1.2",
|
||||
"angular-bootstrap": "~0.10.0",
|
||||
"jsonpath": "*",
|
||||
"moment-timezone": "~0.0.3",
|
||||
"angular-bindonce": "~0.3.1",
|
||||
"angular-ui-ace": "bower",
|
||||
"angular-bootstrap": "~0.10.0",
|
||||
"angular-elastic": "~2.3.3",
|
||||
"inflection": "~1.3.5",
|
||||
"FileSaver": "*",
|
||||
"elasticsearch": "*",
|
||||
"angular-mocks": "~1.2.14",
|
||||
"angular-route": "~1.2.14",
|
||||
"angular-ui-ace": "bower",
|
||||
"async": "~0.2.10",
|
||||
"bluebird": "~2.1.3",
|
||||
"bootstrap": "~3.1.1",
|
||||
"d3": "~3.4.8",
|
||||
"elasticsearch": "*",
|
||||
"Faker": "~1.1.0",
|
||||
"FileSaver": "*",
|
||||
"font-awesome": "~4.0.3",
|
||||
"gridster": "~0.5.0",
|
||||
"inflection": "~1.3.5",
|
||||
"jquery": "~2.1.0",
|
||||
"jsonpath": "*",
|
||||
"lesshat": "~3.0.2",
|
||||
"Faker": "~1.1.0"
|
||||
"lodash": "~2.4.1",
|
||||
"moment": "~2.5.1",
|
||||
"moment-timezone": "~0.0.3",
|
||||
"require-css": "~0.1.2",
|
||||
"requirejs": "~2.1.10",
|
||||
"requirejs-text": "~2.0.10"
|
||||
},
|
||||
"devDependencies": {}
|
||||
}
|
||||
|
|
|
@ -20,15 +20,21 @@
|
|||
"grunt-contrib-requirejs": "~0.4.4",
|
||||
"grunt-contrib-watch": "~0.5.3",
|
||||
"grunt-mocha": "~0.4.10",
|
||||
"grunt-replace": "^0.7.9",
|
||||
"grunt-run": "^0.2.3",
|
||||
"http-proxy": "~1.1.4",
|
||||
"husky": "~0.6.0",
|
||||
"istanbul": "~0.2.4",
|
||||
"load-grunt-config": "~0.7.0",
|
||||
"lodash": "~2.4.1",
|
||||
"mkdirp": "^0.5.0",
|
||||
"mocha": "~1.20.1",
|
||||
"path-browserify": "0.0.0",
|
||||
"progress": "^1.1.8",
|
||||
"request": "^2.40.0",
|
||||
"requirejs": "~2.1.14",
|
||||
"rjs-build-analysis": "0.0.3"
|
||||
"rjs-build-analysis": "0.0.3",
|
||||
"tar": "^1.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "grunt test",
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
require "java"
|
||||
require "warbler"
|
||||
|
||||
HERE = File.expand_path(File.dirname(__FILE__))
|
||||
|
||||
task "default" => "jar:run"
|
||||
|
||||
namespace "jar" do
|
||||
desc "Run the project jar file"
|
||||
task "run" => "jar" do
|
||||
exec("cd #{HERE} && rm -rf /tmp/kibana* && cp kibana.jar /tmp && cd /tmp && unzip -o kibana.jar 'kibana/public/*' && unzip -o kibana.jar kibana/config/web.ru && env PUBLIC_FOLDER=/tmp/kibana/public java -server -jar kibana.jar kibana/config/web.ru")
|
||||
end
|
||||
end
|
||||
|
||||
desc "Create the project jar file"
|
||||
task "jar" do
|
||||
system("cd #{HERE} && jruby -S warble")
|
||||
end
|
||||
|
||||
# desc "Watch for changes"
|
||||
# task "watch" => "vendor/fswatch" do
|
||||
# system("killall fswatch")
|
||||
# system("fswatch #{HERE}/lib \"bash -c \\\"kill -SIGUSR2 \\\`ps u|grep [o]rg.jruby.Main|grep bin/puma|awk {\'print \\\$2\'}\\\`\\\"\" &")
|
||||
# end
|
||||
|
||||
desc "Run the project from jruby"
|
||||
# task "run" => "watch" do
|
||||
task "run" do
|
||||
exec("cd #{HERE} && jruby -S bundle exec jruby -S bin/kibana config/web.ru")
|
||||
end
|
|
@ -1,38 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
#
|
||||
# This file was generated by RubyGems.
|
||||
#
|
||||
# The application 'puma' is installed as part of a gem, and
|
||||
# this file is here to facilitate running it.
|
||||
#
|
||||
|
||||
require 'rubygems'
|
||||
|
||||
version = ">= 0"
|
||||
|
||||
HERE = File.expand_path(File.dirname(__FILE__))
|
||||
|
||||
if ARGV.first
|
||||
str = ARGV.first
|
||||
str = str.dup.force_encoding("BINARY") if str.respond_to? :force_encoding
|
||||
if str =~ /\A_(.*)_\z/
|
||||
version = $1
|
||||
ARGV.shift
|
||||
end
|
||||
end
|
||||
|
||||
# Include the puma config unless it's been overriden
|
||||
unless ARGV.include?('-C')
|
||||
ARGV << '-C'
|
||||
ARGV << "#{HERE}/../config/puma.rb"
|
||||
end
|
||||
|
||||
# Include the rack config if it hasn't been included
|
||||
if (ARGV.grep(/config\/web\.ru/)).empty?
|
||||
ARGV << "#{HERE}/../config/web.ru"
|
||||
end
|
||||
|
||||
print ARGV, "\n"
|
||||
|
||||
gem 'puma', version
|
||||
load Gem.bin_path('puma', 'puma', version)
|
|
@ -1,2 +0,0 @@
|
|||
port 8000
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
# Add the libs directory to the load path
|
||||
ROOT = File.expand_path("#{File.dirname(__FILE__)}/../")
|
||||
$LOAD_PATH.unshift(ROOT)
|
||||
|
||||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
|
||||
# Require the application
|
||||
require "#{ROOT}/lib/app"
|
||||
|
||||
# Run the application
|
||||
run Kibana::App
|
|
@ -1,27 +0,0 @@
|
|||
# Add the root of the project to the $LOAD_PATH, For some reason it seems
|
||||
# to be getting lost when we use warble to make the jar. This fixes it :D
|
||||
$LOAD_PATH.unshift(ROOT)
|
||||
|
||||
require "rack/reverse_proxy"
|
||||
require "routes/home"
|
||||
require "routes/api"
|
||||
|
||||
module Kibana
|
||||
class App < Sinatra::Base
|
||||
|
||||
configure do
|
||||
set :root, ROOT
|
||||
set :public_folder, "#{ROOT}/public"
|
||||
set :httponly, true
|
||||
end
|
||||
|
||||
# Rack middleware goes here
|
||||
use Rack::ReverseProxy do
|
||||
reverse_proxy /^\/elasticsearch(.*)$/, 'http://localhost:9200$1'
|
||||
end
|
||||
|
||||
# Routes go here
|
||||
use Routes::Home
|
||||
use Routes::Api
|
||||
end
|
||||
end
|
|
@ -1,22 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Welcome to the Future Home of Kibana</title>
|
||||
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12 text-center" style="padding-top: 40px;">
|
||||
<h1>Welcome to the Future Home of Kibana</h1>
|
||||
<p>This is the server component of Kibana. It's just a quick prototype of the things we need.</p>
|
||||
<p><a href="/test.html">Static Server</a></p>
|
||||
<p><a href="/api/foo">Server Side APIs</a></p>
|
||||
<p><a href="/elasticsearch">Elasticsearch Proxy</a></p>
|
||||
<h3>Much more coming soon...</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,9 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>This is a test file</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>This is a test</h1>
|
||||
<p>This should work outside of anything else.</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1,16 +0,0 @@
|
|||
require "routes/base"
|
||||
require "lib/helpers"
|
||||
|
||||
module Kibana
|
||||
module Routes
|
||||
class Api < Base
|
||||
|
||||
helpers Kibana::Helpers
|
||||
|
||||
get "/api/foo" do
|
||||
json :foo => doSomething()
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,15 +0,0 @@
|
|||
require "sinatra/base"
|
||||
require "sinatra/json"
|
||||
|
||||
module Kibana
|
||||
module Routes
|
||||
class Base < Sinatra::Base
|
||||
helpers Sinatra::JSON
|
||||
|
||||
configure do
|
||||
# Confirgure stuffs here
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,13 +0,0 @@
|
|||
require "routes/base"
|
||||
|
||||
module Kibana
|
||||
module Routes
|
||||
class Home < Base
|
||||
|
||||
get "/" do
|
||||
File.read(File.join(ROOT, 'public', 'index.html'))
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -25,7 +25,7 @@ define(function (require) {
|
|||
|
||||
require('routes')
|
||||
.when('/dashboard', {
|
||||
templateUrl: 'kibana/apps/dashboard/index.html',
|
||||
template: require('text!apps/dashboard/index.html'),
|
||||
resolve: {
|
||||
dash: function (savedDashboards) {
|
||||
return savedDashboards.get();
|
||||
|
@ -33,7 +33,7 @@ define(function (require) {
|
|||
}
|
||||
})
|
||||
.when('/dashboard/:id', {
|
||||
templateUrl: 'kibana/apps/dashboard/index.html',
|
||||
template: require('text!apps/dashboard/index.html'),
|
||||
resolve: {
|
||||
dash: function (savedDashboards, Notifier, $route, $location, courier) {
|
||||
return savedDashboards.get($route.current.params.id)
|
||||
|
@ -42,7 +42,7 @@ define(function (require) {
|
|||
}
|
||||
});
|
||||
|
||||
app.directive('dashboardApp', function (Notifier, courier, savedVisualizations, appStateFactory, timefilter) {
|
||||
app.directive('dashboardApp', function (Notifier, courier, savedVisualizations, appStateFactory, timefilter, kbnUrl) {
|
||||
return {
|
||||
controller: function ($scope, $route, $routeParams, $location, configFile) {
|
||||
var notify = new Notifier({
|
||||
|
@ -113,7 +113,7 @@ define(function (require) {
|
|||
.then(function () {
|
||||
notify.info('Saved Dashboard as "' + dash.title + '"');
|
||||
if (dash.id !== $routeParams.id) {
|
||||
$location.url('/dashboard/' + encodeURIComponent(dash.id));
|
||||
kbnUrl.change('/dashboard/{{id}}', {id: dash.id});
|
||||
}
|
||||
})
|
||||
.catch(notify.fatal);
|
||||
|
|
|
@ -13,7 +13,7 @@ define(function (require) {
|
|||
});
|
||||
|
||||
// This is the only thing that gets injected into controllers
|
||||
module.service('savedDashboards', function (Promise, SavedDashboard, config, es) {
|
||||
module.service('savedDashboards', function (Promise, SavedDashboard, config, es, kbnUrl) {
|
||||
|
||||
// Returns a single dashboard by ID, should be the name of the dashboard
|
||||
this.get = function (id) {
|
||||
|
@ -23,7 +23,7 @@ define(function (require) {
|
|||
};
|
||||
|
||||
this.urlFor = function (id) {
|
||||
return '#/dashboard/' + encodeURIComponent(id);
|
||||
return kbnUrl.eval('#/dashboard/{{id}}', {id: id});
|
||||
};
|
||||
|
||||
this.delete = function (ids) {
|
||||
|
|
|
@ -46,7 +46,7 @@ define(function (require) {
|
|||
});
|
||||
|
||||
app.controller('discover', function ($scope, config, courier, $route, $window, savedSearches, savedVisualizations,
|
||||
Notifier, $location, globalState, appStateFactory, timefilter, Promise, Private) {
|
||||
Notifier, $location, globalState, appStateFactory, timefilter, Promise, Private, kbnUrl) {
|
||||
|
||||
var Vis = Private(require('components/vis/vis'));
|
||||
var SegmentedFetch = Private(require('apps/discover/_segmented_fetch'));
|
||||
|
@ -110,7 +110,8 @@ define(function (require) {
|
|||
$state.index = config.get('defaultIndex');
|
||||
} else {
|
||||
notify.warning(reason + 'Please set a default index to continue.');
|
||||
$location.url('/settings/indices');
|
||||
kbnUrl.change('/settings/indices');
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -227,7 +228,7 @@ define(function (require) {
|
|||
.then(function () {
|
||||
notify.info('Saved Data Source "' + savedSearch.title + '"');
|
||||
if (savedSearch.id !== $route.current.params.id) {
|
||||
$location.url(globalState.writeToUrl('/discover/' + encodeURIComponent(savedSearch.id)));
|
||||
kbnUrl.change('/discover/{{id}}', { id: savedSearch.id });
|
||||
}
|
||||
});
|
||||
})
|
||||
|
@ -388,7 +389,7 @@ define(function (require) {
|
|||
};
|
||||
|
||||
$scope.newQuery = function () {
|
||||
$location.url('/discover');
|
||||
kbnUrl.change('/discover');
|
||||
};
|
||||
|
||||
$scope.updateDataSource = function () {
|
||||
|
|
|
@ -19,11 +19,10 @@ define(function (require) {
|
|||
scope: {
|
||||
fields: '=',
|
||||
toggle: '=',
|
||||
refresh: '=',
|
||||
data: '=',
|
||||
state: '=',
|
||||
updateFilterInQuery: '=filter',
|
||||
searchSource: '='
|
||||
searchSource: '=',
|
||||
updateFilterInQuery: '=filter'
|
||||
},
|
||||
template: html,
|
||||
controller: function ($scope) {
|
||||
|
@ -165,8 +164,7 @@ define(function (require) {
|
|||
count: 5,
|
||||
grouped: false
|
||||
});
|
||||
var indexPattern = $scope.searchSource.get('index');
|
||||
indexPattern.popularizeField(field.name, 1);
|
||||
$scope.increaseFieldCounter(field, 1);
|
||||
} else {
|
||||
delete field.details;
|
||||
}
|
||||
|
|
|
@ -29,23 +29,28 @@ define(function (require) {
|
|||
if ($scope.mapping[column] && !$scope.mapping[column].indexed) return;
|
||||
|
||||
var sorting = $scope.sorting;
|
||||
var defaultClass = ['fa', 'fa-sort', 'table-header-sortchange'];
|
||||
|
||||
if (!sorting) return [];
|
||||
if (!sorting) return defaultClass;
|
||||
|
||||
if (column === sorting[0]) {
|
||||
return ['fa', sorting[1] === 'asc' ? 'fa-sort-up' : 'fa-sort-down'];
|
||||
} else {
|
||||
return ['fa', 'fa-sort', 'table-header-sortchange'];
|
||||
return defaultClass;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.moveLeft = function (column) {
|
||||
var index = _.indexOf($scope.columns, column);
|
||||
if (index === 0) return;
|
||||
|
||||
_.move($scope.columns, index, --index);
|
||||
};
|
||||
|
||||
$scope.moveRight = function (column) {
|
||||
var index = _.indexOf($scope.columns, column);
|
||||
if (index === $scope.columns.length - 1) return;
|
||||
|
||||
_.move($scope.columns, index, ++index);
|
||||
};
|
||||
|
||||
|
@ -112,7 +117,6 @@ define(function (require) {
|
|||
return {
|
||||
restrict: 'A',
|
||||
scope: {
|
||||
fields: '=',
|
||||
columns: '=',
|
||||
filtering: '=',
|
||||
mapping: '=',
|
||||
|
@ -139,27 +143,14 @@ define(function (require) {
|
|||
$scope.maxLength = 250;
|
||||
}
|
||||
|
||||
|
||||
// for now, rows are "tracked" by their index, but this could eventually
|
||||
// be configured so that changing the order of the rows won't prevent
|
||||
// them from staying open on update
|
||||
function rowId(row) {
|
||||
var id = $scope.rows.indexOf(row);
|
||||
return ~id ? id : null;
|
||||
}
|
||||
|
||||
// inverse of rowId()
|
||||
function rowForId(id) {
|
||||
return $scope.rows[id];
|
||||
}
|
||||
|
||||
// toggle display of the rows details, a full list of the fields from each row
|
||||
$scope.toggleRow = function (row, event) {
|
||||
$scope.toggleRow = function () {
|
||||
var row = $scope.row;
|
||||
var id = row._id;
|
||||
|
||||
$scope.open = !$scope.open;
|
||||
|
||||
var $tr = $(event.delegateTarget.parentElement);
|
||||
var $tr = element;
|
||||
var $detailsTr = $tr.next();
|
||||
|
||||
///
|
||||
|
@ -169,7 +160,7 @@ define(function (require) {
|
|||
$detailsTr.toggle($scope.open);
|
||||
|
||||
// Change the caret icon
|
||||
var $toggleIcon = $($(event.delegateTarget).children('i')[0]);
|
||||
var $toggleIcon = $(element.children().first().find('i')[0]);
|
||||
$toggleIcon.toggleClass('fa-caret-down');
|
||||
$toggleIcon.toggleClass('fa-caret-right');
|
||||
|
||||
|
@ -207,7 +198,12 @@ define(function (require) {
|
|||
$scope.filtering(field, row._source[field] || row[field], operation);
|
||||
};
|
||||
|
||||
$scope.$watch('columns', function () {
|
||||
$scope.$watch('columns', function (columns) {
|
||||
element.empty();
|
||||
createSummaryRow($scope.row, $scope.row._id);
|
||||
});
|
||||
|
||||
$scope.$watch('timefield', function (timefield) {
|
||||
element.empty();
|
||||
createSummaryRow($scope.row, $scope.row._id);
|
||||
});
|
||||
|
@ -216,7 +212,7 @@ define(function (require) {
|
|||
function createSummaryRow(row, id) {
|
||||
|
||||
var expandTd = $('<td>').html('<i class="fa fa-caret-right"></span>')
|
||||
.attr('ng-click', 'toggleRow(row, $event)');
|
||||
.attr('ng-click', 'toggleRow()');
|
||||
$compile(expandTd)($scope);
|
||||
element.append(expandTd);
|
||||
|
||||
|
@ -240,11 +236,7 @@ define(function (require) {
|
|||
*/
|
||||
function _displayField(el, row, field, truncate) {
|
||||
var val = _getValForField(row, field, truncate);
|
||||
if (val instanceof DOMNode) {
|
||||
el.append(val);
|
||||
} else {
|
||||
el.text(val);
|
||||
}
|
||||
el.text(val);
|
||||
return el;
|
||||
}
|
||||
|
||||
|
@ -266,17 +258,9 @@ define(function (require) {
|
|||
// undefined and null should just be an empty string
|
||||
val = (val == null) ? '' : val;
|
||||
|
||||
// truncate
|
||||
// truncate the column text, not the details
|
||||
if (typeof val === 'string' && val.length > $scope.maxLength) {
|
||||
if (untruncate) {
|
||||
var complete = val;
|
||||
val = document.createElement('kbn-truncated');
|
||||
val.setAttribute('orig', complete);
|
||||
val.setAttribute('length', $scope.maxLength);
|
||||
val = $compile(val)($scope)[0];// return the actual element
|
||||
} else {
|
||||
val = val.substring(0, $scope.maxLength) + '...';
|
||||
}
|
||||
val = val.substring(0, $scope.maxLength) + '...';
|
||||
}
|
||||
|
||||
return val;
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
<tbody>
|
||||
<tr ng-repeat="row in rows |limitTo:limit track by row._index+row._id"
|
||||
kbn-table-row="row"
|
||||
columns="columns" mapping="mapping" sorting="sorting" timefield="timefield" max-length="maxLength" filtering="filtering"></tr>
|
||||
columns="columns" mapping="mapping" sorting="sorting" timefield="timefield" max-length="maxLength" filtering="filtering"
|
||||
class="discover-table-row"></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<kbn-infinite-scroll more="addRows"></kbn-infinite-scroll>
|
|
@ -3,7 +3,7 @@
|
|||
<span ng-click="sort(timefield)">Time <i ng-class="headerClass(timefield)"></i></span>
|
||||
</th>
|
||||
<th ng-repeat="name in columns">
|
||||
<span ng-click="sort(name)">
|
||||
<span ng-click="sort(name)" class="table-header-name">
|
||||
{{name}} <i ng-class="headerClass(name)"></i>
|
||||
</span>
|
||||
<span class="table-header-move">
|
||||
|
|
|
@ -15,7 +15,7 @@ define(function (require) {
|
|||
title: 'searches'
|
||||
});
|
||||
|
||||
module.service('savedSearches', function (Promise, config, configFile, es, createNotifier, SavedSearch) {
|
||||
module.service('savedSearches', function (Promise, config, configFile, es, createNotifier, SavedSearch, kbnUrl) {
|
||||
|
||||
|
||||
var notify = createNotifier({
|
||||
|
@ -27,7 +27,7 @@ define(function (require) {
|
|||
};
|
||||
|
||||
this.urlFor = function (id) {
|
||||
return '#/discover/' + encodeURIComponent(id);
|
||||
return kbnUrl.eval('#/discover/{{id}}', {id: id});
|
||||
};
|
||||
|
||||
this.delete = function (ids) {
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
<nav class="navbar navbar-default navbar-static-top subnav">
|
||||
<div class="container-fluid">
|
||||
<ul class="nav navbar-nav">
|
||||
<li ng-repeat="s in sections" ng-class="s.class">
|
||||
<a class="navbar-link" ng-href="{{s.url}}">{{s.display}}</a>
|
||||
<li ng-repeat="section in sections" ng-class="section.class">
|
||||
<a class="navbar-link" ng-href="{{section.url}}">{{section.display}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
@ -14,7 +14,7 @@ define(function (require) {
|
|||
|
||||
// wrapper directive, which sets some global stuff up like the left nav
|
||||
require('modules').get('apps/settings')
|
||||
.directive('kbnSettingsIndices', function ($route, config) {
|
||||
.directive('kbnSettingsIndices', function ($route, config, kbnUrl) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
transclude: true,
|
||||
|
@ -31,7 +31,7 @@ define(function (require) {
|
|||
.map(function (id) {
|
||||
return {
|
||||
id: id,
|
||||
url: '#/settings/indices/' + encodeURIComponent(id),
|
||||
url: kbnUrl.eval('#/settings/indices/{{id}}', {id: id}),
|
||||
class: 'sidebar-item-title ' + ($scope.edittingId === id ? 'active' : ''),
|
||||
default: $scope.defaultIndex === id
|
||||
};
|
||||
|
|
|
@ -41,7 +41,7 @@ define(function (require) {
|
|||
'kibana/notify',
|
||||
'kibana/courier'
|
||||
])
|
||||
.controller('VisEditor', function ($scope, $route, timefilter, appStateFactory, $location, globalState, $timeout) {
|
||||
.controller('VisEditor', function ($scope, $route, timefilter, appStateFactory, $location, kbnUrl, $timeout) {
|
||||
|
||||
var _ = require('lodash');
|
||||
var angular = require('angular');
|
||||
|
@ -157,11 +157,7 @@ define(function (require) {
|
|||
|
||||
if (savedVis.id === $route.current.params.id) return;
|
||||
|
||||
$location.url(
|
||||
globalState.writeToUrl(
|
||||
'/visualize/edit/' + encodeURIComponent(savedVis.id)
|
||||
)
|
||||
);
|
||||
kbnUrl.change('/visualize/edit/{{id}}', {id: savedVis.id});
|
||||
}, notify.fatal);
|
||||
};
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ define(function (require) {
|
|||
title: 'visualizations'
|
||||
});
|
||||
|
||||
app.service('savedVisualizations', function (Promise, es, config, SavedVis, Private, Notifier) {
|
||||
app.service('savedVisualizations', function (Promise, es, config, SavedVis, Private, Notifier, kbnUrl) {
|
||||
var visTypes = Private(require('components/vis_types/index'));
|
||||
var notify = new Notifier({
|
||||
location: 'saved visualization service'
|
||||
|
@ -22,7 +22,7 @@ define(function (require) {
|
|||
};
|
||||
|
||||
this.urlFor = function (id) {
|
||||
return '#/visualize/edit/' + encodeURIComponent(id);
|
||||
return kbnUrl.eval('#/visualize/edit/{{id}}', {id: id});
|
||||
};
|
||||
|
||||
this.delete = function (ids) {
|
||||
|
|
|
@ -24,9 +24,9 @@ define(function (require) {
|
|||
}
|
||||
});
|
||||
|
||||
module.controller('VisualizeWizardStep1', function ($route, $scope, $location, timefilter) {
|
||||
module.controller('VisualizeWizardStep1', function ($route, $scope, $location, timefilter, kbnUrl) {
|
||||
$scope.step2WithSearchUrl = function (hit) {
|
||||
return '#/visualize/step/2?savedSearchId=' + encodeURIComponent(hit.id);
|
||||
return kbnUrl.eval('#/visualize/step/2?savedSearchId={{id}}', {id: hit.id});
|
||||
};
|
||||
|
||||
timefilter.enabled = false;
|
||||
|
@ -38,7 +38,7 @@ define(function (require) {
|
|||
|
||||
$scope.$watch('indexPattern.selection', function (pattern) {
|
||||
if (!pattern) return;
|
||||
$location.url('/visualize/step/2?indexPattern=' + encodeURIComponent(pattern));
|
||||
kbnUrl.change('/visualize/step/2?indexPattern={{pattern}}', {pattern: pattern});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -77,4 +77,4 @@ define(function (require) {
|
|||
|
||||
return AggParams;
|
||||
};
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,7 +8,6 @@ define(function (require) {
|
|||
if (query.query_string && query.query_string.query) {
|
||||
return query.query_string.query;
|
||||
}
|
||||
|
||||
return JSON.stringify(query);
|
||||
}
|
||||
|
||||
|
@ -32,4 +31,4 @@ define(function (require) {
|
|||
]
|
||||
});
|
||||
};
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@ define(function (require) {
|
|||
'kibana/notify'
|
||||
]);
|
||||
|
||||
var configFile = require('config_file');
|
||||
var configFile = JSON.parse(require('text!config'));
|
||||
// allow the rest of the app to get the configFile easily
|
||||
module.constant('configFile', configFile);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
define(function (require) {
|
||||
var errors = require('errors');
|
||||
|
||||
return function RedirectWhenMissingFn($location, $route, globalState, Notifier) {
|
||||
return function RedirectWhenMissingFn($location, kbnUrl, globalState, Notifier) {
|
||||
var SavedObjectNotFound = errors.SavedObjectNotFound;
|
||||
|
||||
var notify = new Notifier();
|
||||
|
@ -27,7 +27,7 @@ define(function (require) {
|
|||
if (!url) url = '/';
|
||||
|
||||
notify.error(err);
|
||||
$route.changeUrl(globalState.writeToUrl(url));
|
||||
kbnUrl.change(url);
|
||||
return;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
define(function (require) {
|
||||
return function EnsureSomeIndexPatternsFn(Private, Notifier, $location, $route) {
|
||||
return function EnsureSomeIndexPatternsFn(Private, Notifier, $location, kbnUrl) {
|
||||
var errors = require('errors');
|
||||
var notify = new Notifier();
|
||||
|
||||
|
@ -7,7 +7,7 @@ define(function (require) {
|
|||
return function promiseHandler(patterns) {
|
||||
if (!patterns || patterns.length === 0) {
|
||||
// notify.warning(new errors.NoDefinedIndexPatterns());
|
||||
$route.change('/settings/indices');
|
||||
kbnUrl.changePath('/settings/indices');
|
||||
}
|
||||
|
||||
return patterns;
|
||||
|
|
|
@ -21,8 +21,8 @@ define(function (require) {
|
|||
template: html,
|
||||
controller: function ($scope) {
|
||||
var init = function () {
|
||||
$scope.formatRelative();
|
||||
$scope.setMode($scope.mode);
|
||||
$scope.formatRelative();
|
||||
};
|
||||
|
||||
$scope.format = 'MMMM Do YYYY, HH:mm:ss.SSS';
|
||||
|
@ -136,4 +136,4 @@ define(function (require) {
|
|||
};
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
|
97
src/kibana/components/url/url.js
Normal file
97
src/kibana/components/url/url.js
Normal file
|
@ -0,0 +1,97 @@
|
|||
define(function (require) {
|
||||
require('filters/uriescape');
|
||||
require('filters/rison');
|
||||
var _ = require('lodash');
|
||||
var rison = require('utils/rison');
|
||||
var location = require('modules').get('kibana/url');
|
||||
|
||||
location.service('kbnUrl', function ($route, $location, $rootScope, globalState, $parse) {
|
||||
var self = this;
|
||||
self.reloading = false;
|
||||
|
||||
self.change = function (url, paramObj, forceReload) {
|
||||
self._changeLocation('url', url, paramObj, forceReload);
|
||||
};
|
||||
|
||||
self.changePath = function (url, paramObj, forceReload) {
|
||||
self._changeLocation('path', url, paramObj, forceReload);
|
||||
};
|
||||
|
||||
self._changeLocation = function (type, url, paramObj, forceReload) {
|
||||
var doReload = false;
|
||||
|
||||
if (_.isBoolean(paramObj)) {
|
||||
forceReload = paramObj;
|
||||
paramObj = undefined;
|
||||
}
|
||||
|
||||
url = self.eval(url, paramObj);
|
||||
|
||||
// path change
|
||||
if (type === 'path') {
|
||||
if (url !== $location.path()) {
|
||||
$location.path(globalState.writeToUrl(url));
|
||||
doReload = (!self.matches(url));
|
||||
}
|
||||
// default to url change
|
||||
} else {
|
||||
if (url !== $location.url()) {
|
||||
$location.url(globalState.writeToUrl(url));
|
||||
doReload = (!self.matches(url));
|
||||
}
|
||||
}
|
||||
|
||||
if (forceReload || doReload) {
|
||||
self.reload();
|
||||
}
|
||||
};
|
||||
|
||||
self.eval = function (url, paramObj) {
|
||||
paramObj = paramObj || {};
|
||||
|
||||
return parseUrlPrams(url, paramObj);
|
||||
};
|
||||
|
||||
self.matches = function (url) {
|
||||
var route = $route.current.$$route;
|
||||
if (!route || !route.regexp) return false;
|
||||
return route.regexp.test(url);
|
||||
};
|
||||
|
||||
$rootScope.$on('$routeUpdate', reloadingComplete);
|
||||
$rootScope.$on('$routeChangeStart', reloadingComplete);
|
||||
|
||||
function parseUrlPrams(url, paramObj) {
|
||||
return url.replace(/\{\{([^\}]+)\}\}/g, function (match, expr) {
|
||||
// remove filters
|
||||
var key = expr.split('|')[0].trim();
|
||||
|
||||
// verify that the expression can be evaluated
|
||||
var p = $parse(key)(paramObj);
|
||||
|
||||
// if evaluation can't be made, throw
|
||||
if (_.isUndefined(p)) {
|
||||
throw new Error('Replacement failed, unresolved expression: ' + expr);
|
||||
}
|
||||
|
||||
// append uriescape filter if not included
|
||||
if (expr.indexOf('uriescape') === -1) {
|
||||
expr += '|uriescape';
|
||||
}
|
||||
|
||||
return $parse(expr)(paramObj);
|
||||
});
|
||||
}
|
||||
|
||||
self.reload = function () {
|
||||
if (!self.reloading) {
|
||||
$route.reload();
|
||||
self.reloading = true;
|
||||
}
|
||||
};
|
||||
|
||||
function reloadingComplete() {
|
||||
self.reloading = false;
|
||||
}
|
||||
});
|
||||
});
|
|
@ -6,16 +6,40 @@ define(function (require) {
|
|||
|
||||
_(AggConfigs).inherits(Registry);
|
||||
function AggConfigs(vis, configStates) {
|
||||
var self = this;
|
||||
this.vis = vis;
|
||||
|
||||
|
||||
AggConfigs.Super.call(this, {
|
||||
index: ['id'],
|
||||
group: ['schema.group', 'type.name'],
|
||||
group: ['schema.group', 'type.name', 'schema.name'],
|
||||
initialSet: (configStates || []).map(function (aggConfigState) {
|
||||
if (aggConfigState instanceof AggConfig) return aggConfigState;
|
||||
return new AggConfig(vis, aggConfigState);
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
// Set the defaults for any schema which has them. If the defaults
|
||||
// for some reason has more then the max only set the max number
|
||||
// of defaults (not sure why a someone define more...
|
||||
// but whatever). Also if a schema.name is already set then don't
|
||||
// set anything.
|
||||
if (vis && vis.type && vis.type.schemas && vis.type.schemas.all) {
|
||||
_(vis.type.schemas.all)
|
||||
.filter(function (schema) {
|
||||
return _.isArray(schema.defaults) && schema.defaults.length > 0;
|
||||
})
|
||||
.each(function (schema) {
|
||||
if (!self.bySchemaName[schema.name]) {
|
||||
var defaults = schema.defaults.slice(0, schema.max);
|
||||
_.each(defaults, function (def) {
|
||||
self.push(new AggConfig(vis, def));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
AggConfigs.prototype.toDsl = function () {
|
||||
|
@ -52,4 +76,4 @@ define(function (require) {
|
|||
|
||||
return AggConfigs;
|
||||
};
|
||||
});
|
||||
});
|
||||
|
|
|
@ -18,7 +18,10 @@ define(function (require) {
|
|||
name: 'metric',
|
||||
title: 'Y-Axis',
|
||||
min: 1,
|
||||
max: 1
|
||||
max: 1,
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
|
@ -44,4 +47,4 @@ define(function (require) {
|
|||
])
|
||||
});
|
||||
};
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,11 +8,12 @@ define(function (require) {
|
|||
|
||||
require('components/config/config');
|
||||
require('components/courier/courier');
|
||||
require('components/notify/notify');
|
||||
require('components/state_management/app_state_factory');
|
||||
require('components/filter_bar/filter_bar');
|
||||
require('components/storage/storage');
|
||||
require('components/notify/notify');
|
||||
require('components/persisted_log/persisted_log');
|
||||
require('components/state_management/app_state_factory');
|
||||
require('components/storage/storage');
|
||||
require('components/url/url');
|
||||
require('directives/click_focus');
|
||||
require('directives/info');
|
||||
require('directives/spinner');
|
||||
|
|
|
@ -4,7 +4,6 @@ define(function (require) {
|
|||
.directive('confirmClick', function () {
|
||||
return {
|
||||
restrict: 'A',
|
||||
scope: {},
|
||||
link: function ($scope, $elem, attrs) {
|
||||
$elem.bind('click', function () {
|
||||
var message = attrs.confirmation || 'Are you sure?';
|
||||
|
|
|
@ -25,7 +25,7 @@ define(function (require) {
|
|||
var stringify = function () {
|
||||
var text;
|
||||
// If both parts are date math, try to look up a reasonable string
|
||||
if (!moment.isMoment($scope.from) && !moment.isMoment($scope.to)) {
|
||||
if ($scope.from && $scope.to && !moment.isMoment($scope.from) && !moment.isMoment($scope.to)) {
|
||||
var tryLookup = lookupByRange[$scope.from.toString() + ' to ' + $scope.to.toString()];
|
||||
if (tryLookup) {
|
||||
$elem.text(tryLookup.display);
|
||||
|
|
|
@ -3,7 +3,7 @@ define(function (require) {
|
|||
var _ = require('lodash');
|
||||
var rison = require('utils/rison');
|
||||
|
||||
module.directive('savedObjectFinder', function (savedSearches, savedVisualizations, savedDashboards, $location, $route) {
|
||||
module.directive('savedObjectFinder', function (savedSearches, savedVisualizations, savedDashboards, $location, kbnUrl) {
|
||||
|
||||
var vars = {
|
||||
searches: {
|
||||
|
@ -85,12 +85,12 @@ define(function (require) {
|
|||
|
||||
// angular wants the '/path', not '#/path'
|
||||
var path = url.substr(1);
|
||||
if ($route.matches(path)) {
|
||||
if (kbnUrl.matches(path)) {
|
||||
$event.preventDefault();
|
||||
|
||||
// change works with paths, but we are only here because the paths
|
||||
// are the same, so we have to change the whole url to be the new path
|
||||
$route.changeUrl(path);
|
||||
kbnUrl.change(path);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
16
src/kibana/filters/rison.js
Normal file
16
src/kibana/filters/rison.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
define(function (require) {
|
||||
var rison = require('utils/rison');
|
||||
var module = require('modules').get('kibana');
|
||||
|
||||
module.filter('rison', function () {
|
||||
return function (str) {
|
||||
return rison.encode(str);
|
||||
};
|
||||
});
|
||||
|
||||
module.filter('risonDecode', function () {
|
||||
return function (str) {
|
||||
return rison.decode(str);
|
||||
};
|
||||
});
|
||||
});
|
|
@ -4,7 +4,7 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
require('modules')
|
||||
.get('kbn/filters')
|
||||
.get('kibana')
|
||||
.filter('shortDots', function (config) {
|
||||
return function (str) {
|
||||
if (!_.isString(str) || config.get('shortDots:enable') !== true) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
define(function (require) {
|
||||
require('modules')
|
||||
.get('kbn/filters')
|
||||
.get('kibana')
|
||||
.filter('uriescape', function () {
|
||||
return function (str) {
|
||||
return encodeURIComponent(str);
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
<meta name="viewport" content="width=device-width">
|
||||
<title>Kibana 4</title>
|
||||
<!-- load the root require context -->
|
||||
<script src="bower_components/requirejs/require.js"></script>
|
||||
<script src="/bower_components/requirejs/require.js"></script>
|
||||
|
||||
<script src="kibana/require.config.js"></script>
|
||||
<script src="/require.config.js"></script>
|
||||
<script>require(['kibana'], function (kibana) { kibana.init(); });</script>
|
||||
<link rel="stylesheet" href="kibana/styles/main.css" >
|
||||
<link rel="stylesheet" href="/styles/main.css" >
|
||||
</head>
|
||||
<body ng-controller="kibana" ng-class="'application-'+activeApp">
|
||||
<kbn-notifications list="notifList"></kbn-notifications>
|
|
@ -12,7 +12,7 @@ define(function (require) {
|
|||
require('angular-route');
|
||||
require('angular-bindonce');
|
||||
|
||||
var configFile = require('config_file');
|
||||
var configFile = JSON.parse(require('text!config'));
|
||||
|
||||
var kibana = modules.get('kibana', [
|
||||
// list external requirements here
|
||||
|
@ -21,7 +21,7 @@ define(function (require) {
|
|||
'ngRoute'
|
||||
]);
|
||||
|
||||
configFile.elasticsearch = configFile.elasticsearch || ('http://' + window.location.hostname + ':9200');
|
||||
configFile.elasticsearch = ('http://' + window.location.hostname + '/elasticsearch/');
|
||||
|
||||
kibana
|
||||
// This stores the Kibana revision number, @REV@ is replaced by grunt.
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
require.config({
|
||||
baseUrl: './kibana',
|
||||
baseUrl: './',
|
||||
paths: {
|
||||
kibana: './index',
|
||||
config_file: '../config',
|
||||
|
||||
kibana: 'index',
|
||||
// special utils
|
||||
routes: 'utils/routes/index',
|
||||
errors: 'components/errors',
|
||||
|
@ -11,27 +9,27 @@ require.config({
|
|||
lodash: 'utils/_mixins',
|
||||
|
||||
// bower_components
|
||||
'angular-bindonce': '../bower_components/angular-bindonce/bindonce',
|
||||
'angular-bootstrap': '../bower_components/angular-bootstrap/ui-bootstrap-tpls',
|
||||
'angular-elastic': '../bower_components/angular-elastic/elastic',
|
||||
'angular-route': '../bower_components/angular-route/angular-route',
|
||||
'angular-ui-ace': '../bower_components/angular-ui-ace/ui-ace',
|
||||
ace: '../bower_components/ace-builds/src-noconflict/ace',
|
||||
angular: '../bower_components/angular/angular',
|
||||
async: '../bower_components/async/lib/async',
|
||||
bower_components: '../bower_components',
|
||||
css: '../bower_components/require-css/css',
|
||||
d3: '../bower_components/d3/d3',
|
||||
elasticsearch: '../bower_components/elasticsearch/elasticsearch.angular',
|
||||
faker: '../bower_components/Faker/faker',
|
||||
file_saver: '../bower_components/FileSaver/FileSaver',
|
||||
gridster: '../bower_components/gridster/dist/jquery.gridster',
|
||||
inflection: '../bower_components/inflection/lib/inflection',
|
||||
jquery: '../bower_components/jquery/dist/jquery',
|
||||
jsonpath: '../bower_components/jsonpath/lib/jsonpath',
|
||||
lodash_src: '../bower_components/lodash/dist/lodash',
|
||||
moment: '../bower_components/moment/moment',
|
||||
text: '../bower_components/requirejs-text/text'
|
||||
'angular-bindonce': 'bower_components/angular-bindonce/bindonce',
|
||||
'angular-bootstrap': 'bower_components/angular-bootstrap/ui-bootstrap-tpls',
|
||||
'angular-elastic': 'bower_components/angular-elastic/elastic',
|
||||
'angular-route': 'bower_components/angular-route/angular-route',
|
||||
'angular-ui-ace': 'bower_components/angular-ui-ace/ui-ace',
|
||||
ace: 'bower_components/ace-builds/src-noconflict/ace',
|
||||
angular: 'bower_components/angular/angular',
|
||||
async: 'bower_components/async/lib/async',
|
||||
bower_components: 'bower_components',
|
||||
css: 'bower_components/require-css/css',
|
||||
d3: 'bower_components/d3/d3',
|
||||
elasticsearch: 'bower_components/elasticsearch/elasticsearch.angular',
|
||||
faker: 'bower_components/Faker/faker',
|
||||
file_saver: 'bower_components/FileSaver/FileSaver',
|
||||
gridster: 'bower_components/gridster/dist/jquery.gridster',
|
||||
inflection: 'bower_components/inflection/lib/inflection',
|
||||
jquery: 'bower_components/jquery/dist/jquery',
|
||||
jsonpath: 'bower_components/jsonpath/lib/jsonpath',
|
||||
lodash_src: 'bower_components/lodash/dist/lodash',
|
||||
moment: 'bower_components/moment/moment',
|
||||
text: 'bower_components/requirejs-text/text'
|
||||
},
|
||||
shim: {
|
||||
angular: {
|
||||
|
|
|
@ -14,4 +14,4 @@ define(function (require) {
|
|||
|
||||
return es;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -62,10 +62,6 @@ define(function (require) {
|
|||
}()));
|
||||
}
|
||||
|
||||
Timefilter.prototype.enabled = function (state) {
|
||||
this.enabled = !!state;
|
||||
};
|
||||
|
||||
Timefilter.prototype.get = function (indexPattern) {
|
||||
var filter;
|
||||
var timefield = indexPattern.timeFieldName && _.find(indexPattern.fields, {name: indexPattern.timeFieldName});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@bs-less-dir: "../../bower_components/bootstrap/less";
|
||||
@bs-less-dir: "../bower_components/bootstrap/less";
|
||||
|
||||
// Core variables and mixins
|
||||
@import "theme/_variables.less";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import "../../bower_components/font-awesome/less/font-awesome.less";
|
||||
@import "../bower_components/font-awesome/less/font-awesome.less";
|
||||
@import (reference) "lesshat.less";
|
||||
|
||||
// generic mixins
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
define(function (require) {
|
||||
return function routeSetup(Promise, kbnSetup, config, $route, indexPatterns, Notifier) {
|
||||
return function routeSetup(Promise, kbnSetup, config, $route, kbnUrl, indexPatterns, Notifier) {
|
||||
|
||||
var errors = require('errors');
|
||||
var NoDefaultIndexPattern = errors.NoDefaultIndexPattern;
|
||||
|
@ -26,7 +26,7 @@ define(function (require) {
|
|||
if (err instanceof NoDefaultIndexPattern || err instanceof NoDefinedIndexPatterns) {
|
||||
// .change short circuits the routes by calling $route.refresh(). We can safely swallow this error
|
||||
// after reporting it to the user
|
||||
$route.change('/settings/indices');
|
||||
kbnUrl.change('/settings/indices');
|
||||
(new Notifier()).error(err);
|
||||
} else {
|
||||
return Promise.reject(err);
|
||||
|
@ -34,4 +34,4 @@ define(function (require) {
|
|||
}
|
||||
};
|
||||
};
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,42 +5,6 @@ define(function (require) {
|
|||
require('components/setup/setup');
|
||||
require('services/promises');
|
||||
|
||||
require('modules').get('kibana')
|
||||
.config(function ($provide) {
|
||||
// decorate the $route object to include a change and changeUrl method
|
||||
$provide.decorator('$route', function ($delegate, $location, $rootScope) {
|
||||
var reloading;
|
||||
var doneReloading = function () { reloading = false; };
|
||||
$rootScope.$on('$routeUpdate', doneReloading);
|
||||
$rootScope.$on('$routeChangeStart', doneReloading);
|
||||
|
||||
var reload = function () {
|
||||
if (!reloading) $delegate.reload();
|
||||
reloading = true;
|
||||
};
|
||||
|
||||
$delegate.change = function (path) {
|
||||
if (path !== $location.path()) {
|
||||
$location.path(path);
|
||||
reload();
|
||||
}
|
||||
};
|
||||
$delegate.changeUrl = function (url) {
|
||||
if (url !== $location.url()) {
|
||||
$location.url(url);
|
||||
reload();
|
||||
}
|
||||
};
|
||||
$delegate.matches = function (url) {
|
||||
var route = $delegate.current.$$route;
|
||||
if (!route || !route.regexp) return null;
|
||||
return route.regexp.test(url);
|
||||
};
|
||||
|
||||
return $delegate;
|
||||
});
|
||||
});
|
||||
|
||||
function RouteManager() {
|
||||
var when = [];
|
||||
var additions = [];
|
||||
|
|
19
src/server/DIST_README.md
Normal file
19
src/server/DIST_README.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
# Kibana @@version
|
||||
|
||||
Kibana is an open source (Apache Licensed), browser based analytics and search dashboard for Elasticsearch. Kibana is a snap to setup and start using. Kibana strives to be easy to get started with, while also being flexible and powerful, just like Elasticsearch.
|
||||
|
||||
## Installation
|
||||
|
||||
* Download: http://www.elasticsearch.org/overview/kibana/installation/
|
||||
* Run **bin/kibana** on unix, or **bin/kibana.bat** on Windows.
|
||||
* Visit http://localhost:5601
|
||||
|
||||
## Need Help?
|
||||
|
||||
Need help? Try #elasticsearch or #logstash on Freenode IRC. You can also find help on the elasticsearch-users@googlegroups.com or logstash-users@googlegroups.com mailing lists.
|
||||
|
||||
You can also find documentation at http://www.elasticsearch.com/guide/en/kibana/current
|
||||
|
||||
## Contributing
|
||||
|
||||
If you have a bugfix or new feature that you would like to contribute to Kibana, please find or open an issue about it first. Kibana is an open source project that is available on Github: https://github.com/elasticsearch/kibana
|
|
@ -1,5 +1,3 @@
|
|||
ruby "1.9.3", :engine => 'jruby', :engine_version => '1.7.13'
|
||||
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem 'sinatra', :require => 'sinatra/base'
|
||||
|
@ -8,3 +6,4 @@ gem 'puma'
|
|||
gem 'warbler'
|
||||
gem 'elasticsearch'
|
||||
gem 'rack-reverse-proxy', :require => 'rack/reverse_proxy'
|
||||
gem 'colorize'
|
|
@ -2,6 +2,7 @@ GEM
|
|||
remote: https://rubygems.org/
|
||||
specs:
|
||||
backports (3.6.0)
|
||||
colorize (0.7.3)
|
||||
elasticsearch (1.0.4)
|
||||
elasticsearch-api (= 1.0.4)
|
||||
elasticsearch-transport (= 1.0.4)
|
||||
|
@ -52,6 +53,7 @@ PLATFORMS
|
|||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
colorize
|
||||
elasticsearch
|
||||
puma
|
||||
rack-reverse-proxy
|
83
src/server/bin/initialize
Executable file
83
src/server/bin/initialize
Executable file
|
@ -0,0 +1,83 @@
|
|||
#!/usr/bin/env ruby
|
||||
require "optparse"
|
||||
require 'rubygems'
|
||||
require 'puma/cli'
|
||||
require "yaml"
|
||||
|
||||
HERE = File.expand_path(File.dirname(__FILE__))
|
||||
|
||||
module Kibana
|
||||
def self.global_settings
|
||||
@settings ||= {}
|
||||
end
|
||||
end
|
||||
|
||||
# Defaults for the options
|
||||
options = {
|
||||
:config => File.expand_path("#{HERE}/../config/kibana.yml") || ENV["CONFIG_PATH"]
|
||||
}
|
||||
|
||||
# Create a new parser
|
||||
parser = OptionParser.new do |opts|
|
||||
opts.on('-e', '--elasticsearch URI', 'Elasticsearch instance') do |arg|
|
||||
options[:elasticsearch] = arg
|
||||
end
|
||||
opts.on('-c', '--config PATH', 'Path to config file') do |arg|
|
||||
options[:config] = arg
|
||||
end
|
||||
opts.on('-p', '--port PORT', 'Kibana port') do |arg|
|
||||
options[:port] = arg
|
||||
end
|
||||
opts.on('-H', '--host HOST', 'Kibana host') do |arg|
|
||||
options[:host] = arg
|
||||
end
|
||||
opts.on('-v', '--version', 'Display version') do |arg|
|
||||
puts ENV['KIBANA_VERSION'] || 'dev-build'
|
||||
exit
|
||||
end
|
||||
opts.on('-h', '--help', 'Display this screen') do
|
||||
puts opts
|
||||
exit
|
||||
end
|
||||
end
|
||||
|
||||
# Set the usage banner
|
||||
parser.banner = "Usage: kibana <options>\n\n"
|
||||
|
||||
# Parse the command line arguments
|
||||
parser.parse! ARGV
|
||||
|
||||
# Load the config from default
|
||||
config = YAML.load(IO.read(options[:config]))
|
||||
|
||||
# Set the override for the port
|
||||
port = (options[:port] || config['port'])
|
||||
|
||||
# Set the override for the host
|
||||
host = (options[:host] || config['host'])
|
||||
|
||||
# Set the override for Elasticsaerch
|
||||
elasticsearch = (options[:elasticsearch] || config['elasticsearch'])
|
||||
|
||||
# If the env isn't set we need to set it to development
|
||||
ENV["RACK_ENV"] = "development" if ENV["RACK_ENV"].nil?
|
||||
|
||||
# Set the global_settings that are shared across every app
|
||||
Kibana.global_settings[:port] = port || 5601
|
||||
Kibana.global_settings[:host] = host || '0.0.0.0'
|
||||
Kibana.global_settings[:config] = config
|
||||
Kibana.global_settings[:elasticsearch] = elasticsearch
|
||||
Kibana.global_settings[:root] = File.expand_path("#{File.dirname(__FILE__)}/../")
|
||||
|
||||
# Set the public folder based on whether we are running in production or not.
|
||||
if ENV['RACK_ENV'] == ('production')
|
||||
Kibana.global_settings[:public_folder] = File.expand_path("#{File.dirname(__FILE__)}/../public/")
|
||||
else
|
||||
Kibana.global_settings[:public_folder] = File.expand_path("#{File.dirname(__FILE__)}/../../kibana/")
|
||||
end
|
||||
|
||||
# Add the root of the project to the load path
|
||||
$LOAD_PATH.unshift(Kibana.global_settings[:root])
|
||||
|
||||
require "lib/server"
|
||||
Kibana::Server.run(Kibana.global_settings)
|
25
src/server/bin/kibana.bat
Normal file
25
src/server/bin/kibana.bat
Normal file
|
@ -0,0 +1,25 @@
|
|||
@echo off
|
||||
|
||||
SETLOCAL
|
||||
if not defined JAVA_HOME goto java_home_err
|
||||
|
||||
set SCRIPT_DIR=%~dp0
|
||||
for %%I in ("%SCRIPT_DIR%..") do set DIR=%%~dpfI
|
||||
|
||||
set RACK_ENV=production
|
||||
set CONFIG_PATH=%DIR%\config\kibana.yml
|
||||
set KIBANA_VERSION=@@version
|
||||
|
||||
|
||||
TITLE Kibana %KIBANA_VERSION%
|
||||
|
||||
"%JAVA_HOME%\bin\java" -jar "%DIR%\lib\kibana.jar" %*
|
||||
|
||||
:java_home_err
|
||||
echo JAVA_HOME enviroment variable must be set!
|
||||
pause
|
||||
goto finally
|
||||
|
||||
:finally
|
||||
|
||||
ENDLOCAL
|
30
src/server/bin/kibana.sh
Executable file
30
src/server/bin/kibana.sh
Executable file
|
@ -0,0 +1,30 @@
|
|||
#!/bin/sh
|
||||
|
||||
SCRIPT=$0
|
||||
|
||||
# SCRIPT may be an arbitrarily deep series of symlinks. Loop until we have the concrete path.
|
||||
while [ -h "$SCRIPT" ] ; do
|
||||
ls=`ls -ld "$SCRIPT"`
|
||||
# Drop everything prior to ->
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
SCRIPT="$link"
|
||||
else
|
||||
SCRIPT=`dirname "$SCRIPT"`/"$link"
|
||||
fi
|
||||
done
|
||||
|
||||
DIR=$(dirname "${SCRIPT}")
|
||||
|
||||
if [ -x "${JAVA_HOME}/bin/java" ]; then
|
||||
JAVA="${JAVA_HOME}/bin/java"
|
||||
else
|
||||
JAVA=`which java`
|
||||
fi
|
||||
|
||||
if [ ! -x "${JAVA}" ]; then
|
||||
echo "Could not find any executable Java binary. Please install Java in your PATH or set JAVA_HOME"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
KIBANA_VERSION=@@version CONFIG_PATH=${DIR}/../config/kibana.yml RACK_ENV=production exec "${JAVA}" -jar "${DIR}/../lib/kibana.jar" "$@"
|
20
src/server/config/kibana.yml
Normal file
20
src/server/config/kibana.yml
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Kibana is served by a backend server. This controls which port to use.
|
||||
port: 5601
|
||||
|
||||
# The Elasticsearch instance to user for all your queries
|
||||
elasticsearch: "http://localhost:9200"
|
||||
|
||||
# Kibana uses and index in Elasticsearch to store saved searches, visualizations
|
||||
# and dashboard. It will create an new index if it doesn't already exist.
|
||||
kibanaIndex: "kibana-int"
|
||||
|
||||
# Applications loaded and included into Kibana. Use the settings below to
|
||||
# customize the applications and thier names.
|
||||
apps:
|
||||
- { id: "discover", name: "Discover" }
|
||||
- { id: "visualize", name: "Visualize" }
|
||||
- { id: "dashboard", name: "Dashboard" }
|
||||
- { id: "settings", name: "Settings" }
|
||||
|
||||
# The default application to laad.
|
||||
defaultAppId: "discover"
|
22
src/server/config/web.ru
Normal file
22
src/server/config/web.ru
Normal file
|
@ -0,0 +1,22 @@
|
|||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
|
||||
ROOT = File.expand_path("#{File.dirname(__FILE__)}/../")
|
||||
|
||||
if ENV['RACK_ENV'] == ('development')
|
||||
PUBLIC_ROOT = File.expand_path("#{File.dirname(__FILE__)}/../../kibana/")
|
||||
CONFIG_PATH = File.expand_path("#{File.dirname(__FILE__)}/kibana.yml")
|
||||
end
|
||||
|
||||
if ENV['RACK_ENV'] == ('production')
|
||||
PUBLIC_ROOT = File.expand_path("#{File.dirname(__FILE__)}/../public/")
|
||||
CONFIG_PATH = ENV["CONFIG_PATH"]
|
||||
end
|
||||
|
||||
$LOAD_PATH.unshift(ROOT)
|
||||
|
||||
# Require the application
|
||||
require "#{ROOT}/lib/app"
|
||||
|
||||
# Run the application
|
||||
run Kibana::App
|
44
src/server/lib/ColorLogger.rb
Normal file
44
src/server/lib/ColorLogger.rb
Normal file
|
@ -0,0 +1,44 @@
|
|||
require "rack/commonlogger"
|
||||
require "colorize"
|
||||
|
||||
class ColorLogger < Rack::CommonLogger
|
||||
def log(env, status, header, begin_at)
|
||||
now = Time.now
|
||||
length = extract_content_length(header)
|
||||
|
||||
case status
|
||||
when 300..399
|
||||
statusColor = :yellow
|
||||
when 400..499
|
||||
statusColor = :red
|
||||
when 500..599
|
||||
statusColor = :magenta
|
||||
else
|
||||
statusColor = :green
|
||||
end
|
||||
|
||||
msg = (now.strftime('%b %d, %Y @ %H:%M:%S.%L')).light_black << ' '
|
||||
msg << env["REQUEST_METHOD"].light_blue << ' '
|
||||
msg << env["PATH_INFO"]
|
||||
msg << (env["QUERY_STRING"].empty? ? '' : "?#{env["QUERY_STRING"]}" ) << ' '
|
||||
msg << status.to_s.send(statusColor) << ' '
|
||||
msg << ((now - begin_at) * 1000).to_i.to_s << 'ms - ' << length
|
||||
msg << "\n"
|
||||
|
||||
# If there is an error then we need to append the stack
|
||||
if env['sinatra.error'] && status != 404
|
||||
error = env['sinatra.error']
|
||||
msg << "#{error.message}\n #{error.backtrace.join("\n ")}".send(statusColor)
|
||||
msg << "\n"
|
||||
end
|
||||
|
||||
logger = @logger || env['rack.errors']
|
||||
if logger.respond_to?(:write)
|
||||
logger.write(msg)
|
||||
else
|
||||
logger << msg
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
46
src/server/lib/JSONLogger.rb
Normal file
46
src/server/lib/JSONLogger.rb
Normal file
|
@ -0,0 +1,46 @@
|
|||
require "rack/commonlogger"
|
||||
|
||||
class JSONLogger < Rack::CommonLogger
|
||||
def log(env, status, header, begin_at)
|
||||
now = Time.now
|
||||
length = extract_content_length(header)
|
||||
|
||||
data = {
|
||||
"@timestamp" => now.iso8601,
|
||||
:status => status.to_s[0..3],
|
||||
:level => status < 399 ? "INFO" : 'ERROR',
|
||||
:name => "Kibana",
|
||||
:request_method => env["REQUEST_METHOD"],
|
||||
:request => env["PATH_INFO"] + (env["QUERY_STRING"].empty? ? "" : "#{env['QUERY_STRING']}"),
|
||||
:path => env["PATH_INFO"],
|
||||
:query_string => env["QUERY_STRING"],
|
||||
:remote_addr => env['HTTP_X_FORWARD_FOR'] || env["REMOTE_ADDR"],
|
||||
:remote_user => env["REMOTE_USER"],
|
||||
:http_version => env["HTTP_VERSION"],
|
||||
:content_length => length,
|
||||
:response_time => ((now - begin_at) * 1000).to_i # convert to milliseconds
|
||||
}
|
||||
|
||||
# If there is an error then we need to append the stack
|
||||
if env['sinatra.error']
|
||||
error = env['sinatra.error']
|
||||
data[:error] = {
|
||||
:name => error.class.to_s,
|
||||
:message => error.message,
|
||||
:stack => error.backtrace
|
||||
}
|
||||
end
|
||||
|
||||
data[:message] = "#{data[:request_method]} #{data[:path]+(data[:query_string].empty? ? '' : '?'+data[:query_string])} #{data[:status]} #{data[:response_time]}ms - #{data[:content_length].empty? ? '-' : data[:content_length]}"
|
||||
|
||||
logger = @logger || env['rack.errors']
|
||||
msg = data.to_json+"\n"
|
||||
|
||||
if logger.respond_to?(:write)
|
||||
logger.write(msg)
|
||||
else
|
||||
logger << msg
|
||||
end
|
||||
end
|
||||
end
|
||||
|
68
src/server/lib/app.rb
Normal file
68
src/server/lib/app.rb
Normal file
|
@ -0,0 +1,68 @@
|
|||
# Add the root of the project to the $LOAD_PATH, For some reason it seems
|
||||
# to be getting lost when we use warble to make the jar. This fixes it :D
|
||||
$LOAD_PATH.unshift(Kibana.global_settings[:root])
|
||||
|
||||
require "logger"
|
||||
require "json"
|
||||
require "lib/JSONLogger"
|
||||
require "lib/ColorLogger"
|
||||
require "routes/home"
|
||||
require "sinatra/json"
|
||||
require "routes/proxy"
|
||||
|
||||
class Logger
|
||||
alias_method :write, :<<
|
||||
end
|
||||
|
||||
module Kibana
|
||||
class App < Sinatra::Base
|
||||
|
||||
helpers Sinatra::JSON
|
||||
|
||||
configure do
|
||||
logger = Logger.new(STDOUT)
|
||||
logger.formatter = proc do |severity, datetime, progname, msg|
|
||||
data = {
|
||||
'@timestamp' => datetime.iso8601,
|
||||
:level => severity,
|
||||
:name => progname || "Kibana",
|
||||
:message => msg
|
||||
}
|
||||
data.to_json + "\n"
|
||||
end
|
||||
set :logger, logger
|
||||
disable :raise_errors
|
||||
disable :show_exceptions
|
||||
disable :dump_errors
|
||||
end
|
||||
|
||||
configure :production do
|
||||
use JSONLogger, settings.logger
|
||||
end
|
||||
|
||||
configure :development do
|
||||
use ColorLogger, settings.logger
|
||||
end
|
||||
|
||||
error do
|
||||
500
|
||||
end
|
||||
|
||||
error 400 do
|
||||
json :status => 500, :message => "Bad Request"
|
||||
end
|
||||
|
||||
error 500 do
|
||||
json :status => 500, :message => "Internal Server Error"
|
||||
end
|
||||
|
||||
not_found do
|
||||
json :status => 404, :message => "Not Found"
|
||||
end
|
||||
|
||||
# Routes go here
|
||||
use Routes::Home
|
||||
use Routes::Proxy
|
||||
|
||||
end
|
||||
end
|
60
src/server/lib/server.rb
Normal file
60
src/server/lib/server.rb
Normal file
|
@ -0,0 +1,60 @@
|
|||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
require "puma"
|
||||
require "colorize"
|
||||
require "json"
|
||||
require "#{Kibana.global_settings[:root]}/lib/app"
|
||||
|
||||
# Require the application
|
||||
module Kibana
|
||||
module Server
|
||||
|
||||
DEFAULTS = {
|
||||
:host => '0.0.0.0',
|
||||
:port => 5601,
|
||||
:threads => '0:16',
|
||||
:verbose => false
|
||||
}
|
||||
|
||||
def self.log(msg)
|
||||
if ENV['RACK_ENV'] == 'production'
|
||||
data = {
|
||||
"@timestamp" => Time.now.iso8601,
|
||||
:level => 'INFO',
|
||||
:name => 'Kibana',
|
||||
:message => msg
|
||||
}
|
||||
puts data.to_json
|
||||
else
|
||||
message = (Time.now.strftime('%b %d, %Y @ %H:%M:%S.%L')).light_black << ' '
|
||||
message << msg.yellow
|
||||
puts message
|
||||
end
|
||||
end
|
||||
|
||||
def self.run(options = {})
|
||||
options = DEFAULTS.merge(options)
|
||||
min, max = options[:threads].split(':', 2)
|
||||
|
||||
app = Kibana::App.new()
|
||||
server = Puma::Server.new(app)
|
||||
|
||||
# Configure server
|
||||
server.add_tcp_listener(options[:host], options[:port])
|
||||
server.min_threads = min
|
||||
server.max_threads = max
|
||||
|
||||
begin
|
||||
log("Kibana server started on tcp://#{options[:host]}:#{options[:port]} in #{ENV['RACK_ENV']} mode.")
|
||||
server.run.join
|
||||
rescue Interrupt
|
||||
log("Kibana server gracefully stopping, waiting for requests to finish")
|
||||
server.stop(true)
|
||||
log("Kibana server stopped.")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
21
src/server/routes/base.rb
Normal file
21
src/server/routes/base.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
require "sinatra/base"
|
||||
require "sinatra/json"
|
||||
require "yaml"
|
||||
|
||||
module Kibana
|
||||
module Routes
|
||||
class Base < Sinatra::Base
|
||||
helpers Sinatra::JSON
|
||||
configure do
|
||||
config = Kibana.global_settings[:config].clone()
|
||||
config['elasticsearch'] = Kibana.global_settings[:elasticsearch]
|
||||
config['port'] = Kibana.global_settings[:port].to_i
|
||||
|
||||
set :root, Kibana.global_settings[:root]
|
||||
set :public_folder, Kibana.global_settings[:public_folder]
|
||||
set :httponly, true
|
||||
set :config, config
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
21
src/server/routes/home.rb
Normal file
21
src/server/routes/home.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
require "routes/base"
|
||||
|
||||
module Kibana
|
||||
module Routes
|
||||
class Home < Base
|
||||
|
||||
get "/" do
|
||||
File.read(File.join(settings.public_folder, 'index.html'))
|
||||
end
|
||||
|
||||
get "/config" do
|
||||
# Clone the settings object and change the elasticsearch attribute
|
||||
# to the proxy for elasticsearch
|
||||
data = settings.config.clone()
|
||||
data['elasticsearch'] = "#{request.scheme}://#{request.host}:#{request.port}/elasticsearch"
|
||||
json data
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
14
src/server/routes/proxy.rb
Normal file
14
src/server/routes/proxy.rb
Normal file
|
@ -0,0 +1,14 @@
|
|||
require "routes/base"
|
||||
require "rack/reverse_proxy"
|
||||
|
||||
module Kibana
|
||||
module Routes
|
||||
class Proxy < Base
|
||||
# Rack middleware goes here
|
||||
config = settings.config
|
||||
use Rack::ReverseProxy do
|
||||
reverse_proxy(/^\/elasticsearch(.*)$/, "#{config["elasticsearch"]}$1")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -4,9 +4,18 @@ module.exports = function (grunt) {
|
|||
'clean:build',
|
||||
'require_css_deps:copy',
|
||||
'less',
|
||||
'copy:kibana_src',
|
||||
'touch_config',
|
||||
'requirejs',
|
||||
'clean:unneeded_source_in_build',
|
||||
'copy:server_src',
|
||||
'download_jruby',
|
||||
'install_gems',
|
||||
'warble',
|
||||
'replace:dist',
|
||||
'copy:dist',
|
||||
'chmod_kibana',
|
||||
'compress:build_zip',
|
||||
'compress:build_tarball'
|
||||
]);
|
||||
};
|
||||
};
|
||||
|
|
9
tasks/chmod_kibana.js
Normal file
9
tasks/chmod_kibana.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
var fs = require('fs');
|
||||
var join = require('path').join;
|
||||
module.exports = function (grunt) {
|
||||
grunt.registerTask('chmod_kibana', 'Chmods bin/kibana', function () {
|
||||
var done = this.async();
|
||||
var path = join(grunt.config.get('build'), 'dist', 'bin', 'kibana');
|
||||
fs.chmod(path, 0755, done);
|
||||
});
|
||||
};
|
|
@ -6,20 +6,19 @@ module.exports = function (grunt) {
|
|||
unneeded_source_in_build: {
|
||||
src: [
|
||||
// select all top level folders in bower_components
|
||||
'<%= build %>/bower_components/*',
|
||||
'<%= build %>/kibana/public/bower_components/*',
|
||||
// exclude the following top level components
|
||||
'!<%= build %>/bower_components/' + notIncludedComponents,
|
||||
|
||||
'!<%= build %>/kibana/public/bower_components/' + notIncludedComponents,
|
||||
// remove the contents of K4D3, font-awesome, and requirejs except necessary files
|
||||
'<%= build %>/bower_components/' + notIncludedComponents + '/*',
|
||||
'!<%= build %>/bower_components/requirejs/require.js',
|
||||
'!<%= build %>/bower_components/font-awesome/fonts',
|
||||
|
||||
'<%= build %>/**/_empty_',
|
||||
'<%= build %>/**/*.less',
|
||||
'<%= appBuild %>/{css-builder,normalize}.js',
|
||||
'<%= app %>/{css-builder,normalize}.js',
|
||||
'<%= build %>/kibana/public/bower_components/' + notIncludedComponents + '/*',
|
||||
'!<%= build %>/kibana/public/bower_components/requirejs/require.js',
|
||||
'!<%= build %>/kibana/public/bower_components/font-awesome/fonts',
|
||||
'<%= build %>/kibana/public/**/_empty_',
|
||||
'<%= build %>/kibana/public/**/*.less',
|
||||
'<%= build %>/kibana/public/config',
|
||||
'<%= build %>/kibana/public/{css-builder,normalize}.js',
|
||||
'<%= app %>/public/{css-builder,normalize}.js',
|
||||
]
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@ module.exports = function (grunt) {
|
|||
|
||||
return _.mapValues({
|
||||
build_zip: archiveName() + '.zip',
|
||||
build_tarball: archiveName() + '.zip',
|
||||
build_tarball: archiveName() + '.tar.gz',
|
||||
plugin: archiveName(true) + '.tar.gz'
|
||||
}, function (filename, task) {
|
||||
return {
|
||||
|
@ -16,11 +16,11 @@ module.exports = function (grunt) {
|
|||
files: [
|
||||
{
|
||||
expand: true,
|
||||
cwd: '<%= build %>',
|
||||
cwd: '<%= build %>/dist',
|
||||
src: ['**/*'],
|
||||
dest: '<%= pkg.name %>' + (task === 'plugin' ? '/_site' : '')
|
||||
}
|
||||
]
|
||||
};
|
||||
});
|
||||
};
|
||||
};
|
||||
|
|
71
tasks/config/copy.js
Normal file
71
tasks/config/copy.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
module.exports = function (grunt) {
|
||||
var config = {
|
||||
|
||||
kibana_src: {
|
||||
expand: true,
|
||||
cwd: '<%= app %>',
|
||||
src: '**',
|
||||
dest: '<%= build %>/src/'
|
||||
},
|
||||
|
||||
server_src: {
|
||||
files: [
|
||||
{
|
||||
src: '<%= src %>/server/Gemfile',
|
||||
dest: '<%= build %>/kibana/Gemfile'
|
||||
},
|
||||
{
|
||||
src: '<%= src %>/server/Gemfile.lock',
|
||||
dest: '<%= build %>/kibana/Gemfile.lock'
|
||||
},
|
||||
{
|
||||
src: '<%= src %>/server/bin/initialize',
|
||||
dest: '<%= build %>/kibana/bin/initialize'
|
||||
},
|
||||
{
|
||||
expand: true,
|
||||
cwd: '<%= src %>/server/config/',
|
||||
src: '**',
|
||||
dest: '<%= build %>/kibana/config'
|
||||
},
|
||||
{
|
||||
expand: true,
|
||||
cwd: '<%= src %>/server/lib/',
|
||||
src: '**',
|
||||
dest: '<%= build %>/kibana/lib'
|
||||
},
|
||||
{
|
||||
expand: true,
|
||||
cwd: '<%= src %>/server/routes/',
|
||||
src: '**',
|
||||
dest: '<%= build %>/kibana/routes'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
dist: {
|
||||
options: { mode: true },
|
||||
files: [
|
||||
{
|
||||
src: '<%= root %>/LICENSE.md',
|
||||
dest: '<%= build %>/dist/LICENSE.md'
|
||||
},
|
||||
{
|
||||
expand: true,
|
||||
cwd: '<%= build %>/kibana/',
|
||||
src: '*.jar',
|
||||
dest: '<%= build %>/dist/lib/'
|
||||
},
|
||||
{
|
||||
expand: true,
|
||||
cwd: '<%= src %>/server/config/',
|
||||
src: 'kibana.yml',
|
||||
dest: '<%= build %>/dist/config/'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return config;
|
||||
};
|
|
@ -17,8 +17,9 @@ module.exports = function (grunt) {
|
|||
ignores: [
|
||||
'node_modules/*',
|
||||
'dist/*',
|
||||
'sample/*'
|
||||
'sample/*',
|
||||
'<%= src %>/kibana/bower_components/**/*'
|
||||
]
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
var bc = require('path').join(__dirname, '../../src/bower_components');
|
||||
var bc = require('path').join(__dirname, '../../src/kibana/bower_components');
|
||||
|
||||
module.exports = {
|
||||
src: {
|
||||
|
|
31
tasks/config/replace.js
Normal file
31
tasks/config/replace.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
var join = require('path').join;
|
||||
module.exports = function (grunt) {
|
||||
var pkg = grunt.config.get('pkg');
|
||||
var build = grunt.config.get('build');
|
||||
var src = grunt.config.get('src');
|
||||
var config = {
|
||||
dist: {
|
||||
options: {
|
||||
patterns: [
|
||||
{ match: 'version', replacement: pkg.version }
|
||||
]
|
||||
},
|
||||
files: [
|
||||
{
|
||||
src: [join(src, 'server', 'DIST_README.md')],
|
||||
dest: join(build, 'dist', 'README.md')
|
||||
},
|
||||
{
|
||||
src: [join(src, 'server', 'bin', 'kibana.sh')],
|
||||
dest: join(build, 'dist', 'bin', 'kibana')
|
||||
},
|
||||
{
|
||||
src: [join(src, 'server', 'bin', 'kibana.bat')],
|
||||
dest: join(build, 'dist', 'bin', 'kibana.bat')
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
return config;
|
||||
};
|
|
@ -2,14 +2,15 @@ module.exports = function (grunt) {
|
|||
var config = {
|
||||
build: {
|
||||
options: {
|
||||
appDir: '<%= src %>',
|
||||
dir: '<%= build %>',
|
||||
mainConfigFile: '<%= app %>/require.config.js',
|
||||
appDir: '<%= build %>/src',
|
||||
dir: '<%= build %>/kibana/public',
|
||||
mainConfigFile: '<%= build %>/src/require.config.js',
|
||||
modules: [
|
||||
{
|
||||
name: 'kibana',
|
||||
excludeShallow: [
|
||||
'../config',
|
||||
'text!config'
|
||||
],
|
||||
include: [
|
||||
'controllers/kibana'
|
||||
|
@ -60,10 +61,10 @@ module.exports = function (grunt) {
|
|||
|
||||
// include each app
|
||||
var main = config.build.options.modules[0];
|
||||
var configFile = require('requirejs')(grunt.config.get('src') + '/config.js');
|
||||
var configFile = require('requirejs')(grunt.config.get('app') + '/config.js');
|
||||
configFile.apps.forEach(function (app) {
|
||||
main.include.push('apps/' + app.id + '/index');
|
||||
});
|
||||
|
||||
return config;
|
||||
};
|
||||
};
|
||||
|
|
28
tasks/config/run.js
Normal file
28
tasks/config/run.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
module.exports = function (grunt) {
|
||||
var jrubyPath = grunt.config.get('jrubyPath');
|
||||
var jruby = jrubyPath + '/bin/jruby';
|
||||
var cmd = grunt.config.get('src') + '/server/bin/initialize';
|
||||
|
||||
var config = {
|
||||
mri_server: {
|
||||
options: {
|
||||
wait: false
|
||||
// quiet: true
|
||||
},
|
||||
cmd: cmd
|
||||
},
|
||||
jruby_server: {
|
||||
options: {
|
||||
wait: false
|
||||
// quiet: true
|
||||
},
|
||||
cmd: jruby,
|
||||
args: [
|
||||
cmd
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
return config;
|
||||
|
||||
};
|
|
@ -1,4 +1,16 @@
|
|||
module.exports = function (grunt) {
|
||||
var kibana_server_tasks = [];
|
||||
if (grunt.option('use-mri')) {
|
||||
kibana_server_tasks = [
|
||||
'stop:mri_server',
|
||||
'run:mri_server'
|
||||
];
|
||||
} else {
|
||||
kibana_server_tasks = [
|
||||
'stop:jruby_server',
|
||||
'run:jruby_server'
|
||||
];
|
||||
}
|
||||
var config = {
|
||||
test: {
|
||||
files: [
|
||||
|
@ -26,6 +38,16 @@ module.exports = function (grunt) {
|
|||
'<%= testUtilsDir %>/istanbul_reporter/report.clientside.jade'
|
||||
],
|
||||
tasks: ['jade:clientside']
|
||||
},
|
||||
kibana_server: {
|
||||
files: [
|
||||
'src/server/**/*.rb',
|
||||
'src/server/**/*.yml'
|
||||
],
|
||||
tasks: kibana_server_tasks,
|
||||
options: {
|
||||
spawn: false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
21
tasks/dev.js
21
tasks/dev.js
|
@ -1,8 +1,21 @@
|
|||
module.exports = function (grunt) {
|
||||
grunt.registerTask('dev', [
|
||||
var useJRuby = grunt.option('use-jruby');
|
||||
var tasks = [
|
||||
'less',
|
||||
'jade',
|
||||
'jade'
|
||||
];
|
||||
if (useJRuby) {
|
||||
tasks = tasks.concat([
|
||||
'download_jruby',
|
||||
'install_gems',
|
||||
'run:jruby_server',
|
||||
'wait_for_jruby'
|
||||
]);
|
||||
} else {
|
||||
tasks = tasks.concat(['run:mri_server']);
|
||||
}
|
||||
grunt.registerTask('dev', tasks.concat([
|
||||
'maybe_start_server',
|
||||
'watch'
|
||||
]);
|
||||
};
|
||||
]));
|
||||
};
|
||||
|
|
46
tasks/download_jruby.js
Normal file
46
tasks/download_jruby.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
var zlib = require('zlib');
|
||||
var tar = require('tar');
|
||||
var request = require('request');
|
||||
var mkdirp = require('mkdirp');
|
||||
var ProgressBar = require('progress');
|
||||
var fs = require('fs');
|
||||
|
||||
module.exports = function (grunt) {
|
||||
grunt.registerTask('download_jruby', 'Downloads and installs jruby', function () {
|
||||
var done = this.async();
|
||||
var jrubyPath = grunt.config.get('jrubyPath');
|
||||
var jrubyVersion = grunt.config.get('jrubyVersion');
|
||||
var url = 'http://jruby.org.s3.amazonaws.com/downloads/' + jrubyVersion + '/jruby-bin-' + jrubyVersion + '.tar.gz';
|
||||
|
||||
fs.stat(jrubyPath, function (err, stat) {
|
||||
if (err) {
|
||||
mkdirp(jrubyPath, function (err) {
|
||||
if (err) return done(err);
|
||||
var unzip = zlib.createGunzip();
|
||||
var out = tar.Extract({ path: jrubyPath, strip: 1 });
|
||||
out.on('close', done).on('error', done);
|
||||
var req = request.get(url);
|
||||
var bar;
|
||||
if (!process.env.JENKINS_HOME) {
|
||||
req.on('response', function (resp) {
|
||||
var total = parseInt(resp.headers['content-length'], 10);
|
||||
bar = new ProgressBar('[:bar] :percent :etas', {
|
||||
complete: '=',
|
||||
incomplete: ' ',
|
||||
width: 80,
|
||||
clear: true,
|
||||
total: total
|
||||
});
|
||||
});
|
||||
req.on('data', function (buffer) {
|
||||
bar.tick(buffer.length);
|
||||
});
|
||||
}
|
||||
req.pipe(unzip).pipe(out);
|
||||
});
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
20
tasks/install_gems.js
Normal file
20
tasks/install_gems.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
var child_process = require('child_process');
|
||||
var join = require('path').join;
|
||||
module.exports = function (grunt) {
|
||||
grunt.registerTask('install_gems', 'Install Ruby Gems', function () {
|
||||
var done = this.async();
|
||||
var gemfile = join(grunt.config.get('src'), 'server', 'Gemfile');
|
||||
var jrubyPath = grunt.config.get('jrubyPath');
|
||||
var jruby = jrubyPath + '/bin/jruby -S';
|
||||
var command = jruby + ' gem install bundler && ' + jruby + ' bundle install --gemfile ' + gemfile;
|
||||
child_process.exec(command, function (err, stdout, stderr) {
|
||||
if (err) {
|
||||
grunt.log.error(stderr);
|
||||
return done(err);
|
||||
}
|
||||
grunt.log.writeln(stdout);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
@ -8,8 +8,8 @@ module.exports = function (grunt) {
|
|||
].forEach(function (dep) {
|
||||
grunt.file.copy(
|
||||
join(grunt.config.get('bowerComponentsDir'), 'require-css', dep),
|
||||
join(grunt.config.get('app'), dep)
|
||||
join(grunt.config.get('build'), 'src', dep)
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,20 +1,34 @@
|
|||
var _ = require('lodash');
|
||||
module.exports = function (grunt) {
|
||||
/* jshint scripturl:true */
|
||||
grunt.registerTask('test', [
|
||||
var rubyTasks;
|
||||
if (grunt.option('use-mri')) {
|
||||
rubyTasks = [
|
||||
'run:mri_server',
|
||||
];
|
||||
} else {
|
||||
rubyTasks = [
|
||||
'download_jruby',
|
||||
'install_gems',
|
||||
'run:jruby_server',
|
||||
'wait_for_jruby'
|
||||
];
|
||||
}
|
||||
grunt.registerTask('test', rubyTasks.concat([
|
||||
'maybe_start_server',
|
||||
'jade',
|
||||
'mocha:unit',
|
||||
'jshint'
|
||||
]);
|
||||
]));
|
||||
|
||||
grunt.registerTask('coverage', [
|
||||
grunt.registerTask('coverage', rubyTasks.concat([
|
||||
'blanket',
|
||||
'maybe_start_server',
|
||||
'mocha:coverage'
|
||||
]);
|
||||
]));
|
||||
|
||||
grunt.registerTask('test:watch', [
|
||||
grunt.registerTask('test:watch', rubyTasks.concat([
|
||||
'maybe_start_server',
|
||||
'watch:test'
|
||||
]);
|
||||
]));
|
||||
};
|
||||
|
|
8
tasks/touch_config.js
Normal file
8
tasks/touch_config.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
module.exports = function (grunt) {
|
||||
var join = require('path').join;
|
||||
grunt.registerTask('touch_config', function () {
|
||||
var configFile = join(grunt.config.get('build'), 'src', 'config');
|
||||
grunt.log.ok('Touching: ' + configFile);
|
||||
grunt.file.write(configFile, 'delete this');
|
||||
});
|
||||
};
|
18
tasks/wait_for_jruby.js
Normal file
18
tasks/wait_for_jruby.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
var request = require('request');
|
||||
module.exports = function (grunt) {
|
||||
|
||||
grunt.registerTask('wait_for_jruby', 'Is it started yet?', function () {
|
||||
var done = this.async();
|
||||
function checkJRuby() {
|
||||
request('http://127.0.0.1:5601', function (err, resp) {
|
||||
if (err) {
|
||||
setTimeout(checkJRuby, 1000);
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
});
|
||||
}
|
||||
checkJRuby();
|
||||
|
||||
});
|
||||
};
|
20
tasks/warble.js
Normal file
20
tasks/warble.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
var child_process = require('child_process');
|
||||
var join = require('path').join;
|
||||
module.exports = function (grunt) {
|
||||
grunt.registerTask('warble', 'Creates an executable jar.', function () {
|
||||
var done = this.async();
|
||||
var jrubyPath = grunt.config.get('jrubyPath');
|
||||
var command = jrubyPath + '/bin/jruby -S warble';
|
||||
var options = {
|
||||
cwd: join(grunt.config.get('build'), 'kibana')
|
||||
};
|
||||
child_process.exec(command, options, function (err, stdout, stderr) {
|
||||
if (err) {
|
||||
grunt.log.error(stderr);
|
||||
return done(err);
|
||||
}
|
||||
grunt.log.writeln(stdout);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
};
|
|
@ -5,7 +5,7 @@
|
|||
<link rel="stylesheet" href="/node_modules/mocha/mocha.css" />
|
||||
<script src="/node_modules/expect.js/expect.js"></script>
|
||||
<script src="/node_modules/mocha/mocha.js"></script>
|
||||
<script src="/src/bower_components/requirejs/require.js"></script>
|
||||
<script src="/src/kibana/bower_components/requirejs/require.js"></script>
|
||||
<script src="/src/kibana/require.config.js"></script>
|
||||
<script>(function () {
|
||||
var COVERAGE = !!(/coverage/i.test(window.location.search));
|
||||
|
@ -18,13 +18,14 @@
|
|||
require.config({
|
||||
baseUrl: '/src/kibana',
|
||||
paths: {
|
||||
config: '/config',
|
||||
test_utils: '../../test/utils',
|
||||
fixtures: '../../test/unit/fixtures',
|
||||
specs: '../../test/unit/specs',
|
||||
sinon: '../../test/utils/sinon',
|
||||
bluebird: '../bower_components/bluebird/js/browser/bluebird',
|
||||
angular: '../bower_components/angular-mocks/angular-mocks',
|
||||
angular_src: '../bower_components/angular/angular'
|
||||
bluebird: 'bower_components/bluebird/js/browser/bluebird',
|
||||
angular: 'bower_components/angular-mocks/angular-mocks',
|
||||
angular_src: 'bower_components/angular/angular'
|
||||
},
|
||||
shim: {
|
||||
angular: {
|
||||
|
@ -61,6 +62,7 @@
|
|||
'kibana',
|
||||
'sinon/sinon',
|
||||
'specs/apps/discover/hit_sort_fn',
|
||||
'specs/apps/discover/directives/table',
|
||||
'specs/apps/discover/segmented_fetch',
|
||||
'specs/directives/confirm-click',
|
||||
'specs/directives/timepicker',
|
||||
|
@ -71,10 +73,12 @@
|
|||
'specs/filters/field_type',
|
||||
'specs/filters/uriescape',
|
||||
'specs/filters/moment',
|
||||
'specs/filters/rison',
|
||||
'specs/filters/short_dots',
|
||||
'specs/filters/start_from',
|
||||
'specs/services/storage',
|
||||
'specs/services/persisted_log',
|
||||
'specs/services/url',
|
||||
'specs/utils/datemath',
|
||||
'specs/utils/interval',
|
||||
'specs/utils/versionmath',
|
||||
|
|
|
@ -7,7 +7,6 @@ define(function (require) {
|
|||
require('angular-route');
|
||||
|
||||
// Load the code for the directive
|
||||
require('index');
|
||||
require('apps/visualize/index');
|
||||
require('apps/dashboard/index');
|
||||
|
||||
|
@ -54,4 +53,4 @@ define(function (require) {
|
|||
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
|
381
test/unit/specs/apps/discover/directives/table.js
Normal file
381
test/unit/specs/apps/discover/directives/table.js
Normal file
|
@ -0,0 +1,381 @@
|
|||
define(function (require) {
|
||||
var angular = require('angular');
|
||||
var $ = require('jquery');
|
||||
var _ = require('lodash');
|
||||
var sinon = require('test_utils/auto_release_sinon');
|
||||
|
||||
// Load the kibana app dependencies.
|
||||
require('angular-route');
|
||||
|
||||
require('apps/discover/index');
|
||||
|
||||
var $parentScope, $scope, config;
|
||||
|
||||
// Stub out a minimal mapping of 3 fields
|
||||
var mapping = {
|
||||
bytes: {
|
||||
indexed: true,
|
||||
type: 'number'
|
||||
},
|
||||
request: {
|
||||
indexed: false,
|
||||
type: 'string'
|
||||
},
|
||||
timestamp: {
|
||||
indexed: true,
|
||||
type: 'date'
|
||||
},
|
||||
};
|
||||
|
||||
// Sets up the directive, take an element, and a list of properties to attach to the parent scope.
|
||||
var init = function ($elem, props) {
|
||||
module('kibana');
|
||||
inject(function ($rootScope, $compile, _config_) {
|
||||
config = _config_;
|
||||
$parentScope = $rootScope;
|
||||
_.assign($parentScope, props);
|
||||
$compile($elem)($parentScope);
|
||||
$elem.scope().$digest();
|
||||
$scope = $elem.isolateScope();
|
||||
});
|
||||
};
|
||||
|
||||
var destroy = function () {
|
||||
$scope.$destroy();
|
||||
$parentScope.$destroy();
|
||||
};
|
||||
|
||||
// For testing column removing/adding for the header and the rows
|
||||
//
|
||||
var columnTests = function (elemType, parentElem) {
|
||||
it('should create only the toggle column by default', function (done) {
|
||||
var childElems = parentElem.find(elemType);
|
||||
expect(childElems.length).to.be(1);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should create a time column if the timefield is defined', function (done) {
|
||||
// Should include a column for toggling and the time column by default
|
||||
$parentScope.timefield = 'timestamp';
|
||||
parentElem.scope().$digest();
|
||||
var childElems = parentElem.find(elemType);
|
||||
expect(childElems.length).to.be(2);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should be able to add and remove columns', function (done) {
|
||||
var childElems;
|
||||
// Should include a column for toggling and the time column by default
|
||||
$parentScope.columns = ['bytes'];
|
||||
parentElem.scope().$digest();
|
||||
childElems = parentElem.find(elemType);
|
||||
expect(childElems.length).to.be(2);
|
||||
expect($(childElems[1]).text()).to.contain('bytes');
|
||||
|
||||
$parentScope.columns = ['bytes', 'request'];
|
||||
parentElem.scope().$digest();
|
||||
childElems = parentElem.find(elemType);
|
||||
expect(childElems.length).to.be(3);
|
||||
expect($(childElems[2]).text()).to.contain('request');
|
||||
|
||||
$parentScope.columns = ['request'];
|
||||
parentElem.scope().$digest();
|
||||
childElems = parentElem.find(elemType);
|
||||
expect(childElems.length).to.be(2);
|
||||
expect($(childElems[1]).text()).to.contain('request');
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
describe('discover table directives', function () {
|
||||
|
||||
describe('kbnTableHeader', function () {
|
||||
|
||||
var $elem = angular.element(
|
||||
'<thead kbn-table-header columns="columns" mapping="mapping" sort="sort" timefield="timefield"></thead>'
|
||||
);
|
||||
|
||||
beforeEach(function () {
|
||||
init($elem, {
|
||||
mapping: mapping,
|
||||
columns: [],
|
||||
sorting: [],
|
||||
});
|
||||
});
|
||||
afterEach(function () {
|
||||
destroy();
|
||||
});
|
||||
|
||||
describe('adding and removing columns', function () {
|
||||
columnTests('th', $elem);
|
||||
});
|
||||
|
||||
|
||||
describe('sorting', function () {
|
||||
it('should have a sort function that sets the elements of the sort array', function (done) {
|
||||
expect($scope.sort).to.be.a(Function);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should have a headClasser function that determines the css classes of the sort icons', function (done) {
|
||||
expect($scope.headerClass).to.be.a(Function);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should sort asc by default, then by desc if already sorting', function (done) {
|
||||
var field = 'bytes';
|
||||
|
||||
// Should not be sorted at first
|
||||
expect($scope.sorting).to.eql(undefined);
|
||||
expect($scope.headerClass(field)).to.contain('fa-sort');
|
||||
|
||||
$scope.sort(field);
|
||||
expect($scope.sorting).to.eql([field, 'asc']);
|
||||
expect($scope.headerClass(field)).to.contain('fa-sort-up');
|
||||
|
||||
$scope.sort(field);
|
||||
expect($scope.sorting).to.eql([field, 'desc']);
|
||||
expect($scope.headerClass(field)).to.contain('fa-sort-down');
|
||||
|
||||
$scope.sort(field);
|
||||
expect($scope.sorting).to.eql([field, 'asc']);
|
||||
expect($scope.headerClass(field)).to.contain('fa-sort-up');
|
||||
|
||||
// Should show the default sort for any other field
|
||||
expect($scope.headerClass('timestamp')).to.contain('fa-sort');
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('should NOT sort unindexed fields', function (done) {
|
||||
$scope.sort('request');
|
||||
expect($scope.sorting).to.be(undefined);
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('moving columns', function () {
|
||||
beforeEach(function () {
|
||||
$parentScope.columns = _.keys($scope.mapping);
|
||||
$elem.scope().$digest();
|
||||
});
|
||||
|
||||
it('should move columns to the right', function () {
|
||||
|
||||
$scope.moveRight('bytes');
|
||||
expect($scope.columns[1]).to.be('bytes');
|
||||
|
||||
$scope.moveRight('bytes');
|
||||
expect($scope.columns[2]).to.be('bytes');
|
||||
});
|
||||
|
||||
it('shouldnt move the last column to the right', function () {
|
||||
expect($scope.columns[2]).to.be('timestamp');
|
||||
|
||||
$scope.moveRight('timestamp');
|
||||
expect($scope.columns[2]).to.be('timestamp');
|
||||
});
|
||||
|
||||
it('should move columns to the left', function () {
|
||||
$scope.moveLeft('timestamp');
|
||||
expect($scope.columns[1]).to.be('timestamp');
|
||||
|
||||
$scope.moveLeft('request');
|
||||
expect($scope.columns[1]).to.be('request');
|
||||
});
|
||||
|
||||
it('shouldnt move the first column to the left', function () {
|
||||
expect($scope.columns[0]).to.be('bytes');
|
||||
|
||||
$scope.moveLeft('bytes');
|
||||
expect($scope.columns[0]).to.be('bytes');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
var longString = Array(50).join('_');
|
||||
|
||||
var getFakeRow = function (id) {
|
||||
var columns = _.keys(mapping);
|
||||
return {
|
||||
_formatted: _.zipObject(_.map(columns, function (c) { return [c, c + '_formatted_' + id + longString]; })),
|
||||
_source: _.zipObject(_.map(columns, function (c) { return [c, c + '_original_' + id + longString]; })),
|
||||
_id: id,
|
||||
_index: 'test',
|
||||
sort: [id]
|
||||
};
|
||||
};
|
||||
|
||||
describe('kbnTable', function () {
|
||||
|
||||
var $elem = angular.element(
|
||||
'<kbn-table ' +
|
||||
'columns="columns" ' +
|
||||
'rows="rows" ' +
|
||||
'sorting="sorting"' +
|
||||
'filtering="filtering"' +
|
||||
'maxLength=maxLength ' +
|
||||
'mapping="mapping"' +
|
||||
'timefield="timefield" ' +
|
||||
'></thead>'
|
||||
);
|
||||
|
||||
beforeEach(function () {
|
||||
|
||||
// A tiny window
|
||||
sinon.stub($.prototype, 'height', function () { return 100; });
|
||||
|
||||
// Convince the infinite scroll that there's still a lot of room left.
|
||||
sinon.stub($.prototype, 'scrollTop', function () { return -200; });
|
||||
|
||||
var rows = _.times(200, function (i) {
|
||||
return getFakeRow(i);
|
||||
});
|
||||
init($elem, {
|
||||
columns: ['bytes'],
|
||||
rows: rows,
|
||||
sorting: [],
|
||||
filtering: sinon.spy(),
|
||||
maxLength: 50,
|
||||
mapping: mapping,
|
||||
timefield: 'timestamp'
|
||||
});
|
||||
});
|
||||
afterEach(function () {
|
||||
destroy();
|
||||
});
|
||||
|
||||
it('should have a header and a table element', function (done) {
|
||||
expect($elem.find('thead').length).to.be(1);
|
||||
expect($elem.find('table').length).to.be(1);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('should have 50 rows to start', function (done) {
|
||||
var tr = $elem.find('.discover-table-row');
|
||||
expect(tr.length).to.be(50);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should have an addRows function that adds 50 rows', function (done) {
|
||||
expect($scope.addRows).to.be.a(Function);
|
||||
$scope.addRows();
|
||||
$elem.scope().$digest();
|
||||
|
||||
var tr = $elem.find('.discover-table-row');
|
||||
expect(tr.length).to.be(100);
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('kbnTableRow', function () {
|
||||
|
||||
var $elem = angular.element(
|
||||
'<tr kbn-table-row="row" ' +
|
||||
'columns="columns" ' +
|
||||
'sorting="sorting"' +
|
||||
'filtering="filtering"' +
|
||||
'max-length=maxLength ' +
|
||||
'mapping="mapping"' +
|
||||
'timefield="timefield" ' +
|
||||
'></tr>'
|
||||
);
|
||||
|
||||
beforeEach(function () {
|
||||
|
||||
init($elem, {
|
||||
row: getFakeRow(0),
|
||||
columns: [],
|
||||
sorting: [],
|
||||
filtering: sinon.spy(),
|
||||
maxLength: 50,
|
||||
mapping: mapping,
|
||||
});
|
||||
|
||||
// Ignore the metaFields (_id, _type, etc) since we don't have a mapping for them
|
||||
sinon.stub(config, 'get').withArgs('metaFields').returns([]);
|
||||
|
||||
});
|
||||
afterEach(function () {
|
||||
destroy();
|
||||
});
|
||||
|
||||
describe('adding and removing columns', function () {
|
||||
columnTests('td', $elem);
|
||||
});
|
||||
|
||||
describe('details row', function () {
|
||||
it('should be an empty tr by default', function () {
|
||||
expect($elem.next().is('tr')).to.be(true);
|
||||
expect($elem.next().text()).to.be('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('details row', function () {
|
||||
it('should be an empty tr by default', function () {
|
||||
expect($elem.next().is('tr')).to.be(true);
|
||||
expect($elem.next().text()).to.be('');
|
||||
});
|
||||
|
||||
it('should expand the detail row when the toggle arrow is clicked', function () {
|
||||
$elem.children(':first-child').click();
|
||||
$scope.$digest();
|
||||
expect($elem.next().text()).to.not.be('');
|
||||
});
|
||||
|
||||
describe('expanded', function () {
|
||||
var $details;
|
||||
beforeEach(function () {
|
||||
// Open the row
|
||||
$scope.toggleRow();
|
||||
$scope.$digest();
|
||||
$details = $elem.next();
|
||||
});
|
||||
afterEach(function () {
|
||||
// Close the row
|
||||
$scope.toggleRow();
|
||||
$scope.$digest();
|
||||
});
|
||||
|
||||
it('should be a tr', function () {
|
||||
expect($details.is('tr')).to.be(true);
|
||||
});
|
||||
|
||||
it('should have a row for each field', function () {
|
||||
var rows = $details.find('tr');
|
||||
var row = $scope.row;
|
||||
expect($details.find('tr').length).to.be(3);
|
||||
});
|
||||
|
||||
it('should have a row for each field', function () {
|
||||
var rows = $details.find('tr');
|
||||
var row = $scope.row;
|
||||
expect($details.find('tr').length).to.be(3);
|
||||
});
|
||||
|
||||
describe('filtering', function () {
|
||||
it('should filter when you click on the filter buttons', function () {
|
||||
$details.find('.fa-search-plus').first().click();
|
||||
expect($scope.filtering.calledOnce).to.be(true);
|
||||
$details.find('.fa-search-minus').first().click();
|
||||
expect($scope.filtering.calledTwice).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
});
|
|
@ -9,6 +9,7 @@ define(function (require) {
|
|||
var AggConfigs;
|
||||
var SpiedAggConfig;
|
||||
var indexPattern;
|
||||
var Schemas;
|
||||
|
||||
beforeEach(module('kibana'));
|
||||
beforeEach(inject(function (Private) {
|
||||
|
@ -23,6 +24,7 @@ define(function (require) {
|
|||
AggConfigs = Private(require('components/vis/_agg_configs'));
|
||||
Registry = require('utils/registry/registry');
|
||||
indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern'));
|
||||
Schemas = Private(require('components/vis_types/_schemas'));
|
||||
}));
|
||||
|
||||
it('extends Registry', function () {
|
||||
|
@ -38,7 +40,7 @@ define(function (require) {
|
|||
});
|
||||
|
||||
var ac = new AggConfigs(vis);
|
||||
expect(ac).to.have.length(0);
|
||||
expect(ac).to.have.length(1);
|
||||
});
|
||||
|
||||
it('converts configStates into AggConfig objects if they are not already', function () {
|
||||
|
@ -58,8 +60,60 @@ define(function (require) {
|
|||
})
|
||||
]);
|
||||
|
||||
expect(ac).to.have.length(2);
|
||||
expect(SpiedAggConfig).to.have.property('callCount', 1);
|
||||
expect(ac).to.have.length(3);
|
||||
expect(SpiedAggConfig).to.have.property('callCount', 3);
|
||||
});
|
||||
|
||||
describe('defaults', function () {
|
||||
var vis;
|
||||
beforeEach(function () {
|
||||
vis = {
|
||||
type: {
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Simple',
|
||||
min: 1,
|
||||
max: 2,
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' },
|
||||
{ schema: 'metric', type: 'avg' },
|
||||
{ schema: 'metric', type: 'sum' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'segment',
|
||||
title: 'Example',
|
||||
min: 0,
|
||||
max: 1,
|
||||
defaults: [
|
||||
{ schema: 'segment', type: 'terms' },
|
||||
{ schema: 'segment', type: 'filters' }
|
||||
]
|
||||
}
|
||||
])
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
it('should only set the number of defaults defined by the max', function () {
|
||||
var ac = new AggConfigs(vis);
|
||||
expect(ac.bySchemaName['metric']).to.have.length(2);
|
||||
});
|
||||
|
||||
it('should set the defaults defined in the schema when none exist', function () {
|
||||
var ac = new AggConfigs(vis);
|
||||
expect(ac).to.have.length(3);
|
||||
});
|
||||
|
||||
it('should NOT set the defaults defined in the schema when some exist', function () {
|
||||
var ac = new AggConfigs(vis, [{ schema: 'segment', type: 'date_histogram' }]);
|
||||
expect(ac).to.have.length(3);
|
||||
expect(ac.bySchemaName['segment'][0].type.name).to.equal('date_histogram');
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -140,7 +194,7 @@ define(function (require) {
|
|||
}
|
||||
}(vis.aggs.toDsl()));
|
||||
|
||||
expect(aggInfos).to.have.length(0);
|
||||
expect(aggInfos).to.have.length(1);
|
||||
});
|
||||
|
||||
it('skips aggs that don\'t have a dsl representation', function () {
|
||||
|
@ -190,4 +244,4 @@ define(function (require) {
|
|||
});
|
||||
});
|
||||
}];
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,9 +8,6 @@ define(function (require) {
|
|||
// Load the kibana app dependencies.
|
||||
require('angular-route');
|
||||
|
||||
// Load kibana and its applications
|
||||
require('index');
|
||||
|
||||
require('apps/discover/index');
|
||||
|
||||
var $parentScope, $scope, $elem;
|
||||
|
@ -37,7 +34,7 @@ define(function (require) {
|
|||
$elem.scope().$digest();
|
||||
|
||||
// Grab the isolate scope so we can test it
|
||||
$scope = $elem.isolateScope();
|
||||
$scope = $elem.scope();
|
||||
|
||||
// Add a function to check the run status of.
|
||||
$scope.runThis = sinon.spy();
|
||||
|
@ -123,4 +120,4 @@ define(function (require) {
|
|||
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,12 +2,7 @@ define(function (require) {
|
|||
var angular = require('angular');
|
||||
var $ = require('jquery');
|
||||
|
||||
// Load the kibana app dependencies.
|
||||
require('angular-route');
|
||||
|
||||
// Load kibana and its applications
|
||||
require('index');
|
||||
|
||||
require('apps/discover/index');
|
||||
|
||||
var $parentScope, $scope, $elem;
|
||||
|
@ -66,4 +61,4 @@ define(function (require) {
|
|||
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue