mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Discover] Support storing time with saved searches (#138377)
* [Discover] Implement UI for storing time with a saved search * [Discover] Save time range data with a saved search * [Discover] Improve updating of values * [Discover] Restore time range after loading a saved search * [Discover] Add time range validation * [Discover] Add refresh interval validation * [Discover] Update how saved search gets restored * [Discover] Improve tests * [Discover] Update tests * [Discover] Improve type imports * [Discover] Update copy * [Discover] Fix types after the merge * [Discover] Update test name * [Discover] Fix types * [Discover] Update mapping * [Discover] Update mapping * Explicitly set field limit for .kibana_ esArchives Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Rudolf Meijering <skaapgif@gmail.com>
This commit is contained in:
parent
ac0688b90f
commit
1a70f6fd37
22 changed files with 351 additions and 17 deletions
|
@ -6,8 +6,10 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiFormRow, EuiSwitch } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { SavedObjectSaveModal, showSaveModal, OnSaveProps } from '@kbn/saved-objects-plugin/public';
|
||||
import { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { SavedSearch, SaveSavedSearchOptions } from '@kbn/saved-search-plugin/public';
|
||||
|
@ -108,20 +110,24 @@ export async function onSaveSearch({
|
|||
const onSave = async ({
|
||||
newTitle,
|
||||
newCopyOnSave,
|
||||
newTimeRestore,
|
||||
newDescription,
|
||||
isTitleDuplicateConfirmed,
|
||||
onTitleDuplicate,
|
||||
}: {
|
||||
newTitle: string;
|
||||
newTimeRestore: boolean;
|
||||
newCopyOnSave: boolean;
|
||||
newDescription: string;
|
||||
isTitleDuplicateConfirmed: boolean;
|
||||
onTitleDuplicate: () => void;
|
||||
}) => {
|
||||
const currentTitle = savedSearch.title;
|
||||
const currentTimeRestore = savedSearch.timeRestore;
|
||||
const currentRowsPerPage = savedSearch.rowsPerPage;
|
||||
savedSearch.title = newTitle;
|
||||
savedSearch.description = newDescription;
|
||||
savedSearch.timeRestore = newTimeRestore;
|
||||
savedSearch.rowsPerPage = uiSettings.get(DOC_TABLE_LEGACY)
|
||||
? currentRowsPerPage
|
||||
: state.appStateContainer.getState().rowsPerPage;
|
||||
|
@ -143,6 +149,7 @@ export async function onSaveSearch({
|
|||
// If the save wasn't successful, put the original values back.
|
||||
if (!response.id || response.error) {
|
||||
savedSearch.title = currentTitle;
|
||||
savedSearch.timeRestore = currentTimeRestore;
|
||||
savedSearch.rowsPerPage = currentRowsPerPage;
|
||||
} else {
|
||||
state.resetInitialAppState();
|
||||
|
@ -156,6 +163,7 @@ export async function onSaveSearch({
|
|||
title={savedSearch.title ?? ''}
|
||||
showCopyOnSave={!!savedSearch.id}
|
||||
description={savedSearch.description}
|
||||
timeRestore={savedSearch.timeRestore}
|
||||
onSave={onSave}
|
||||
onClose={onClose ?? (() => {})}
|
||||
/>
|
||||
|
@ -167,13 +175,42 @@ const SaveSearchObjectModal: React.FC<{
|
|||
title: string;
|
||||
showCopyOnSave: boolean;
|
||||
description?: string;
|
||||
onSave: (props: OnSaveProps & { newRowsPerPage?: number }) => void;
|
||||
timeRestore?: boolean;
|
||||
onSave: (props: OnSaveProps & { newTimeRestore: boolean }) => void;
|
||||
onClose: () => void;
|
||||
}> = ({ title, description, showCopyOnSave, onSave, onClose }) => {
|
||||
}> = ({ title, description, showCopyOnSave, timeRestore: savedTimeRestore, onSave, onClose }) => {
|
||||
const [timeRestore, setTimeRestore] = useState<boolean>(savedTimeRestore || false);
|
||||
|
||||
const onModalSave = (params: OnSaveProps) => {
|
||||
onSave(params);
|
||||
onSave({
|
||||
...params,
|
||||
newTimeRestore: timeRestore,
|
||||
});
|
||||
};
|
||||
|
||||
const options = (
|
||||
<EuiFormRow
|
||||
helpText={
|
||||
<FormattedMessage
|
||||
id="discover.topNav.saveModal.storeTimeWithSearchToggleDescription"
|
||||
defaultMessage="Update the time filter and refresh interval to the current selection when using this search."
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiSwitch
|
||||
data-test-subj="storeTimeWithSearch"
|
||||
checked={timeRestore}
|
||||
onChange={(event) => setTimeRestore(event.target.checked)}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="discover.topNav.saveModal.storeTimeWithSearchToggleLabel"
|
||||
defaultMessage="Store time with saved search"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
);
|
||||
|
||||
return (
|
||||
<SavedObjectSaveModal
|
||||
title={title}
|
||||
|
@ -183,6 +220,7 @@ const SaveSearchObjectModal: React.FC<{
|
|||
defaultMessage: 'search',
|
||||
})}
|
||||
showDescription={true}
|
||||
options={options}
|
||||
onSave={onModalSave}
|
||||
onClose={onClose}
|
||||
/>
|
||||
|
|
|
@ -32,6 +32,7 @@ import { LoadingIndicator } from '../../components/common/loading_indicator';
|
|||
import { DiscoverError } from '../../components/common/error_alert';
|
||||
import { useDiscoverServices } from '../../hooks/use_discover_services';
|
||||
import { getUrlTracker } from '../../kibana_services';
|
||||
import { restoreStateFromSavedSearch } from '../../services/saved_searches/restore_from_saved_search';
|
||||
|
||||
const DiscoverMainAppMemoized = memo(DiscoverMainApp);
|
||||
|
||||
|
@ -129,6 +130,11 @@ export function DiscoverMainRoute(props: Props) {
|
|||
currentSavedSearch.searchSource.setField('index', currentDataView);
|
||||
}
|
||||
|
||||
restoreStateFromSavedSearch({
|
||||
savedSearch: currentSavedSearch,
|
||||
timefilter: services.timefilter,
|
||||
});
|
||||
|
||||
setSavedSearch(currentSavedSearch);
|
||||
|
||||
if (currentSavedSearch.id) {
|
||||
|
@ -163,8 +169,9 @@ export function DiscoverMainRoute(props: Props) {
|
|||
}
|
||||
}, [
|
||||
id,
|
||||
services.data.search,
|
||||
services.data,
|
||||
services.spaces,
|
||||
services.timefilter,
|
||||
core.savedObjects.client,
|
||||
core.application.navigateToApp,
|
||||
core.theme,
|
||||
|
|
|
@ -34,6 +34,7 @@ import { FetchStatus } from '../../types';
|
|||
import { getDataViewAppState } from '../utils/get_switch_data_view_app_state';
|
||||
import { SortPairArr } from '../../../components/doc_table/utils/get_sort';
|
||||
import { DataTableRecord } from '../../../types';
|
||||
import { restoreStateFromSavedSearch } from '../../../services/saved_searches/restore_from_saved_search';
|
||||
|
||||
const MAX_NUM_OF_COLUMNS = 50;
|
||||
|
||||
|
@ -193,6 +194,12 @@ export function useDiscoverState({
|
|||
savedSearch: newSavedSearch,
|
||||
storage,
|
||||
});
|
||||
|
||||
restoreStateFromSavedSearch({
|
||||
savedSearch: newSavedSearch,
|
||||
timefilter: services.timefilter,
|
||||
});
|
||||
|
||||
await stateContainer.replaceUrlAppState(newAppState);
|
||||
setState(newAppState);
|
||||
},
|
||||
|
|
|
@ -69,6 +69,20 @@ export async function persistSavedSearch(
|
|||
savedSearch.isTextBasedQuery = isTextBasedQuery;
|
||||
}
|
||||
|
||||
const { from, to } = services.timefilter.getTime();
|
||||
const refreshInterval = services.timefilter.getRefreshInterval();
|
||||
savedSearch.timeRange =
|
||||
savedSearch.timeRestore || savedSearch.timeRange
|
||||
? {
|
||||
from,
|
||||
to,
|
||||
}
|
||||
: undefined;
|
||||
savedSearch.refreshInterval =
|
||||
savedSearch.timeRestore || savedSearch.refreshInterval
|
||||
? { value: refreshInterval.value, pause: refreshInterval.pause }
|
||||
: undefined;
|
||||
|
||||
try {
|
||||
const id = await saveSavedSearch(savedSearch, saveOptions, services.core.savedObjects.client);
|
||||
if (id) {
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import dateMath from '@kbn/datemath';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { ToastsStart } from '@kbn/core/public';
|
||||
import { isTimeRangeValid } from '../../../utils/validate_time';
|
||||
|
||||
/**
|
||||
* Validates a given time filter range, provided by URL or UI
|
||||
|
@ -18,9 +18,7 @@ export function validateTimeRange(
|
|||
{ from, to }: { from: string; to: string },
|
||||
toastNotifications: ToastsStart
|
||||
): boolean {
|
||||
const fromMoment = dateMath.parse(from);
|
||||
const toMoment = dateMath.parse(to);
|
||||
if (!fromMoment || !toMoment || !fromMoment.isValid() || !toMoment.isValid()) {
|
||||
if (!isTimeRangeValid({ from, to })) {
|
||||
toastNotifications.addDanger({
|
||||
title: i18n.translate('discover.notifications.invalidTimeRangeTitle', {
|
||||
defaultMessage: `Invalid time range`,
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { TimefilterContract } from '@kbn/data-plugin/public';
|
||||
import type { TimeRange, RefreshInterval } from '@kbn/data-plugin/common';
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { restoreStateFromSavedSearch } from './restore_from_saved_search';
|
||||
|
||||
describe('discover restore state from saved search', () => {
|
||||
let timefilterMock: TimefilterContract;
|
||||
const timeRange: TimeRange = {
|
||||
from: 'now-30m',
|
||||
to: 'now',
|
||||
};
|
||||
const refreshInterval: RefreshInterval = {
|
||||
value: 5000,
|
||||
pause: false,
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
timefilterMock = {
|
||||
setTime: jest.fn(),
|
||||
setRefreshInterval: jest.fn(),
|
||||
} as unknown as TimefilterContract;
|
||||
});
|
||||
|
||||
test('should not update timefilter if attributes are not set', async () => {
|
||||
restoreStateFromSavedSearch({
|
||||
savedSearch: {} as SavedSearch,
|
||||
timefilter: timefilterMock,
|
||||
});
|
||||
|
||||
expect(timefilterMock.setTime).not.toHaveBeenCalled();
|
||||
expect(timefilterMock.setRefreshInterval).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should not update timefilter if timeRestore is disabled', async () => {
|
||||
restoreStateFromSavedSearch({
|
||||
savedSearch: {
|
||||
timeRestore: false,
|
||||
timeRange,
|
||||
refreshInterval,
|
||||
} as SavedSearch,
|
||||
timefilter: timefilterMock,
|
||||
});
|
||||
|
||||
expect(timefilterMock.setTime).not.toHaveBeenCalled();
|
||||
expect(timefilterMock.setRefreshInterval).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should update timefilter if timeRestore is enabled', async () => {
|
||||
restoreStateFromSavedSearch({
|
||||
savedSearch: {
|
||||
timeRestore: true,
|
||||
timeRange,
|
||||
refreshInterval,
|
||||
} as SavedSearch,
|
||||
timefilter: timefilterMock,
|
||||
});
|
||||
|
||||
expect(timefilterMock.setTime).toHaveBeenCalledWith(timeRange);
|
||||
expect(timefilterMock.setRefreshInterval).toHaveBeenCalledWith(refreshInterval);
|
||||
});
|
||||
|
||||
test('should not update timefilter if attributes are missing', async () => {
|
||||
restoreStateFromSavedSearch({
|
||||
savedSearch: {
|
||||
timeRestore: true,
|
||||
} as SavedSearch,
|
||||
timefilter: timefilterMock,
|
||||
});
|
||||
|
||||
expect(timefilterMock.setTime).not.toHaveBeenCalled();
|
||||
expect(timefilterMock.setRefreshInterval).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should not update timefilter if attributes are invalid', async () => {
|
||||
restoreStateFromSavedSearch({
|
||||
savedSearch: {
|
||||
timeRestore: true,
|
||||
timeRange: {
|
||||
from: 'test',
|
||||
to: 'now',
|
||||
},
|
||||
refreshInterval: {
|
||||
pause: false,
|
||||
value: -500,
|
||||
},
|
||||
} as SavedSearch,
|
||||
timefilter: timefilterMock,
|
||||
});
|
||||
|
||||
expect(timefilterMock.setTime).not.toHaveBeenCalled();
|
||||
expect(timefilterMock.setRefreshInterval).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { TimefilterContract } from '@kbn/data-plugin/public';
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { isRefreshIntervalValid, isTimeRangeValid } from '../../utils/validate_time';
|
||||
|
||||
export const restoreStateFromSavedSearch = ({
|
||||
savedSearch,
|
||||
timefilter,
|
||||
}: {
|
||||
savedSearch: SavedSearch;
|
||||
timefilter: TimefilterContract;
|
||||
}) => {
|
||||
if (!savedSearch) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (savedSearch.timeRestore && savedSearch.timeRange && isTimeRangeValid(savedSearch.timeRange)) {
|
||||
timefilter.setTime(savedSearch.timeRange);
|
||||
}
|
||||
if (
|
||||
savedSearch.timeRestore &&
|
||||
savedSearch.refreshInterval &&
|
||||
isRefreshIntervalValid(savedSearch.refreshInterval)
|
||||
) {
|
||||
timefilter.setRefreshInterval(savedSearch.refreshInterval);
|
||||
}
|
||||
};
|
38
src/plugins/discover/public/utils/validate_time.test.ts
Normal file
38
src/plugins/discover/public/utils/validate_time.test.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { RefreshInterval, TimeRange } from '@kbn/data-plugin/common';
|
||||
import { isTimeRangeValid, isRefreshIntervalValid } from './validate_time';
|
||||
|
||||
describe('discover validate time', () => {
|
||||
test('should validate time ranges correctly', async () => {
|
||||
expect(isTimeRangeValid({ from: '2020-06-02T13:36:13.689Z', to: 'now' })).toEqual(true);
|
||||
expect(isTimeRangeValid({ from: 'now', to: 'now+1h' })).toEqual(true);
|
||||
expect(isTimeRangeValid({ from: '', to: '' })).toEqual(false);
|
||||
expect(isTimeRangeValid({} as unknown as TimeRange)).toEqual(false);
|
||||
expect(isTimeRangeValid(undefined)).toEqual(false);
|
||||
});
|
||||
|
||||
test('should validate that refresh interval is valid', async () => {
|
||||
expect(isRefreshIntervalValid({ value: 5000, pause: false })).toEqual(true);
|
||||
expect(isRefreshIntervalValid({ value: 0, pause: false })).toEqual(true);
|
||||
expect(isRefreshIntervalValid({ value: 4000, pause: true })).toEqual(true);
|
||||
});
|
||||
|
||||
test('should validate that refresh interval is invalid', async () => {
|
||||
expect(isRefreshIntervalValid({ value: -5000, pause: false })).toEqual(false);
|
||||
expect(
|
||||
isRefreshIntervalValid({ value: 'test', pause: false } as unknown as RefreshInterval)
|
||||
).toEqual(false);
|
||||
expect(
|
||||
isRefreshIntervalValid({ value: 4000, pause: 'test' } as unknown as RefreshInterval)
|
||||
).toEqual(false);
|
||||
expect(isRefreshIntervalValid({} as unknown as RefreshInterval)).toEqual(false);
|
||||
expect(isRefreshIntervalValid(undefined)).toEqual(false);
|
||||
});
|
||||
});
|
30
src/plugins/discover/public/utils/validate_time.ts
Normal file
30
src/plugins/discover/public/utils/validate_time.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import dateMath from '@kbn/datemath';
|
||||
import type { RefreshInterval } from '@kbn/data-plugin/common';
|
||||
|
||||
export function isTimeRangeValid(timeRange?: { from: string; to: string }): boolean {
|
||||
if (!timeRange?.from || !timeRange?.to) {
|
||||
return false;
|
||||
}
|
||||
const fromMoment = dateMath.parse(timeRange.from);
|
||||
const toMoment = dateMath.parse(timeRange.to);
|
||||
return Boolean(fromMoment && toMoment && fromMoment.isValid() && toMoment.isValid());
|
||||
}
|
||||
|
||||
export function isRefreshIntervalValid(refreshInterval?: RefreshInterval): boolean {
|
||||
if (!refreshInterval) {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
typeof refreshInterval?.value === 'number' &&
|
||||
refreshInterval?.value >= 0 &&
|
||||
typeof refreshInterval?.pause === 'boolean'
|
||||
);
|
||||
}
|
|
@ -105,6 +105,7 @@ describe('getSavedSearch', () => {
|
|||
"hideChart": false,
|
||||
"id": "ccf1af80-2297-11ec-86e0-1155ffb9c7a7",
|
||||
"isTextBasedQuery": undefined,
|
||||
"refreshInterval": undefined,
|
||||
"rowHeight": undefined,
|
||||
"rowsPerPage": undefined,
|
||||
"searchSource": Object {
|
||||
|
@ -145,6 +146,8 @@ describe('getSavedSearch', () => {
|
|||
"desc",
|
||||
],
|
||||
],
|
||||
"timeRange": undefined,
|
||||
"timeRestore": undefined,
|
||||
"title": "test1",
|
||||
"viewMode": undefined,
|
||||
}
|
||||
|
@ -198,6 +201,7 @@ describe('getSavedSearch', () => {
|
|||
"hideChart": true,
|
||||
"id": "ccf1af80-2297-11ec-86e0-1155ffb9c7a7",
|
||||
"isTextBasedQuery": true,
|
||||
"refreshInterval": undefined,
|
||||
"rowHeight": undefined,
|
||||
"rowsPerPage": undefined,
|
||||
"searchSource": Object {
|
||||
|
@ -238,6 +242,8 @@ describe('getSavedSearch', () => {
|
|||
"desc",
|
||||
],
|
||||
],
|
||||
"timeRange": undefined,
|
||||
"timeRestore": undefined,
|
||||
"title": "test2",
|
||||
"viewMode": undefined,
|
||||
}
|
||||
|
|
|
@ -92,6 +92,7 @@ describe('saveSavedSearch', () => {
|
|||
kibanaSavedObjectMeta: { searchSourceJSON: '{}' },
|
||||
sort: [],
|
||||
title: 'title',
|
||||
timeRestore: false,
|
||||
},
|
||||
{ references: [] }
|
||||
);
|
||||
|
@ -112,6 +113,7 @@ describe('saveSavedSearch', () => {
|
|||
kibanaSavedObjectMeta: { searchSourceJSON: '{}' },
|
||||
sort: [],
|
||||
title: 'title',
|
||||
timeRestore: false,
|
||||
},
|
||||
{ references: [] }
|
||||
);
|
||||
|
|
|
@ -43,6 +43,7 @@ describe('saved_searches_utils', () => {
|
|||
"hideChart": true,
|
||||
"id": "id",
|
||||
"isTextBasedQuery": false,
|
||||
"refreshInterval": undefined,
|
||||
"rowHeight": undefined,
|
||||
"rowsPerPage": undefined,
|
||||
"searchSource": SearchSource {
|
||||
|
@ -66,6 +67,8 @@ describe('saved_searches_utils', () => {
|
|||
},
|
||||
"sharingSavedObjectProps": Object {},
|
||||
"sort": Array [],
|
||||
"timeRange": undefined,
|
||||
"timeRestore": undefined,
|
||||
"title": "saved search",
|
||||
"viewMode": undefined,
|
||||
}
|
||||
|
@ -123,6 +126,7 @@ describe('saved_searches_utils', () => {
|
|||
"kibanaSavedObjectMeta": Object {
|
||||
"searchSourceJSON": "{}",
|
||||
},
|
||||
"refreshInterval": undefined,
|
||||
"rowHeight": undefined,
|
||||
"rowsPerPage": undefined,
|
||||
"sort": Array [
|
||||
|
@ -131,6 +135,8 @@ describe('saved_searches_utils', () => {
|
|||
"asc",
|
||||
],
|
||||
],
|
||||
"timeRange": undefined,
|
||||
"timeRestore": false,
|
||||
"title": "title",
|
||||
"viewMode": undefined,
|
||||
}
|
||||
|
|
|
@ -43,6 +43,9 @@ export const fromSavedSearchAttributes = (
|
|||
hideAggregatedPreview: attributes.hideAggregatedPreview,
|
||||
rowHeight: attributes.rowHeight,
|
||||
isTextBasedQuery: attributes.isTextBasedQuery,
|
||||
timeRestore: attributes.timeRestore,
|
||||
timeRange: attributes.timeRange,
|
||||
refreshInterval: attributes.refreshInterval,
|
||||
rowsPerPage: attributes.rowsPerPage,
|
||||
});
|
||||
|
||||
|
@ -61,5 +64,8 @@ export const toSavedSearchAttributes = (
|
|||
hideAggregatedPreview: savedSearch.hideAggregatedPreview,
|
||||
rowHeight: savedSearch.rowHeight,
|
||||
isTextBasedQuery: savedSearch.isTextBasedQuery ?? false,
|
||||
timeRestore: savedSearch.timeRestore ?? false,
|
||||
timeRange: savedSearch.timeRange,
|
||||
refreshInterval: savedSearch.refreshInterval,
|
||||
rowsPerPage: savedSearch.rowsPerPage,
|
||||
});
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import type { ResolvedSimpleSavedObject } from '@kbn/core/public';
|
||||
import type { ISearchSource } from '@kbn/data-plugin/public';
|
||||
import type { ISearchSource, RefreshInterval, TimeRange } from '@kbn/data-plugin/common';
|
||||
|
||||
export enum VIEW_MODE {
|
||||
DOCUMENT_LEVEL = 'documents',
|
||||
|
@ -39,6 +39,11 @@ export interface SavedSearchAttributes {
|
|||
viewMode?: VIEW_MODE;
|
||||
hideAggregatedPreview?: boolean;
|
||||
rowHeight?: number;
|
||||
|
||||
timeRestore?: boolean;
|
||||
timeRange?: TimeRange;
|
||||
refreshInterval?: RefreshInterval;
|
||||
|
||||
rowsPerPage?: number;
|
||||
}
|
||||
|
||||
|
@ -67,5 +72,11 @@ export interface SavedSearch {
|
|||
hideAggregatedPreview?: boolean;
|
||||
rowHeight?: number;
|
||||
isTextBasedQuery?: boolean;
|
||||
|
||||
// for restoring time range with a saved search
|
||||
timeRestore?: boolean;
|
||||
timeRange?: TimeRange;
|
||||
refreshInterval?: RefreshInterval;
|
||||
|
||||
rowsPerPage?: number;
|
||||
}
|
||||
|
|
|
@ -51,6 +51,21 @@ export function getSavedSearchObjectType(
|
|||
grid: { type: 'object', enabled: false },
|
||||
version: { type: 'integer' },
|
||||
rowHeight: { type: 'text' },
|
||||
timeRestore: { type: 'boolean', index: false, doc_values: false },
|
||||
timeRange: {
|
||||
dynamic: false,
|
||||
properties: {
|
||||
from: { type: 'keyword', index: false, doc_values: false },
|
||||
to: { type: 'keyword', index: false, doc_values: false },
|
||||
},
|
||||
},
|
||||
refreshInterval: {
|
||||
dynamic: false,
|
||||
properties: {
|
||||
pause: { type: 'boolean', index: false, doc_values: false },
|
||||
value: { type: 'integer', index: false, doc_values: false },
|
||||
},
|
||||
},
|
||||
rowsPerPage: { type: 'integer', index: false, doc_values: false },
|
||||
},
|
||||
},
|
||||
|
|
|
@ -423,7 +423,10 @@
|
|||
"number_of_shards": "1",
|
||||
"priority": "10",
|
||||
"refresh_interval": "1s",
|
||||
"routing_partition_size": "1"
|
||||
"routing_partition_size": "1",
|
||||
"mapping": {
|
||||
"total_fields": { "limit": 1500 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -462,7 +462,10 @@
|
|||
"number_of_shards": "1",
|
||||
"priority": "10",
|
||||
"refresh_interval": "1s",
|
||||
"routing_partition_size": "1"
|
||||
"routing_partition_size": "1",
|
||||
"mapping": {
|
||||
"total_fields": { "limit": 1500 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -470,7 +470,10 @@
|
|||
"number_of_shards": "1",
|
||||
"priority": "10",
|
||||
"refresh_interval": "1s",
|
||||
"routing_partition_size": "1"
|
||||
"routing_partition_size": "1",
|
||||
"mapping": {
|
||||
"total_fields": { "limit": 1500 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -462,7 +462,10 @@
|
|||
"number_of_shards": "1",
|
||||
"priority": "10",
|
||||
"refresh_interval": "1s",
|
||||
"routing_partition_size": "1"
|
||||
"routing_partition_size": "1",
|
||||
"mapping": {
|
||||
"total_fields": { "limit": 1500 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -470,7 +470,10 @@
|
|||
"number_of_shards": "1",
|
||||
"priority": "10",
|
||||
"refresh_interval": "1s",
|
||||
"routing_partition_size": "1"
|
||||
"routing_partition_size": "1",
|
||||
"mapping": {
|
||||
"total_fields": { "limit": 1500 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,10 @@
|
|||
"index": {
|
||||
"auto_expand_replicas": "0-1",
|
||||
"number_of_replicas": "0",
|
||||
"number_of_shards": "1"
|
||||
"number_of_shards": "1",
|
||||
"mapping": {
|
||||
"total_fields": { "limit": 1500 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,10 @@
|
|||
"index": {
|
||||
"auto_expand_replicas": "0-1",
|
||||
"number_of_replicas": "0",
|
||||
"number_of_shards": "1"
|
||||
"number_of_shards": "1",
|
||||
"mapping": {
|
||||
"total_fields": { "limit": 1500 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue