mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 01:13:23 -04:00
commit
0eda612c0a
50 changed files with 1941 additions and 747 deletions
|
@ -300,7 +300,7 @@ define(function (require) {
|
|||
* @returns {object}
|
||||
*/
|
||||
var cleanFilter = function (filter) {
|
||||
return _.omit(filter, ['$$hashKey', 'meta']);
|
||||
return _.omit(filter, ['meta']);
|
||||
};
|
||||
|
||||
// switch to filtered query if there are filters
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
define(function (require) {
|
||||
return function CourierFetchRequestStatus() {
|
||||
return {
|
||||
ABORTED: {},
|
||||
DUPLICATE: {},
|
||||
INCOMPLETE: {}
|
||||
ABORTED: { CourierFetchRequestStatus: 'aborted' },
|
||||
DUPLICATE: { CourierFetchRequestStatus: 'duplicate' },
|
||||
INCOMPLETE: { CourierFetchRequestStatus: 'incomplete' }
|
||||
};
|
||||
};
|
||||
});
|
|
@ -241,6 +241,7 @@ define(function (require) {
|
|||
return self.id;
|
||||
});
|
||||
};
|
||||
|
||||
return docSource.doCreate(source)
|
||||
.then(finish)
|
||||
.catch(function (err) {
|
||||
|
|
|
@ -12,21 +12,25 @@
|
|||
<div class="bar" ng-show="filters.length">
|
||||
<div class="filter" ng-class="{ negate: filter.meta.negate, disabled: filter.meta.disabled }" ng-repeat="filter in filters">
|
||||
<div class="filter-description">
|
||||
<!--<span><i class="fa" ng-class="{'fa-plus': !filter.meta.negate, 'fa-minus': filter.meta.negate}"></i></span>-->
|
||||
<span ng-if="filter.$state.store == 'globalState'"><i class="fa fa-fw fa-thumb-tack pinned"></i></span>
|
||||
<span>{{ filter.meta.key }}:</span>
|
||||
<span>"{{ filter.meta.value }}"</span>
|
||||
</div>
|
||||
<div class="filter-actions">
|
||||
<a class="action filter-toggle" ng-click="toggleFilter(filter)">
|
||||
<i ng-show="filter.meta.disabled" class="fa fa-square-o"></i>
|
||||
<i ng-hide="filter.meta.disabled" class="fa fa-check-square-o"></i>
|
||||
<i ng-show="filter.meta.disabled" class="fa fa-fw fa-square-o disabled"></i>
|
||||
<i ng-hide="filter.meta.disabled" class="fa fa-fw fa-check-square-o enabled"></i>
|
||||
</a>
|
||||
<a class="action filter-pin" ng-click="pinFilter(filter)">
|
||||
<i ng-show="filter.$state.store == 'globalState'" class="fa fa-fw fa-thumb-tack pinned"></i>
|
||||
<i ng-hide="filter.$state.store == 'globalState'" class="fa fa-fw fa-thumb-tack fa-rotate-270 unpinned"></i>
|
||||
</a>
|
||||
<a class="action filter-invert" ng-click="invertFilter(filter)">
|
||||
<i ng-show="filter.meta.negate" class="fa fa-search-plus"></i>
|
||||
<i ng-hide="filter.meta.negate" class="fa fa-search-minus"></i>
|
||||
<i ng-show="filter.meta.negate" class="fa fa-fw fa-search-plus negative"></i>
|
||||
<i ng-hide="filter.meta.negate" class="fa fa-fw fa-search-minus positive"></i>
|
||||
</a>
|
||||
<a class="action filter-remove" ng-click="removeFilter(filter)">
|
||||
<i class="fa fa-trash"></i>
|
||||
<i class="fa fa-fw fa-trash"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -52,6 +56,12 @@
|
|||
<div class="filter-link">
|
||||
<div class="filter-description"><a ng-click="toggleAll(true)">Disable</a></div>
|
||||
</div>
|
||||
<div class="filter-link">
|
||||
<div class="filter-description"><a ng-click="pinAll(true)">Pin</a></div>
|
||||
</div>
|
||||
<div class="filter-link">
|
||||
<div class="filter-description"><a ng-click="pinAll(false)">Unpin</a></div>
|
||||
</div>
|
||||
<div class="filter-link">
|
||||
<div class="filter-description"><a ng-click="invertAll()">Invert</a></div>
|
||||
</div>
|
||||
|
|
|
@ -4,34 +4,43 @@ define(function (require) {
|
|||
var template = require('text!components/filter_bar/filter_bar.html');
|
||||
var moment = require('moment');
|
||||
|
||||
var toggleFilter = require('components/filter_bar/lib/toggleFilter');
|
||||
var toggleAll = require('components/filter_bar/lib/toggleAll');
|
||||
var invertFilter = require('components/filter_bar/lib/invertFilter');
|
||||
var invertAll = require('components/filter_bar/lib/invertAll');
|
||||
var removeFilter = require('components/filter_bar/lib/removeFilter');
|
||||
var removeAll = require('components/filter_bar/lib/removeAll');
|
||||
|
||||
var filterAppliedAndUnwrap = require('components/filter_bar/lib/filterAppliedAndUnwrap');
|
||||
|
||||
module.directive('filterBar', function (Private, Promise) {
|
||||
module.directive('filterBar', function (Private, Promise, getAppState) {
|
||||
var mapAndFlattenFilters = Private(require('components/filter_bar/lib/mapAndFlattenFilters'));
|
||||
var mapFlattenAndWrapFilters = Private(require('components/filter_bar/lib/mapFlattenAndWrapFilters'));
|
||||
var extractTimeFilter = Private(require('components/filter_bar/lib/extractTimeFilter'));
|
||||
var filterOutTimeBasedFilter = Private(require('components/filter_bar/lib/filterOutTimeBasedFilter'));
|
||||
var filterAppliedAndUnwrap = require('components/filter_bar/lib/filterAppliedAndUnwrap');
|
||||
var changeTimeFilter = Private(require('components/filter_bar/lib/changeTimeFilter'));
|
||||
var queryFilter = Private(require('components/filter_bar/query_filter'));
|
||||
|
||||
return {
|
||||
restrict: 'E',
|
||||
template: template,
|
||||
scope: {
|
||||
state: '='
|
||||
},
|
||||
scope: {},
|
||||
link: function ($scope, $el, attrs) {
|
||||
// bind query filter actions to the scope
|
||||
[
|
||||
'addFilters',
|
||||
'toggleFilter',
|
||||
'toggleAll',
|
||||
'pinFilter',
|
||||
'pinAll',
|
||||
'invertFilter',
|
||||
'invertAll',
|
||||
'removeFilter',
|
||||
'removeAll'
|
||||
].forEach(function (method) {
|
||||
$scope[method] = queryFilter[method];
|
||||
});
|
||||
|
||||
$scope.state = getAppState();
|
||||
|
||||
$scope.applyFilters = function (filters) {
|
||||
var newFilters = filterAppliedAndUnwrap(filters);
|
||||
$scope.state.filters = _.union($scope.state.filters, newFilters);
|
||||
// add new filters
|
||||
$scope.addFilters(filterAppliedAndUnwrap(filters));
|
||||
$scope.newFilters = [];
|
||||
|
||||
// change time filter
|
||||
if ($scope.changeTimeFilter && $scope.changeTimeFilter.meta && $scope.changeTimeFilter.meta.apply) {
|
||||
changeTimeFilter($scope.changeTimeFilter);
|
||||
}
|
||||
|
@ -42,10 +51,20 @@ define(function (require) {
|
|||
$scope.changeTimeFilter = null;
|
||||
};
|
||||
|
||||
// update the scope filter list on filter changes
|
||||
$scope.$listen(queryFilter, 'update', function () {
|
||||
updateFilters();
|
||||
});
|
||||
|
||||
// when appState changes, update scope's state
|
||||
$scope.$watch(getAppState, function (appState) {
|
||||
$scope.state = appState;
|
||||
});
|
||||
|
||||
$scope.$watch('state.$newFilters', function (filters) {
|
||||
if (!filters) return;
|
||||
|
||||
// If the filters is not undefined and the length is greater then
|
||||
// If filters is not undefined and the length is greater than
|
||||
// one we need to set the newFilters attribute and allow the
|
||||
// users to decide what they want to apply.
|
||||
if (filters.length > 1) {
|
||||
|
@ -72,24 +91,22 @@ define(function (require) {
|
|||
return filters;
|
||||
})
|
||||
.then(filterOutTimeBasedFilter)
|
||||
.then(function (filters) {
|
||||
$scope.state.filters = _.union($scope.state.filters, filters);
|
||||
});
|
||||
.then($scope.addFilters);
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$watch('state.filters', function (filters) {
|
||||
function updateFilters() {
|
||||
var filters = queryFilter.getFilters();
|
||||
mapAndFlattenFilters(filters).then(function (results) {
|
||||
$scope.filters = results;
|
||||
// used to display the current filters in the state
|
||||
$scope.filters = _.sortBy(results, function (filter) {
|
||||
return !filter.meta.pinned;
|
||||
});
|
||||
$scope.$emit('filterbar:updated');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$scope.toggleFilter = toggleFilter($scope);
|
||||
$scope.toggleAll = toggleAll($scope);
|
||||
$scope.invertFilter = invertFilter($scope);
|
||||
$scope.invertAll = invertAll($scope);
|
||||
$scope.removeFilter = removeFilter($scope);
|
||||
$scope.removeAll = removeAll($scope);
|
||||
updateFilters();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -99,8 +99,8 @@ filter-bar .bar {
|
|||
}
|
||||
|
||||
> .filter-actions {
|
||||
font-size: 1.3em;
|
||||
line-height: 1.1em;
|
||||
font-size: 1.1em;
|
||||
line-height: 1.4em;
|
||||
position: absolute;
|
||||
padding: 4px 8px;
|
||||
top: 0;
|
||||
|
@ -109,18 +109,22 @@ filter-bar .bar {
|
|||
display: none;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
> .filter-actions > .action {
|
||||
border-right: 1px solid rgba(255, 255, 255, 0.4);
|
||||
padding-right: 6px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
> * {
|
||||
border-right: 1px solid rgba(255, 255, 255, 0.4);
|
||||
padding-right: 0;
|
||||
margin-right: 5px;
|
||||
|
||||
> .filter-actions > .action:last-child {
|
||||
border-right: 0;
|
||||
padding-right: 0;
|
||||
margin-right: 0;
|
||||
&:last-child {
|
||||
border-right: 0;
|
||||
padding-right: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.unpinned {
|
||||
.opacity(.7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.negate {
|
||||
|
|
|
@ -29,8 +29,7 @@ define(function (require) {
|
|||
|
||||
if (!filters.length) return;
|
||||
|
||||
filters = uniqFilters(filters);
|
||||
filters = dedupFilters($state.filters, filters);
|
||||
filters = dedupFilters($state.filters, uniqFilters(filters));
|
||||
// We need to add a bunch of filter deduping here.
|
||||
$state.$newFilters = filters;
|
||||
}
|
||||
|
|
33
src/kibana/components/filter_bar/lib/compareFilters.js
Normal file
33
src/kibana/components/filter_bar/lib/compareFilters.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
var angular = require('angular');
|
||||
var excludedAttributes;
|
||||
var comparators;
|
||||
|
||||
/**
|
||||
* Compare two filters to see if they match
|
||||
* @param {object} first The first filter to compare
|
||||
* @param {object} second The second filter to compare
|
||||
* @param {object} comparatorOptions Parameters to use for comparison
|
||||
* @returns {bool} Filters are the same
|
||||
*/
|
||||
return function (first, second, comparatorOptions) {
|
||||
excludedAttributes = ['$$hashKey', 'meta'];
|
||||
comparators = _.defaults(comparatorOptions || {}, {
|
||||
state: false,
|
||||
negate: false,
|
||||
disabled: false,
|
||||
});
|
||||
|
||||
if (!comparators.state) excludedAttributes.push('$state');
|
||||
|
||||
return _.isEqual(mapFilter(first), mapFilter(second));
|
||||
};
|
||||
|
||||
function mapFilter(filter) {
|
||||
var cleaned = _.omit(filter, excludedAttributes);
|
||||
if (comparators.negate) cleaned.negate = filter.meta && !!filter.meta.negate;
|
||||
if (comparators.disabled) cleaned.disabled = filter.meta && !!filter.meta.disabled;
|
||||
return cleaned;
|
||||
}
|
||||
});
|
|
@ -1,12 +1,22 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
var excludedAttributes = ['meta', '$$hashKey'];
|
||||
return function (existing, filters) {
|
||||
filters = _.filter(filters, function (item) {
|
||||
return !_.find(existing, function (existingFilter) {
|
||||
return _.isEqual(_.omit(existingFilter, excludedAttributes), _.omit(item, excludedAttributes));
|
||||
var angular = require('angular');
|
||||
var compareFilters = require('components/filter_bar/lib/compareFilters');
|
||||
|
||||
/**
|
||||
* Combine 2 filter collections, removing duplicates
|
||||
* @param {object} existing The filters to compare to
|
||||
* @param {object} filters The filters being added
|
||||
* @param {object} comparatorOptions Parameters to use for comparison
|
||||
* @returns {object} An array of filters that were not in existing
|
||||
*/
|
||||
return function (existingFilters, filters, comparatorOptions) {
|
||||
if (!_.isArray(filters)) filters = [filters];
|
||||
|
||||
return _.filter(filters, function (filter) {
|
||||
return !_.find(existingFilters, function (existingFilter) {
|
||||
return compareFilters(existingFilter, filter, comparatorOptions);
|
||||
});
|
||||
});
|
||||
return filters;
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
define(function (require) {
|
||||
return function ($scope) {
|
||||
var invertFilter = require('components/filter_bar/lib/invertFilter')($scope);
|
||||
|
||||
/**
|
||||
* Removes all filters
|
||||
* @returns {void}
|
||||
*/
|
||||
return function () {
|
||||
$scope.filters.forEach(function (filter) {
|
||||
invertFilter(filter);
|
||||
});
|
||||
|
||||
$scope.state.filters = $scope.filters;
|
||||
};
|
||||
};
|
||||
});
|
|
@ -1,19 +0,0 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
return function ($scope) {
|
||||
/**
|
||||
* Inverts the nagate value on the filter
|
||||
* @param {object} filter The filter to toggle
|
||||
& @param {boolean} force disabled true/false
|
||||
* @returns {void}
|
||||
*/
|
||||
return function (filter) {
|
||||
// Toggle the negate meta state
|
||||
filter.meta.negate = !filter.meta.negate;
|
||||
|
||||
// Save the filters back to the searchSource
|
||||
$scope.state.filters = $scope.filters;
|
||||
return filter;
|
||||
};
|
||||
};
|
||||
});
|
|
@ -5,8 +5,13 @@ define(function (require) {
|
|||
return _.deepGet(filter, 'meta.disabled');
|
||||
};
|
||||
|
||||
return function (newFitlers, oldFilters) {
|
||||
var diff = _.difference(oldFilters, newFitlers);
|
||||
return (diff.length && _.every(diff, pluckDisabled));
|
||||
/**
|
||||
* Checks to see if only disabled filters have been changed
|
||||
* @returns {bool} Only disabled filters
|
||||
*/
|
||||
return function (newFilters, oldFilters) {
|
||||
return _.every(newFilters.concat(oldFilters), function (newFilter) {
|
||||
return pluckDisabled(newFilter);
|
||||
});
|
||||
};
|
||||
});
|
||||
|
|
19
src/kibana/components/filter_bar/lib/onlyStateChanged.js
Normal file
19
src/kibana/components/filter_bar/lib/onlyStateChanged.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
|
||||
var makeComparable = function (filter) {
|
||||
return _.omit(filter, ['$state', '$$hashKey']);
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks to see if only disabled filters have been changed
|
||||
* @returns {bool} Only disabled filters
|
||||
*/
|
||||
return function (newFilters, oldFilters) {
|
||||
var comparableOldFilters = _.map(oldFilters, makeComparable);
|
||||
return _.every(newFilters, function (newFilter, i) {
|
||||
var match = _.find(comparableOldFilters, makeComparable(newFilter));
|
||||
return !!match;
|
||||
});
|
||||
};
|
||||
});
|
|
@ -1,11 +0,0 @@
|
|||
define(function (require) {
|
||||
return function ($scope) {
|
||||
/**
|
||||
* Removes all filters
|
||||
* @returns {void}
|
||||
*/
|
||||
return function () {
|
||||
$scope.state.filters = [];
|
||||
};
|
||||
};
|
||||
});
|
|
@ -1,20 +0,0 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
return function ($scope) {
|
||||
/**
|
||||
* Removes the filter from the searchSource
|
||||
* @param {object} filter The filter to remove
|
||||
* @returns {void}
|
||||
*/
|
||||
return function (invalidFilter) {
|
||||
// Remove the filter from the the scope $filters and map it back
|
||||
// to the original format to save in searchSource
|
||||
$scope.state.filters = _($scope.filters)
|
||||
.filter(function (filter) {
|
||||
return filter !== invalidFilter;
|
||||
})
|
||||
.value();
|
||||
};
|
||||
|
||||
};
|
||||
});
|
|
@ -1,19 +0,0 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
return function ($scope) {
|
||||
var toggleFilter = require('components/filter_bar/lib/toggleFilter')($scope);
|
||||
|
||||
/**
|
||||
* Disables all filters
|
||||
* @params {boolean} force disable/enable all filters
|
||||
* @returns {void}
|
||||
*/
|
||||
return function (force) {
|
||||
$scope.filters.forEach(function (filter) {
|
||||
toggleFilter(filter, force);
|
||||
});
|
||||
|
||||
$scope.state.filters = $scope.filters;
|
||||
};
|
||||
};
|
||||
});
|
|
@ -1,20 +0,0 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
return function ($scope) {
|
||||
/**
|
||||
* Toggles the filter between enabled/disabled.
|
||||
* @param {object} filter The filter to toggle
|
||||
& @param {boolean} force disabled true/false
|
||||
* @returns {void}
|
||||
*/
|
||||
return function (filter, force) {
|
||||
// Toggle the disabled flag
|
||||
var disabled = _.isUndefined(force) ? !filter.meta.disabled : force;
|
||||
filter.meta.disabled = disabled;
|
||||
|
||||
// Save the filters back to the searchSource
|
||||
$scope.state.filters = $scope.filters;
|
||||
return filter;
|
||||
};
|
||||
};
|
||||
});
|
|
@ -1,10 +1,16 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
var dedupFilters = require('components/filter_bar/lib/dedupFilters');
|
||||
return function (filters) {
|
||||
|
||||
/**
|
||||
* Remove duplicate filters from an array of filters
|
||||
* @param {array} filters The filters to remove duplicates from
|
||||
* @returns {object} The original filters array with duplicates removed
|
||||
*/
|
||||
return function (filters, comparatorOptions) {
|
||||
var results = [];
|
||||
_.each(filters, function (filter) {
|
||||
results = _.union(results, dedupFilters(results, [filter]));
|
||||
results = _.union(results, dedupFilters(results, [filter], comparatorOptions));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
define(function (require) {
|
||||
return function watchFiltersProvider(Private, Promise, Notifier) {
|
||||
var _ = require('lodash');
|
||||
var onlyDisabled = require('components/filter_bar/lib/onlyDisabled');
|
||||
var EventEmitter = Private(require('factories/events'));
|
||||
var notify = new Notifier({ location: 'Fitler Bar' });
|
||||
|
||||
return function ($scope, handlers) {
|
||||
var emitter = new EventEmitter();
|
||||
|
||||
$scope.$watch('state.filters', function (newFilters, oldFilters) {
|
||||
if (newFilters === oldFilters) return;
|
||||
|
||||
return emitter.emit('update')
|
||||
.then(function () {
|
||||
if (onlyDisabled(newFilters, oldFilters)) return;
|
||||
return emitter.emit('fetch');
|
||||
});
|
||||
});
|
||||
|
||||
return emitter;
|
||||
};
|
||||
};
|
||||
});
|
329
src/kibana/components/filter_bar/query_filter.js
Normal file
329
src/kibana/components/filter_bar/query_filter.js
Normal file
|
@ -0,0 +1,329 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
|
||||
return function (Private, $rootScope, getAppState, globalState) {
|
||||
var EventEmitter = Private(require('factories/events'));
|
||||
var onlyDisabled = require('components/filter_bar/lib/onlyDisabled');
|
||||
var onlyStateChanged = require('components/filter_bar/lib/onlyStateChanged');
|
||||
var uniqFilters = require('components/filter_bar/lib/uniqFilters');
|
||||
var compareFilters = require('components/filter_bar/lib/compareFilters');
|
||||
|
||||
var queryFilter = new EventEmitter();
|
||||
|
||||
queryFilter.getFilters = function () {
|
||||
var compareOptions = { disabled: true, negate: true };
|
||||
var appFilters = queryFilter.getAppFilters();
|
||||
var globalFilters = queryFilter.getGlobalFilters();
|
||||
|
||||
return uniqFilters(globalFilters.concat(appFilters), compareOptions);
|
||||
};
|
||||
|
||||
queryFilter.getAppFilters = function () {
|
||||
var appState = getAppState();
|
||||
if (!appState || !appState.filters) return [];
|
||||
return (appState.filters) ? _.map(appState.filters, appendStoreType('appState')) : [];
|
||||
};
|
||||
|
||||
queryFilter.getGlobalFilters = function () {
|
||||
if (!globalState.filters) return [];
|
||||
return _.map(globalState.filters, appendStoreType('globalState'));
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds new filters to the scope and state
|
||||
* @param {object|array} fitlers Filter(s) to add
|
||||
* @param {bool} global Should be added to global state
|
||||
* @returns {object} Resulting new filter list
|
||||
*/
|
||||
queryFilter.addFilters = function (filters, global) {
|
||||
var appState = getAppState();
|
||||
var state = (global) ? globalState : appState;
|
||||
|
||||
if (!_.isArray(filters)) {
|
||||
filters = [filters];
|
||||
}
|
||||
|
||||
if (global) {
|
||||
// simply concat global filters, they will be deduped
|
||||
globalState.filters = globalState.filters.concat(filters);
|
||||
} else if (appState) {
|
||||
if (!appState.filters) appState.filters = [];
|
||||
var mergeOptions = { disabled: true, negate: false };
|
||||
var appFilters = appState.filters.concat(filters);
|
||||
var merged = mergeAndMutateFilters(globalState.filters, appFilters, mergeOptions);
|
||||
globalState.filters = merged[0];
|
||||
appState.filters = merged[1];
|
||||
}
|
||||
|
||||
return saveState();
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the filter from the proper state
|
||||
* @param {object} matchFilter The filter to remove
|
||||
* @returns {object} Resulting new filter list
|
||||
*/
|
||||
queryFilter.removeFilter = function (matchFilter) {
|
||||
var state = getStateByFilter(matchFilter);
|
||||
if (!state) return;
|
||||
|
||||
_.pull(state.filters, matchFilter);
|
||||
return saveState();
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes all filters
|
||||
* @returns {object} Resulting new filter list
|
||||
*/
|
||||
queryFilter.removeAll = function () {
|
||||
var appState = getAppState();
|
||||
appState.filters = [];
|
||||
globalState.filters = [];
|
||||
return saveState();
|
||||
};
|
||||
|
||||
/**
|
||||
* Toggles the filter between enabled/disabled.
|
||||
* @param {object} filter The filter to toggle
|
||||
& @param {boolean} force Disabled true/false
|
||||
* @returns {object} updated filter
|
||||
*/
|
||||
queryFilter.toggleFilter = function (filter, force) {
|
||||
// Toggle the disabled flag
|
||||
var disabled = _.isUndefined(force) ? !filter.meta.disabled : !!force;
|
||||
filter.meta.disabled = disabled;
|
||||
|
||||
// Save the filters back to the searchSource
|
||||
saveState();
|
||||
return filter;
|
||||
};
|
||||
|
||||
/**
|
||||
* Disables all filters
|
||||
* @params {boolean} force Disable/enable all filters
|
||||
* @returns {object} Resulting updated filter list
|
||||
*/
|
||||
queryFilter.toggleAll = function (force) {
|
||||
function doToggle(filter) {
|
||||
queryFilter.toggleFilter(filter, force);
|
||||
}
|
||||
|
||||
executeOnFilters(doToggle);
|
||||
return queryFilter.getFilters();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Inverts the nagate value on the filter
|
||||
* @param {object} filter The filter to toggle
|
||||
* @returns {object} updated filter
|
||||
*/
|
||||
queryFilter.invertFilter = function (filter) {
|
||||
// Toggle the negate meta state
|
||||
filter.meta.negate = !filter.meta.negate;
|
||||
|
||||
saveState();
|
||||
return filter;
|
||||
};
|
||||
|
||||
/**
|
||||
* Inverts all filters
|
||||
* @returns {object} Resulting updated filter list
|
||||
*/
|
||||
queryFilter.invertAll = function () {
|
||||
executeOnFilters(queryFilter.invertFilter);
|
||||
return queryFilter.getFilters();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Pins the filter to the global state
|
||||
* @param {object} filter The filter to pin
|
||||
* @param {boolean} force pinned state
|
||||
* @returns {object} filter passed in
|
||||
*/
|
||||
queryFilter.pinFilter = function (filter, force) {
|
||||
var appState = getAppState();
|
||||
if (!appState) return filter;
|
||||
|
||||
// ensure that both states have a filters property
|
||||
if (!_.isArray(globalState.filters)) globalState.filters = [];
|
||||
if (!_.isArray(appState.filters)) appState.filters = [];
|
||||
|
||||
var appIndex = _.indexOf(appState.filters, filter);
|
||||
var globalIndex = _.indexOf(globalState.filters, filter);
|
||||
if (appIndex === -1 && globalIndex === -1) return;
|
||||
|
||||
if (appIndex !== -1 && force !== false) {
|
||||
appState.filters.splice(appIndex, 1);
|
||||
globalState.filters.push(filter);
|
||||
} else if (globalIndex !== -1 && force !== true) {
|
||||
globalState.filters.splice(globalIndex, 1);
|
||||
appState.filters.push(filter);
|
||||
}
|
||||
|
||||
saveState();
|
||||
return filter;
|
||||
};
|
||||
|
||||
/**
|
||||
* Pins all filters
|
||||
* @params {boolean} force Pin/Unpin all filters
|
||||
* @returns {object} Resulting updated filter list
|
||||
*/
|
||||
queryFilter.pinAll = function (force) {
|
||||
function pin(filter) {
|
||||
queryFilter.pinFilter(filter, force);
|
||||
}
|
||||
|
||||
executeOnFilters(pin);
|
||||
return queryFilter.getFilters();
|
||||
};
|
||||
|
||||
initWatchers();
|
||||
|
||||
return queryFilter;
|
||||
|
||||
/**
|
||||
* Saves both app and global states, ensuring filters are persisted
|
||||
* @returns {object} Resulting filter list, app and global combined
|
||||
*/
|
||||
function saveState() {
|
||||
var appState = getAppState();
|
||||
if (appState) appState.save();
|
||||
globalState.save();
|
||||
return queryFilter.getFilters();
|
||||
}
|
||||
|
||||
function appendStoreType(type) {
|
||||
return function (filter) {
|
||||
filter.$state = {
|
||||
store: type
|
||||
};
|
||||
return filter;
|
||||
};
|
||||
}
|
||||
|
||||
// get state (app or global) or the filter passed in
|
||||
function getStateByFilter(filter) {
|
||||
var appState = getAppState();
|
||||
if (appState) {
|
||||
var appIndex = _.indexOf(appState.filters, filter);
|
||||
if (appIndex !== -1) return appState;
|
||||
}
|
||||
|
||||
var globalIndex = _.indexOf(globalState.filters, filter);
|
||||
if (globalIndex !== -1) return globalState;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// helper to run a function on all filters in all states
|
||||
function executeOnFilters(fn) {
|
||||
var appState = getAppState();
|
||||
var appFilters;
|
||||
if (appState && appState.filters) {
|
||||
appFilters = appState.filters;
|
||||
} else {
|
||||
appFilters = [];
|
||||
}
|
||||
globalState.filters.concat(appFilters).forEach(fn);
|
||||
}
|
||||
|
||||
function mergeAndMutateFilters(globalFilters, appFilters, compareOptions) {
|
||||
appFilters = appFilters || [];
|
||||
globalFilters = globalFilters || [];
|
||||
compareOptions = _.defaults(compareOptions || {}, { disabled: true, negate: true });
|
||||
|
||||
// existing globalFilters should be mutated by appFilters
|
||||
appFilters = _.filter(appFilters, function (filter) {
|
||||
var match = _.find(globalFilters, function (globalFilter) {
|
||||
return compareFilters(globalFilter, filter, compareOptions);
|
||||
});
|
||||
|
||||
// if the filter remains, it doesn't match any filters in global state
|
||||
if (!match) return true;
|
||||
|
||||
// filter matches a filter in globalFilters, mutate existing global filter
|
||||
_.assign(match.meta, filter.meta);
|
||||
return false;
|
||||
});
|
||||
|
||||
appFilters = uniqFilters(appFilters, { disabled: true });
|
||||
globalFilters = uniqFilters(globalFilters, { disabled: true });
|
||||
|
||||
return [globalFilters, appFilters];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes state watchers that use the event emitter
|
||||
* @returns {void}
|
||||
*/
|
||||
function initWatchers() {
|
||||
var removeAppStateWatchers;
|
||||
|
||||
$rootScope.$watch(getAppState, function () {
|
||||
removeAppStateWatchers && removeAppStateWatchers();
|
||||
removeAppStateWatchers = initAppStateWatchers();
|
||||
});
|
||||
|
||||
function initAppStateWatchers() {
|
||||
// multi watch on the app and global states
|
||||
var stateWatchers = [{
|
||||
fn: $rootScope.$watch,
|
||||
deep: true,
|
||||
get: queryFilter.getGlobalFilters
|
||||
}, {
|
||||
fn: $rootScope.$watch,
|
||||
deep: true,
|
||||
get: queryFilter.getAppFilters
|
||||
}];
|
||||
|
||||
// when states change, use event emitter to trigger updates and fetches
|
||||
return $rootScope.$watchMulti(stateWatchers, function (next, prev) {
|
||||
var doUpdate = false;
|
||||
var doFetch = false;
|
||||
var newFilters = [];
|
||||
var oldFilters = [];
|
||||
|
||||
// iterate over each state type, checking for changes
|
||||
stateWatchers.forEach(function (watcher, i) {
|
||||
var nextVal = next[i];
|
||||
var prevVal = prev[i];
|
||||
newFilters = newFilters.concat(nextVal);
|
||||
oldFilters = oldFilters.concat(prevVal);
|
||||
|
||||
// no update or fetch if there was no change
|
||||
if (nextVal === prevVal) return;
|
||||
if (nextVal) doUpdate = true;
|
||||
|
||||
// don't trigger fetch when only disabled filters
|
||||
if (!onlyDisabled(nextVal, prevVal)) doFetch = true;
|
||||
});
|
||||
|
||||
// make sure change wasn't only a state move
|
||||
if (doFetch && newFilters.length === oldFilters.length) {
|
||||
if (onlyStateChanged(newFilters, oldFilters)) doFetch = false;
|
||||
}
|
||||
|
||||
// reconcile filter in global and app states
|
||||
var filters = mergeAndMutateFilters(next[0], next[1]);
|
||||
globalState.filters = filters[0];
|
||||
var appState = getAppState();
|
||||
if (appState) {
|
||||
appState.filters = filters[1];
|
||||
}
|
||||
saveState();
|
||||
|
||||
if (!doUpdate) return;
|
||||
|
||||
return queryFilter.emit('update')
|
||||
.then(function () {
|
||||
if (!doFetch) return;
|
||||
return queryFilter.emit('fetch');
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
|
@ -1,73 +1,79 @@
|
|||
// Adds a filter to a passed state
|
||||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
var self = this;
|
||||
return function (Private) {
|
||||
var _ = require('lodash');
|
||||
var queryFilter = Private(require('components/filter_bar/query_filter'));
|
||||
var filterManager = {};
|
||||
|
||||
this.init = function ($state) {
|
||||
self.$state = $state;
|
||||
};
|
||||
filterManager.add = function (field, values, operation, index) {
|
||||
values = _.isArray(values) ? values : [values];
|
||||
var fieldName = _.isObject(field) ? field.name : field;
|
||||
var filters = _.flatten([queryFilter.getAppFilters()], true);
|
||||
var newFilters = [];
|
||||
|
||||
this.add = function (field, values, operation, index) {
|
||||
var negate = (operation === '-');
|
||||
|
||||
values = _.isArray(values) ? values : [values];
|
||||
|
||||
// Have we been passed a simple name or an actual field object?
|
||||
|
||||
var fieldName = _.isObject(field) ? field.name : field;
|
||||
|
||||
var negate = operation === '-';
|
||||
var filters = _.flatten([self.$state.filters], true);
|
||||
|
||||
// TODO: On array fields, negating does not negate the combination, rather all terms
|
||||
_.each(values, function (value) {
|
||||
var existing = _.find(filters, function (filter) {
|
||||
if (!filter) return;
|
||||
|
||||
if (fieldName === '_exists_' && filter.exists) {
|
||||
return filter.exists.field === value;
|
||||
}
|
||||
|
||||
if (filter.query) {
|
||||
return filter.query.match[fieldName] && filter.query.match[fieldName].query === value;
|
||||
}
|
||||
});
|
||||
|
||||
if (existing) {
|
||||
if (existing.meta.negate !== negate) {
|
||||
existing.meta.negate = negate;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (fieldName) {
|
||||
case '_exists_':
|
||||
filters.push({ meta: { negate: negate, index: index }, exists: { field: value } });
|
||||
break;
|
||||
default:
|
||||
// TODO: On array fields, negating does not negate the combination, rather all terms
|
||||
_.each(values, function (value) {
|
||||
var filter;
|
||||
if (field.scripted) {
|
||||
var existing = _.find(filters, function (filter) {
|
||||
if (!filter) return;
|
||||
|
||||
if (fieldName === '_exists_' && filter.exists) {
|
||||
return filter.exists.field === value;
|
||||
}
|
||||
|
||||
if (filter.query) {
|
||||
return filter.query.match[fieldName] && filter.query.match[fieldName].query === value;
|
||||
}
|
||||
});
|
||||
|
||||
if (existing) {
|
||||
existing.meta.disabled = false;
|
||||
if (existing.meta.negate !== negate) {
|
||||
queryFilter.invertFilter(existing);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (fieldName) {
|
||||
case '_exists_':
|
||||
filter = {
|
||||
meta: { negate: negate, index: index, field: fieldName },
|
||||
script: {
|
||||
script: '(' + field.script + ') == value',
|
||||
lang: field.lang,
|
||||
params: {
|
||||
value: value
|
||||
}
|
||||
meta: {
|
||||
negate: negate,
|
||||
index: index
|
||||
},
|
||||
exists: {
|
||||
field: value
|
||||
}
|
||||
};
|
||||
} else {
|
||||
filter = { meta: { negate: negate, index: index }, query: { match: {} } };
|
||||
filter.query.match[fieldName] = { query: value, type: 'phrase' };
|
||||
break;
|
||||
default:
|
||||
if (field.scripted) {
|
||||
filter = {
|
||||
meta: { negate: negate, index: index, field: fieldName },
|
||||
script: {
|
||||
script: '(' + field.script + ') == value',
|
||||
lang: field.lang,
|
||||
params: {
|
||||
value: value
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
filter = { meta: { negate: negate, index: index }, query: { match: {} } };
|
||||
filter.query.match[fieldName] = { query: value, type: 'phrase' };
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
filters.push(filter);
|
||||
|
||||
break;
|
||||
}
|
||||
});
|
||||
newFilters.push(filter);
|
||||
});
|
||||
|
||||
self.$state.filters = filters;
|
||||
queryFilter.addFilters(newFilters);
|
||||
};
|
||||
|
||||
return filterManager;
|
||||
};
|
||||
|
||||
return this;
|
||||
});
|
||||
|
|
|
@ -58,8 +58,7 @@ define(function (require) {
|
|||
State.prototype.fetch = function () {
|
||||
var stash = this._readFromURL();
|
||||
|
||||
// nothing to read from the url?
|
||||
// we should save if were are ordered to persist
|
||||
// nothing to read from the url? save if ordered to persist
|
||||
if (stash === null) {
|
||||
if (this._persistAcrossApps) {
|
||||
return this.save();
|
||||
|
|
|
@ -41,6 +41,8 @@ define(function (require) {
|
|||
var vals = new Array(expressions.length);
|
||||
var prev = new Array(expressions.length);
|
||||
var fire = false;
|
||||
var init = 0;
|
||||
var neededInits = expressions.length;
|
||||
|
||||
// first, register all of the multi-watchers
|
||||
var unwatchers = expressions.map(function (expr, i) {
|
||||
|
@ -48,6 +50,10 @@ define(function (require) {
|
|||
if (!expr) return;
|
||||
|
||||
return expr.fn.call($scope, expr.get, function (newVal, oldVal) {
|
||||
if (newVal === oldVal) {
|
||||
init += 1;
|
||||
}
|
||||
|
||||
vals[i] = newVal;
|
||||
prev[i] = oldVal;
|
||||
fire = true;
|
||||
|
@ -58,12 +64,16 @@ define(function (require) {
|
|||
// the other watchers triggered this cycle
|
||||
var flip = false;
|
||||
unwatchers.push($scope.$watch(function () {
|
||||
if (init < neededInits) return init;
|
||||
|
||||
if (fire) {
|
||||
fire = false;
|
||||
flip = !flip;
|
||||
}
|
||||
return flip;
|
||||
}, function () {
|
||||
if (init < neededInits) return false;
|
||||
|
||||
fn(vals.slice(0), prev.slice(0));
|
||||
vals.forEach(function (v, i) {
|
||||
prev[i] = v;
|
||||
|
@ -104,4 +114,4 @@ define(function (require) {
|
|||
return $delegate;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,12 +1,12 @@
|
|||
define(function (require) {
|
||||
var moment = require('moment');
|
||||
var filterManager = require('components/filter_manager/filter_manager');
|
||||
var $ = require('jquery');
|
||||
require('modules')
|
||||
.get('app/dashboard')
|
||||
.directive('dashboardPanel', function (savedVisualizations, savedSearches, Notifier, Private, $compile) {
|
||||
var _ = require('lodash');
|
||||
var loadPanel = Private(require('plugins/dashboard/components/panel/lib/load_panel'));
|
||||
var filterManager = Private(require('components/filter_manager/filter_manager'));
|
||||
var notify = new Notifier();
|
||||
|
||||
require('components/visualize/visualize');
|
||||
|
@ -32,7 +32,6 @@ define(function (require) {
|
|||
$scope.edit = panelConfig.edit;
|
||||
$scope.$on('$destroy', panelConfig.savedObj.destroy);
|
||||
|
||||
filterManager.init($state);
|
||||
$scope.filter = function (field, value, operator) {
|
||||
var index = $scope.savedObj.searchSource.get('index').id;
|
||||
filterManager.add(field, value, operator, index);
|
||||
|
|
|
@ -50,7 +50,7 @@ define(function (require) {
|
|||
app.directive('dashboardApp', function (Notifier, courier, AppState, timefilter, kbnUrl) {
|
||||
return {
|
||||
controller: function ($scope, $route, $routeParams, $location, configFile, Private, getAppState) {
|
||||
var filterBarWatchFilters = Private(require('components/filter_bar/lib/watchFilters'));
|
||||
var queryFilter = Private(require('components/filter_bar/query_filter'));
|
||||
|
||||
var notify = new Notifier({
|
||||
location: 'Dashboard'
|
||||
|
@ -110,22 +110,24 @@ define(function (require) {
|
|||
}
|
||||
|
||||
function updateQueryOnRootSource() {
|
||||
var filters = $state.filters;
|
||||
var filters = queryFilter.getFilters();
|
||||
if ($state.query) {
|
||||
dash.searchSource.set('filter', _.union($state.filters, [{
|
||||
query: $state.query
|
||||
dash.searchSource.set('filter', _.union(filters, [{
|
||||
query: $state.query
|
||||
}]));
|
||||
} else {
|
||||
dash.searchSource.set('filter', filters);
|
||||
}
|
||||
}
|
||||
|
||||
filterBarWatchFilters($scope)
|
||||
.on('update', function () {
|
||||
// update root source when filters update
|
||||
$scope.$listen(queryFilter, 'update', function () {
|
||||
updateQueryOnRootSource();
|
||||
$state.save();
|
||||
})
|
||||
.on('fetch', $scope.refresh);
|
||||
});
|
||||
|
||||
// update data when filters fire fetch event
|
||||
$scope.$listen(queryFilter, 'fetch', $scope.refresh);
|
||||
|
||||
$scope.newDashboard = function () {
|
||||
kbnUrl.change('/dashboard', {});
|
||||
|
|
|
@ -3,7 +3,6 @@ define(function (require) {
|
|||
var angular = require('angular');
|
||||
var moment = require('moment');
|
||||
var ConfigTemplate = require('utils/config_template');
|
||||
var filterManager = require('components/filter_manager/filter_manager');
|
||||
var getSort = require('components/doc_table/lib/get_sort');
|
||||
var rison = require('utils/rison');
|
||||
|
||||
|
@ -69,7 +68,8 @@ define(function (require) {
|
|||
var docTitle = Private(require('components/doc_title/doc_title'));
|
||||
var brushEvent = Private(require('utils/brush_event'));
|
||||
var HitSortFn = Private(require('plugins/discover/_hit_sort_fn'));
|
||||
var filterBarWatchFilters = Private(require('components/filter_bar/lib/watchFilters'));
|
||||
var queryFilter = Private(require('components/filter_bar/query_filter'));
|
||||
var filterManager = Private(require('components/filter_manager/filter_manager'));
|
||||
|
||||
var notify = new Notifier({
|
||||
location: 'Discover'
|
||||
|
@ -115,7 +115,7 @@ define(function (require) {
|
|||
columns: savedSearch.columns || ['_source'],
|
||||
index: $scope.indexPattern.id,
|
||||
interval: 'auto',
|
||||
filters: _.cloneDeep($scope.searchSource.get('filter'))
|
||||
filters: _.cloneDeep($scope.searchSource.getOwn('filter'))
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -127,7 +127,6 @@ define(function (require) {
|
|||
});
|
||||
|
||||
var metaFields = config.get('metaFields');
|
||||
filterManager.init($state);
|
||||
|
||||
$scope.opts = {
|
||||
// number of records to fetch, then paginate through
|
||||
|
@ -165,13 +164,15 @@ define(function (require) {
|
|||
if (!angular.equals(sort, currentSort)) $scope.fetch();
|
||||
});
|
||||
|
||||
filterBarWatchFilters($scope)
|
||||
.on('update', function () {
|
||||
// update data source when filters update
|
||||
$scope.$listen(queryFilter, 'update', function () {
|
||||
return $scope.updateDataSource().then(function () {
|
||||
$state.save();
|
||||
});
|
||||
})
|
||||
.on('fetch', $scope.fetch);
|
||||
});
|
||||
|
||||
// fetch data when filters fire fetch event
|
||||
$scope.$listen(queryFilter, 'fetch', $scope.fetch);
|
||||
|
||||
$scope.$watch('opts.timefield', function (timefield) {
|
||||
timefilter.enabled = !!timefield;
|
||||
|
@ -424,7 +425,7 @@ define(function (require) {
|
|||
fields: {'*': {}},
|
||||
fragment_size: 2147483647 // Limit of an integer.
|
||||
})
|
||||
.set('filter', $state.filters || []);
|
||||
.set('filter', queryFilter.getFilters());
|
||||
});
|
||||
|
||||
// TODO: On array fields, negating does not negate the combination, rather all terms
|
||||
|
|
|
@ -58,7 +58,7 @@ define(function (require) {
|
|||
var Notifier = require('components/notify/_notifier');
|
||||
var docTitle = Private(require('components/doc_title/doc_title'));
|
||||
var brushEvent = Private(require('utils/brush_event'));
|
||||
var filterBarWatchFilters = Private(require('components/filter_bar/lib/watchFilters'));
|
||||
var queryFilter = Private(require('components/filter_bar/query_filter'));
|
||||
var filterBarClickHandler = Private(require('components/filter_bar/filter_bar_click_handler'));
|
||||
|
||||
var notify = new Notifier({
|
||||
|
@ -152,19 +152,16 @@ define(function (require) {
|
|||
timefilter.enabled = !!timeField;
|
||||
});
|
||||
|
||||
filterBarWatchFilters($scope)
|
||||
.on('update', function () {
|
||||
if ($state.filters && $state.filters.length) {
|
||||
searchSource.set('filter', $state.filters);
|
||||
} else {
|
||||
searchSource.set('filter', []);
|
||||
}
|
||||
// update the searchSource when filters update
|
||||
$scope.$listen(queryFilter, 'update', function () {
|
||||
searchSource.set('filter', queryFilter.getFilters());
|
||||
$state.save();
|
||||
})
|
||||
.on('fetch', function () {
|
||||
$scope.fetch();
|
||||
});
|
||||
|
||||
// fetch data when filters fire fetch event
|
||||
$scope.$listen(queryFilter, 'fetch', $scope.fetch);
|
||||
|
||||
|
||||
$scope.$listen($state, 'fetch_with_changes', function (keys) {
|
||||
if (_.contains(keys, 'linked') && $state.linked === true) {
|
||||
// abort and reload route
|
||||
|
@ -187,7 +184,7 @@ define(function (require) {
|
|||
}
|
||||
|
||||
if (_.isEqual(keys, ['filters'])) {
|
||||
// updates will happen in filterBarWatchFilters() if needed
|
||||
// updates will happen in filter watcher if needed
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -210,7 +207,7 @@ define(function (require) {
|
|||
|
||||
$scope.fetch = function () {
|
||||
$state.save();
|
||||
searchSource.set('filter', $state.filters);
|
||||
searchSource.set('filter', queryFilter.getFilters());
|
||||
if (!$state.linked) searchSource.set('query', $state.query);
|
||||
if ($scope.vis.type.requiresSearch) {
|
||||
courier.fetch();
|
||||
|
|
|
@ -5,6 +5,7 @@ define(function (require) {
|
|||
{ name: 'ssl', type: 'boolean', indexed: true, analyzed: true, sortable: true, filterable: true, count: 20 },
|
||||
{ name: '@timestamp', type: 'date', indexed: true, analyzed: true, sortable: true, filterable: true, count: 30 },
|
||||
{ name: 'time', type: 'date', indexed: true, analyzed: true, sortable: true, filterable: true, count: 30 },
|
||||
{ name: '@tags', type: 'string', indexed: true, analyzed: true, sortable: true, filterable: true },
|
||||
{ name: 'utc_time', type: 'date', indexed: true, analyzed: true, sortable: true, filterable: true },
|
||||
{ name: 'phpmemory', type: 'number', indexed: true, analyzed: true, sortable: true, filterable: true },
|
||||
{ name: 'ip', type: 'ip', indexed: true, analyzed: true, sortable: true, filterable: true },
|
||||
|
|
18
test/unit/fixtures/mock_state.js
Normal file
18
test/unit/fixtures/mock_state.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
var sinon = require('test_utils/auto_release_sinon');
|
||||
|
||||
function MockState(defaults) {
|
||||
this.on = _.noop;
|
||||
this.off = _.noop;
|
||||
this.save = sinon.stub();
|
||||
_.assign(this, defaults);
|
||||
}
|
||||
|
||||
MockState.prototype.resetStub = function () {
|
||||
this.save = sinon.stub();
|
||||
return this;
|
||||
};
|
||||
|
||||
return MockState;
|
||||
});
|
|
@ -147,6 +147,7 @@ define(function (require) {
|
|||
var section = getSections($elem);
|
||||
$scope.columns.push('bytes');
|
||||
$scope.$digest();
|
||||
|
||||
expect(section.selected.text()).to.contain('bytes');
|
||||
expect(section.popular.text()).to.not.contain('bytes');
|
||||
|
||||
|
|
130
test/unit/specs/components/filter_bar/_addFilters.js
Normal file
130
test/unit/specs/components/filter_bar/_addFilters.js
Normal file
|
@ -0,0 +1,130 @@
|
|||
define(function (require) {
|
||||
return ['add filters', function () {
|
||||
var _ = require('lodash');
|
||||
var sinon = require('test_utils/auto_release_sinon');
|
||||
var MockState = require('fixtures/mock_state');
|
||||
var storeNames = {
|
||||
app: 'appState',
|
||||
global: 'globalState'
|
||||
};
|
||||
var filters;
|
||||
var queryFilter;
|
||||
var $rootScope, appState, globalState;
|
||||
|
||||
beforeEach(module('kibana'));
|
||||
|
||||
beforeEach(function () {
|
||||
appState = new MockState({ filters: [] });
|
||||
globalState = new MockState({ filters: [] });
|
||||
|
||||
filters = [
|
||||
{
|
||||
query: { match: { extension: { query: 'jpg', type: 'phrase' } } },
|
||||
meta: { negate: false, disabled: false }
|
||||
},
|
||||
{
|
||||
query: { match: { '@tags': { query: 'info', type: 'phrase' } } },
|
||||
meta: { negate: false, disabled: false }
|
||||
},
|
||||
{
|
||||
query: { match: { '_type': { query: 'nginx', type: 'phrase' } } },
|
||||
meta: { negate: false, disabled: false }
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
module('kibana/global_state', function ($provide) {
|
||||
$provide.service('getAppState', function () {
|
||||
return function () {
|
||||
return appState;
|
||||
};
|
||||
});
|
||||
|
||||
$provide.service('globalState', function () {
|
||||
return globalState;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
inject(function (_$rootScope_, Private) {
|
||||
$rootScope = _$rootScope_;
|
||||
queryFilter = Private(require('components/filter_bar/query_filter'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('adding filters', function () {
|
||||
it('should add filters to appState', function () {
|
||||
queryFilter.addFilters(filters);
|
||||
expect(appState.filters.length).to.be(3);
|
||||
expect(globalState.filters.length).to.be(0);
|
||||
});
|
||||
|
||||
it('should add filters to globalState', function () {
|
||||
queryFilter.addFilters(filters, true);
|
||||
expect(appState.filters.length).to.be(0);
|
||||
expect(globalState.filters.length).to.be(3);
|
||||
});
|
||||
|
||||
it('should accept a single filter', function () {
|
||||
queryFilter.addFilters(filters[0]);
|
||||
expect(appState.filters.length).to.be(1);
|
||||
expect(globalState.filters.length).to.be(0);
|
||||
});
|
||||
|
||||
it('should fire the update and fetch events', function () {
|
||||
var emitSpy = sinon.spy(queryFilter, 'emit');
|
||||
|
||||
// set up the watchers
|
||||
$rootScope.$digest();
|
||||
queryFilter.addFilters(filters);
|
||||
// trigger the digest loop to fire the watchers
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(emitSpy.callCount).to.be(2);
|
||||
expect(emitSpy.firstCall.args[0]).to.be('update');
|
||||
expect(emitSpy.secondCall.args[0]).to.be('fetch');
|
||||
});
|
||||
});
|
||||
|
||||
describe('filter reconciliation', function () {
|
||||
it('should de-dupe appState filters being added', function () {
|
||||
var newFilter = _.cloneDeep(filters[1]);
|
||||
appState.filters = filters;
|
||||
expect(appState.filters.length).to.be(3);
|
||||
|
||||
queryFilter.addFilters(newFilter);
|
||||
$rootScope.$digest();
|
||||
expect(appState.filters.length).to.be(3);
|
||||
});
|
||||
|
||||
it('should de-dupe globalState filters being added', function () {
|
||||
var newFilter = _.cloneDeep(filters[1]);
|
||||
globalState.filters = filters;
|
||||
expect(globalState.filters.length).to.be(3);
|
||||
|
||||
queryFilter.addFilters(newFilter, true);
|
||||
$rootScope.$digest();
|
||||
expect(globalState.filters.length).to.be(3);
|
||||
});
|
||||
|
||||
it('should mutate global filters on appState filter changes', function () {
|
||||
var idx = 1;
|
||||
globalState.filters = filters;
|
||||
var appFilter = _.cloneDeep(filters[idx]);
|
||||
appFilter.meta.negate = true;
|
||||
// use addFilters here, so custom adding logic can be applied
|
||||
queryFilter.addFilters(appFilter);
|
||||
|
||||
var res = queryFilter.getFilters();
|
||||
expect(res).to.have.length(3);
|
||||
_.each(res, function (filter, i) {
|
||||
expect(filter.$state.store).to.be('globalState');
|
||||
// make sure global filter actually mutated
|
||||
expect(filter.meta.negate).to.be(i === idx);
|
||||
});
|
||||
});
|
||||
});
|
||||
}];
|
||||
});
|
164
test/unit/specs/components/filter_bar/_getFilters.js
Normal file
164
test/unit/specs/components/filter_bar/_getFilters.js
Normal file
|
@ -0,0 +1,164 @@
|
|||
define(function (require) {
|
||||
return ['get filters', function () {
|
||||
var _ = require('lodash');
|
||||
var MockState = require('fixtures/mock_state');
|
||||
var storeNames = {
|
||||
app: 'appState',
|
||||
global: 'globalState'
|
||||
};
|
||||
var queryFilter;
|
||||
var $rootScope, appState, globalState;
|
||||
|
||||
beforeEach(module('kibana'));
|
||||
|
||||
beforeEach(function () {
|
||||
appState = new MockState({ filters: [] });
|
||||
globalState = new MockState({ filters: [] });
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
module('kibana/global_state', function ($provide) {
|
||||
$provide.service('getAppState', function () {
|
||||
return function () {
|
||||
return appState;
|
||||
};
|
||||
});
|
||||
|
||||
$provide.service('globalState', function () {
|
||||
return globalState;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
inject(function (_$rootScope_, Private) {
|
||||
$rootScope = _$rootScope_;
|
||||
queryFilter = Private(require('components/filter_bar/query_filter'));
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFilters method', function () {
|
||||
var filters;
|
||||
|
||||
beforeEach(function () {
|
||||
filters = [
|
||||
{ query: { match: { extension: { query: 'jpg', type: 'phrase' } } } },
|
||||
{ query: { match: { '@tags': { query: 'info', type: 'phrase' } } } }
|
||||
];
|
||||
});
|
||||
|
||||
it('should return app and global filters', function () {
|
||||
appState.filters = [filters[0]];
|
||||
globalState.filters = [filters[1]];
|
||||
|
||||
// global filters should be listed first
|
||||
var res = queryFilter.getFilters();
|
||||
expect(res[0]).to.eql(filters[1]);
|
||||
expect(res[1]).to.eql(filters[0]);
|
||||
|
||||
// should return updated version of filters
|
||||
var newFilter = { query: { match: { '_type': { query: 'nginx', type: 'phrase' } } } };
|
||||
appState.filters.push(newFilter);
|
||||
|
||||
res = queryFilter.getFilters();
|
||||
expect(res).to.contain(newFilter);
|
||||
});
|
||||
|
||||
it('should append the state store', function () {
|
||||
appState.filters = [filters[0]];
|
||||
globalState.filters = [filters[1]];
|
||||
|
||||
var res = queryFilter.getFilters();
|
||||
expect(res[0].$state.store).to.be(storeNames.global);
|
||||
expect(res[1].$state.store).to.be(storeNames.app);
|
||||
});
|
||||
|
||||
it('should return filters from specific states', function () {
|
||||
var states = [
|
||||
[ globalState, queryFilter.getGlobalFilters ],
|
||||
[ appState, queryFilter.getAppFilters ],
|
||||
];
|
||||
|
||||
_.each(states, function (state) {
|
||||
state[0].filters = filters;
|
||||
var res = state[1]();
|
||||
expect(res.length).to.be(state[0].filters.length);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('filter reconciliation', function () {
|
||||
var filters;
|
||||
|
||||
beforeEach(function () {
|
||||
filters = [
|
||||
{
|
||||
query: { match: { extension: { query: 'jpg', type: 'phrase' } } },
|
||||
meta: { negate: false, disabled: false }
|
||||
},
|
||||
{
|
||||
query: { match: { '@tags': { query: 'info', type: 'phrase' } } },
|
||||
meta: { negate: false, disabled: false }
|
||||
},
|
||||
{
|
||||
query: { match: { '_type': { query: 'nginx', type: 'phrase' } } },
|
||||
meta: { negate: false, disabled: false }
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
it('should skip appState filters that match globalState filters', function () {
|
||||
globalState.filters = filters;
|
||||
var appFilter = _.cloneDeep(filters[1]);
|
||||
appState.filters.push(appFilter);
|
||||
|
||||
// global filters should be listed first
|
||||
var res = queryFilter.getFilters();
|
||||
expect(res).to.have.length(3);
|
||||
_.each(res, function (filter) {
|
||||
expect(filter.$state.store).to.be('globalState');
|
||||
});
|
||||
});
|
||||
|
||||
it('should append conflicting appState filters', function () {
|
||||
globalState.filters = filters;
|
||||
var appFilter = _.cloneDeep(filters[1]);
|
||||
appFilter.meta.negate = true;
|
||||
appState.filters.push(appFilter);
|
||||
|
||||
// global filters should be listed first
|
||||
var res = queryFilter.getFilters();
|
||||
expect(res).to.have.length(4);
|
||||
expect(res.filter(function (filter) {
|
||||
return filter.$state.store === storeNames.global;
|
||||
}).length).to.be(3);
|
||||
expect(res.filter(function (filter) {
|
||||
return filter.$state.store === storeNames.app;
|
||||
}).length).to.be(1);
|
||||
});
|
||||
|
||||
it('should not affect disabled filters', function () {
|
||||
// test adding to globalState
|
||||
globalState.filters = _.map(filters, function (filter) {
|
||||
var f = _.cloneDeep(filter);
|
||||
f.meta.disabled = true;
|
||||
return f;
|
||||
});
|
||||
_.each(filters, function (filter) { globalState.filters.push(filter); });
|
||||
var res = queryFilter.getFilters();
|
||||
expect(res).to.have.length(6);
|
||||
|
||||
// test adding to appState
|
||||
globalState.filters = _.map(filters, function (filter) {
|
||||
var f = _.cloneDeep(filter);
|
||||
f.meta.disabled = true;
|
||||
return f;
|
||||
});
|
||||
_.each(filters, function (filter) { appState.filters.push(filter); });
|
||||
res = queryFilter.getFilters();
|
||||
expect(res).to.have.length(6);
|
||||
});
|
||||
});
|
||||
}];
|
||||
});
|
114
test/unit/specs/components/filter_bar/_invertFilters.js
Normal file
114
test/unit/specs/components/filter_bar/_invertFilters.js
Normal file
|
@ -0,0 +1,114 @@
|
|||
define(function (require) {
|
||||
return ['invert filters', function () {
|
||||
var _ = require('lodash');
|
||||
var sinon = require('test_utils/auto_release_sinon');
|
||||
var MockState = require('fixtures/mock_state');
|
||||
var storeNames = {
|
||||
app: 'appState',
|
||||
global: 'globalState'
|
||||
};
|
||||
var filters;
|
||||
var queryFilter;
|
||||
var $rootScope, appState, globalState;
|
||||
|
||||
beforeEach(module('kibana'));
|
||||
|
||||
beforeEach(function () {
|
||||
appState = new MockState({ filters: [] });
|
||||
globalState = new MockState({ filters: [] });
|
||||
|
||||
filters = [
|
||||
{
|
||||
query: { match: { extension: { query: 'jpg', type: 'phrase' } } },
|
||||
meta: { negate: false, disabled: false }
|
||||
},
|
||||
{
|
||||
query: { match: { '@tags': { query: 'info', type: 'phrase' } } },
|
||||
meta: { negate: false, disabled: false }
|
||||
},
|
||||
{
|
||||
query: { match: { '_type': { query: 'nginx', type: 'phrase' } } },
|
||||
meta: { negate: false, disabled: false }
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
module('kibana/global_state', function ($provide) {
|
||||
$provide.service('getAppState', function () {
|
||||
return function () {
|
||||
return appState;
|
||||
};
|
||||
});
|
||||
|
||||
$provide.service('globalState', function () {
|
||||
return globalState;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
inject(function (_$rootScope_, Private) {
|
||||
$rootScope = _$rootScope_;
|
||||
queryFilter = Private(require('components/filter_bar/query_filter'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('inverting a filter', function () {
|
||||
it('should swap the negate property in appState', function () {
|
||||
_.each(filters, function (filter) {
|
||||
expect(filter.meta.negate).to.be(false);
|
||||
appState.filters.push(filter);
|
||||
});
|
||||
|
||||
queryFilter.invertFilter(filters[1]);
|
||||
expect(appState.filters[1].meta.negate).to.be(true);
|
||||
});
|
||||
|
||||
it('should toggle the negate property in globalState', function () {
|
||||
_.each(filters, function (filter) {
|
||||
expect(filter.meta.negate).to.be(false);
|
||||
globalState.filters.push(filter);
|
||||
});
|
||||
|
||||
queryFilter.invertFilter(filters[1]);
|
||||
expect(globalState.filters[1].meta.negate).to.be(true);
|
||||
});
|
||||
|
||||
it('should fire the update and fetch events', function () {
|
||||
var emitSpy = sinon.spy(queryFilter, 'emit');
|
||||
appState.filters = filters;
|
||||
|
||||
// set up the watchers
|
||||
$rootScope.$digest();
|
||||
queryFilter.invertFilter(filters[1]);
|
||||
// trigger the digest loop to fire the watchers
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(emitSpy.callCount).to.be(2);
|
||||
expect(emitSpy.firstCall.args[0]).to.be('update');
|
||||
expect(emitSpy.secondCall.args[0]).to.be('fetch');
|
||||
});
|
||||
});
|
||||
|
||||
describe('bulk inverting', function () {
|
||||
beforeEach(function () {
|
||||
appState.filters = filters;
|
||||
globalState.filters = _.map(_.cloneDeep(filters), function (filter) {
|
||||
filter.meta.negate = true;
|
||||
return filter;
|
||||
});
|
||||
});
|
||||
|
||||
it('should swap the negate state for all filters', function () {
|
||||
queryFilter.invertAll();
|
||||
_.each(appState.filters, function (filter) {
|
||||
expect(filter.meta.negate).to.be(true);
|
||||
});
|
||||
_.each(globalState.filters, function (filter) {
|
||||
expect(filter.meta.negate).to.be(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
}];
|
||||
});
|
160
test/unit/specs/components/filter_bar/_pinFilters.js
Normal file
160
test/unit/specs/components/filter_bar/_pinFilters.js
Normal file
|
@ -0,0 +1,160 @@
|
|||
define(function (require) {
|
||||
return ['pin filters', function () {
|
||||
var _ = require('lodash');
|
||||
var sinon = require('test_utils/auto_release_sinon');
|
||||
var MockState = require('fixtures/mock_state');
|
||||
var storeNames = {
|
||||
app: 'appState',
|
||||
global: 'globalState'
|
||||
};
|
||||
var filters;
|
||||
var queryFilter;
|
||||
var $rootScope, appState, globalState;
|
||||
|
||||
beforeEach(module('kibana'));
|
||||
|
||||
beforeEach(function () {
|
||||
appState = new MockState({ filters: [] });
|
||||
globalState = new MockState({ filters: [] });
|
||||
|
||||
filters = [
|
||||
{
|
||||
query: { match: { extension: { query: 'gif', type: 'phrase' } } },
|
||||
meta: { negate: false, disabled: false }
|
||||
},
|
||||
{
|
||||
query: { match: { extension: { query: 'jpg', type: 'phrase' } } },
|
||||
meta: { negate: true, disabled: false }
|
||||
},
|
||||
{
|
||||
query: { match: { extension: { query: 'png', type: 'phrase' } } },
|
||||
meta: { negate: true, disabled: true }
|
||||
},
|
||||
{
|
||||
query: { match: { '@tags': { query: 'info', type: 'phrase' } } },
|
||||
meta: { negate: false, disabled: false }
|
||||
},
|
||||
{
|
||||
query: { match: { '@tags': { query: 'success', type: 'phrase' } } },
|
||||
meta: { negate: false, disabled: false }
|
||||
},
|
||||
{
|
||||
query: { match: { '@tags': { query: 'security', type: 'phrase' } } },
|
||||
meta: { negate: true, disabled: false }
|
||||
},
|
||||
{
|
||||
query: { match: { '_type': { query: 'nginx', type: 'phrase' } } },
|
||||
meta: { negate: false, disabled: false }
|
||||
},
|
||||
{
|
||||
query: { match: { '_type': { query: 'apache', type: 'phrase' } } },
|
||||
meta: { negate: true, disabled: true }
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
module('kibana/global_state', function ($provide) {
|
||||
$provide.service('getAppState', function () {
|
||||
return function () {
|
||||
return appState;
|
||||
};
|
||||
});
|
||||
|
||||
$provide.service('globalState', function () {
|
||||
return globalState;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
inject(function (_$rootScope_, Private) {
|
||||
$rootScope = _$rootScope_;
|
||||
queryFilter = Private(require('components/filter_bar/query_filter'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('pin a filter', function () {
|
||||
beforeEach(function () {
|
||||
globalState.filters = _.filter(filters, function (filter) {
|
||||
return !!filter.query.match._type;
|
||||
});
|
||||
appState.filters = _.filter(filters, function (filter) {
|
||||
return !filter.query.match._type;
|
||||
});
|
||||
expect(globalState.filters).to.have.length(2);
|
||||
expect(appState.filters).to.have.length(6);
|
||||
});
|
||||
|
||||
it('should move filter from appState to globalState', function () {
|
||||
var filter = appState.filters[1];
|
||||
|
||||
queryFilter.pinFilter(filter);
|
||||
expect(globalState.filters).to.contain(filter);
|
||||
expect(globalState.filters).to.have.length(3);
|
||||
expect(appState.filters).to.have.length(5);
|
||||
});
|
||||
|
||||
it('should move filter from globalState to appState', function () {
|
||||
var filter = globalState.filters[1];
|
||||
|
||||
queryFilter.pinFilter(filter);
|
||||
expect(appState.filters).to.contain(filter);
|
||||
expect(globalState.filters).to.have.length(1);
|
||||
expect(appState.filters).to.have.length(7);
|
||||
});
|
||||
|
||||
|
||||
it('should only fire the update event', function () {
|
||||
var filter = appState.filters[1];
|
||||
var emitSpy = sinon.spy(queryFilter, 'emit');
|
||||
|
||||
// set up the watchers
|
||||
$rootScope.$digest();
|
||||
queryFilter.pinFilter(filter);
|
||||
// trigger the digest loop to fire the watchers
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(emitSpy.callCount).to.be(1);
|
||||
expect(emitSpy.firstCall.args[0]).to.be('update');
|
||||
});
|
||||
});
|
||||
|
||||
describe('bulk pinning', function () {
|
||||
beforeEach(function () {
|
||||
globalState.filters = _.filter(filters, function (filter) {
|
||||
return !!filter.query.match.extension;
|
||||
});
|
||||
appState.filters = _.filter(filters, function (filter) {
|
||||
return !filter.query.match.extension;
|
||||
});
|
||||
expect(globalState.filters).to.have.length(3);
|
||||
expect(appState.filters).to.have.length(5);
|
||||
});
|
||||
|
||||
it('should swap the filters in both states', function () {
|
||||
var appSample = _.sample(appState.filters);
|
||||
var globalSample = _.sample(globalState.filters);
|
||||
|
||||
queryFilter.pinAll();
|
||||
expect(globalState.filters).to.have.length(5);
|
||||
expect(appState.filters).to.have.length(3);
|
||||
|
||||
expect(globalState.filters).to.contain(appSample);
|
||||
expect(appState.filters).to.contain(globalSample);
|
||||
});
|
||||
|
||||
it('should move all filters to globalState', function () {
|
||||
queryFilter.pinAll(true);
|
||||
expect(globalState.filters).to.have.length(8);
|
||||
expect(appState.filters).to.have.length(0);
|
||||
});
|
||||
|
||||
it('should move all filters to appState', function () {
|
||||
queryFilter.pinAll(false);
|
||||
expect(globalState.filters).to.have.length(0);
|
||||
expect(appState.filters).to.have.length(8);
|
||||
});
|
||||
});
|
||||
}];
|
||||
});
|
116
test/unit/specs/components/filter_bar/_removeFilters.js
Normal file
116
test/unit/specs/components/filter_bar/_removeFilters.js
Normal file
|
@ -0,0 +1,116 @@
|
|||
define(function (require) {
|
||||
return ['remove filters', function () {
|
||||
var _ = require('lodash');
|
||||
var sinon = require('test_utils/auto_release_sinon');
|
||||
var MockState = require('fixtures/mock_state');
|
||||
var storeNames = {
|
||||
app: 'appState',
|
||||
global: 'globalState'
|
||||
};
|
||||
var filters;
|
||||
var queryFilter;
|
||||
var $rootScope, appState, globalState;
|
||||
|
||||
beforeEach(module('kibana'));
|
||||
|
||||
beforeEach(function () {
|
||||
appState = new MockState({ filters: [] });
|
||||
globalState = new MockState({ filters: [] });
|
||||
|
||||
filters = [
|
||||
{
|
||||
query: { match: { extension: { query: 'jpg', type: 'phrase' } } },
|
||||
meta: { negate: false, disabled: false }
|
||||
},
|
||||
{
|
||||
query: { match: { '@tags': { query: 'info', type: 'phrase' } } },
|
||||
meta: { negate: false, disabled: false }
|
||||
},
|
||||
{
|
||||
query: { match: { '_type': { query: 'nginx', type: 'phrase' } } },
|
||||
meta: { negate: false, disabled: false }
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
module('kibana/global_state', function ($provide) {
|
||||
$provide.service('getAppState', function () {
|
||||
return function () {
|
||||
return appState;
|
||||
};
|
||||
});
|
||||
|
||||
$provide.service('globalState', function () {
|
||||
return globalState;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
inject(function (_$rootScope_, Private) {
|
||||
$rootScope = _$rootScope_;
|
||||
queryFilter = Private(require('components/filter_bar/query_filter'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('removing a filter', function () {
|
||||
it('should remove the filter from appState', function () {
|
||||
appState.filters = filters;
|
||||
expect(appState.filters).to.have.length(3);
|
||||
queryFilter.removeFilter(filters[0]);
|
||||
expect(appState.filters).to.have.length(2);
|
||||
});
|
||||
|
||||
it('should remove the filter from globalState', function () {
|
||||
globalState.filters = filters;
|
||||
expect(globalState.filters).to.have.length(3);
|
||||
queryFilter.removeFilter(filters[0]);
|
||||
expect(globalState.filters).to.have.length(2);
|
||||
});
|
||||
|
||||
it('should fire the update and fetch events', function () {
|
||||
var emitSpy = sinon.spy(queryFilter, 'emit');
|
||||
appState.filters = filters;
|
||||
|
||||
// set up the watchers
|
||||
$rootScope.$digest();
|
||||
queryFilter.removeFilter(filters[0]);
|
||||
// trigger the digest loop to fire the watchers
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(emitSpy.callCount).to.be(2);
|
||||
expect(emitSpy.firstCall.args[0]).to.be('update');
|
||||
expect(emitSpy.secondCall.args[0]).to.be('fetch');
|
||||
});
|
||||
|
||||
it('should only remove matching instances', function () {
|
||||
globalState.filters.push(filters[0]);
|
||||
globalState.filters.push(filters[1]);
|
||||
appState.filters.push(filters[2]);
|
||||
|
||||
queryFilter.removeFilter(_.cloneDeep(filters[0]));
|
||||
expect(globalState.filters).to.have.length(2);
|
||||
expect(appState.filters).to.have.length(1);
|
||||
|
||||
queryFilter.removeFilter(_.cloneDeep(filters[2]));
|
||||
expect(globalState.filters).to.have.length(2);
|
||||
expect(appState.filters).to.have.length(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('bulk removal', function () {
|
||||
it('should remove all the filters from both states', function () {
|
||||
globalState.filters.push(filters[0]);
|
||||
globalState.filters.push(filters[1]);
|
||||
appState.filters.push(filters[2]);
|
||||
expect(globalState.filters).to.have.length(2);
|
||||
expect(appState.filters).to.have.length(1);
|
||||
|
||||
queryFilter.removeAll();
|
||||
expect(globalState.filters).to.have.length(0);
|
||||
expect(appState.filters).to.have.length(0);
|
||||
});
|
||||
});
|
||||
}];
|
||||
});
|
158
test/unit/specs/components/filter_bar/_toggleFilters.js
Normal file
158
test/unit/specs/components/filter_bar/_toggleFilters.js
Normal file
|
@ -0,0 +1,158 @@
|
|||
define(function (require) {
|
||||
return ['toggle filters', function () {
|
||||
var _ = require('lodash');
|
||||
var sinon = require('test_utils/auto_release_sinon');
|
||||
var MockState = require('fixtures/mock_state');
|
||||
var storeNames = {
|
||||
app: 'appState',
|
||||
global: 'globalState'
|
||||
};
|
||||
var filters;
|
||||
var queryFilter;
|
||||
var $rootScope, appState, globalState;
|
||||
|
||||
beforeEach(module('kibana'));
|
||||
|
||||
beforeEach(function () {
|
||||
appState = new MockState({ filters: [] });
|
||||
globalState = new MockState({ filters: [] });
|
||||
|
||||
filters = [
|
||||
{
|
||||
query: { match: { extension: { query: 'jpg', type: 'phrase' } } },
|
||||
meta: { negate: false, disabled: false }
|
||||
},
|
||||
{
|
||||
query: { match: { '@tags': { query: 'info', type: 'phrase' } } },
|
||||
meta: { negate: false, disabled: false }
|
||||
},
|
||||
{
|
||||
query: { match: { '_type': { query: 'nginx', type: 'phrase' } } },
|
||||
meta: { negate: false, disabled: false }
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
module('kibana/global_state', function ($provide) {
|
||||
$provide.service('getAppState', function () {
|
||||
return function () {
|
||||
return appState;
|
||||
};
|
||||
});
|
||||
|
||||
$provide.service('globalState', function () {
|
||||
return globalState;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
inject(function (_$rootScope_, Private) {
|
||||
$rootScope = _$rootScope_;
|
||||
queryFilter = Private(require('components/filter_bar/query_filter'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('toggling a filter', function () {
|
||||
it('should toggle the disabled property in appState', function () {
|
||||
_.each(filters, function (filter) {
|
||||
expect(filter.meta.disabled).to.be(false);
|
||||
appState.filters.push(filter);
|
||||
});
|
||||
|
||||
queryFilter.toggleFilter(filters[1]);
|
||||
expect(appState.filters[1].meta.disabled).to.be(true);
|
||||
});
|
||||
|
||||
it('should toggle the disabled property in globalState', function () {
|
||||
_.each(filters, function (filter) {
|
||||
expect(filter.meta.disabled).to.be(false);
|
||||
globalState.filters.push(filter);
|
||||
});
|
||||
|
||||
queryFilter.toggleFilter(filters[1]);
|
||||
expect(globalState.filters[1].meta.disabled).to.be(true);
|
||||
});
|
||||
|
||||
it('should fire the update and fetch events', function () {
|
||||
var emitSpy = sinon.spy(queryFilter, 'emit');
|
||||
appState.filters = filters;
|
||||
|
||||
// set up the watchers
|
||||
$rootScope.$digest();
|
||||
queryFilter.toggleFilter(filters[1]);
|
||||
// trigger the digest loop to fire the watchers
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(emitSpy.callCount).to.be(2);
|
||||
expect(emitSpy.firstCall.args[0]).to.be('update');
|
||||
expect(emitSpy.secondCall.args[0]).to.be('fetch');
|
||||
});
|
||||
|
||||
it('should always enable the filter', function () {
|
||||
appState.filters = filters.map(function (filter) {
|
||||
filter.meta.disabled = true;
|
||||
return filter;
|
||||
});
|
||||
|
||||
expect(appState.filters[1].meta.disabled).to.be(true);
|
||||
queryFilter.toggleFilter(filters[1], false);
|
||||
expect(appState.filters[1].meta.disabled).to.be(false);
|
||||
queryFilter.toggleFilter(filters[1], false);
|
||||
expect(appState.filters[1].meta.disabled).to.be(false);
|
||||
});
|
||||
|
||||
it('should always disable the filter', function () {
|
||||
globalState.filters = filters;
|
||||
|
||||
expect(globalState.filters[1].meta.disabled).to.be(false);
|
||||
queryFilter.toggleFilter(filters[1], true);
|
||||
expect(globalState.filters[1].meta.disabled).to.be(true);
|
||||
queryFilter.toggleFilter(filters[1], true);
|
||||
expect(globalState.filters[1].meta.disabled).to.be(true);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('bulk toggling', function () {
|
||||
beforeEach(function () {
|
||||
appState.filters = filters;
|
||||
globalState.filters = _.map(_.cloneDeep(filters), function (filter) {
|
||||
filter.meta.disabled = true;
|
||||
return filter;
|
||||
});
|
||||
});
|
||||
|
||||
it('should swap the enabled state for all filters', function () {
|
||||
queryFilter.toggleAll();
|
||||
_.each(appState.filters, function (filter) {
|
||||
expect(filter.meta.disabled).to.be(true);
|
||||
});
|
||||
_.each(globalState.filters, function (filter) {
|
||||
expect(filter.meta.disabled).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
it('should enable all filters', function () {
|
||||
queryFilter.toggleAll(true);
|
||||
_.each(appState.filters, function (filter) {
|
||||
expect(filter.meta.disabled).to.be(true);
|
||||
});
|
||||
_.each(globalState.filters, function (filter) {
|
||||
expect(filter.meta.disabled).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should disable all filters', function () {
|
||||
queryFilter.toggleAll(false);
|
||||
_.each(appState.filters, function (filter) {
|
||||
expect(filter.meta.disabled).to.be(false);
|
||||
});
|
||||
_.each(globalState.filters, function (filter) {
|
||||
expect(filter.meta.disabled).to.be(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
}];
|
||||
});
|
|
@ -3,7 +3,6 @@ define(function (require) {
|
|||
describe('Filter Bar Directive', function () {
|
||||
describe('dedupFilters(existing, filters)', function () {
|
||||
|
||||
|
||||
it('should return only filters which are not in the existing', function () {
|
||||
var existing = [
|
||||
{ range: { bytes: { from: 0, to: 1024 } } },
|
||||
|
@ -25,13 +24,26 @@ define(function (require) {
|
|||
];
|
||||
var filters = [
|
||||
{ range: { bytes: { from: 1024, to: 2048 } } },
|
||||
{ meta: { negate: false }, query: { match: { _term: { query: 'apache', type: 'phrase' } } } }
|
||||
{ query: { match: { _term: { query: 'apache', type: 'phrase' } } } }
|
||||
];
|
||||
var results = dedupFilters(existing, filters);
|
||||
expect(results).to.contain(filters[0]);
|
||||
expect(results).to.not.contain(filters[1]);
|
||||
});
|
||||
|
||||
it('should ignore $state attribute', function () {
|
||||
var existing = [
|
||||
{ range: { bytes: { from: 0, to: 1024 } } },
|
||||
{ $state: { store: 'appState' }, query: { match: { _term: { query: 'apache', type: 'phrase' } } } }
|
||||
];
|
||||
var filters = [
|
||||
{ range: { bytes: { from: 1024, to: 2048 } } },
|
||||
{ $state: { store: 'globalState' }, query: { match: { _term: { query: 'apache', type: 'phrase' } } } }
|
||||
];
|
||||
var results = dedupFilters(existing, filters);
|
||||
expect(results).to.contain(filters[0]);
|
||||
expect(results).to.not.contain(filters[1]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -16,4 +16,4 @@ define(function (require) {
|
|||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,16 +5,31 @@ define(function (require) {
|
|||
var $ = require('jquery');
|
||||
|
||||
require('components/filter_bar/filter_bar');
|
||||
var MockState = require('fixtures/mock_state');
|
||||
|
||||
describe('Filter Bar Directive', function () {
|
||||
var $rootScope, $compile, $timeout, Promise;
|
||||
var appState, queryFilter, mapFilter, getIndexPatternStub, indexPattern, $el;
|
||||
// require('test_utils/no_digest_promises').activateForSuite();
|
||||
|
||||
var $rootScope, $compile, getIndexPatternStub, indexPattern;
|
||||
beforeEach(function () {
|
||||
appState = new MockState({ filters: [] });
|
||||
|
||||
beforeEach(function (done) {
|
||||
module('kibana/global_state', function ($provide) {
|
||||
$provide.service('getAppState', function () {
|
||||
return function () {
|
||||
return appState;
|
||||
};
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
// load the application
|
||||
module('kibana');
|
||||
|
||||
getIndexPatternStub = sinon.stub();
|
||||
|
||||
module('kibana/courier', function ($provide) {
|
||||
$provide.service('courier', function () {
|
||||
var courier = { indexPatterns: { get: getIndexPatternStub } };
|
||||
|
@ -22,38 +37,59 @@ define(function (require) {
|
|||
});
|
||||
});
|
||||
|
||||
inject(function (Promise, Private, _$rootScope_, _$compile_) {
|
||||
inject(function (Private, $injector, _$rootScope_, _$compile_, _$timeout_) {
|
||||
$rootScope = _$rootScope_;
|
||||
$compile = _$compile_;
|
||||
$timeout = _$timeout_;
|
||||
Promise = $injector.get('Promise');
|
||||
mapFilter = Private(require('components/filter_bar/lib/mapFilter'));
|
||||
|
||||
indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern'));
|
||||
getIndexPatternStub.returns(Promise.resolve(indexPattern));
|
||||
|
||||
$rootScope.state = {
|
||||
filters: [
|
||||
{ meta: { index: 'logstash-*' }, query: { match: { '_type': { query: 'apache' } } } },
|
||||
{ meta: { index: 'logstash-*' }, query: { match: { '_type': { query: 'nginx' } } } },
|
||||
{ meta: { index: 'logstash-*' }, exists: { field: '@timestamp' } },
|
||||
{ meta: { index: 'logstash-*' }, missing: { field: 'host' }, disabled: true },
|
||||
]
|
||||
var queryFilter = Private(require('components/filter_bar/query_filter'));
|
||||
queryFilter.getFilters = function () {
|
||||
return appState.filters;
|
||||
};
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should render all the filters in state', function () {
|
||||
var el = $compile('<filter-bar state=state></filter-bar>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
var filters = el.find('.filter');
|
||||
expect(filters).to.have.length(4);
|
||||
expect($(filters[0]).find('span')[0].innerHTML).to.equal('_type:');
|
||||
expect($(filters[0]).find('span')[1].innerHTML).to.equal('"apache"');
|
||||
expect($(filters[1]).find('span')[0].innerHTML).to.equal('_type:');
|
||||
expect($(filters[1]).find('span')[1].innerHTML).to.equal('"nginx"');
|
||||
expect($(filters[2]).find('span')[0].innerHTML).to.equal('exists:');
|
||||
expect($(filters[2]).find('span')[1].innerHTML).to.equal('"@timestamp"');
|
||||
expect($(filters[3]).find('span')[0].innerHTML).to.equal('missing:');
|
||||
expect($(filters[3]).find('span')[1].innerHTML).to.equal('"host"');
|
||||
});
|
||||
describe('Element rendering', function () {
|
||||
beforeEach(function (done) {
|
||||
var filters = [
|
||||
{ meta: { index: 'logstash-*' }, query: { match: { '_type': { query: 'apache' } } } },
|
||||
{ meta: { index: 'logstash-*' }, query: { match: { '_type': { query: 'nginx' } } } },
|
||||
{ meta: { index: 'logstash-*' }, exists: { field: '@timestamp' } },
|
||||
{ meta: { index: 'logstash-*' }, missing: { field: 'host' }, disabled: true },
|
||||
];
|
||||
|
||||
Promise.map(filters, mapFilter).then(function (filters) {
|
||||
appState.filters = filters;
|
||||
$el = $compile('<filter-bar></filter-bar>')($rootScope);
|
||||
});
|
||||
|
||||
var off = $rootScope.$on('filterbar:updated', function () {
|
||||
off();
|
||||
// force a nextTick so it continues *after* the $digest loop completes
|
||||
setTimeout(done, 0);
|
||||
});
|
||||
|
||||
// kick off the digest loop
|
||||
$rootScope.$digest();
|
||||
});
|
||||
|
||||
it('should render all the filters in state', function () {
|
||||
var filters = $el.find('.filter');
|
||||
expect(filters).to.have.length(4);
|
||||
expect($(filters[0]).find('span')[0].innerHTML).to.equal('_type:');
|
||||
expect($(filters[0]).find('span')[1].innerHTML).to.equal('"apache"');
|
||||
expect($(filters[1]).find('span')[0].innerHTML).to.equal('_type:');
|
||||
expect($(filters[1]).find('span')[1].innerHTML).to.equal('"nginx"');
|
||||
expect($(filters[2]).find('span')[0].innerHTML).to.equal('exists:');
|
||||
expect($(filters[2]).find('span')[1].innerHTML).to.equal('"@timestamp"');
|
||||
expect($(filters[3]).find('span')[0].innerHTML).to.equal('missing:');
|
||||
expect($(filters[3]).find('span')[1].innerHTML).to.equal('"host"');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,23 +3,95 @@ define(function (require) {
|
|||
describe('Filter Bar Directive', function () {
|
||||
describe('onlyDisabled()', function () {
|
||||
|
||||
it('should return true if all filters remove are disabled', function () {
|
||||
it('should return true if all filters are disabled', function () {
|
||||
var filters = [
|
||||
{ meta: { disabled: true } },
|
||||
{ meta: { disabled: true } },
|
||||
{ meta: { disabled: true } }
|
||||
];
|
||||
var newFilters = [{ meta: { disabled: true } }];
|
||||
expect(onlyDisabled(newFilters, filters)).to.be(true);
|
||||
});
|
||||
|
||||
it('should return false if all filters are not disabled', function () {
|
||||
var filters = [
|
||||
{ meta: { disabled: false } },
|
||||
{ meta: { disabled: false } },
|
||||
{ meta: { disabled: false } }
|
||||
];
|
||||
var newFilters = [{ meta: { disabled: false } }];
|
||||
expect(onlyDisabled(newFilters, filters)).to.be(false);
|
||||
});
|
||||
|
||||
it('should return false if only old filters are disabled', function () {
|
||||
var filters = [
|
||||
{ meta: { disabled: true } },
|
||||
{ meta: { disabled: true } },
|
||||
{ meta: { disabled: true } }
|
||||
];
|
||||
var newFilters = [{ meta: { disabled: false } }];
|
||||
expect(onlyDisabled(newFilters, filters)).to.be(false);
|
||||
});
|
||||
|
||||
it('should return false if new filters are not disabled', function () {
|
||||
var filters = [
|
||||
{ meta: { disabled: false } },
|
||||
{ meta: { disabled: false } },
|
||||
{ meta: { disabled: false } }
|
||||
];
|
||||
var newFilters = [{ meta: { disabled: true } }];
|
||||
expect(onlyDisabled(newFilters, filters)).to.be(false);
|
||||
});
|
||||
|
||||
it('should return true when all removed filters were disabled', function () {
|
||||
var filters = [
|
||||
{ meta: { disabled: true } },
|
||||
{ meta: { disabled: true } },
|
||||
{ meta: { disabled: true } }
|
||||
];
|
||||
var newFilters = [];
|
||||
expect(onlyDisabled(newFilters, filters)).to.be(true);
|
||||
});
|
||||
|
||||
it('should return false when all removed filters were not disabled', function () {
|
||||
var filters = [
|
||||
{ meta: { disabled: false } },
|
||||
{ meta: { disabled: false } },
|
||||
{ meta: { disabled: false } }
|
||||
];
|
||||
var newFilters = [];
|
||||
expect(onlyDisabled(newFilters, filters)).to.be(false);
|
||||
});
|
||||
|
||||
it('should return true if all changed filters are disabled', function () {
|
||||
var filters = [
|
||||
{ meta: { disabled: true, negate: false } },
|
||||
{ meta: { disabled: true, negate: false } }
|
||||
];
|
||||
var newFilters = [
|
||||
{ meta: { disabled: true, negate: true } },
|
||||
{ meta: { disabled: true, negate: true } }
|
||||
];
|
||||
expect(onlyDisabled(newFilters, filters)).to.be(true);
|
||||
});
|
||||
|
||||
it('should return false if all filters remove were not disabled', function () {
|
||||
var filters = [
|
||||
{ meta: { disabled: false } },
|
||||
{ meta: { disabled: false } },
|
||||
{ meta: { disabled: true } }
|
||||
];
|
||||
var newFilters = [{ meta: { disabled: false } }];
|
||||
expect(onlyDisabled(newFilters, filters)).to.be(false);
|
||||
});
|
||||
|
||||
it('should return false when all removed filters are not disabled', function () {
|
||||
var filters = [
|
||||
{ meta: { disabled: true } },
|
||||
{ meta: { disabled: false } },
|
||||
{ meta: { disabled: true } }
|
||||
];
|
||||
var newFilters = [filters[1]];
|
||||
expect(onlyDisabled(newFilters, filters)).to.be(true);
|
||||
});
|
||||
|
||||
it('should return false if all filters remove are not disabled', function () {
|
||||
var filters = [
|
||||
{ meta: { disabled: true } },
|
||||
{ meta: { disabled: false } },
|
||||
{ meta: { disabled: false } }
|
||||
];
|
||||
var newFilters = [filters[1]];
|
||||
var newFilters = [];
|
||||
expect(onlyDisabled(newFilters, filters)).to.be(false);
|
||||
});
|
||||
|
||||
|
|
59
test/unit/specs/components/filter_bar/query_filter.js
Normal file
59
test/unit/specs/components/filter_bar/query_filter.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
var queryFilter;
|
||||
var EventEmitter;
|
||||
var $rootScope;
|
||||
|
||||
describe('Query Filter', function () {
|
||||
describe('Module', function () {
|
||||
beforeEach(module('kibana'));
|
||||
|
||||
beforeEach(function () {
|
||||
inject(function (_$rootScope_, Private) {
|
||||
$rootScope = _$rootScope_;
|
||||
queryFilter = Private(require('components/filter_bar/query_filter'));
|
||||
EventEmitter = Private(require('factories/events'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('module instance', function () {
|
||||
it('should be an event emitter', function () {
|
||||
expect(queryFilter).to.be.an(EventEmitter);
|
||||
});
|
||||
});
|
||||
|
||||
describe('module methods', function () {
|
||||
it('should have methods for getting filters', function () {
|
||||
expect(queryFilter.getFilters).to.be.a('function');
|
||||
expect(queryFilter.getAppFilters).to.be.a('function');
|
||||
expect(queryFilter.getGlobalFilters).to.be.a('function');
|
||||
});
|
||||
|
||||
it('should have methods for modifying filters', function () {
|
||||
expect(queryFilter.addFilters).to.be.a('function');
|
||||
expect(queryFilter.toggleFilter).to.be.a('function');
|
||||
expect(queryFilter.toggleAll).to.be.a('function');
|
||||
expect(queryFilter.removeFilter).to.be.a('function');
|
||||
expect(queryFilter.removeAll).to.be.a('function');
|
||||
expect(queryFilter.invertFilter).to.be.a('function');
|
||||
expect(queryFilter.invertAll).to.be.a('function');
|
||||
expect(queryFilter.pinFilter).to.be.a('function');
|
||||
expect(queryFilter.pinAll).to.be.a('function');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Actions', function () {
|
||||
var childSuites = [
|
||||
require('specs/components/filter_bar/_getFilters'),
|
||||
require('specs/components/filter_bar/_addFilters'),
|
||||
require('specs/components/filter_bar/_removeFilters'),
|
||||
require('specs/components/filter_bar/_toggleFilters'),
|
||||
require('specs/components/filter_bar/_invertFilters'),
|
||||
require('specs/components/filter_bar/_pinFilters'),
|
||||
].forEach(function (s) {
|
||||
describe(s[0], s[1]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,40 +0,0 @@
|
|||
define(function (require) {
|
||||
var removeAll = require('components/filter_bar/lib/removeAll');
|
||||
|
||||
describe('Filter Bar Directive', function () {
|
||||
|
||||
var $rootScope, $compile;
|
||||
|
||||
beforeEach(function (done) {
|
||||
// load the application
|
||||
module('kibana');
|
||||
|
||||
inject(function (_$rootScope_, _$compile_) {
|
||||
$rootScope = _$rootScope_;
|
||||
$compile = _$compile_;
|
||||
$rootScope.state = {
|
||||
filters: [
|
||||
{ query: { match: { '@tags': { query: 'test' } } } },
|
||||
{ query: { match: { '@tags': { query: 'bar' } } } },
|
||||
{ exists: { field: '@timestamp' } },
|
||||
{ missing: { field: 'host' }, meta: { disabled: true } },
|
||||
]
|
||||
};
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('removeAll', function () {
|
||||
it('should remove all the filters', function () {
|
||||
var fn = removeAll($rootScope);
|
||||
expect($rootScope.state.filters).to.have.length(4);
|
||||
fn();
|
||||
expect($rootScope.state.filters).to.have.length(0);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
define(function (require) {
|
||||
var removeFilter = require('components/filter_bar/lib/removeFilter');
|
||||
|
||||
describe('Filter Bar Directive', function () {
|
||||
|
||||
var $rootScope, $compile;
|
||||
|
||||
beforeEach(function (done) {
|
||||
// load the application
|
||||
module('kibana');
|
||||
|
||||
inject(function (_$rootScope_, _$compile_) {
|
||||
$rootScope = _$rootScope_;
|
||||
$compile = _$compile_;
|
||||
$rootScope.state = {
|
||||
filters: [
|
||||
{ query: { match: { '@tags': { query: 'test' } } } },
|
||||
{ query: { match: { '@tags': { query: 'bar' } } } },
|
||||
{ exists: { field: '@timestamp' } },
|
||||
{ missing: { field: 'host' }, meta: { disabled: true } },
|
||||
]
|
||||
};
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('removeFilter', function () {
|
||||
it('should remove the filter from the state', function () {
|
||||
var filter = $rootScope.state.filters[2];
|
||||
var fn = removeFilter($rootScope);
|
||||
fn(filter);
|
||||
expect($rootScope.state.filters).to.not.contain(filter);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
define(function (require) {
|
||||
describe('Filter Bar Directive', function () {
|
||||
var toggleAll = require('components/filter_bar/lib/toggleAll');
|
||||
var _ = require('lodash');
|
||||
var sinon = require('test_utils/auto_release_sinon');
|
||||
var mapFilter, $rootScope, $compile, Promise, getIndexPatternStub, indexPattern;
|
||||
|
||||
beforeEach(module('kibana'));
|
||||
|
||||
beforeEach(function () {
|
||||
getIndexPatternStub = sinon.stub();
|
||||
module('kibana/courier', function ($provide) {
|
||||
$provide.service('courier', function () {
|
||||
var courier = { indexPatterns: { get: getIndexPatternStub } };
|
||||
return courier;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(inject(function (_Promise_, _$rootScope_, _$compile_, Private) {
|
||||
Promise = _Promise_;
|
||||
mapFilter = Private(require('components/filter_bar/lib/mapFilter'));
|
||||
indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern'));
|
||||
getIndexPatternStub.returns(Promise.resolve(indexPattern));
|
||||
$rootScope = _$rootScope_;
|
||||
$compile = _$compile_;
|
||||
$rootScope.state = {
|
||||
filters: [
|
||||
{ meta: { index: 'logstash-*' }, query: { match: { '_type': { query: 'apache' } } } },
|
||||
{ meta: { index: 'logstash-*' }, query: { match: { '_type': { query: 'nginx' } } } },
|
||||
{ meta: { index: 'logstash-*' }, exists: { field: '@timestamp' } },
|
||||
{ meta: { index: 'logstash-*', disabled: true }, missing: { field: 'host' } },
|
||||
]
|
||||
};
|
||||
}));
|
||||
|
||||
describe('toggleAll', function () {
|
||||
var fn;
|
||||
|
||||
beforeEach(function (done) {
|
||||
var _filters = _($rootScope.state.filters)
|
||||
.filter(function (filter) { return filter; })
|
||||
.flatten(true)
|
||||
.value();
|
||||
|
||||
Promise.map(_filters, mapFilter).then(function (filters) {
|
||||
$rootScope.filters = filters;
|
||||
done();
|
||||
});
|
||||
$rootScope.$apply();
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
fn = toggleAll($rootScope);
|
||||
});
|
||||
|
||||
var pickDisabled = function (filter) {
|
||||
return filter.meta.disabled;
|
||||
};
|
||||
|
||||
it('should toggle all the filters', function () {
|
||||
expect(_.filter($rootScope.state.filters, pickDisabled)).to.have.length(1);
|
||||
fn();
|
||||
expect(_.filter($rootScope.state.filters, pickDisabled)).to.have.length(3);
|
||||
});
|
||||
|
||||
it('should disable all the filters', function () {
|
||||
expect(_.filter($rootScope.state.filters, pickDisabled)).to.have.length(1);
|
||||
fn(true);
|
||||
expect(_.filter($rootScope.state.filters, pickDisabled)).to.have.length(4);
|
||||
});
|
||||
|
||||
it('should enable all the filters', function () {
|
||||
expect(_.filter($rootScope.state.filters, pickDisabled)).to.have.length(1);
|
||||
fn(false);
|
||||
expect(_.filter($rootScope.state.filters, pickDisabled)).to.have.length(0);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
define(function (require) {
|
||||
describe('Filter Bar Directive', function () {
|
||||
var sinon = require('test_utils/auto_release_sinon');
|
||||
var toggleFilter = require('components/filter_bar/lib/toggleFilter');
|
||||
var $rootScope, $compile, mapFilter, getIndexPatternStub, indexPattern;
|
||||
|
||||
beforeEach(module('kibana'));
|
||||
|
||||
beforeEach(function () {
|
||||
getIndexPatternStub = sinon.stub();
|
||||
module('kibana/courier', function ($provide) {
|
||||
$provide.service('courier', function () {
|
||||
var courier = { indexPatterns: { get: getIndexPatternStub } };
|
||||
return courier;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(inject(function (Promise, Private, _$rootScope_, _$compile_) {
|
||||
mapFilter = Private(require('components/filter_bar/lib/mapFilter'));
|
||||
$rootScope = _$rootScope_;
|
||||
$compile = _$compile_;
|
||||
indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern'));
|
||||
getIndexPatternStub.returns(Promise.resolve(indexPattern));
|
||||
$rootScope.state = {
|
||||
filters: [
|
||||
{ meta: { index: 'logstash-*' }, query: { match: { '_type': { query: 'apache' } } } },
|
||||
{ meta: { index: 'logstash-*' }, query: { match: { '_type': { query: 'nginx' } } } },
|
||||
{ meta: { index: 'logstash-*' }, exists: { field: '@timestamp' } },
|
||||
{ missing: { field: 'host' }, meta: { disabled: true, index: 'logstash-*' } },
|
||||
]
|
||||
};
|
||||
}));
|
||||
|
||||
describe('toggleFilter', function () {
|
||||
it('should toggle filters on and off', function (done) {
|
||||
var filter = $rootScope.state.filters[0];
|
||||
var fn = toggleFilter($rootScope);
|
||||
mapFilter(filter).then(fn).then(function (result) {
|
||||
expect(result.meta).to.have.property('disabled', true);
|
||||
done();
|
||||
});
|
||||
$rootScope.$apply();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
|
@ -12,6 +12,35 @@ define(function (require) {
|
|||
expect(results).to.have.length(1);
|
||||
});
|
||||
|
||||
it('should filter out duplicates, ignoring meta attributes', function () {
|
||||
var before = [
|
||||
{
|
||||
meta: { negate: true },
|
||||
query: { _type: { match: { query: 'apache', type: 'phrase' } } }
|
||||
},
|
||||
{
|
||||
meta: { negate: false },
|
||||
query: { _type: { match: { query: 'apache', type: 'phrase' } } }
|
||||
}
|
||||
];
|
||||
var results = uniqFilters(before);
|
||||
expect(results).to.have.length(1);
|
||||
});
|
||||
|
||||
it('should filter out duplicates, ignoring $state attributes', function () {
|
||||
var before = [
|
||||
{
|
||||
$state: { store: 'appState' },
|
||||
query: { _type: { match: { query: 'apache', type: 'phrase' } } }
|
||||
},
|
||||
{
|
||||
$state: { store: 'globalState' },
|
||||
query: { _type: { match: { query: 'apache', type: 'phrase' } } }
|
||||
}
|
||||
];
|
||||
var results = uniqFilters(before);
|
||||
expect(results).to.have.length(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
define(function (require) {
|
||||
describe('Filter Bar watchFilters()', function () {
|
||||
var sinon = require('test_utils/auto_release_sinon');
|
||||
var _ = require('lodash');
|
||||
|
||||
var watchFilters;
|
||||
var Promise;
|
||||
var EventEmitter;
|
||||
var $scope;
|
||||
|
||||
beforeEach(module('kibana'));
|
||||
beforeEach(inject(function (Private, $injector) {
|
||||
Promise = $injector.get('Promise');
|
||||
EventEmitter = Private(require('factories/events'));
|
||||
watchFilters = Private(require('components/filter_bar/lib/watchFilters'));
|
||||
$scope = {
|
||||
$watch: sinon.stub()
|
||||
};
|
||||
}));
|
||||
|
||||
it('returns an event emitter', function () {
|
||||
expect(watchFilters($scope)).to.be.an(EventEmitter);
|
||||
});
|
||||
|
||||
it('listens to the filters on state', function () {
|
||||
watchFilters($scope, { update: _.noop, fetch: _.noop });
|
||||
expect($scope.$watch).to.have.property('callCount', 1);
|
||||
|
||||
var call = $scope.$watch.getCall(0);
|
||||
expect(call.args[0]).to.be('state.filters');
|
||||
});
|
||||
|
||||
describe('change handling', function () {
|
||||
require('test_utils/no_digest_promises').activateForSuite();
|
||||
|
||||
it('calls update and fetch', function () {
|
||||
var onFetch = sinon.stub();
|
||||
var onUpdate = sinon.stub();
|
||||
|
||||
watchFilters($scope).on('fetch', onFetch).on('update', onUpdate);
|
||||
var handler = $scope.$watch.args[0][1];
|
||||
|
||||
return handler([ {} ], [])
|
||||
.then(function () {
|
||||
expect(onUpdate).to.have.property('callCount', 1);
|
||||
expect(onFetch).to.have.property('callCount', 1);
|
||||
});
|
||||
});
|
||||
|
||||
it('only calls update if all filters are disabled', function () {
|
||||
var onFetch = sinon.stub();
|
||||
var onUpdate = sinon.stub();
|
||||
|
||||
watchFilters($scope).on('fetch', onFetch).on('update', onUpdate);
|
||||
var handler = $scope.$watch.args[0][1];
|
||||
|
||||
return handler([ ], [ { meta: { disabled: true } } ])
|
||||
.then(function () {
|
||||
expect(onUpdate).to.have.property('callCount', 1);
|
||||
expect(onFetch).to.have.property('callCount', 0);
|
||||
});
|
||||
});
|
||||
|
||||
it('calls nothing if there were no changes', function () {
|
||||
var onFetch = sinon.stub();
|
||||
var onUpdate = sinon.stub();
|
||||
|
||||
watchFilters($scope).on('fetch', onFetch).on('update', onUpdate);
|
||||
var handler = $scope.$watch.args[0][1];
|
||||
var cur = [];
|
||||
var prev = cur;
|
||||
|
||||
return Promise.try(handler, [cur, prev])
|
||||
.then(function () {
|
||||
expect(onUpdate).to.have.property('callCount', 0);
|
||||
expect(onFetch).to.have.property('callCount', 0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -1,18 +1,35 @@
|
|||
define(function (require) {
|
||||
var filterManager = require('components/filter_manager/filter_manager');
|
||||
var $state;
|
||||
var _ = require('lodash');
|
||||
var MockState = require('fixtures/mock_state');
|
||||
var filterManager;
|
||||
var appState;
|
||||
|
||||
describe('Filter Manager', function () {
|
||||
beforeEach(module('kibana'));
|
||||
|
||||
beforeEach(function () {
|
||||
$state = {
|
||||
filters: []
|
||||
};
|
||||
filterManager.init($state);
|
||||
|
||||
module('kibana/global_state', function ($provide) {
|
||||
$provide.service('getAppState', function () {
|
||||
return function () {
|
||||
return appState;
|
||||
};
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should have an init function that sets the state to be used', function () {
|
||||
expect(filterManager.init).to.be.a(Function);
|
||||
filterManager.init($state);
|
||||
expect(filterManager.$state).to.be($state);
|
||||
beforeEach(function () {
|
||||
inject(function (Private) {
|
||||
filterManager = Private(require('components/filter_manager/filter_manager'));
|
||||
appState = new MockState();
|
||||
appState.filters = [];
|
||||
|
||||
// mock queryFilter's invertFilter since it's used in the manager
|
||||
var queryFilter = Private(require('components/filter_bar/query_filter'));
|
||||
queryFilter.invertFilter = function (filter) {
|
||||
filter.meta.negate = !filter.meta.negate;
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
it('should have an `add` function', function () {
|
||||
|
@ -20,35 +37,49 @@ define(function (require) {
|
|||
});
|
||||
|
||||
it('should add a filter', function () {
|
||||
expect($state.filters.length).to.be(0);
|
||||
expect(appState.filters.length).to.be(0);
|
||||
filterManager.add('myField', 1, '+', 'myIndex');
|
||||
expect($state.filters.length).to.be(1);
|
||||
expect(appState.filters.length).to.be(1);
|
||||
});
|
||||
|
||||
it('should add multiple filters if passed an array of values', function () {
|
||||
filterManager.add('myField', [1, 2, 3], '+', 'myIndex');
|
||||
expect($state.filters.length).to.be(3);
|
||||
expect(appState.filters.length).to.be(3);
|
||||
});
|
||||
|
||||
it('should add an exists filter if _exists_ is used as the field', function () {
|
||||
filterManager.add('_exists_', 'myField', '+', 'myIndex');
|
||||
expect($state.filters[0].exists).to.eql({field: 'myField'});
|
||||
expect(appState.filters[0].exists).to.eql({field: 'myField'});
|
||||
});
|
||||
|
||||
it('Should negate existing filter instead of added a conflicting filter', function () {
|
||||
filterManager.add('myField', 1, '+', 'myIndex');
|
||||
expect($state.filters.length).to.be(1);
|
||||
expect(appState.filters.length).to.be(1);
|
||||
filterManager.add('myField', 1, '-', 'myIndex');
|
||||
expect($state.filters.length).to.be(1);
|
||||
expect($state.filters[0].meta.negate).to.be(true);
|
||||
expect(appState.filters.length).to.be(1);
|
||||
expect(appState.filters[0].meta.negate).to.be(true);
|
||||
|
||||
filterManager.add('_exists_', 'myField', '+', 'myIndex');
|
||||
expect($state.filters.length).to.be(2);
|
||||
expect(appState.filters.length).to.be(2);
|
||||
filterManager.add('_exists_', 'myField', '-', 'myIndex');
|
||||
expect($state.filters.length).to.be(2);
|
||||
expect($state.filters[1].meta.negate).to.be(true);
|
||||
expect(appState.filters.length).to.be(2);
|
||||
expect(appState.filters[1].meta.negate).to.be(true);
|
||||
});
|
||||
|
||||
it('should enable matching filters being changed', function () {
|
||||
_.each([true, false], function (negate) {
|
||||
appState.filters = [{
|
||||
query: { match: { myField: { query: 1 } } },
|
||||
meta: { disabled: true, negate: negate }
|
||||
}];
|
||||
expect(appState.filters.length).to.be(1);
|
||||
expect(appState.filters[0].meta.disabled).to.be(true);
|
||||
|
||||
filterManager.add('myField', 1, '+', 'myIndex');
|
||||
expect(appState.filters.length).to.be(1);
|
||||
expect(appState.filters[0].meta.disabled).to.be(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
describe('$scope.$watchMulti', function () {
|
||||
var sinon = require('test_utils/auto_release_sinon');
|
||||
|
||||
|
@ -11,119 +12,189 @@ define(function (require) {
|
|||
$scope = $rootScope.$new();
|
||||
}));
|
||||
|
||||
it('exposes $watchMulti on all scopes', function () {
|
||||
expect($rootScope.$watchMulti).to.be.a('function');
|
||||
expect($scope).to.have.property('$watchMulti', $rootScope.$watchMulti);
|
||||
describe('basic functionality', function () {
|
||||
it('exposes $watchMulti on all scopes', function () {
|
||||
expect($rootScope.$watchMulti).to.be.a('function');
|
||||
expect($scope).to.have.property('$watchMulti', $rootScope.$watchMulti);
|
||||
|
||||
var $isoScope = $scope.$new(true);
|
||||
expect($isoScope).to.have.property('$watchMulti', $rootScope.$watchMulti);
|
||||
});
|
||||
|
||||
it('only triggers a single watch on initialization', function () {
|
||||
var stub = sinon.stub();
|
||||
|
||||
$scope.$watchMulti([
|
||||
'one',
|
||||
'two',
|
||||
'three'
|
||||
], stub);
|
||||
$rootScope.$apply();
|
||||
|
||||
expect(stub.callCount).to.be(1);
|
||||
});
|
||||
|
||||
it('only triggers a single watch when multiple values change', function () {
|
||||
var stub = sinon.spy(function (a, b) {});
|
||||
|
||||
$scope.$watchMulti([
|
||||
'one',
|
||||
'two',
|
||||
'three'
|
||||
], stub);
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(stub.callCount).to.be(1);
|
||||
|
||||
$scope.one = 'a';
|
||||
$scope.two = 'b';
|
||||
$scope.three = 'c';
|
||||
$rootScope.$apply();
|
||||
|
||||
expect(stub.callCount).to.be(2);
|
||||
});
|
||||
|
||||
it('passes an array of the current values as the first arg, and an array of the previous values as the second',
|
||||
function () {
|
||||
var stub = sinon.spy(function (a, b) {});
|
||||
|
||||
$scope.one = 'a';
|
||||
$scope.two = 'b';
|
||||
$scope.three = 'c';
|
||||
$scope.$watchMulti([
|
||||
'one',
|
||||
'two',
|
||||
'three'
|
||||
], stub);
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(stub.firstCall.args).to.eql([
|
||||
['a', 'b', 'c'],
|
||||
['a', 'b', 'c']
|
||||
]);
|
||||
|
||||
$scope.one = 'do';
|
||||
$scope.two = 're';
|
||||
$scope.three = 'mi';
|
||||
$rootScope.$apply();
|
||||
|
||||
expect(stub.secondCall.args).to.eql([
|
||||
['do', 're', 'mi'],
|
||||
['a', 'b', 'c']
|
||||
]);
|
||||
});
|
||||
|
||||
it('the current value is always up to date', function () {
|
||||
var count = 0;
|
||||
|
||||
$scope.vals = [1, 0];
|
||||
$scope.$watchMulti([ 'vals[0]', 'vals[1]' ], function (cur, prev) {
|
||||
expect(cur).to.eql($scope.vals);
|
||||
count++;
|
||||
var $isoScope = $scope.$new(true);
|
||||
expect($isoScope).to.have.property('$watchMulti', $rootScope.$watchMulti);
|
||||
});
|
||||
|
||||
var $child = $scope.$new();
|
||||
$child.$watch('vals[0]', function (cur) {
|
||||
$child.vals[1] = cur;
|
||||
});
|
||||
it('returns a working unwatch function', function () {
|
||||
$scope.a = 0;
|
||||
$scope.b = 0;
|
||||
var triggers = 0;
|
||||
var unwatch = $scope.$watchMulti(['a', 'b'], function () { triggers++; });
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(count).to.be(2);
|
||||
// initial watch
|
||||
$scope.$apply();
|
||||
expect(triggers).to.be(1);
|
||||
|
||||
// prove that it triggers on chagne
|
||||
$scope.a++;
|
||||
$scope.$apply();
|
||||
expect(triggers).to.be(2);
|
||||
|
||||
// remove watchers
|
||||
expect($scope.$$watchers).to.not.eql([]);
|
||||
unwatch();
|
||||
expect($scope.$$watchers).to.eql([]);
|
||||
|
||||
// prove that it doesn't trigger anymore
|
||||
$scope.a++;
|
||||
$scope.$apply();
|
||||
expect(triggers).to.be(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns a working unwatch function', function () {
|
||||
$scope.a = 0;
|
||||
$scope.b = 0;
|
||||
var triggers = 0;
|
||||
var unwatch = $scope.$watchMulti(['a', 'b'], function () { triggers++; });
|
||||
describe('simple scope watchers', function () {
|
||||
it('only triggers a single watch on initialization', function () {
|
||||
var stub = sinon.stub();
|
||||
|
||||
// initial watch
|
||||
$scope.$apply();
|
||||
expect(triggers).to.be(1);
|
||||
$scope.$watchMulti([
|
||||
'one',
|
||||
'two',
|
||||
'three'
|
||||
], stub);
|
||||
$rootScope.$apply();
|
||||
|
||||
// prove that it triggers on chagne
|
||||
$scope.a++;
|
||||
$scope.$apply();
|
||||
expect(triggers).to.be(2);
|
||||
expect(stub.callCount).to.be(1);
|
||||
});
|
||||
|
||||
// remove watchers
|
||||
expect($scope.$$watchers).to.not.eql([]);
|
||||
unwatch();
|
||||
expect($scope.$$watchers).to.eql([]);
|
||||
it('only triggers a single watch when multiple values change', function () {
|
||||
var stub = sinon.spy(function (a, b) {});
|
||||
|
||||
// prove that it doesn't trigger anymore
|
||||
$scope.a++;
|
||||
$scope.$apply();
|
||||
expect(triggers).to.be(2);
|
||||
$scope.$watchMulti([
|
||||
'one',
|
||||
'two',
|
||||
'three'
|
||||
], stub);
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(stub.callCount).to.be(1);
|
||||
|
||||
$scope.one = 'a';
|
||||
$scope.two = 'b';
|
||||
$scope.three = 'c';
|
||||
$rootScope.$apply();
|
||||
|
||||
expect(stub.callCount).to.be(2);
|
||||
});
|
||||
|
||||
it('passes an array of the current and previous values, in order',
|
||||
function () {
|
||||
var stub = sinon.spy(function (a, b) {});
|
||||
|
||||
$scope.one = 'a';
|
||||
$scope.two = 'b';
|
||||
$scope.three = 'c';
|
||||
$scope.$watchMulti([
|
||||
'one',
|
||||
'two',
|
||||
'three'
|
||||
], stub);
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(stub.firstCall.args).to.eql([
|
||||
['a', 'b', 'c'],
|
||||
['a', 'b', 'c']
|
||||
]);
|
||||
|
||||
$scope.one = 'do';
|
||||
$scope.two = 're';
|
||||
$scope.three = 'mi';
|
||||
$rootScope.$apply();
|
||||
|
||||
expect(stub.secondCall.args).to.eql([
|
||||
['do', 're', 'mi'],
|
||||
['a', 'b', 'c']
|
||||
]);
|
||||
});
|
||||
|
||||
it('always has an up to date value', function () {
|
||||
var count = 0;
|
||||
|
||||
$scope.vals = [1, 0];
|
||||
$scope.$watchMulti([ 'vals[0]', 'vals[1]' ], function (cur, prev) {
|
||||
expect(cur).to.eql($scope.vals);
|
||||
count++;
|
||||
});
|
||||
|
||||
var $child = $scope.$new();
|
||||
$child.$watch('vals[0]', function (cur) {
|
||||
$child.vals[1] = cur;
|
||||
});
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(count).to.be(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('complex watch expressions', function () {
|
||||
var stateWatchers;
|
||||
var firstValue;
|
||||
var secondValue;
|
||||
|
||||
beforeEach(function () {
|
||||
var firstGetter = function () {
|
||||
return firstValue;
|
||||
};
|
||||
|
||||
var secondGetter = function () {
|
||||
return secondValue;
|
||||
};
|
||||
|
||||
stateWatchers = [{
|
||||
fn: $rootScope.$watch,
|
||||
get: firstGetter
|
||||
}, {
|
||||
fn: $rootScope.$watch,
|
||||
get: secondGetter
|
||||
}];
|
||||
});
|
||||
|
||||
it('should trigger the watcher on initialization', function () {
|
||||
var stub = sinon.stub();
|
||||
firstValue = 'first';
|
||||
secondValue = 'second';
|
||||
|
||||
$scope.$watchMulti(stateWatchers, stub);
|
||||
$rootScope.$apply();
|
||||
|
||||
expect(stub.callCount).to.be(1);
|
||||
|
||||
expect(stub.firstCall.args[0]).to.eql([firstValue, secondValue]);
|
||||
expect(stub.firstCall.args[1]).to.eql([firstValue, secondValue]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('nested watchers', function () {
|
||||
it('should trigger the handler at least once', function () {
|
||||
var $scope = $rootScope.$new();
|
||||
$scope.$$watchers = [{
|
||||
get: _.noop,
|
||||
fn: _.noop,
|
||||
eq: false,
|
||||
last: false
|
||||
}, {
|
||||
get: _.noop,
|
||||
fn: registerWatchers,
|
||||
eq: false,
|
||||
last: false
|
||||
}];
|
||||
|
||||
var first = sinon.stub();
|
||||
var second = sinon.stub();
|
||||
|
||||
function registerWatchers() {
|
||||
$scope.$watchMulti([first, second], function () {
|
||||
expect(first.callCount).to.be.greaterThan(0);
|
||||
expect(second.callCount).to.be.greaterThan(0);
|
||||
});
|
||||
}
|
||||
$scope.$digest();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,6 +2,7 @@ define(function (require) {
|
|||
var sinon = require('test_utils/auto_release_sinon');
|
||||
var faker = require('faker');
|
||||
var _ = require('lodash');
|
||||
var MockState = require('fixtures/mock_state');
|
||||
|
||||
// global vars, injected and mocked in init()
|
||||
var kbnUrl;
|
||||
|
@ -29,8 +30,7 @@ define(function (require) {
|
|||
});
|
||||
|
||||
$provide.service('globalState', function () {
|
||||
globalStateMock = {};
|
||||
globalStateMock.on = globalStateMock.off = _.noop;
|
||||
globalStateMock = new MockState();
|
||||
globalStateMock.removeFromUrl = function (url) {
|
||||
return url;
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue