Adapt the app for Kibana 7.3.0

This commit is contained in:
JuanCarlos 2019-08-01 15:00:25 +02:00
parent de0e46a714
commit 61ee711bd0
No known key found for this signature in database
GPG Key ID: B1C4FB733616273A
10 changed files with 721 additions and 530 deletions

View File

@ -1,10 +1,10 @@
{
"name": "wazuh",
"version": "3.9.4",
"revision": "0527",
"code": "0527-0",
"revision": "0528",
"code": "0528-0",
"kibana": {
"version": "7.2.0"
"version": "7.3.0"
},
"description": "Wazuh app",
"main": "index.js",

View File

@ -15,7 +15,7 @@ import { uiModules } from 'ui/modules';
import discoverTemplate from '../templates/kibana-template/kibana-discover-template.html';
uiModules.get('app/wazuh', ['kibana/courier']).directive('kbnDis', [
function() {
function () {
return {
restrict: 'E',
scope: {},
@ -25,7 +25,7 @@ uiModules.get('app/wazuh', ['kibana/courier']).directive('kbnDis', [
]);
// Added dependencies (from Kibana module)
import 'ui/pager';
import 'plugins/kibana/discover/doc_table/pager';
import 'ui/render_directive';
// Added from its index.js
@ -40,10 +40,7 @@ import 'plugins/kibana/discover/controllers/discover';
import 'ui/style_compile/style_compile';
import 'ui/registry/doc_views';
import 'plugins/kbn_doc_views/kbn_doc_views';
import 'ui/pager_control';
import 'ui/pager';
import { data } from 'plugins/data';
import 'plugins/kibana/discover/doc_table/pager_control';
import _ from 'lodash';
import { i18n } from '@kbn/i18n';
import React from 'react';
@ -71,15 +68,17 @@ import {
} from 'ui/courier';
import { toastNotifications } from 'ui/notify';
import { VisProvider } from 'ui/vis';
import { VislibSeriesResponseHandlerProvider } from 'ui/vis/response_handlers/vislib';
import { DocTitleProvider } from 'ui/doc_title';
import { FilterBarQueryFilterProvider } from 'ui/filter_bar/query_filter';
import { FilterBarQueryFilterProvider } from 'ui/filter_manager/query_filter';
import { vislibSeriesResponseHandlerProvider } from 'ui/vis/response_handlers/vislib';
import { docTitle } from 'ui/doc_title';
import { intervalOptions } from 'ui/agg_types/buckets/_interval_options';
import { stateMonitorFactory } from 'ui/state_management/state_monitor_factory';
import uiRoutes from 'ui/routes';
import { StateProvider } from 'ui/state_management/state';
import { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query';
import { FilterManagerProvider } from 'ui/filter_manager';
import { subscribeWithScope } from 'ui/utils/subscribe_with_scope';
import { getFilterGenerator } from 'ui/filter_manager';
import { SavedObjectsClientProvider } from 'ui/saved_objects';
import { VisualizeLoaderProvider } from 'ui/visualize/loader/visualize_loader';
import { recentlyAccessed } from 'ui/persisted_log';
@ -104,15 +103,14 @@ import { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_s
const { getRootBreadcrumbs, getSavedSearchBreadcrumbs } = data.search.ui;
import { buildVislibDimensions } from 'ui/visualize/loader/pipeline_helpers/build_pipeline';
import 'ui/capabilities/route_setup';
import { defaultSearchStrategy } from 'ui/courier/search_strategy/default_search_strategy';
import { data } from 'plugins/data/setup';
data.search.loadLegacyDirectives();
const fetchStatuses = {
UNINITIALIZED: 'uninitialized',
LOADING: 'loading',
COMPLETE: 'complete'
COMPLETE: 'complete',
};
const app = uiModules.get('apps/discover', [
@ -123,7 +121,7 @@ const app = uiModules.get('apps/discover', [
'app/wazuh'
]);
app.directive('discoverAppW', function() {
app.directive('discoverAppW', function () {
return {
restrict: 'E',
controllerAs: 'discoverApp',
@ -138,7 +136,6 @@ function discoverController(
$timeout,
$window,
AppState,
Notifier,
Private,
Promise,
config,
@ -158,17 +155,13 @@ function discoverController(
const visualizeLoader = Private(VisualizeLoaderProvider);
let visualizeHandler;
const Vis = Private(VisProvider);
const docTitle = Private(DocTitleProvider);
const queryFilter = Private(FilterBarQueryFilterProvider);
const responseHandler = Private(VislibSeriesResponseHandlerProvider).handler;
const filterManager = Private(FilterManagerProvider);
const notify = new Notifier({
location: 'Discover'
});
const responseHandler = vislibSeriesResponseHandlerProvider().handler;
const getUnhashableStates = Private(getUnhashableStatesProvider);
const shareContextMenuExtensions = Private(
ShareContextMenuExtensionsRegistryProvider
);
const shareContextMenuExtensions = Private(ShareContextMenuExtensionsRegistryProvider);
const queryFilter = Private(FilterBarQueryFilterProvider);
const filterGen = getFilterGenerator(queryFilter);
const inspectorAdapters = {
requests: new RequestAdapter()
};
@ -186,7 +179,7 @@ function discoverController(
$scope.fetchStatus = fetchStatuses.UNINITIALIZED;
$scope.refreshInterval = timefilter.getRefreshInterval();
$scope.intervalEnabled = function(interval) {
$scope.intervalEnabled = function (interval) {
return interval.val !== 'custom';
};
@ -198,9 +191,9 @@ function discoverController(
if (filterUpdateSubscription) filterUpdateSubscription.unsubscribe();
});
const $appStatus = ($scope.appStatus = this.appStatus = {
const $appStatus = $scope.appStatus = this.appStatus = {
dirty: !savedSearch.id
});
};
// WAZUH MODIFIED
$scope.topNavMenu = [];
@ -228,35 +221,26 @@ function discoverController(
$scope.searchSource.setParent(timeRangeSearchSource);
const pageTitleSuffix =
savedSearch.id && savedSearch.title ? `: ${savedSearch.title}` : '';
const pageTitleSuffix = savedSearch.id && savedSearch.title ? `: ${savedSearch.title}` : '';
docTitle.change(`Wazuh${pageTitleSuffix}`);
const discoverBreadcrumbsTitle = i18n.translate(
'kbn.discover.discoverBreadcrumbTitle',
{
defaultMessage: 'Wazuh'
}
);
const discoverBreadcrumbsTitle = i18n.translate('kbn.discover.discoverBreadcrumbTitle', {
defaultMessage: 'Wazuh',
});
if (savedSearch.id && savedSearch.title) {
chrome.breadcrumbs.set([
{
text: discoverBreadcrumbsTitle,
href: '#/discover'
},
{ text: savedSearch.title }
]);
chrome.breadcrumbs.set([{
text: discoverBreadcrumbsTitle,
href: '#/discover'
}, { text: savedSearch.title }]);
} else {
chrome.breadcrumbs.set([
{
text: discoverBreadcrumbsTitle
}
]);
chrome.breadcrumbs.set([{
text: discoverBreadcrumbsTitle,
}]);
}
let stateMonitor;
const $state = ($scope.state = new AppState(getStateDefaults()));
const $state = $scope.state = new AppState(getStateDefaults());
$scope.filters = queryFilter.getFilters();
$scope.screenTitle = savedSearch.title;
@ -308,7 +292,7 @@ function discoverController(
}
return await new Promise(resolve => {
const unwatch = $scope.$watch('fetchStatus', newValue => {
const unwatch = $scope.$watch('fetchStatus', (newValue) => {
if (newValue === fetchStatuses.COMPLETE) {
unwatch();
resolve($scope.fieldCounts);
@ -329,10 +313,7 @@ function discoverController(
const timeFieldName = $scope.indexPattern.timeFieldName;
const hideTimeColumn = config.get('doc_table:hideTimeColumn');
const fields =
timeFieldName && !hideTimeColumn
? [timeFieldName, ...selectedFields]
: selectedFields;
const fields = (timeFieldName && !hideTimeColumn) ? [timeFieldName, ...selectedFields] : selectedFields;
return {
searchFields: fields,
selectFields: fields
@ -358,9 +339,7 @@ function discoverController(
},
fields: selectFields,
metaFields: $scope.indexPattern.metaFields,
conflictedTypesFields: $scope.indexPattern.fields
.filter(f => f.type === 'conflict')
.map(f => f.name),
conflictedTypesFields: $scope.indexPattern.fields.filter(f => f.type === 'conflict').map(f => f.name),
indexPatternId: searchSource.getField('index').id
};
};
@ -371,19 +350,10 @@ function discoverController(
return {
query: $scope.searchSource.getField('query') || {
query: '',
language:
localStorage.get('kibana.userQueryLanguage') ||
config.get('search:queryLanguage')
language: localStorage.get('kibana.userQueryLanguage') || config.get('search:queryLanguage')
},
sort: getSort.array(
savedSearch.sort,
$scope.indexPattern,
config.get('discover:sort:defaultOrder')
),
columns:
savedSearch.columns.length > 0
? savedSearch.columns
: config.get('defaultColumns').slice(),
sort: getSort.array(savedSearch.sort, $scope.indexPattern, config.get('discover:sort:defaultOrder')),
columns: savedSearch.columns.length > 0 ? savedSearch.columns : config.get('defaultColumns').slice(),
index: $scope.indexPattern.id,
interval: 'auto',
filters: _.cloneDeep($scope.searchSource.getOwnField('filter'))
@ -396,138 +366,123 @@ function discoverController(
$scope.getBucketIntervalToolTipText = () => {
return i18n.translate('kbn.discover.bucketIntervalTooltip', {
// eslint-disable-next-line max-len
defaultMessage:
'This interval creates {bucketsDescription} to show in the selected time range, so it has been scaled to {bucketIntervalDescription}',
defaultMessage: 'This interval creates {bucketsDescription} to show in the selected time range, so it has been scaled to {bucketIntervalDescription}',
values: {
bucketsDescription:
$scope.bucketInterval.scale > 1
? i18n.translate(
'kbn.discover.bucketIntervalTooltip.tooLargeBucketsText',
{
defaultMessage: 'buckets that are too large'
}
)
: i18n.translate(
'kbn.discover.bucketIntervalTooltip.tooManyBucketsText',
{
defaultMessage: 'too many buckets'
}
),
bucketIntervalDescription: $scope.bucketInterval.description
}
bucketsDescription: $scope.bucketInterval.scale > 1
? i18n.translate('kbn.discover.bucketIntervalTooltip.tooLargeBucketsText', {
defaultMessage: 'buckets that are too large',
})
: i18n.translate('kbn.discover.bucketIntervalTooltip.tooManyBucketsText', {
defaultMessage: 'too many buckets',
}),
bucketIntervalDescription: $scope.bucketInterval.description,
},
});
};
$scope.$watchCollection('state.columns', function() {
$scope.$watchCollection('state.columns', function () {
$state.save();
});
$scope.opts = {
// number of records to fetch, then paginate through
sampleSize: config.get('discover:sampleSize'),
timefield:
isDefaultTypeIndexPattern($scope.indexPattern) &&
$scope.indexPattern.timeFieldName,
timefield: isDefaultTypeIndexPattern($scope.indexPattern) && $scope.indexPattern.timeFieldName,
savedSearch: savedSearch,
indexPatternList: $route.current.locals.ip.list
indexPatternList: $route.current.locals.ip.list,
};
const init = _.once(function() {
const init = _.once(function () {
stateMonitor = stateMonitorFactory.create($state, getStateDefaults());
stateMonitor.onChange(status => {
stateMonitor.onChange((status) => {
$appStatus.dirty = status.dirty || !savedSearch.id;
});
$scope.$on('$destroy', () => stateMonitor.destroy());
$scope.updateDataSource().then(function() {
$scope.$listen(timefilter, 'fetch', function() {
// WAZUH
$rootScope.$broadcast('updateVis');
$scope.fetch();
});
$scope.updateDataSource()
.then(function () {
$scope.$listen(timefilter, 'autoRefreshFetch', $scope.fetch);
$scope.$listen(timefilter, 'refreshIntervalUpdate', $scope.updateRefreshInterval);
$scope.$listen(timefilter, 'timeUpdate', $scope.updateTime);
$scope.$listen(timefilter, 'refreshIntervalUpdate', () => {
$scope.updateRefreshInterval();
});
$scope.$listen(timefilter, 'timeUpdate', () => {
$scope.updateTime();
});
$scope.$watchCollection('state.sort', function (sort) {
if (!sort) return;
$scope.$watchCollection('state.sort', function(sort) {
if (!sort) return;
// get the current sort from {key: val} to ["key", "val"];
const currentSort = Object.entries(
$scope.searchSource.getField('sort')
).pop();
// get the current sort from {key: val} to ["key", "val"];
const currentSort = Object.entries(
$scope.searchSource.getField('sort')
).pop();
// if the searchSource doesn't know, tell it so
if (!angular.equals(sort, currentSort)) $scope.fetch();
});
// if the searchSource doesn't know, tell it so
if (!angular.equals(sort, currentSort)) $scope.fetch();
});
// update data source when filters update
filterUpdateSubscription = subscribeWithScope($scope, queryFilter.getUpdates$(), {
next: () => {
$scope.filters = queryFilter.getFilters();
$scope
.updateDataSource()
.then(function () {
/////////////////////////////// WAZUH ///////////////////////////////////
if (!filtersAreReady()) return;
discoverPendingUpdates.removeAll();
discoverPendingUpdates.addItem(
$state.query,
queryFilter.getFilters()
);
$rootScope.$broadcast('updateVis');
$rootScope.$broadcast('fetch');
if ($location.search().tab != 'configuration') {
loadedVisualizations.removeAll();
$rootScope.rendered = false;
$rootScope.loadingStatus = 'Fetching data...';
}
////////////////////////////////////////////////////////////////////////////
$state.save();
})
.catch(console.error); // eslint-disable-line
}
});
// update data source when filters update
filterUpdateSubscription = queryFilter.getUpdates$().subscribe(() => {
$scope.filters = queryFilter.getFilters();
$scope
.updateDataSource()
.then(function() {
/////////////////////////////// WAZUH ///////////////////////////////////
if (!filtersAreReady()) return;
discoverPendingUpdates.removeAll();
discoverPendingUpdates.addItem(
$state.query,
queryFilter.getFilters()
);
$rootScope.$broadcast('updateVis');
$rootScope.$broadcast('fetch');
if ($location.search().tab != 'configuration') {
loadedVisualizations.removeAll();
$rootScope.rendered = false;
$rootScope.loadingStatus = 'Fetching data...';
}
////////////////////////////////////////////////////////////////////////////
$state.save();
})
.catch(console.error); // eslint-disable-line
});
// fetch data when filters fire fetch event
filterFetchSubscription = subscribeWithScope($scope, queryFilter.getUpdates$(), {
next: $scope.fetch
});
// fetch data when filters fire fetch event
filterFetchSubscription = queryFilter
.getFetches$()
.subscribe($scope.fetch);
// update data source when hitting forward/back and the query changes
$scope.$listen($state, 'fetch_with_changes', function (diff) {
if (diff.indexOf('query') >= 0) $scope.fetch();
});
// update data source when hitting forward/back and the query changes
$scope.$listen($state, 'fetch_with_changes', function(diff) {
if (diff.indexOf('query') >= 0) $scope.fetch();
});
$scope.$watch('opts.timefield', function (timefield) {
$scope.enableTimeRangeSelector = !!timefield;
});
$scope.$watch('opts.timefield', function(timefield) {
$scope.enableTimeRangeSelector = !!timefield;
});
$scope.$watch('state.interval', function () {
$scope.fetch();
});
$scope.$watch('state.interval', function() {
$scope.fetch();
});
$scope.$watch('vis.aggs', function () {
// no timefield, no vis, nothing to update
if (!$scope.opts.timefield) return;
$scope.$watch('vis.aggs', function() {
// no timefield, no vis, nothing to update
if (!$scope.opts.timefield) return;
const buckets = $scope.vis.getAggConfig().bySchemaGroup.buckets;
const buckets = $scope.vis.getAggConfig().bySchemaGroup.buckets;
if (buckets && buckets.length === 1) {
$scope.bucketInterval = buckets[0].buckets.getInterval();
}
});
if (buckets && buckets.length === 1) {
$scope.bucketInterval = buckets[0].buckets.getInterval();
}
});
$scope.$watch('state.query', (newQuery) => {
const query = migrateLegacyQuery(newQuery);
$scope.updateQueryAndFetch({ query });
});
$scope.$watch('state.query', newQuery => {
const query = migrateLegacyQuery(newQuery);
$scope.updateQueryAndFetch({ query });
});
$scope.$watchMulti(
['rows', 'fetchStatus'],
(function updateResultState() {
$scope.$watchMulti([
'rows',
'fetchStatus'
], (function updateResultState() {
let prev = {};
const status = {
LOADING: 'loading', // initial data load
@ -540,16 +495,14 @@ function discoverController(
if (rows == null && oldRows == null) return status.LOADING;
const rowsEmpty = _.isEmpty(rows);
const preparingForFetch =
fetchStatus === fetchStatuses.UNINITIALIZED;
const preparingForFetch = fetchStatus === fetchStatuses.UNINITIALIZED;
if (preparingForFetch) return status.LOADING;
else if (rowsEmpty && fetchStatus === fetchStatuses.LOADING)
return status.LOADING;
else if (rowsEmpty && fetchStatus === fetchStatuses.LOADING) return status.LOADING;
else if (!rowsEmpty) return status.READY;
else return status.NO_RESULTS;
}
return function() {
return function () {
const current = {
rows: $scope.rows,
fetchStatus: $scope.fetchStatus
@ -561,24 +514,21 @@ function discoverController(
current.fetchStatus,
prev.fetchStatus
);
// Copying it to the rootScope to access it from the Wazuh App //
$rootScope.resultState = $scope.resultState;
/////////////////////////////////////////////////////////////////
prev = current;
};
})()
);
}()));
if ($scope.opts.timefield) {
setupVisualization();
$scope.updateTime();
}
if ($scope.opts.timefield) {
setupVisualization();
$scope.updateTime();
}
init.complete = true;
$state.replace();
});
init.complete = true;
$state.replace();
});
});
////////////////////////////////////////////////////////////////////////
@ -586,26 +536,25 @@ function discoverController(
////////////////////////////////////////////////////////////////////////
/**
* Wazuh - aux function for checking filters status
*/
* Wazuh - aux function for checking filters status
*/
const filtersAreReady = () => {
const currentUrlPath = $location.path();
if (currentUrlPath && !currentUrlPath.includes('wazuh-discover')) {
let filters = queryFilter.getFilters();
filters = Array.isArray(filters)
? filters.filter(
item => (((item || {}).$state || {}).store || '') === 'appState'
)
item => (((item || {}).$state || {}).store || '') === 'appState'
)
: [];
if (!filters || !filters.length) return false;
}
return true;
};
$scope.opts.fetch = $scope.fetch = function() {
$scope.opts.fetch = $scope.fetch = function () {
// Wazuh filters are not ready yet
if (!filtersAreReady()) return;
// ignore requests to fetch before the app inits
if (!init.complete) return;
@ -613,19 +562,34 @@ function discoverController(
$scope.updateTime();
$scope
.updateDataSource()
// Abort any in-progress requests before fetching again
$scope.searchSource.cancelQueued();
$scope.updateDataSource()
.then(setupVisualization)
.then(function() {
.then(function () {
$state.save();
$scope.fetchStatus = fetchStatuses.LOADING;
logInspectorRequest();
return courier.fetch();
return $scope.searchSource.fetch();
})
.catch(notify.error);
.then(onResults)
.catch((error) => {
const fetchError = getPainlessError(error);
if (fetchError) {
$scope.fetchError = fetchError;
} else {
toastNotifications.addError(error, {
title: i18n.translate('kbn.discover.errorLoadingData', {
defaultMessage: 'Error loading data',
}),
});
}
});
};
$scope.updateQueryAndFetch = function({ query, dateRange }) {
$scope.updateQueryAndFetch = function ({ query, dateRange }) {
// Wazuh filters are not ready yet
if (!filtersAreReady()) return;
@ -635,7 +599,6 @@ function discoverController(
$rootScope.$broadcast('updateVis');
$rootScope.$broadcast('fetch');
////////////////////////////////////////////////////////////////////////////
timefilter.setTime(dateRange);
$state.query = query;
$scope.fetch();
@ -647,12 +610,8 @@ function discoverController(
if ($scope.opts.timefield) {
const tabifiedData = tabifyAggResponse($scope.vis.aggs, resp);
$scope.searchSource.rawResponse = resp;
Promise.resolve(
buildVislibDimensions($scope.vis, {
timeRange: $scope.timeRange,
searchSource: $scope.searchSource
})
)
Promise
.resolve(buildVislibDimensions($scope.vis, { timeRange: $scope.timeRange, searchSource: $scope.searchSource }))
.then(resp => responseHandler(tabifiedData, resp))
.then(resp => {
if (visualizeHandler) {
@ -662,7 +621,7 @@ function discoverController(
visType: $scope.vis.type.name,
visData: resp,
visConfig: $scope.vis.params,
params: {}
params: {},
}
});
}
@ -673,7 +632,7 @@ function discoverController(
$scope.rows = resp.hits.hits;
// if we haven't counted yet, reset the counts
const counts = ($scope.fieldCounts = $scope.fieldCounts || {});
const counts = $scope.fieldCounts = $scope.fieldCounts || {};
$scope.rows.forEach(hit => {
const fields = Object.keys($scope.indexPattern.flattenHit(hit));
@ -683,8 +642,6 @@ function discoverController(
});
$scope.fetchStatus = fetchStatuses.COMPLETE;
return $scope.searchSource.onResults().then(onResults);
}
let inspectorRequest;
@ -692,15 +649,11 @@ function discoverController(
function logInspectorRequest() {
inspectorAdapters.requests.reset();
const title = i18n.translate('kbn.discover.inspectorRequestDataTitle', {
defaultMessage: 'Data'
defaultMessage: 'Data',
});
const description = i18n.translate('kbn.discover.inspectorRequestDescription', {
defaultMessage: 'This request queries Elasticsearch to fetch the data for the search.',
});
const description = i18n.translate(
'kbn.discover.inspectorRequestDescription',
{
defaultMessage:
'This request queries Elasticsearch to fetch the data for the search.'
}
);
inspectorRequest = inspectorAdapters.requests.start(title, { description });
inspectorRequest.stats(getRequestInspectorStats($scope.searchSource));
$scope.searchSource.getSearchRequestBody().then(body => {
@ -714,27 +667,7 @@ function discoverController(
.ok({ json: resp });
}
function startSearching() {
return $scope.searchSource
.onResults()
.then(onResults)
.catch(error => {
const fetchError = getPainlessError(error);
if (fetchError) {
$scope.fetchError = fetchError;
} else {
notify.error(error);
}
// Restart. This enables auto-refresh functionality.
startSearching();
});
}
startSearching();
$scope.updateTime = function() {
$scope.updateTime = function () {
/////////////////////////////// WAZUH ///////////////////////////////////
if ($location.search().tab != 'configuration') {
loadedVisualizations.removeAll();
@ -742,7 +675,6 @@ function discoverController(
$rootScope.loadingStatus = 'Fetching data...';
}
////////////////////////////////////////////////////////////////////////////
$scope.timeRange = {
from: dateMath.parse(timefilter.getTime().from),
to: dateMath.parse(timefilter.getTime().to, { roundUp: true })
@ -750,26 +682,26 @@ function discoverController(
$scope.time = timefilter.getTime();
};
$scope.toMoment = function(datetime) {
$scope.toMoment = function (datetime) {
return moment(datetime).format(config.get('dateFormat'));
};
$scope.updateRefreshInterval = function() {
$scope.updateRefreshInterval = function () {
$scope.refreshInterval = timefilter.getRefreshInterval();
};
$scope.onRefreshChange = function({ isPaused, refreshInterval }) {
$scope.onRefreshChange = function ({ isPaused, refreshInterval }) {
timefilter.setRefreshInterval({
pause: isPaused,
value: refreshInterval ? refreshInterval : $scope.refreshInterval.value
});
};
$scope.resetQuery = function() {
$scope.resetQuery = function () {
kbnUrl.change('/discover/{{id}}', { id: $route.current.params.id });
};
$scope.newQuery = function() {
$scope.newQuery = function () {
kbnUrl.change('/discover');
};
@ -786,47 +718,39 @@ function discoverController(
};
// TODO: On array fields, negating does not negate the combination, rather all terms
$scope.filterQuery = function(field, values, operation) {
$scope.filterQuery = function (field, values, operation) {
// Commented due to https://github.com/elastic/kibana/issues/22426
//$scope.indexPattern.popularizeField(field, 1);
filterActions.addFilter(
field,
values,
operation,
$scope.indexPattern.id,
$scope.state,
filterManager
);
filterActions.addFilter(field, values, operation, $scope.indexPattern.id, $scope.state, filterGen);
};
$scope.addColumn = function addColumn(columnName) {
// Commented due to https://github.com/elastic/kibana/issues/22426
//$scope.indexPattern.popularizeField(columnName, 1);
//$scope.indexPattern.popularizeField(field, 1);
columnActions.addColumn($scope.state.columns, columnName);
};
$scope.removeColumn = function removeColumn(columnName) {
// Commented due to https://github.com/elastic/kibana/issues/22426
//$scope.indexPattern.popularizeField(columnName, 1);
columnActions.removeColumn($scope.state.columns, columnName);
//$scope.indexPattern.popularizeField(field, 1); columnActions.removeColumn($scope.state.columns, columnName);
};
$scope.moveColumn = function moveColumn(columnName, newIndex) {
columnActions.moveColumn($scope.state.columns, columnName, newIndex);
};
$scope.scrollToTop = function() {
$scope.scrollToTop = function () {
$window.scrollTo(0, 0);
};
$scope.scrollToBottom = function() {
$scope.scrollToBottom = function () {
// delay scrolling to after the rows have been rendered
$timeout(() => {
$element.find('#discoverBottomMarker').focus();
}, 0);
};
$scope.showAllRows = function() {
$scope.showAllRows = function () {
$scope.minimumVisibleRows = $scope.hits;
};
@ -845,12 +769,11 @@ function discoverController(
params: {
field: $scope.opts.timefield,
interval: $state.interval,
timeRange: timefilter.getTime()
timeRange: timefilter.getTime(),
}
}
];
// we have a vis, just modify the aggs
if ($scope.vis) {
const visState = $scope.vis.getEnabledState();
visState.aggs = visStateAggs;
@ -859,6 +782,7 @@ function discoverController(
return;
}
const visSavedObject = {
indexPattern: $scope.indexPattern.id,
visState: {
@ -879,34 +803,24 @@ function discoverController(
visSavedObject.vis = $scope.vis;
$scope.searchSource.onRequestStart((searchSource, searchRequest) => {
return $scope.vis
.getAggConfig()
.onSearchRequestStart(searchSource, searchRequest);
return $scope.vis.getAggConfig().onSearchRequestStart(searchSource, searchRequest);
});
$scope.searchSource.setField('aggs', function() {
$scope.searchSource.setField('aggs', function () {
//////////////////// WAZUH ////////////////////////////////
// Old code: //
// return $scope.vis.getAggConfig().toDsl(); //
const result = $scope.vis.getAggConfig().toDsl();
if (((result[2] || {}).date_histogram || {}).interval === '0ms') {
result[2].date_histogram.interval = '1d';
}
return result;
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
});
$timeout(async () => {
const visEl = $element.find('#discoverHistogram')[0];
if (visEl) {
visualizeHandler = await visualizeLoader.embedVisualizationWithSavedObject(
visEl,
visSavedObject,
{
autoFetch: false
}
);
}
visualizeHandler = await visualizeLoader.embedVisualizationWithSavedObject(visEl, visSavedObject, {
autoFetch: false,
});
});
}
@ -914,7 +828,7 @@ function discoverController(
const {
loaded: loadedIndexPattern,
stateVal,
stateValFound
stateValFound,
} = $route.current.locals.ip;
const ownIndexPattern = $scope.searchSource.getOwnField('index');
@ -924,47 +838,36 @@ function discoverController(
}
if (stateVal && !stateValFound) {
const warningTitle = i18n(
'kbn.discover.valueIsNotConfiguredIndexPatternIDWarningTitle',
{
defaultMessage: '{stateVal} is not a configured index pattern ID',
values: {
stateVal: `"${stateVal}"`
}
}
);
const warningTitle = i18n.translate('kbn.discover.valueIsNotConfiguredIndexPatternIDWarningTitle', {
defaultMessage: '{stateVal} is not a configured index pattern ID',
values: {
stateVal: `"${stateVal}"`,
},
});
if (ownIndexPattern) {
toastNotifications.addWarning({
title: warningTitle,
text: i18n(
'kbn.discover.showingSavedIndexPatternWarningDescription',
{
defaultMessage:
'Showing the saved index pattern: "{ownIndexPatternTitle}" ({ownIndexPatternId})',
values: {
ownIndexPatternTitle: ownIndexPattern.title,
ownIndexPatternId: ownIndexPattern.id
}
}
)
text: i18n.translate('kbn.discover.showingSavedIndexPatternWarningDescription', {
defaultMessage: 'Showing the saved index pattern: "{ownIndexPatternTitle}" ({ownIndexPatternId})',
values: {
ownIndexPatternTitle: ownIndexPattern.title,
ownIndexPatternId: ownIndexPattern.id,
},
}),
});
return ownIndexPattern;
}
toastNotifications.addWarning({
title: warningTitle,
text: i18n(
'kbn.discover.showingDefaultIndexPatternWarningDescription',
{
defaultMessage:
'Showing the default index pattern: "{loadedIndexPatternTitle}" ({loadedIndexPatternId})',
values: {
loadedIndexPatternTitle: loadedIndexPattern.title,
loadedIndexPatternId: loadedIndexPattern.id
}
}
)
text: i18n.translate('kbn.discover.showingDefaultIndexPatternWarningDescription', {
defaultMessage: 'Showing the default index pattern: "{loadedIndexPatternTitle}" ({loadedIndexPatternId})',
values: {
loadedIndexPatternTitle: loadedIndexPattern.title,
loadedIndexPatternId: loadedIndexPattern.id,
},
}),
});
}
@ -973,9 +876,10 @@ function discoverController(
// Block the UI from loading if the user has loaded a rollup index pattern but it isn't
// supported.
$scope.isUnsupportedIndexPattern =
!isDefaultTypeIndexPattern($route.current.locals.ip.loaded) &&
!hasSearchStategyForIndexPattern($route.current.locals.ip.loaded);
$scope.isUnsupportedIndexPattern = (
!isDefaultTypeIndexPattern($route.current.locals.ip.loaded)
&& !hasSearchStategyForIndexPattern($route.current.locals.ip.loaded)
);
if ($scope.isUnsupportedIndexPattern) {
$scope.unsupportedIndexPatternType = $route.current.locals.ip.loaded.type;
@ -1017,7 +921,7 @@ function discoverController(
queryFilter
.addFilters(wzCurrentFilters)
.then(() => {})
.then(() => { })
.catch(error => console.log(error.message || error)); // eslint-disable-line
}
};
@ -1046,6 +950,5 @@ function discoverController(
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
init();
}
}

View File

@ -25,7 +25,7 @@
// @ts-ignore
import chrome from 'ui/chrome';
// @ts-ignore
import { FilterBarQueryFilterProvider } from 'ui/filter_bar/query_filter';
import { FilterBarQueryFilterProvider } from 'ui/filter_manager/query_filter';
// @ts-ignore
import { IPrivate } from 'ui/private';
import { EmbeddedVisualizeHandler } from './embedded_visualize_handler';

View File

@ -27,9 +27,9 @@ import classNames from 'classnames';
import React, { Component } from 'react';
import chrome from 'ui/chrome';
import { IndexPattern } from 'ui/index_patterns';
import { FilterEditor } from 'ui/filter_bar/filter_editor';
import { FilterEditor } from 'plugins/data/filter/filter_bar/filter_editor';
import { FilterItem } from './filter_item';
import { FilterOptions } from 'ui/filter_bar/filter_options';
import { FilterOptions } from 'plugins/data/filter/filter_bar/filter_options';
const config = chrome.getUiSettingsClient();

View File

@ -24,7 +24,7 @@ import { InjectedIntl, injectI18n } from '@kbn/i18n/react';
import classNames from 'classnames';
import React, { Component } from 'react';
import { IndexPattern } from 'ui/index_patterns';
import { FilterEditor } from 'ui/filter_bar/filter_editor';
import { FilterEditor } from 'plugins/data/filter/filter_bar/filter_editor';
import { FilterView } from './filter_view';
interface Props {
@ -64,7 +64,7 @@ class FilterItemUI extends Component<Props, State> {
const dataTestSubjValue = filter.meta.value ? `filter-value-${filter.meta.value}` : '';
const dataTestSubjDisabled = `filter-${
this.props.filter.meta.disabled ? 'disabled' : 'enabled'
}`;
}`;
const badge = (
<FilterView
@ -83,13 +83,13 @@ class FilterItemUI extends Component<Props, State> {
{
name: isFilterPinned(filter)
? this.props.intl.formatMessage({
id: 'common.ui.filterBar.unpinFilterButtonLabel',
defaultMessage: 'Unpin',
})
id: 'common.ui.filterBar.unpinFilterButtonLabel',
defaultMessage: 'Unpin',
})
: this.props.intl.formatMessage({
id: 'common.ui.filterBar.pinFilterButtonLabel',
defaultMessage: 'Pin across all apps',
}),
id: 'common.ui.filterBar.pinFilterButtonLabel',
defaultMessage: 'Pin across all apps',
}),
icon: 'pin',
onClick: () => {
this.closePopover();
@ -109,13 +109,13 @@ class FilterItemUI extends Component<Props, State> {
{
name: negate
? this.props.intl.formatMessage({
id: 'common.ui.filterBar.includeFilterButtonLabel',
defaultMessage: 'Include results',
})
id: 'common.ui.filterBar.includeFilterButtonLabel',
defaultMessage: 'Include results',
})
: this.props.intl.formatMessage({
id: 'common.ui.filterBar.excludeFilterButtonLabel',
defaultMessage: 'Exclude results',
}),
id: 'common.ui.filterBar.excludeFilterButtonLabel',
defaultMessage: 'Exclude results',
}),
icon: negate ? 'plusInCircle' : 'minusInCircle',
onClick: () => {
this.closePopover();
@ -126,13 +126,13 @@ class FilterItemUI extends Component<Props, State> {
{
name: disabled
? this.props.intl.formatMessage({
id: 'common.ui.filterBar.enableFilterButtonLabel',
defaultMessage: 'Re-enable',
})
id: 'common.ui.filterBar.enableFilterButtonLabel',
defaultMessage: 'Re-enable',
})
: this.props.intl.formatMessage({
id: 'common.ui.filterBar.disableFilterButtonLabel',
defaultMessage: 'Temporarily disable',
}),
id: 'common.ui.filterBar.disableFilterButtonLabel',
defaultMessage: 'Temporarily disable',
}),
icon: `${disabled ? 'eye' : 'eyeClosed'}`,
onClick: () => {
this.closePopover();

View File

@ -19,7 +19,7 @@ import React, { SFC } from 'react';
import {
existsOperator,
isOneOfOperator
} from 'ui/filter_bar/filter_editor/lib/filter_operators';
} from 'plugins/data/filter/filter_bar/filter_editor/lib/filter_operators';
interface Props {
filter: Filter;
@ -76,12 +76,12 @@ export const FilterView: SFC<Props> = ({ filter, ...rest }: Props) => {
<span>{getFilterDisplayText(filter)}</span>
</EuiBadge>
) : (
<EuiBadge
className={rest.className}
>
<span>{getFilterDisplayText(filter)}</span>
</EuiBadge>
);
<EuiBadge
className={rest.className}
>
<span>{getFilterDisplayText(filter)}</span>
</EuiBadge>
);
};
export function getFilterDisplayText(filter: Filter) {
@ -91,8 +91,8 @@ export function getFilterDisplayText(filter: Filter) {
const prefix = filter.meta.negate
? ` ${i18n.translate('common.ui.filterBar.negatedFilterPrefix', {
defaultMessage: 'NOT '
})}`
defaultMessage: 'NOT '
})}`
: '';
switch (filter.meta.type) {
@ -107,7 +107,7 @@ export function getFilterDisplayText(filter: Filter) {
case 'phrases':
return `${prefix}${filter.meta.key} ${isOneOfOperator.message} ${
filter.meta.value
}`;
}`;
case 'query_string':
return `${prefix}${filter.meta.value}`;
case 'range':

View File

@ -0,0 +1,380 @@
/*
* Author: Elasticsearch B.V.
* Updated by Wazuh, Inc.
*
* Copyright (C) 2015-2019 Wazuh, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Find more information about this on the LICENSE file.
*/
import { doesKueryExpressionHaveLuceneSyntaxError } from '@kbn/es-query';
import { IndexPattern } from 'ui/index_patterns';
import classNames from 'classnames';
import _ from 'lodash';
import { get, isEqual } from 'lodash';
import React, { Component } from 'react';
import { Storage } from 'ui/storage';
import { timeHistory } from 'ui/timefilter/time_history';
import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiLink, EuiSuperDatePicker } from '@elastic/eui';
// @ts-ignore
import { EuiSuperUpdateButton } from '@elastic/eui';
import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react';
import { documentationLinks } from 'ui/documentation_links';
import { Toast, toastNotifications } from 'ui/notify';
import chrome from 'ui/chrome';
import { PersistedLog } from 'ui/persisted_log';
import { QueryBarInput } from 'plugins/data/query/query_bar/components/query_bar_input';
import { getQueryLog } from 'plugins/data/query/query_bar/lib/get_query_log';
import { Query } from 'plugins/data/query/query_bar/index';
const config = chrome.getUiSettingsClient();
interface DateRange {
from: string;
to: string;
}
interface Props {
query: Query;
onSubmit: (payload: { dateRange: DateRange; query: Query }) => void;
disableAutoFocus?: boolean;
appName: string;
screenTitle: string;
indexPatterns: Array<IndexPattern | string>;
store: Storage;
intl: InjectedIntl;
prepend?: any;
showDatePicker?: boolean;
dateRangeFrom?: string;
dateRangeTo?: string;
isRefreshPaused?: boolean;
refreshInterval?: number;
showAutoRefreshOnly?: boolean;
onRefreshChange?: (options: { isPaused: boolean; refreshInterval: number }) => void;
customSubmitButton?: any;
}
interface State {
query: Query;
inputIsPristine: boolean;
currentProps?: Props;
dateRangeFrom: string;
dateRangeTo: string;
isDateRangeInvalid: boolean;
}
export class QueryBarUI extends Component<Props, State> {
public static getDerivedStateFromProps(nextProps: Props, prevState: State) {
if (isEqual(prevState.currentProps, nextProps)) {
return null;
}
let nextQuery = null;
if (nextProps.query.query !== prevState.query.query) {
nextQuery = {
query: nextProps.query.query,
language: nextProps.query.language,
};
} else if (nextProps.query.language !== prevState.query.language) {
nextQuery = {
query: '',
language: nextProps.query.language,
};
}
let nextDateRange = null;
if (
nextProps.dateRangeFrom !== get(prevState, 'currentProps.dateRangeFrom') ||
nextProps.dateRangeTo !== get(prevState, 'currentProps.dateRangeTo')
) {
nextDateRange = {
dateRangeFrom: nextProps.dateRangeFrom,
dateRangeTo: nextProps.dateRangeTo,
};
}
const nextState: any = {
currentProps: nextProps,
};
if (nextQuery) {
nextState.query = nextQuery;
}
if (nextDateRange) {
nextState.dateRangeFrom = nextDateRange.dateRangeFrom;
nextState.dateRangeTo = nextDateRange.dateRangeTo;
}
return nextState;
}
/*
Keep the "draft" value in local state until the user actually submits the query. There are a couple advantages:
1. Each app doesn't have to maintain its own "draft" value if it wants to put off updating the query in app state
until the user manually submits their changes. Most apps have watches on the query value in app state so we don't
want to trigger those on every keypress. Also, some apps (e.g. dashboard) already juggle multiple query values,
each with slightly different semantics and I'd rather not add yet another variable to the mix.
2. Changes to the local component state won't trigger an Angular digest cycle. Triggering digest cycles on every
keypress has been a major source of performance issues for us in previous implementations of the query bar.
See https://github.com/elastic/kibana/issues/14086
*/
public state = {
query: {
query: this.props.query.query,
language: this.props.query.language,
},
inputIsPristine: true,
currentProps: this.props,
dateRangeFrom: _.get(this.props, 'dateRangeFrom', 'now-15m'),
dateRangeTo: _.get(this.props, 'dateRangeTo', 'now'),
isDateRangeInvalid: false,
};
public inputRef: HTMLInputElement | null = null;
private persistedLog: PersistedLog | undefined;
public isDirty = () => {
if (!this.props.showDatePicker) {
return this.state.query.query !== this.props.query.query;
}
return (
this.state.query.query !== this.props.query.query ||
this.state.dateRangeFrom !== this.props.dateRangeFrom ||
this.state.dateRangeTo !== this.props.dateRangeTo
);
};
public onClickSubmitButton = (event: React.MouseEvent<HTMLButtonElement>) => {
if (this.persistedLog) {
this.persistedLog.add(this.state.query.query);
}
this.onSubmit(() => event.preventDefault());
};
public onChange = (query: Query) => {
this.setState({
query,
inputIsPristine: false,
});
};
public onTimeChange = ({
start,
end,
isInvalid,
isQuickSelection,
}: {
start: string;
end: string;
isInvalid: boolean;
isQuickSelection: boolean;
}) => {
this.setState(
{
dateRangeFrom: start,
dateRangeTo: end,
isDateRangeInvalid: isInvalid,
},
() => isQuickSelection && this.onSubmit()
);
};
public onSubmit = (preventDefault?: () => void) => {
if (preventDefault) {
preventDefault();
}
this.handleLuceneSyntaxWarning();
timeHistory.add({
from: this.state.dateRangeFrom,
to: this.state.dateRangeTo,
});
this.props.onSubmit({
query: {
query: this.state.query.query,
language: this.state.query.language,
},
dateRange: {
from: this.state.dateRangeFrom,
to: this.state.dateRangeTo,
},
});
};
private onInputSubmit = (query: Query) => {
this.setState({ query }, () => {
this.onSubmit();
});
};
public componentDidMount() {
this.persistedLog = getQueryLog(this.props.appName, this.props.query.language);
}
public componentDidUpdate(prevProps: Props) {
if (prevProps.query.language !== this.props.query.language) {
this.persistedLog = getQueryLog(this.props.appName, this.props.query.language);
}
}
public render() {
const classes = classNames('kbnQueryBar', {
'kbnQueryBar--withDatePicker': this.props.showDatePicker,
});
return (
<EuiFlexGroup className={classes} responsive={!!this.props.showDatePicker} gutterSize="s">
<EuiFlexItem>
<QueryBarInput
appName={this.props.appName}
disableAutoFocus={this.props.disableAutoFocus}
indexPatterns={this.props.indexPatterns}
prepend={this.props.prepend}
query={this.state.query}
screenTitle={this.props.screenTitle}
store={this.props.store}
onChange={this.onChange}
onSubmit={this.onInputSubmit}
persistedLog={this.persistedLog}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>{this.renderUpdateButton()}</EuiFlexItem>
</EuiFlexGroup>
);
}
private renderUpdateButton() {
const button = this.props.customSubmitButton ? (
React.cloneElement(this.props.customSubmitButton, { onClick: this.onClickSubmitButton })
) : (
<EuiSuperUpdateButton
needsUpdate={this.isDirty()}
isDisabled={this.state.isDateRangeInvalid}
onClick={this.onClickSubmitButton}
data-test-subj="querySubmitButton"
/>
);
if (!this.props.showDatePicker) {
return button;
}
return (
<EuiFlexGroup responsive={false} gutterSize="s">
{this.renderDatePicker()}
<EuiFlexItem grow={false}>{button}</EuiFlexItem>
</EuiFlexGroup>
);
}
private renderDatePicker() {
if (!this.props.showDatePicker) {
return null;
}
const recentlyUsedRanges = timeHistory
.get()
.map(({ from, to }: { from: string; to: string }) => {
return {
start: from,
end: to,
};
});
const commonlyUsedRanges = config
.get('timepicker:quickRanges')
.map(({ from, to, display }: { from: string; to: string; display: string }) => {
return {
start: from,
end: to,
label: display,
};
});
return (
<EuiFlexItem className="kbnQueryBar__datePickerWrapper">
<EuiSuperDatePicker
start={this.state.dateRangeFrom}
end={this.state.dateRangeTo}
isPaused={this.props.isRefreshPaused}
refreshInterval={this.props.refreshInterval}
onTimeChange={this.onTimeChange}
onRefreshChange={this.props.onRefreshChange}
showUpdateButton={false}
recentlyUsedRanges={recentlyUsedRanges}
commonlyUsedRanges={commonlyUsedRanges}
dateFormat={config.get('dateFormat')}
isAutoRefreshOnly={this.props.showAutoRefreshOnly}
/>
</EuiFlexItem>
);
}
private handleLuceneSyntaxWarning() {
const { intl, store } = this.props;
const { query, language } = this.state.query;
if (
language === 'kuery' &&
typeof query === 'string' &&
!store.get('kibana.luceneSyntaxWarningOptOut') &&
doesKueryExpressionHaveLuceneSyntaxError(query)
) {
const toast = toastNotifications.addWarning({
title: intl.formatMessage({
id: 'data.query.queryBar.luceneSyntaxWarningTitle',
defaultMessage: 'Lucene syntax warning',
}),
text: (
<div>
<p>
<FormattedMessage
id="data.query.queryBar.luceneSyntaxWarningMessage"
defaultMessage="It looks like you may be trying to use Lucene query syntax, although you
have Kibana Query Language (KQL) selected. Please review the KQL docs {link}."
values={{
link: (
<EuiLink href={documentationLinks.query.kueryQuerySyntax} target="_blank">
<FormattedMessage
id="data.query.queryBar.syntaxOptionsDescription.docsLinkText"
defaultMessage="here"
/>
</EuiLink>
),
}}
/>
</p>
<EuiFlexGroup justifyContent="flexEnd" gutterSize="s">
<EuiFlexItem grow={false}>
<EuiButton size="s" onClick={() => this.onLuceneSyntaxWarningOptOut(toast)}>
Don't show again
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</div>
),
});
}
}
private onLuceneSyntaxWarningOptOut(toast: Toast) {
this.props.store.set('kibana.luceneSyntaxWarningOptOut', true);
toastNotifications.remove(toast);
}
}
// @ts-ignore
export const QueryBar = injectI18n(QueryBarUI);

View File

@ -13,36 +13,34 @@
*/
// @ts-ignore
import { data } from 'plugins/data';
import { EuiFilterButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { Filter } from '@kbn/es-query';
import { InjectedIntl, injectI18n } from '@kbn/i18n/react';
import classNames from 'classnames';
import React, { Component } from 'react';
import ResizeObserver from 'resize-observer-polyfill';
import { FilterBar } from './filter_bar';
import { IndexPattern } from 'ui/index_patterns';
const { QueryBar } = data.query.ui;
import { Storage } from 'ui/storage';
interface Query {
query: string;
language: string;
}
import { QueryBar } from './query_bar';
import { Query } from 'plugins/data/query/query_bar/index';
import { FilterBar } from './filter_bar';
interface DateRange {
from: string;
to: string;
}
/**
* NgReact lib requires that changes to the props need to be made in the directive config as well
* See [search_bar\directive\index.js] file
*/
interface Props {
query: {
query: string;
language: string;
};
query: Query;
onQuerySubmit: (payload: { dateRange: DateRange; query: Query }) => void;
disableAutoFocus?: boolean;
appName: string;
screenTitle: string;
indexPatterns: IndexPattern[];
store: Storage;
filters: Filter[];
@ -87,9 +85,9 @@ class SearchBarUI extends Component<Props, State> {
};
// member-ordering rules conflict with use-before-declaration rules
/* tslint:disable */
/* eslint-disable */
public ro = new ResizeObserver(this.setFilterBarHeight);
/* tslint:enable */
/* eslint-enable */
public toggleFiltersVisible = () => {
this.setState({
@ -113,25 +111,25 @@ class SearchBarUI extends Component<Props, State> {
public render() {
const filtersAppliedText = this.props.intl.formatMessage({
id: 'common.ui.searchBar.filtersButtonFiltersAppliedTitle',
id: 'data.search.searchBar.filtersButtonFiltersAppliedTitle',
defaultMessage: 'filters applied.',
});
const clickToShowOrHideText = this.state.isFiltersVisible
? this.props.intl.formatMessage({
id: 'common.ui.searchBar.filtersButtonClickToShowTitle',
defaultMessage: 'Select to hide',
})
id: 'data.search.searchBar.filtersButtonClickToShowTitle',
defaultMessage: 'Select to hide',
})
: this.props.intl.formatMessage({
id: 'common.ui.searchBar.filtersButtonClickToHideTitle',
defaultMessage: 'Select to show',
});
id: 'data.search.searchBar.filtersButtonClickToHideTitle',
defaultMessage: 'Select to show',
});
const filterTriggerButton = (
<EuiFilterButton
onClick={this.toggleFiltersVisible}
isSelected={this.state.isFiltersVisible}
hasActiveFilters={this.state.isFiltersVisible}
numFilters={this.props.filters.length > 0 ? this.props.filters.length : null}
numFilters={this.props.filters.length > 0 ? this.props.filters.length : undefined}
aria-controls="GlobalFilterGroup"
aria-expanded={!!this.state.isFiltersVisible}
title={`${this.props.filters.length} ${filtersAppliedText} ${clickToShowOrHideText}`}
@ -149,6 +147,7 @@ class SearchBarUI extends Component<Props, State> {
{this.props.showQueryBar ? (
<QueryBar
query={this.props.query}
screenTitle={this.props.screenTitle}
onSubmit={this.props.onQuerySubmit}
appName={this.props.appName}
indexPatterns={this.props.indexPatterns}
@ -163,8 +162,8 @@ class SearchBarUI extends Component<Props, State> {
onRefreshChange={this.props.onRefreshChange}
/>
) : (
''
)}
''
)}
{this.props.showFilterBar ? (
<div
@ -188,8 +187,8 @@ class SearchBarUI extends Component<Props, State> {
</div>
</div>
) : (
''
)}
''
)}
</div>
);
}

View File

@ -5,101 +5,56 @@
<div data-transclude-slots>
<!-- Breadcrumbs. -->
<div data-transclude-slot="topLeftCorner" class="kuiLocalBreadcrumbs">
<h1 tabindex="0" id="kui_local_breadcrumb" class="kuiLocalBreadcrumb" ng-if="opts.savedSearch.id">
<h1 id="kui_local_breadcrumb" class="kuiLocalBreadcrumb" ng-if="opts.savedSearch.id">
<span class="kuiLocalBreadcrumb__emphasis">
<span
id="reload_saved_search"
aria-label="{{::'kbn.discover.reloadSavedSearchAriaLabel' | i18n: {defaultMessage: 'Reload saved search'} }}"
<button class="kuiLink" type="button" id="reload_saved_search" aria-label="{{::'kbn.discover.reloadSavedSearchAriaLabel' | i18n: {defaultMessage: 'Reload saved search'} }}"
tooltip="{{::'kbn.discover.reloadSavedSearchTooltip' | i18n: {defaultMessage: 'Reload saved search'} }}"
tooltip-placement="right"
tooltip-append-to-body="1"
ng-click="resetQuery()"
kbn-accessible-click
class="kuiIcon fa-undo small"
></span>&nbsp;
tooltip-placement="right" tooltip-append-to-body="1" ng-click="resetQuery()">
<span class="kuiIcon fa-undo small"></span>
{{::'kbn.discover.reloadSavedSearchButton' | i18n: {defaultMessage: 'Reload'} }}
</button>
</span>
</h1>
<div class="kuiLocalBreadcrumb">
<span data-test-subj="discoverQueryHits" class="kuiLocalBreadcrumb__emphasis">{{(hits || 0) | number:0}}</span>
<span
i18n-id="kbn.discover.hitsPluralTitle"
i18n-default-message="{hits, plural, one {hit} other {hits}}"
i18n-values="{ hits }"
></span>
<span i18n-id="kbn.discover.hitsPluralTitle" i18n-default-message="{hits, plural, one {hit} other {hits}}"
i18n-values="{ hits }"></span>
</div>
</div>
<!-- Search. -->
<div data-transclude-slot="bottomRow" class="fullWidth">
<wz-search-bar
query="state.query"
screen-title="screenTitle"
on-query-submit="updateQueryAndFetch"
app-name="'discover'"
index-patterns="[indexPattern]"
filters="filters"
on-filters-updated="onFiltersUpdated"
show-date-picker="enableTimeRangeSelector"
date-range-from="time.from"
date-range-to="time.to"
is-refresh-paused="refreshInterval.pause"
refresh-interval="refreshInterval.value"
on-refresh-change="onRefreshChange"
></wz-search-bar>
<wz-search-bar query="state.query" screen-title="screenTitle" on-query-submit="updateQueryAndFetch" app-name="'discover'"
index-patterns="[indexPattern]" filters="filters" on-filters-updated="onFiltersUpdated" show-date-picker="enableTimeRangeSelector"
date-range-from="time.from" date-range-to="time.to" is-refresh-paused="refreshInterval.pause"
refresh-interval="refreshInterval.value" on-refresh-change="onRefreshChange">
</wz-search-bar>
</div>
</div>
</kbn-top-nav>
<main class="container-fluid">
<div class="row">
<div class="col-md-2 sidebar-container collapsible-sidebar" id="discover-sidebar">
<disc-field-chooser
class="dscFieldChooser"
columns="state.columns"
hits="rows"
field-counts="fieldCounts"
index-pattern="searchSource.getField('index')"
index-pattern-list="opts.indexPatternList"
state="state"
on-add-field="addColumn"
on-add-filter="filterQuery"
on-remove-field="removeColumn"
>
<disc-field-chooser class="dscFieldChooser" columns="state.columns" hits="rows" field-counts="fieldCounts"
index-pattern="searchSource.getField('index')" index-pattern-list="opts.indexPatternList" state="state"
on-add-field="addColumn" on-add-filter="filterQuery" on-remove-field="removeColumn">
</disc-field-chooser>
</div>
<div class="dscWrapper col-md-10">
<div class="dscWrapper__content">
<discover-unsupported-index-pattern
ng-if="isUnsupportedIndexPattern"
unsupported-type="unsupportedIndexPatternType"
></discover-unsupported-index-pattern>
<discover-unsupported-index-pattern ng-if="isUnsupportedIndexPattern" unsupported-type="unsupportedIndexPatternType"></discover-unsupported-index-pattern>
<discover-no-results
ng-show="resultState === 'none'"
shard-failures="failures"
time-field-name="opts.timefield"
query-language="state.query.language"
get-doc-link="getDocLink"
></discover-no-results>
<discover-no-results ng-show="resultState === 'none'" shard-failures="failures" time-field-name="opts.timefield"
query-language="state.query.language" get-doc-link="getDocLink"></discover-no-results>
<!-- loading -->
<div ng-show="resultState === 'loading'">
<discover-fetch-error
ng-show="fetchError"
fetch-error="fetchError"
></discover-fetch-error>
<discover-fetch-error ng-show="fetchError" fetch-error="fetchError"></discover-fetch-error>
<div
ng-hide="fetchError"
class="dscOverlay"
>
<h2
i18n-id="kbn.discover.searchingTitle"
i18n-default-message="Searching"
class="euiTitle euiTitle--small"
></h2>
<div ng-hide="fetchError" class="dscOverlay">
<h2 i18n-id="kbn.discover.searchingTitle" i18n-default-message="Searching" class="euiTitle euiTitle--small"></h2>
<div class="euiSpacer euiSpacer--m"></div>
<div class="euiLoadingSpinner euiLoadingSpinner--large" data-test-subj="loadingSpinner"></div>
</div>
@ -107,112 +62,61 @@
<!-- result -->
<div class="dscResults" ng-show="resultState === 'ready'">
<button
class="kuiButton kuiButton--basic kuiButton--iconText dscSkipButton"
ng-click="showAllRows(); scrollToBottom()"
>
<button class="kuiButton kuiButton--basic kuiButton--iconText dscSkipButton" ng-click="showAllRows(); scrollToBottom()">
<span class="kuiButton__inner">
<span aria-hidden="true" class="kuiButton__icon kuiIcon fa-chevron-down"></span>
<span
i18n-id="kbn.discover.skipToBottomButtonLabel"
i18n-default-message="Skip to bottom"
></span>
<span i18n-id="kbn.discover.skipToBottomButtonLabel" i18n-default-message="Skip to bottom"></span>
</span>
</button>
<section
aria-label="{{::'kbn.discover.histogramOfFoundDocumentsAriaLabel' | i18n: {defaultMessage: 'Histogram of found documents'} }}"
class="dscTimechart"
ng-if="opts.timefield"
>
<section aria-label="{{::'kbn.discover.histogramOfFoundDocumentsAriaLabel' | i18n: {defaultMessage: 'Histogram of found documents'} }}"
class="dscTimechart" ng-if="opts.timefield">
<header class="dscTimechart__header">
<div class="small">
<span
tooltip="{{::'kbn.discover.howToChangeTheTimeTooltip' | i18n: {defaultMessage: 'To change the time, click the clock icon in the navigation bar'} }}"
>
<label for="dscResultsIntervalSelector" tooltip="{{::'kbn.discover.howToChangeTheTimeTooltip' | i18n: {defaultMessage: 'To change the time, click the clock icon in the navigation bar'} }}">
{{toMoment(timeRange.from)}} - {{toMoment(timeRange.to)}}
</span>
</label>
&mdash;
<span class="form-inline">
<select
class="dscResults__interval form-control"
ng-model="state.interval"
<select id="dscResultsIntervalSelector" class="dscResults__interval form-control" ng-model="state.interval"
ng-options="interval.val as interval.display for interval in intervalOptions | filter: intervalEnabled"
ng-blur="toggleInterval()"
data-test-subj="discoverIntervalSelect"
>
ng-blur="toggleInterval()" data-test-subj="discoverIntervalSelect">
</select>
<span ng-if="bucketInterval.scaled">
<icon-tip
content="getBucketIntervalToolTipText()"
position="'top'"
></icon-tip>
<span
i18n-id="kbn.discover.scaledToDescription"
i18n-default-message="Scaled to {bucketIntervalDescription}"
<icon-tip content="getBucketIntervalToolTipText()" position="'top'"></icon-tip>
<span i18n-id="kbn.discover.scaledToDescription" i18n-default-message="Scaled to {bucketIntervalDescription}"
i18n-values="{
bucketIntervalDescription: bucketInterval.description
}"
></span>
bucketIntervalDescription: bucketInterval.description
}"></span>
</span>
</span>
</div>
</header>
<div id="discoverHistogram"
ng-show="vis && rows.length !== 0"
style="display: flex; height: 200px"
>
<div id="discoverHistogram" ng-show="vis && rows.length !== 0" style="display: flex; height: 200px">
</div>
</section>
<section
class="dscTable"
fixed-scroll
aria-label="{{::'kbn.discover.documentsAriaLabel' | i18n: {defaultMessage: 'Documents'} }}"
>
<doc-table
hits="rows"
index-pattern="indexPattern"
sorting="state.sort"
columns="state.columns"
infinite-scroll="true"
filter="filterQuery"
filters="state.filters"
data-shared-item
data-title="{{opts.savedSearch.lastSavedTitle}}"
data-description="{{opts.savedSearch.description}}"
minimum-visible-rows="minimumVisibleRows"
render-complete
on-add-column="addColumn"
on-change-sort-order="setSortOrder"
on-move-column="moveColumn"
on-remove-column="removeColumn"
></doc-table>
<section class="dscTable" fixed-scroll aria-label="{{::'kbn.discover.documentsAriaLabel' | i18n: {defaultMessage: 'Documents'} }}">
<doc-table hits="rows" index-pattern="indexPattern" sorting="state.sort" columns="state.columns"
infinite-scroll="true" filter="filterQuery" filters="state.filters" data-shared-item data-title="{{opts.savedSearch.lastSavedTitle}}"
data-description="{{opts.savedSearch.description}}" minimum-visible-rows="minimumVisibleRows"
render-complete on-add-column="addColumn" on-change-sort-order="setSortOrder" on-move-column="moveColumn"
on-remove-column="removeColumn"></doc-table>
<a tabindex="0" id="discoverBottomMarker"></a>
<div
ng-if="rows.length == opts.sampleSize"
class="dscTable__footer"
>
<span
i18n-id="kbn.discover.howToSeeOtherMatchingDocumentsDescription"
i18n-default-message="These are the first {sampleSize} documents matching
your search, refine your search to see others. "
<div ng-if="rows.length == opts.sampleSize" class="dscTable__footer">
<span i18n-id="kbn.discover.howToSeeOtherMatchingDocumentsDescription" i18n-default-message="These are the first {sampleSize} documents matching
your search, refine your search to see others. "
i18n-values="{
sampleSize: opts.sampleSize,
}"
></span>
<a
kbn-accessible-click
ng-click="scrollToTop()"
i18n-id="kbn.discover.backToTopLinkText"
i18n-default-message="Back to top."
></a>
sampleSize: opts.sampleSize,
}"></span>
<a kbn-accessible-click ng-click="scrollToTop()" i18n-id="kbn.discover.backToTopLinkText"
i18n-default-message="Back to top."></a>
</div>
</section>
</div>
@ -220,4 +124,4 @@
</div>
</div>
</main>
</discover-app-w>
</discover-app-w>

View File

@ -1,11 +1,15 @@
<discover-app-w class="app-container">
<!-- Local nav. -->
<div data-transclude-slot="topLeftCorner" class="kuiLocalBreadcrumbs" ng-if="tabView === 'discover'">
<h1 tabindex="0" id="kui_local_breadcrumb" class="kuiLocalBreadcrumb" ng-if="opts.savedSearch.id">
<!-- Breadcrumbs. -->
<h1 id="kui_local_breadcrumb" class="kuiLocalBreadcrumb" ng-if="opts.savedSearch.id">
<span class="kuiLocalBreadcrumb__emphasis">
<span id="reload_saved_search" aria-label="{{::'kbn.discover.reloadSavedSearchAriaLabel' | i18n: {defaultMessage: 'Reload saved search'} }}"
<button class="kuiLink" type="button" id="reload_saved_search" aria-label="{{::'kbn.discover.reloadSavedSearchAriaLabel' | i18n: {defaultMessage: 'Reload saved search'} }}"
tooltip="{{::'kbn.discover.reloadSavedSearchTooltip' | i18n: {defaultMessage: 'Reload saved search'} }}"
tooltip-placement="right" tooltip-append-to-body="1" ng-click="resetQuery()" kbn-accessible-click class="kuiIcon fa-undo small"></span>&nbsp;
tooltip-placement="right" tooltip-append-to-body="1" ng-click="resetQuery()">
<span class="kuiIcon fa-undo small"></span>
{{::'kbn.discover.reloadSavedSearchButton' | i18n: {defaultMessage: 'Reload'} }}
</button>
</span>
</h1>
<div class="kuiLocalBreadcrumb">
@ -19,8 +23,8 @@
<div data-transclude-slots>
<!-- Search. -->
<div data-transclude-slot="bottomRow" class="fullWidth">
<wz-search-bar query="state.query" on-query-submit="updateQueryAndFetch" app-name="'discover'" index-patterns="[indexPattern]"
filters="filters" on-filters-updated="onFiltersUpdated" show-date-picker="enableTimeRangeSelector"
<wz-search-bar query="state.query" screen-title="screenTitle" on-query-submit="updateQueryAndFetch" app-name="'discover'"
index-patterns="[indexPattern]" filters="filters" on-filters-updated="onFiltersUpdated" show-date-picker="enableTimeRangeSelector"
date-range-from="time.from" date-range-to="time.to" is-refresh-paused="refreshInterval.pause"
refresh-interval="refreshInterval.value" on-refresh-change="onRefreshChange" watch-depth="reference"
show-filter-bar="tabView !== 'cluster-monitoring'"></wz-search-bar>
@ -51,7 +55,7 @@
<div ng-hide="fetchError" class="dscOverlay">
<h2 i18n-id="kbn.discover.searchingTitle" i18n-default-message="Searching" class="euiTitle euiTitle--small"></h2>
<div class="euiSpacer euiSpacer--m"></div>
<div class="euiLoadingSpinner euiLoadingSpinner--large"></div>
<div class="euiLoadingSpinner euiLoadingSpinner--large" data-test-subj="loadingSpinner"></div>
<div class="euiSpacer euiSpacer--m"></div>
<div ng-show="fetchStatus">{{fetchStatus.complete}} / {{fetchStatus.total}}</div>
</div>
@ -70,14 +74,15 @@
class="dscTimechart" ng-if="opts.timefield">
<header class="dscTimechart__header">
<div class="small">
<span tooltip="{{::'kbn.discover.howToChangeTheTimeTooltip' | i18n: {defaultMessage: 'To change the time, click the clock icon in the navigation bar'} }}">
<label for="dscResultsIntervalSelector" tooltip="{{::'kbn.discover.howToChangeTheTimeTooltip' | i18n: {defaultMessage: 'To change the time, click the clock icon in the navigation bar'} }}">
{{toMoment(timeRange.from)}} - {{toMoment(timeRange.to)}}
</span>
</label>
&mdash;
<span class="form-inline">
<select class="dscResults__interval form-control" ng-model="state.interval" ng-options="interval.val as interval.display for interval in intervalOptions | filter: intervalEnabled"
<select id="dscResultsIntervalSelector" class="dscResults__interval form-control" ng-model="state.interval"
ng-options="interval.val as interval.display for interval in intervalOptions | filter: intervalEnabled"
ng-blur="toggleInterval()" data-test-subj="discoverIntervalSelect">
</select>
<span ng-if="bucketInterval.scaled">