mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
Merge branch 'master' into better_tooltips
Conflicts: src/kibana/components/vislib/lib/tooltip.js
This commit is contained in:
commit
0054b82108
10 changed files with 145 additions and 50 deletions
|
@ -172,21 +172,25 @@ define(function (require) {
|
|||
timefilter.enabled = !!timefield;
|
||||
});
|
||||
|
||||
// options are 'loading', 'ready', 'none', undefined
|
||||
$scope.$watchMulti([
|
||||
'rows',
|
||||
'fetchStatus'
|
||||
], (function updateResultState() {
|
||||
var prev = {};
|
||||
var status = {
|
||||
LOADING: 'loading', // initial data load
|
||||
READY: 'ready', // results came back
|
||||
NO_RESULTS: 'none' // no results came back
|
||||
};
|
||||
|
||||
function pick(rows, oldRows, fetchStatus, oldFetchStatus) {
|
||||
// initial state, pretend we are loading
|
||||
if (rows == null && oldRows == null) return 'loading';
|
||||
if (rows == null && oldRows == null) return status.LOADING;
|
||||
|
||||
var rowsEmpty = _.isEmpty(rows);
|
||||
if (rowsEmpty && fetchStatus) return 'loading';
|
||||
else if (!rowsEmpty) return 'ready';
|
||||
else return 'none';
|
||||
if (rowsEmpty && fetchStatus) return status.LOADING;
|
||||
else if (!rowsEmpty) return status.READY;
|
||||
else return status.NO_RESULTS;
|
||||
}
|
||||
|
||||
return function () {
|
||||
|
@ -242,6 +246,15 @@ define(function (require) {
|
|||
};
|
||||
|
||||
$scope.opts.fetch = $scope.fetch = function () {
|
||||
// flag used to set the scope based on data from segmentedFetch
|
||||
var resetRows = true;
|
||||
|
||||
function flushResponseData() {
|
||||
$scope.hits = 0;
|
||||
$scope.rows = [];
|
||||
$scope.rows.fieldCounts = {};
|
||||
}
|
||||
|
||||
// ignore requests to fetch before the app inits
|
||||
if (!init.complete) return;
|
||||
|
||||
|
@ -288,11 +301,17 @@ define(function (require) {
|
|||
$scope.fetchStatus = status;
|
||||
},
|
||||
first: function (resp) {
|
||||
$scope.hits = 0;
|
||||
$scope.rows = [];
|
||||
$scope.rows.fieldCounts = {};
|
||||
if (!$scope.rows) {
|
||||
flushResponseData();
|
||||
}
|
||||
},
|
||||
each: notify.timed('handle each segment', function (resp, req) {
|
||||
if (resetRows) {
|
||||
if (!resp.hits.total) return;
|
||||
resetRows = false;
|
||||
flushResponseData();
|
||||
}
|
||||
|
||||
$scope.hits += resp.hits.total;
|
||||
var rows = $scope.rows;
|
||||
var counts = rows.fieldCounts;
|
||||
|
@ -339,10 +358,15 @@ define(function (require) {
|
|||
});
|
||||
}),
|
||||
eachMerged: function (merged) {
|
||||
$scope.mergedEsResp = merged;
|
||||
if (!resetRows) {
|
||||
$scope.mergedEsResp = merged;
|
||||
}
|
||||
}
|
||||
})
|
||||
.finally(function () {
|
||||
if (resetRows) {
|
||||
flushResponseData();
|
||||
}
|
||||
$scope.fetchStatus = false;
|
||||
});
|
||||
})
|
||||
|
@ -601,6 +625,7 @@ define(function (require) {
|
|||
$scope.searchSource.set('aggs', undefined);
|
||||
delete $scope.vis;
|
||||
}
|
||||
|
||||
// we shouldn't have one, or already do, return whatever we already have
|
||||
if (!$scope.opts.timefield || $scope.vis) return Promise.resolve($scope.vis);
|
||||
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
.vis-editor {
|
||||
.flex-parent();
|
||||
|
||||
@vis-editor-sidebar-basis: (100/12) * 2%; // two of twelve columns
|
||||
@vis-editor-sidebar-min-width: 350px;
|
||||
@vis-editor-nesting-width: 8px;
|
||||
@vis-editor-agg-editor-spacing: 5px;
|
||||
|
||||
navbar {
|
||||
.bitty-modal-container {
|
||||
position: relative;
|
||||
|
@ -33,12 +38,28 @@
|
|||
|
||||
&-sidebar {
|
||||
.flex-parent(0, 0, auto);
|
||||
|
||||
overflow: auto;
|
||||
|
||||
// overrided for tablet and desktop
|
||||
@media (min-width: @screen-md-min) {
|
||||
.flex-basis(@vis-editor-sidebar-basis);
|
||||
min-width: @vis-editor-sidebar-min-width;
|
||||
max-width: @vis-editor-sidebar-min-width;
|
||||
margin-bottom: (@input-height-base * 2) - 3;
|
||||
}
|
||||
|
||||
&-buttons {
|
||||
// overrides for tablet and desktop
|
||||
@media (min-width: @screen-md-min) {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
min-width: @vis-editor-sidebar-min-width;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-item {
|
||||
border-top: 0 !important;
|
||||
}
|
||||
|
||||
.sidebar-container {
|
||||
|
@ -79,7 +100,6 @@
|
|||
&-group {
|
||||
.flex-parent();
|
||||
color: @text-color;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
&-header {
|
||||
|
|
|
@ -29,13 +29,15 @@
|
|||
</vis-editor-agg-group>
|
||||
|
||||
<!-- apply/discard -->
|
||||
<li class="sidebar-item" ng-if="vis.dirty">
|
||||
<li class="vis-editor-sidebar-buttons sidebar-item">
|
||||
<button
|
||||
ng-disabled="!vis.dirty"
|
||||
type="submit"
|
||||
class="sidebar-item-button success">
|
||||
Apply
|
||||
</button>
|
||||
<button
|
||||
ng-disabled="!vis.dirty"
|
||||
type="button"
|
||||
ng-click="reset()"
|
||||
class="sidebar-item-button warn">
|
||||
|
|
|
@ -19,4 +19,4 @@
|
|||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
@import "../editor/editor.less";
|
||||
@import "../editor/editor.less";
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
|
||||
return function AppStateProvider(Private) {
|
||||
return function AppStateProvider(Private, $rootScope) {
|
||||
var State = Private(require('components/state_management/state'));
|
||||
|
||||
_(AppState).inherits(State);
|
||||
function AppState(defaults) {
|
||||
AppState.Super.call(this, '_a', defaults);
|
||||
}
|
||||
|
||||
// When we have a route change, destroy the app state
|
||||
$rootScope.$on('$routeChangeStart', _.bindKey(this, 'destroy'));
|
||||
}
|
||||
|
||||
return AppState;
|
||||
};
|
||||
|
|
|
@ -29,12 +29,9 @@ define(function (require) {
|
|||
|
||||
return function (selection) {
|
||||
|
||||
// if tooltip not appended to body, append one
|
||||
if (d3.select('body').select('.' + self.tooltipClass)[0][0] === null) {
|
||||
d3.select('body').append('div').attr('class', self.tooltipClass);
|
||||
}
|
||||
|
||||
// if container not saved on Tooltip, save it
|
||||
if (self.container === undefined || self.container !== d3.select(self.el).select('.' + self.containerClass)) {
|
||||
self.container = d3.select(self.el).select('.' + self.containerClass);
|
||||
}
|
||||
|
@ -42,67 +39,62 @@ define(function (require) {
|
|||
var tooltipDiv = d3.select('.' + self.tooltipClass);
|
||||
|
||||
selection.each(function (data, i) {
|
||||
|
||||
// DOM element on which the tooltip is called
|
||||
var element = d3.select(this);
|
||||
|
||||
// define selections relative to el of tooltip
|
||||
var offset;
|
||||
|
||||
element
|
||||
.on('mousemove.tip', function (d) {
|
||||
// get x and y coordinates of the mouse event
|
||||
var mouseMove = {
|
||||
left: d3.event.clientX,
|
||||
top: d3.event.clientY
|
||||
};
|
||||
|
||||
offset = self.getOffsets(tooltipDiv, mouseMove);
|
||||
offset = self.getOffsets(mouseMove);
|
||||
|
||||
// return text and position for tooltip
|
||||
return tooltipDiv.datum(self.events.eventResponse(d, i))
|
||||
.html(tooltipFormatter)
|
||||
.style('display', 'block')
|
||||
.style('visibility', 'visible')
|
||||
.style('left', mouseMove.left + offset.left + 'px')
|
||||
.style('top', mouseMove.top + offset.top + 'px');
|
||||
})
|
||||
|
||||
.on('mouseout.tip', function () {
|
||||
// hide tooltip
|
||||
return tooltipDiv.style('display', 'none');
|
||||
return tooltipDiv.style('visibility', 'hidden')
|
||||
.style('left', '-500px')
|
||||
.style('top', '-500px');
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
Tooltip.prototype.getOffsets = function (tooltipDiv, mouseMove) {
|
||||
Tooltip.prototype.getOffsets = function (mouseMove) {
|
||||
|
||||
var self = this;
|
||||
var offset = {top: 10, left: 10};
|
||||
|
||||
var offset = {top: -10, left: 10};
|
||||
|
||||
if ($(self.el).find('.' + self.containerClass)) {
|
||||
var container = $(self.el).find('.' + self.containerClass);
|
||||
var container = $(self.el).find('.' + self.containerClass);
|
||||
var chartXOffset = container.offset().left;
|
||||
var chartYOffset = container.offset().top;
|
||||
var chartWidth = container.width();
|
||||
var chartHeight = container.height();
|
||||
var tipWidth = tooltipDiv[0][0].clientWidth;
|
||||
var tipHeight = tooltipDiv[0][0].clientHeight;
|
||||
|
||||
var chartWidth = container.width();
|
||||
var chartHeight = container.height();
|
||||
var tip = $('.' + self.tooltipClass)[0];
|
||||
var tipWidth = tip.clientWidth;
|
||||
var tipHeight = tip.clientHeight;
|
||||
|
||||
// change xOffset to keep tooltip within container
|
||||
// if tip width + xOffset puts it over right edge of container, flip left
|
||||
// unless flip left puts it over left edge of container
|
||||
if ((mouseMove.left + offset.left + tipWidth) > (chartXOffset + chartWidth) &&
|
||||
(mouseMove.left - tipWidth - 10) > chartXOffset) {
|
||||
// change yOffset to keep tooltip within container
|
||||
if (mouseMove.left + offset.left + tipWidth > chartXOffset + chartWidth &&
|
||||
mouseMove.left - tipWidth - 10 > chartXOffset) {
|
||||
offset.left = -10 - tipWidth;
|
||||
}
|
||||
|
||||
// change yOffset to keep tooltip within container
|
||||
if ((mouseMove.top + tipHeight - 10) > (chartYOffset + chartHeight)) {
|
||||
if (mouseMove.top + tipHeight - 10 > chartYOffset + chartHeight) {
|
||||
offset.top = chartYOffset + chartHeight;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return offset;
|
||||
};
|
||||
|
||||
|
|
|
@ -212,8 +212,8 @@ p.rows-label, p.columns-label {
|
|||
stroke: 3px;
|
||||
}
|
||||
|
||||
.k4tip, .vis-tooltip {
|
||||
display: none;
|
||||
.vis-tooltip {
|
||||
visibility: hidden;
|
||||
line-height: 1.1;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
|
|
|
@ -16,9 +16,4 @@
|
|||
@sidebar-active-color: @component-active-color;
|
||||
@sidebar-active-bg: @component-active-bg;
|
||||
@sidebar-active-hover-bg: @component-active-bg;
|
||||
@sidebar-active-hover-color: @component-active-color;
|
||||
|
||||
@vis-editor-sidebar-basis: (100/12) * 2%; // two of twelve columns
|
||||
@vis-editor-sidebar-min-width: 350px;
|
||||
@vis-editor-nesting-width: 8px;
|
||||
@vis-editor-agg-editor-spacing: 5px;
|
||||
@sidebar-active-hover-color: @component-active-color;
|
|
@ -107,6 +107,7 @@
|
|||
'specs/factories/base_object',
|
||||
'specs/state_management/state',
|
||||
'specs/state_management/global_state',
|
||||
'specs/state_management/app_state',
|
||||
'specs/utils/diff_object',
|
||||
'specs/factories/events',
|
||||
'specs/vislib/color',
|
||||
|
|
58
test/unit/specs/state_management/app_state.js
Normal file
58
test/unit/specs/state_management/app_state.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
define(function (require) {
|
||||
var sinon = require('test_utils/auto_release_sinon');
|
||||
require('components/state_management/app_state');
|
||||
|
||||
describe('State Management', function () {
|
||||
var $rootScope, AppState;
|
||||
|
||||
beforeEach(function () {
|
||||
module('kibana');
|
||||
|
||||
inject(function (_$rootScope_, _$location_, Private) {
|
||||
$rootScope = _$rootScope_;
|
||||
AppState = Private(require('components/state_management/app_state'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('App State', function () {
|
||||
var appState;
|
||||
|
||||
beforeEach(function () {
|
||||
appState = new AppState();
|
||||
});
|
||||
|
||||
it('should have _urlParam of _a', function () {
|
||||
expect(appState).to.have.property('_urlParam');
|
||||
expect(appState._urlParam).to.equal('_a');
|
||||
});
|
||||
|
||||
it('should use passed in params', function () {
|
||||
var params = {
|
||||
test: true,
|
||||
mock: false
|
||||
};
|
||||
|
||||
appState = new AppState(params);
|
||||
expect(appState).to.have.property('_defaults');
|
||||
|
||||
Object.keys(params).forEach(function (key) {
|
||||
expect(appState._defaults).to.have.property(key);
|
||||
expect(appState._defaults[key]).to.equal(params[key]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should have a destroy method', function () {
|
||||
expect(appState).to.have.property('destroy');
|
||||
});
|
||||
|
||||
it('should be destroyed on $routeChangeStart', function () {
|
||||
var destroySpy = sinon.spy(appState, 'destroy');
|
||||
var url = '/test/path';
|
||||
|
||||
$rootScope.$emit('$routeChangeStart');
|
||||
|
||||
expect(destroySpy.callCount).to.be(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue