diff --git a/.gitignore b/.gitignore index efb5c577746334..02b20da297fc67 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,5 @@ package-lock.json *.sublime-* npm-debug.log* .tern-project +x-pack/legacy/plugins/apm/tsconfig.json +apm.tsconfig.json diff --git a/docs/user/ml/index.asciidoc b/docs/user/ml/index.asciidoc index b7bf459c39d984..a2c23aad98d5be 100644 --- a/docs/user/ml/index.asciidoc +++ b/docs/user/ml/index.asciidoc @@ -24,7 +24,7 @@ can then optionally import that data into an {es} index. You need the following permissions to use the Data Visualizer with file upload: -* cluster privileges: `monitor`, `manage_index_pipelines` +* cluster privileges: `monitor`, `manage_ingest_pipelines` * index privileges: `read`, `manage`, `index` For more information, see {ref}/security-privileges.html[Security privileges] diff --git a/src/legacy/core_plugins/data/public/filter/action/apply_filter_action.ts b/src/legacy/core_plugins/data/public/filter/action/apply_filter_action.ts index 8d2337264d02fd..abe9ec6d6e8731 100644 --- a/src/legacy/core_plugins/data/public/filter/action/apply_filter_action.ts +++ b/src/legacy/core_plugins/data/public/filter/action/apply_filter_action.ts @@ -24,8 +24,13 @@ import { createAction, IncompatibleActionError, } from '../../../../../../plugins/ui_actions/public'; -import { FilterManager, esFilters } from '../../../../../../plugins/data/public'; -import { TimefilterContract, changeTimeFilter, extractTimeFilter } from '../../timefilter'; +import { + esFilters, + FilterManager, + TimefilterContract, + changeTimeFilter, + extractTimeFilter, +} from '../../../../../../plugins/data/public'; import { applyFiltersPopover } from '../apply_filters/apply_filters_popover'; import { IndexPatternsStart } from '../../index_patterns'; export const GLOBAL_APPLY_FILTER_ACTION = 'GLOBAL_APPLY_FILTER_ACTION'; diff --git a/src/legacy/core_plugins/data/public/index.ts b/src/legacy/core_plugins/data/public/index.ts index 502ca206e8e125..60828b4a2a2025 100644 --- a/src/legacy/core_plugins/data/public/index.ts +++ b/src/legacy/core_plugins/data/public/index.ts @@ -61,12 +61,3 @@ export { mockFields, mockIndexPattern, } from './index_patterns'; - -export { - TimeHistoryContract, - TimefilterContract, - getTime, - InputTimeRange, - extractTimeFilter, - changeTimeFilter, -} from './timefilter'; diff --git a/src/legacy/core_plugins/data/public/mocks.ts b/src/legacy/core_plugins/data/public/mocks.ts index 4a7fe8efa40689..d3b5944127965d 100644 --- a/src/legacy/core_plugins/data/public/mocks.ts +++ b/src/legacy/core_plugins/data/public/mocks.ts @@ -19,13 +19,11 @@ import { indexPatternsServiceMock } from './index_patterns/index_patterns_service.mock'; import { queryServiceMock } from './query/query_service.mock'; -import { timefilterServiceMock } from './timefilter/timefilter_service.mock'; function createDataSetupMock() { return { indexPatterns: indexPatternsServiceMock.createSetupContract(), query: queryServiceMock.createSetupContract(), - timefilter: timefilterServiceMock.createSetupContract(), }; } diff --git a/src/legacy/core_plugins/data/public/plugin.ts b/src/legacy/core_plugins/data/public/plugin.ts index 03c9b0e93309da..76beb4ee560535 100644 --- a/src/legacy/core_plugins/data/public/plugin.ts +++ b/src/legacy/core_plugins/data/public/plugin.ts @@ -20,7 +20,6 @@ import { CoreSetup, CoreStart, Plugin } from 'kibana/public'; import { SearchService, SearchStart, createSearchBar, StatetfulSearchBarProps } from './search'; import { QueryService, QuerySetup } from './query'; -import { TimefilterService, TimefilterSetup } from './timefilter'; import { IndexPatternsService, IndexPatternsSetup, IndexPatternsStart } from './index_patterns'; import { Storage, IStorageWrapper } from '../../../../../src/plugins/kibana_utils/public'; import { DataPublicPluginStart } from '../../../../plugins/data/public'; @@ -44,7 +43,6 @@ export interface DataPluginStartDependencies { */ export interface DataSetup { query: QuerySetup; - timefilter: TimefilterSetup; indexPatterns: IndexPatternsSetup; } @@ -55,7 +53,6 @@ export interface DataSetup { */ export interface DataStart { query: QuerySetup; - timefilter: TimefilterSetup; indexPatterns: IndexPatternsStart; search: SearchStart; ui: { @@ -79,24 +76,16 @@ export class DataPlugin implements Plugin ({ +jest.mock('../../../../../../../plugins/data/public/query/persisted_log', () => ({ PersistedLog: mockPersistedLogFactory, })); diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx index 9f03f7fd307789..5576427b1592a6 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx @@ -37,6 +37,7 @@ import { Toast } from 'src/core/public'; import { AutocompleteSuggestion, AutocompleteSuggestionType, + PersistedLog, } from '../../../../../../../plugins/data/public'; import { withKibana, @@ -47,7 +48,6 @@ import { Query, getQueryLog } from '../index'; import { fromUser, matchPairs, toUser } from '../lib'; import { QueryLanguageSwitcher } from './language_switcher'; import { SuggestionsComponent } from './typeahead/suggestions_component'; -import { PersistedLog } from '../../persisted_log'; import { fetchIndexPatterns } from '../lib/fetch_index_patterns'; import { IDataPluginServices } from '../../../types'; diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.test.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.test.tsx index 7281eea956fbf8..ae08083f82af3e 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.test.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.test.tsx @@ -29,12 +29,11 @@ import { KibanaContextProvider } from 'src/plugins/kibana_react/public'; import { I18nProvider } from '@kbn/i18n/react'; const startMock = coreMock.createStart(); -import { timefilterServiceMock } from '../../../timefilter/timefilter_service.mock'; -const timefilterSetupMock = timefilterServiceMock.createSetupContract(); - -timefilterSetupMock.history.get.mockImplementation(() => { - return []; -}); +const mockTimeHistory = { + get: () => { + return []; + }, +}; startMock.uiSettings.get.mockImplementation((key: string) => { switch (key) { @@ -140,7 +139,7 @@ describe('QueryBarTopRowTopRow', () => { screenTitle: 'Another Screen', isDirty: false, indexPatterns: [mockIndexPattern], - timeHistory: timefilterSetupMock.history, + timeHistory: mockTimeHistory, }) ); @@ -154,7 +153,7 @@ describe('QueryBarTopRowTopRow', () => { query: kqlQuery, screenTitle: 'Another Screen', indexPatterns: [mockIndexPattern], - timeHistory: timefilterSetupMock.history, + timeHistory: mockTimeHistory, disableAutoFocus: true, isDirty: false, }) @@ -167,7 +166,7 @@ describe('QueryBarTopRowTopRow', () => { const component = mount( wrapQueryBarTopRowInContext({ isDirty: false, - timeHistory: timefilterSetupMock.history, + timeHistory: mockTimeHistory, }) ); @@ -179,7 +178,7 @@ describe('QueryBarTopRowTopRow', () => { const component = mount( wrapQueryBarTopRowInContext({ showDatePicker: false, - timeHistory: timefilterSetupMock.history, + timeHistory: mockTimeHistory, isDirty: false, }) ); @@ -196,7 +195,7 @@ describe('QueryBarTopRowTopRow', () => { showDatePicker: true, dateRangeFrom: 'now-7d', dateRangeTo: 'now', - timeHistory: timefilterSetupMock.history, + timeHistory: mockTimeHistory, }) ); @@ -212,7 +211,7 @@ describe('QueryBarTopRowTopRow', () => { showDatePicker: true, dateRangeFrom: 'now-7d', dateRangeTo: 'now', - timeHistory: timefilterSetupMock.history, + timeHistory: mockTimeHistory, }) ); @@ -232,7 +231,7 @@ describe('QueryBarTopRowTopRow', () => { showDatePicker: false, dateRangeFrom: 'now-7d', dateRangeTo: 'now', - timeHistory: timefilterSetupMock.history, + timeHistory: mockTimeHistory, }) ); @@ -249,7 +248,7 @@ describe('QueryBarTopRowTopRow', () => { indexPatterns: [mockIndexPattern], showQueryInput: false, showDatePicker: false, - timeHistory: timefilterSetupMock.history, + timeHistory: mockTimeHistory, }) ); @@ -263,7 +262,7 @@ describe('QueryBarTopRowTopRow', () => { isDirty: false, screenTitle: 'Another Screen', showDatePicker: false, - timeHistory: timefilterSetupMock.history, + timeHistory: mockTimeHistory, }) ); diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.tsx index d2953621d86d1b..d31ac2d76d0d9a 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.tsx @@ -35,15 +35,14 @@ import { import { EuiSuperUpdateButton, OnRefreshProps } from '@elastic/eui'; import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; import { Toast } from 'src/core/public'; -import { TimeRange } from 'src/plugins/data/public'; +import { TimeRange, TimeHistoryContract } from 'src/plugins/data/public'; import { useKibana } from '../../../../../../../plugins/kibana_react/public'; +import { PersistedLog } from '../../../../../../../plugins/data/public'; import { IndexPattern } from '../../../index_patterns'; import { QueryBarInput } from './query_bar_input'; import { Query, getQueryLog } from '../index'; -import { TimeHistoryContract } from '../../../timefilter'; import { IDataPluginServices } from '../../../types'; -import { PersistedLog } from '../../persisted_log'; interface Props { query?: Query; diff --git a/src/legacy/core_plugins/data/public/query/query_bar/lib/get_query_log.ts b/src/legacy/core_plugins/data/public/query/query_bar/lib/get_query_log.ts index f78eb5e07f1899..66424d9a1d6a35 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/lib/get_query_log.ts +++ b/src/legacy/core_plugins/data/public/query/query_bar/lib/get_query_log.ts @@ -19,7 +19,7 @@ import { UiSettingsClientContract } from 'src/core/public'; import { IStorageWrapper } from 'src/plugins/kibana_utils/public'; -import { PersistedLog } from '../../persisted_log'; +import { PersistedLog } from '../../../../../../../plugins/data/public'; export function getQueryLog( uiSettings: UiSettingsClientContract, diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/create_search_bar.tsx b/src/legacy/core_plugins/data/public/search/search_bar/components/create_search_bar.tsx index 12cea46f158c1c..4485b74ca09010 100644 --- a/src/legacy/core_plugins/data/public/search/search_bar/components/create_search_bar.tsx +++ b/src/legacy/core_plugins/data/public/search/search_bar/components/create_search_bar.tsx @@ -23,7 +23,6 @@ import { CoreStart } from 'src/core/public'; import { DataPublicPluginStart } from 'src/plugins/data/public'; import { IStorageWrapper } from 'src/plugins/kibana_utils/public'; import { KibanaContextProvider } from '../../../../../../../../src/plugins/kibana_react/public'; -import { TimefilterSetup } from '../../../timefilter'; import { SearchBar } from '../../../'; import { SearchBarOwnProps } from '.'; import { esFilters } from '../../../../../../../plugins/data/public'; @@ -32,7 +31,6 @@ interface StatefulSearchBarDeps { core: CoreStart; data: DataPublicPluginStart; storage: IStorageWrapper; - timefilter: TimefilterSetup; } export type StatetfulSearchBarProps = SearchBarOwnProps & { @@ -45,20 +43,21 @@ const defaultFiltersUpdated = (data: DataPublicPluginStart) => { }; }; -const defaultOnRefreshChange = (timefilter: TimefilterSetup) => { +const defaultOnRefreshChange = (data: DataPublicPluginStart) => { + const { timefilter } = data.query.timefilter; return (options: { isPaused: boolean; refreshInterval: number }) => { - timefilter.timefilter.setRefreshInterval({ + timefilter.setRefreshInterval({ value: options.refreshInterval, pause: options.isPaused, }); }; }; -export function createSearchBar({ core, storage, timefilter, data }: StatefulSearchBarDeps) { +export function createSearchBar({ core, storage, data }: StatefulSearchBarDeps) { // App name should come from the core application service. // Until it's available, we'll ask the user to provide it for the pre-wired component. return (props: StatetfulSearchBarProps) => { - const { filterManager } = data.query; + const { filterManager, timefilter } = data.query; const tfRefreshInterval = timefilter.timefilter.getRefreshInterval(); const fmFilters = filterManager.getFilters(); const [refreshInterval, setRefreshInterval] = useState(tfRefreshInterval.value); @@ -119,7 +118,7 @@ export function createSearchBar({ core, storage, timefilter, data }: StatefulSea isRefreshPaused={refreshPaused} filters={filters} onFiltersUpdated={defaultFiltersUpdated(data)} - onRefreshChange={defaultOnRefreshChange(timefilter)} + onRefreshChange={defaultOnRefreshChange(data)} {...props} /> diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.test.tsx b/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.test.tsx index 9b77ec369c55b8..44637365247fbd 100644 --- a/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.test.tsx +++ b/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.test.tsx @@ -27,9 +27,13 @@ import { I18nProvider } from '@kbn/i18n/react'; import { coreMock } from '../../../../../../../../src/core/public/mocks'; const startMock = coreMock.createStart(); -import { timefilterServiceMock } from '../../../timefilter/timefilter_service.mock'; import { mount } from 'enzyme'; -const timefilterSetupMock = timefilterServiceMock.createSetupContract(); + +const mockTimeHistory = { + get: () => { + return []; + }, +}; jest.mock('../../../../../data/public', () => { return { @@ -86,7 +90,7 @@ const kqlQuery = { function wrapSearchBarInContext(testProps: any) { const defaultOptions = { appName: 'test', - timeHistory: timefilterSetupMock.history, + timeHistory: mockTimeHistory, intl: null as any, }; diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx b/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx index d3a26239e1006c..a57b7b17a0da66 100644 --- a/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx +++ b/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx @@ -25,6 +25,7 @@ import ResizeObserver from 'resize-observer-polyfill'; import { get, isEqual } from 'lodash'; import { TimeRange } from 'src/plugins/data/common/types'; +import { TimeHistoryContract } from 'src/plugins/data/public'; import { IndexPattern, Query, FilterBar } from '../../../../../data/public'; import { QueryBarTopRow } from '../../../query'; import { SavedQuery, SavedQueryAttributes } from '../index'; @@ -32,7 +33,6 @@ import { SavedQueryMeta, SaveQueryForm } from './saved_query_management/save_que import { SavedQueryManagementComponent } from './saved_query_management/saved_query_management_component'; import { SavedQueryService } from '../lib/saved_query_service'; import { createSavedQueryService } from '../lib/saved_query_service'; -import { TimeHistoryContract } from '../../../timefilter'; import { withKibana, KibanaReactContextValue, diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx index 64c75609476813..adf0e1e084a644 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx @@ -56,7 +56,7 @@ import { capabilities } from 'ui/capabilities'; import { Subscription } from 'rxjs'; import { npStart } from 'ui/new_platform'; import { SavedObjectFinder } from 'ui/saved_objects/components/saved_object_finder'; -import { extractTimeFilter, changeTimeFilter } from '../../../data/public'; +import { extractTimeFilter, changeTimeFilter } from '../../../../../plugins/data/public'; import { start as data } from '../../../data/public/legacy'; import { esFilters } from '../../../../../plugins/data/public'; diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_state.test.ts b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_state.test.ts index a25ce1e607f9a4..5e81373001bf57 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_state.test.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_state.test.ts @@ -23,7 +23,7 @@ import { DashboardStateManager } from './dashboard_state_manager'; import { getAppStateMock, getSavedDashboardMock } from './__tests__'; import { AppStateClass } from 'ui/state_management/app_state'; import { DashboardAppState } from './types'; -import { TimeRange } from 'src/plugins/data/public'; +import { TimeRange, TimefilterContract } from 'src/plugins/data/public'; import { ViewMode } from 'src/plugins/embeddable/public'; import { InputTimeRange } from 'ui/timefilter'; @@ -33,22 +33,19 @@ jest.mock('ui/registry/field_formats', () => ({ }, })); -import { dataPluginMock } from '../../../../core_plugins/data/public/mocks'; -const dataSetupMock = dataPluginMock.createSetup(); - describe('DashboardState', function() { let dashboardState: DashboardStateManager; const savedDashboard = getSavedDashboardMock(); let mockTime: TimeRange = { to: 'now', from: 'now-15m' }; - const mockTimefilter = dataSetupMock.timefilter!.timefilter; - - mockTimefilter.setTime.mockImplementation((time: InputTimeRange) => { - mockTime = time as TimeRange; - }); - mockTimefilter.getTime.mockImplementation(() => { - return mockTime; - }); + const mockTimefilter = { + getTime: () => { + return mockTime; + }, + setTime: (time: InputTimeRange) => { + mockTime = time as TimeRange; + }, + } as TimefilterContract; function initDashboardState() { dashboardState = new DashboardStateManager({ diff --git a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_search.test.tsx b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_search.test.tsx index c207585499483f..badfbb4b14a4c1 100644 --- a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_search.test.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_search.test.tsx @@ -16,13 +16,13 @@ * specific language governing permissions and limitations * under the License. */ -import React from 'react'; +import React, { EventHandler, MouseEvent as ReactMouseEvent } from 'react'; import { act } from 'react-dom/test-utils'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; // @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; import { DiscoverFieldSearch, Props } from './discover_field_search'; -import { EuiButtonGroupProps } from '@elastic/eui'; +import { EuiButtonGroupProps, EuiPopover } from '@elastic/eui'; import { ReactWrapper } from 'enzyme'; describe('DiscoverFieldSearch', () => { @@ -136,4 +136,44 @@ describe('DiscoverFieldSearch', () => { typeSelector.simulate('change', { target: { value: 'any' } }); expect(onChange).toBeCalledWith('type', 'any'); }); + + test('click on filter button should open and close popover', () => { + const component = mountComponent(); + const btn = findTestSubject(component, 'toggleFieldFilterButton'); + btn.simulate('click'); + let popover = component.find(EuiPopover); + expect(popover.prop('isOpen')).toBe(true); + btn.simulate('click'); + popover = component.find(EuiPopover); + expect(popover.prop('isOpen')).toBe(false); + }); + + test('click outside popover should close popover', () => { + const triggerDocumentMouseDown: EventHandler = (e: ReactMouseEvent) => { + const event = new Event('mousedown'); + // @ts-ignore + event.euiGeneratedBy = e.nativeEvent.euiGeneratedBy; + document.dispatchEvent(event); + }; + const triggerDocumentMouseUp: EventHandler = (e: ReactMouseEvent) => { + const event = new Event('mouseup'); + // @ts-ignore + event.euiGeneratedBy = e.nativeEvent.euiGeneratedBy; + document.dispatchEvent(event); + }; + const component = mountWithIntl( +
+ +
+ ); + const btn = findTestSubject(component, 'toggleFieldFilterButton'); + btn.simulate('click'); + let popover = component.find(EuiPopover); + expect(popover.length).toBe(1); + expect(popover.prop('isOpen')).toBe(true); + component.find('#wrapperId').simulate('mousedown'); + component.find('#wrapperId').simulate('mouseup'); + popover = component.find(EuiPopover); + expect(popover.prop('isOpen')).toBe(false); + }); }); diff --git a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_search.tsx b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_search.tsx index f0685c4357c5af..3d93487d9e6ccd 100644 --- a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_search.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_field_search.tsx @@ -32,6 +32,7 @@ import { EuiForm, EuiFormRow, EuiButtonGroup, + EuiOutsideClickDetector, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -244,6 +245,7 @@ export function DiscoverFieldSearch({ onChange, value, types }: Props) { ); + return ( @@ -260,33 +262,37 @@ export function DiscoverFieldSearch({ onChange, value, types }: Props) {
- {}} - button={buttonContent} - > - - {i18n.translate('kbn.discover.fieldChooser.filter.filterByTypeLabel', { - defaultMessage: 'Filter by type', - })} - - {selectionPanel} - - {}} isDisabled={!isPopoverOpen}> + { + setPopoverOpen(false); + }} + button={buttonContent} + > + + {i18n.translate('kbn.discover.fieldChooser.filter.filterByTypeLabel', { + defaultMessage: 'Filter by type', })} - checked={values.missing} - onChange={handleMissingChange} - data-test-subj="missingSwitch" - /> - - + + {selectionPanel} + + + + +
); diff --git a/src/legacy/core_plugins/kibana/public/discover/embeddable/search_embeddable.ts b/src/legacy/core_plugins/kibana/public/discover/embeddable/search_embeddable.ts index 31b28d21fe8d84..732fb6d2e4e709 100644 --- a/src/legacy/core_plugins/kibana/public/discover/embeddable/search_embeddable.ts +++ b/src/legacy/core_plugins/kibana/public/discover/embeddable/search_embeddable.ts @@ -21,10 +21,14 @@ import * as Rx from 'rxjs'; import { Subscription } from 'rxjs'; import { i18n } from '@kbn/i18n'; import { TExecuteTriggerActions } from 'src/plugins/ui_actions/public'; -import { TimeRange, onlyDisabledFiltersChanged } from '../../../../../../plugins/data/public'; -import { setup as data } from '../../../../data/public/legacy'; -import { Query, getTime } from '../../../../data/public'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { npStart } from 'ui/new_platform'; +import { + esFilters, + TimeRange, + onlyDisabledFiltersChanged, + getTime, +} from '../../../../../../plugins/data/public'; +import { Query } from '../../../../data/public'; import { APPLY_FILTER_TRIGGER, Container, @@ -49,6 +53,8 @@ import { } from '../kibana_services'; import { SEARCH_EMBEDDABLE_TYPE } from './constants'; +const { data } = npStart.plugins; + interface SearchScope extends ng.IScope { columns?: string[]; description?: string; @@ -136,9 +142,9 @@ export class SearchEmbeddable extends Embeddable requests: new RequestAdapter(), }; this.initializeSearchScope(); - this.autoRefreshFetchSubscription = data.timefilter.timefilter - .getAutoRefreshFetch$() - .subscribe(this.fetch); + const { timefilter } = data.query.timefilter; + + this.autoRefreshFetchSubscription = timefilter.getAutoRefreshFetch$().subscribe(this.fetch); this.subscription = Rx.merge(this.getOutput$(), this.getInput$()).subscribe(() => { this.panelTitle = this.output.title || ''; diff --git a/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js b/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js index c0a7615f207ed5..f5011611368012 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js +++ b/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js @@ -31,8 +31,7 @@ import editorTemplate from './editor.html'; import { DashboardConstants } from '../../dashboard/dashboard_constants'; import { VisualizeConstants } from '../visualize_constants'; import { getEditBreadcrumbs, getCreateBreadcrumbs } from '../breadcrumbs'; -import { extractTimeFilter, changeTimeFilter } from '../../../../data/public'; - +import { extractTimeFilter, changeTimeFilter } from '../../../../../../plugins/data/public'; import { addHelpMenuToAppChrome } from '../help_menu/help_menu_util'; import { diff --git a/src/legacy/core_plugins/navigation/public/top_nav_menu/top_nav_menu.test.tsx b/src/legacy/core_plugins/navigation/public/top_nav_menu/top_nav_menu.test.tsx index 4f8c5d11f19161..9077de89103277 100644 --- a/src/legacy/core_plugins/navigation/public/top_nav_menu/top_nav_menu.test.tsx +++ b/src/legacy/core_plugins/navigation/public/top_nav_menu/top_nav_menu.test.tsx @@ -22,11 +22,15 @@ import { TopNavMenu } from './top_nav_menu'; import { TopNavMenuData } from './top_nav_menu_data'; import { shallowWithIntl } from 'test_utils/enzyme_helpers'; -import { timefilterServiceMock } from '../../../../core_plugins/data/public/timefilter/timefilter_service.mock'; -const timefilterSetupMock = timefilterServiceMock.createSetupContract(); - jest.mock('ui/new_platform'); +const mockTimeHistory = { + add: () => {}, + get: () => { + return []; + }, +}; + const dataShim = { ui: { SearchBar: () =>
, @@ -77,7 +81,7 @@ describe('TopNavMenu', () => { ); diff --git a/src/legacy/core_plugins/timelion/public/legacy.ts b/src/legacy/core_plugins/timelion/public/legacy.ts index 77cd94279c879a..d989a68d40eeb4 100644 --- a/src/legacy/core_plugins/timelion/public/legacy.ts +++ b/src/legacy/core_plugins/timelion/public/legacy.ts @@ -21,13 +21,12 @@ import { PluginInitializerContext } from 'kibana/public'; import { npSetup, npStart } from 'ui/new_platform'; import { plugin } from '.'; import { setup as visualizations } from '../../visualizations/public/np_ready/public/legacy'; -import { setup as data } from '../../data/public/legacy'; import { TimelionPluginSetupDependencies } from './plugin'; import { LegacyDependenciesPlugin } from './shim'; const setupPlugins: Readonly = { visualizations, - data, + data: npSetup.plugins.data, expressions: npSetup.plugins.expressions, // Temporary solution diff --git a/src/legacy/core_plugins/timelion/public/plugin.ts b/src/legacy/core_plugins/timelion/public/plugin.ts index 6447e3bbc5f516..6291948f750775 100644 --- a/src/legacy/core_plugins/timelion/public/plugin.ts +++ b/src/legacy/core_plugins/timelion/public/plugin.ts @@ -25,12 +25,11 @@ import { HttpSetup, } from 'kibana/public'; import { Plugin as ExpressionsPlugin } from 'src/plugins/expressions/public'; +import { DataPublicPluginSetup, TimefilterContract } from 'src/plugins/data/public'; import { VisualizationsSetup } from '../../visualizations/public/np_ready/public'; import { getTimelionVisualizationConfig } from './timelion_vis_fn'; import { getTimelionVisualization } from './vis'; import { getTimeChart } from './panels/timechart/timechart'; -import { DataSetup } from '../../data/public'; -import { TimefilterSetup } from '../../data/public/timefilter'; import { Panel } from './panels/panel'; import { LegacyDependenciesPlugin, LegacyDependenciesPluginSetup } from './shim'; @@ -39,14 +38,14 @@ export interface TimelionVisualizationDependencies extends LegacyDependenciesPlu uiSettings: UiSettingsClientContract; http: HttpSetup; timelionPanels: Map; - timefilter: TimefilterSetup; + timefilter: TimefilterContract; } /** @internal */ export interface TimelionPluginSetupDependencies { expressions: ReturnType; visualizations: VisualizationsSetup; - data: DataSetup; + data: DataPublicPluginSetup; // Temporary solution __LEGACY: LegacyDependenciesPlugin; @@ -69,8 +68,8 @@ export class TimelionPlugin implements Plugin, void> { const dependencies: TimelionVisualizationDependencies = { uiSettings: core.uiSettings, http: core.http, - timefilter: data.timefilter, timelionPanels, + timefilter: data.query.timefilter.timefilter, ...(await __LEGACY.setup(core, timelionPanels)), }; diff --git a/src/legacy/core_plugins/timelion/public/vis/timelion_request_handler.ts b/src/legacy/core_plugins/timelion/public/vis/timelion_request_handler.ts index 156c06a6055287..6239e4027c392a 100644 --- a/src/legacy/core_plugins/timelion/public/vis/timelion_request_handler.ts +++ b/src/legacy/core_plugins/timelion/public/vis/timelion_request_handler.ts @@ -78,7 +78,7 @@ export function getTimelionRequestHandler(dependencies: TimelionVisualizationDep const esQueryConfigs = getEsQueryConfig(uiSettings); // parse the time range client side to make sure it behaves like other charts - const timeRangeBounds = timefilter.timefilter.calculateBounds(timeRange); + const timeRangeBounds = timefilter.calculateBounds(timeRange); try { return await http.post('../api/timelion/run', { diff --git a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js index 611a182cf5d7f0..bb055d6ce1e334 100644 --- a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js +++ b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js @@ -19,6 +19,12 @@ import sinon from 'sinon'; +const mockObservable = () => { + return { + subscribe: () => {} + }; +}; + export const npSetup = { core: { chrome: {} @@ -44,8 +50,16 @@ export const npSetup = { }, }, data: { + autocomplete: { + addProvider: sinon.fake(), + getProvider: sinon.fake(), + }, query: { filterManager: sinon.fake(), + timefilter: { + timefilter: sinon.fake(), + history: sinon.fake(), + } }, }, inspector: { @@ -64,6 +78,10 @@ export const npSetup = { }, }; +let refreshInterval = undefined; +let isTimeRangeSelectorEnabled = true; +let isAutoRefreshSelectorEnabled = true; + export const npStart = { core: { chrome: {} @@ -80,6 +98,9 @@ export const npStart = { registerType: sinon.fake(), }, data: { + autocomplete: { + getProvider: sinon.fake(), + }, getSuggestions: sinon.fake(), query: { filterManager: { @@ -91,13 +112,48 @@ export const npStart = { addFilters: sinon.fake(), setFilters: sinon.fake(), removeAll: sinon.fake(), - getUpdates$: () => { - return { - subscribe: () => {} - }; - }, + getUpdates$: mockObservable, }, + timefilter: { + timefilter: { + getFetch$: mockObservable, + getAutoRefreshFetch$: mockObservable, + getEnabledUpdated$: mockObservable, + getTimeUpdate$: mockObservable, + getRefreshIntervalUpdate$: mockObservable, + isTimeRangeSelectorEnabled: () => { + return isTimeRangeSelectorEnabled; + }, + isAutoRefreshSelectorEnabled: () => { + return isAutoRefreshSelectorEnabled; + }, + disableAutoRefreshSelector: () => { + isAutoRefreshSelectorEnabled = false; + }, + enableAutoRefreshSelector: () => { + isAutoRefreshSelectorEnabled = true; + }, + getRefreshInterval: () => { + return refreshInterval; + }, + setRefreshInterval: (interval) => { + refreshInterval = interval; + }, + enableTimeRangeSelector: () => { + isTimeRangeSelectorEnabled = true; + }, + disableTimeRangeSelector: () => { + isTimeRangeSelectorEnabled = false; + }, + getTime: sinon.fake(), + setTime: sinon.fake(), + getBounds: sinon.fake(), + calculateBounds: sinon.fake(), + createFilter: sinon.fake(), + }, + history: sinon.fake(), + }, }, }, inspector: { diff --git a/src/legacy/ui/public/timefilter/index.ts b/src/legacy/ui/public/timefilter/index.ts index c102d979c951a0..82e2531ec62a68 100644 --- a/src/legacy/ui/public/timefilter/index.ts +++ b/src/legacy/ui/public/timefilter/index.ts @@ -18,20 +18,20 @@ */ import uiRoutes from 'ui/routes'; -import { TimefilterContract, TimeHistoryContract } from '../../../core_plugins/data/public'; +import { npStart } from 'ui/new_platform'; +import { TimefilterContract, TimeHistoryContract } from '../../../../plugins/data/public'; import { registerTimefilterWithGlobalState } from './setup_router'; -import { start as data } from '../../../core_plugins/data/public/legacy'; export { getTime, InputTimeRange, TimeHistoryContract, TimefilterContract, -} from '../../../core_plugins/data/public'; +} from '../../../../plugins/data/public'; export type Timefilter = TimefilterContract; export type TimeHistory = TimeHistoryContract; -export const timeHistory = data.timefilter.history; -export const timefilter = data.timefilter.timefilter; +export const timeHistory = npStart.plugins.data.query.timefilter.history; +export const timefilter = npStart.plugins.data.query.timefilter.timefilter; uiRoutes.addSetupWork((globalState, $rootScope) => { return registerTimefilterWithGlobalState(timefilter, globalState, $rootScope); diff --git a/src/legacy/ui/public/timefilter/setup_router.ts b/src/legacy/ui/public/timefilter/setup_router.ts index ffc8a1fca6c641..0a73378f99cd7d 100644 --- a/src/legacy/ui/public/timefilter/setup_router.ts +++ b/src/legacy/ui/public/timefilter/setup_router.ts @@ -22,8 +22,7 @@ import { IScope } from 'angular'; import moment from 'moment'; import { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; import chrome from 'ui/chrome'; -import { RefreshInterval, TimeRange } from 'src/plugins/data/public'; -import { TimefilterContract } from '../../../core_plugins/data/public/timefilter'; +import { RefreshInterval, TimeRange, TimefilterContract } from 'src/plugins/data/public'; // TODO // remove everything underneath once globalState is no longer an angular service diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts index 2269ba3c55bce3..4aae63c24d7fc7 100644 --- a/src/plugins/data/public/mocks.ts +++ b/src/plugins/data/public/mocks.ts @@ -31,8 +31,8 @@ const autocompleteMock: any = { const createSetupContract = (): Setup => { const querySetupMock = queryServiceMock.createSetupContract(); - const setupContract: Setup = { - autocomplete: autocompleteMock as Setup['autocomplete'], + const setupContract = { + autocomplete: autocompleteMock, search: searchSetupMock, query: querySetupMock, }; @@ -42,8 +42,8 @@ const createSetupContract = (): Setup => { const createStartContract = (): Start => { const queryStartMock = queryServiceMock.createStartContract(); - const startContract: Start = { - autocomplete: autocompleteMock as Start['autocomplete'], + const startContract = { + autocomplete: autocompleteMock, getSuggestions: jest.fn(), search: { search: jest.fn() }, query: queryStartMock, diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index a13e912e778462..79db34c022b39f 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -18,6 +18,7 @@ */ import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from '../../../core/public'; +import { Storage } from '../../kibana_utils/public'; import { DataPublicPluginSetup, DataPublicPluginStart } from './types'; import { AutocompleteProviderRegister } from './autocomplete_provider'; import { getSuggestionsProvider } from './suggestions_provider'; @@ -35,11 +36,13 @@ export class DataPublicPlugin implements Plugin { expect(updateListener.callCount).toBe(1); }); - test('app state should accept array', async () => { + test('app state should accept array and preserve order', async () => { const f1 = getFilter(esFilters.FilterStateStore.APP_STATE, false, false, 'age', 34); const f2 = getFilter(esFilters.FilterStateStore.APP_STATE, false, false, 'gender', 'female'); + filterManager.addFilters([f1]); filterManager.addFilters([f2]); const appFilters = filterManager.getAppFilters(); expect(appFilters).toHaveLength(2); - expect(appFilters).toEqual([f2, f1]); + expect(appFilters).toEqual([f1, f2]); expect(filterManager.getGlobalFilters()).toHaveLength(0); }); @@ -206,7 +207,7 @@ describe('filter_manager', () => { expect(updateListener.callCount).toBe(1); }); - test('global state should be accept array', async () => { + test('global state should be accept array and preserve order', async () => { const f1 = getFilter(esFilters.FilterStateStore.GLOBAL_STATE, false, false, 'age', 34); const f2 = getFilter( esFilters.FilterStateStore.GLOBAL_STATE, @@ -215,11 +216,36 @@ describe('filter_manager', () => { 'gender', 'female' ); + filterManager.addFilters([f1, f2]); expect(filterManager.getAppFilters()).toHaveLength(0); const globalFilters = filterManager.getGlobalFilters(); expect(globalFilters).toHaveLength(2); - expect(globalFilters).toEqual([f2, f1]); + expect(globalFilters).toEqual([f1, f2]); + }); + + test('mixed filters: global filters should stay in the beginning', async () => { + const f1 = getFilter(esFilters.FilterStateStore.GLOBAL_STATE, false, false, 'age', 34); + const f2 = getFilter(esFilters.FilterStateStore.APP_STATE, false, false, 'gender', 'female'); + filterManager.addFilters([f1, f2]); + const filters = filterManager.getFilters(); + expect(filters).toHaveLength(2); + expect(filters).toEqual([f1, f2]); + }); + + test('mixed filters: global filters should move to the beginning', async () => { + const f1 = getFilter(esFilters.FilterStateStore.APP_STATE, false, false, 'age', 34); + const f2 = getFilter( + esFilters.FilterStateStore.GLOBAL_STATE, + false, + false, + 'gender', + 'female' + ); + filterManager.addFilters([f1, f2]); + const filters = filterManager.getFilters(); + expect(filters).toHaveLength(2); + expect(filters).toEqual([f2, f1]); }); test('add multiple filters at once', async () => { diff --git a/src/plugins/data/public/query/filter_manager/filter_manager.ts b/src/plugins/data/public/query/filter_manager/filter_manager.ts index f691398fb91d3e..06e2b77dca238f 100644 --- a/src/plugins/data/public/query/filter_manager/filter_manager.ts +++ b/src/plugins/data/public/query/filter_manager/filter_manager.ts @@ -77,11 +77,16 @@ export class FilterManager { private handleStateUpdate(newFilters: esFilters.Filter[]) { // global filters should always be first + newFilters.sort(({ $state: a }: esFilters.Filter, { $state: b }: esFilters.Filter): number => { - return a!.store === esFilters.FilterStateStore.GLOBAL_STATE && - b!.store !== esFilters.FilterStateStore.GLOBAL_STATE - ? -1 - : 1; + if (a!.store === b!.store) { + return 0; + } else { + return a!.store === esFilters.FilterStateStore.GLOBAL_STATE && + b!.store !== esFilters.FilterStateStore.GLOBAL_STATE + ? -1 + : 1; + } }); const filtersUpdated = !_.isEqual(this.filters, newFilters); diff --git a/src/plugins/data/public/query/index.tsx b/src/plugins/data/public/query/index.tsx index 42647b9d98201d..9d7c2ffc56f70b 100644 --- a/src/plugins/data/public/query/index.tsx +++ b/src/plugins/data/public/query/index.tsx @@ -19,3 +19,7 @@ export * from './query_service'; export * from './filter_manager'; + +export * from './timefilter'; + +export * from './persisted_log'; diff --git a/src/plugins/data/public/query/mocks.ts b/src/plugins/data/public/query/mocks.ts index e5030c5765316b..f2832b6b67fa2a 100644 --- a/src/plugins/data/public/query/mocks.ts +++ b/src/plugins/data/public/query/mocks.ts @@ -17,21 +17,24 @@ * under the License. */ -import { QueryService, QueryStart, QuerySetup } from '.'; +import { QueryService, QuerySetup } from '.'; +import { timefilterServiceMock } from './timefilter/timefilter_service.mock'; type QueryServiceClientContract = PublicMethodsOf; const createSetupContractMock = () => { const setupContract: jest.Mocked = { filterManager: jest.fn() as any, + timefilter: timefilterServiceMock.createSetupContract(), }; return setupContract; }; const createStartContractMock = () => { - const startContract: jest.Mocked = { + const startContract = { filterManager: jest.fn() as any, + timefilter: timefilterServiceMock.createStartContract(), }; return startContract; diff --git a/src/legacy/core_plugins/data/public/query/persisted_log/index.ts b/src/plugins/data/public/query/persisted_log/index.ts similarity index 100% rename from src/legacy/core_plugins/data/public/query/persisted_log/index.ts rename to src/plugins/data/public/query/persisted_log/index.ts diff --git a/src/legacy/core_plugins/data/public/query/persisted_log/persisted_log.test.ts b/src/plugins/data/public/query/persisted_log/persisted_log.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/query/persisted_log/persisted_log.test.ts rename to src/plugins/data/public/query/persisted_log/persisted_log.test.ts diff --git a/src/legacy/core_plugins/data/public/query/persisted_log/persisted_log.ts b/src/plugins/data/public/query/persisted_log/persisted_log.ts similarity index 100% rename from src/legacy/core_plugins/data/public/query/persisted_log/persisted_log.ts rename to src/plugins/data/public/query/persisted_log/persisted_log.ts diff --git a/src/plugins/data/public/query/query_service.ts b/src/plugins/data/public/query/query_service.ts index d34909a5e03b79..206f8ac284ec37 100644 --- a/src/plugins/data/public/query/query_service.ts +++ b/src/plugins/data/public/query/query_service.ts @@ -18,7 +18,9 @@ */ import { UiSettingsClientContract } from 'src/core/public'; +import { IStorageWrapper } from 'src/plugins/kibana_utils/public'; import { FilterManager } from './filter_manager'; +import { TimefilterService, TimefilterSetup } from './timefilter'; /** * Query Service @@ -26,23 +28,33 @@ import { FilterManager } from './filter_manager'; */ export interface QueryServiceDependencies { + storage: IStorageWrapper; uiSettings: UiSettingsClientContract; } export class QueryService { filterManager!: FilterManager; + timefilter!: TimefilterSetup; - public setup({ uiSettings }: QueryServiceDependencies) { + public setup({ uiSettings, storage }: QueryServiceDependencies) { this.filterManager = new FilterManager(uiSettings); + const timefilterService = new TimefilterService(); + this.timefilter = timefilterService.setup({ + uiSettings, + storage, + }); + return { filterManager: this.filterManager, + timefilter: this.timefilter, }; } public start() { return { filterManager: this.filterManager, + timefilter: this.timefilter, }; } diff --git a/src/legacy/core_plugins/data/public/timefilter/get_time.test.ts b/src/plugins/data/public/query/timefilter/get_time.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/timefilter/get_time.test.ts rename to src/plugins/data/public/query/timefilter/get_time.test.ts diff --git a/src/legacy/core_plugins/data/public/timefilter/get_time.ts b/src/plugins/data/public/query/timefilter/get_time.ts similarity index 94% rename from src/legacy/core_plugins/data/public/timefilter/get_time.ts rename to src/plugins/data/public/query/timefilter/get_time.ts index 18a43d789714d7..55ee6527fbb1a3 100644 --- a/src/legacy/core_plugins/data/public/timefilter/get_time.ts +++ b/src/plugins/data/public/query/timefilter/get_time.ts @@ -19,7 +19,9 @@ import dateMath from '@elastic/datemath'; import { TimeRange } from 'src/plugins/data/public'; -import { IndexPattern, Field } from '../index_patterns'; + +// TODO: remove this +import { IndexPattern, Field } from '../../../../../legacy/core_plugins/data/public/index_patterns'; interface CalculateBoundsOptions { forceNow?: Date; diff --git a/src/legacy/core_plugins/data/public/timefilter/index.ts b/src/plugins/data/public/query/timefilter/index.ts similarity index 100% rename from src/legacy/core_plugins/data/public/timefilter/index.ts rename to src/plugins/data/public/query/timefilter/index.ts diff --git a/src/legacy/core_plugins/data/public/timefilter/lib/change_time_filter.test.ts b/src/plugins/data/public/query/timefilter/lib/change_time_filter.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/timefilter/lib/change_time_filter.test.ts rename to src/plugins/data/public/query/timefilter/lib/change_time_filter.test.ts diff --git a/src/legacy/core_plugins/data/public/timefilter/lib/change_time_filter.ts b/src/plugins/data/public/query/timefilter/lib/change_time_filter.ts similarity index 100% rename from src/legacy/core_plugins/data/public/timefilter/lib/change_time_filter.ts rename to src/plugins/data/public/query/timefilter/lib/change_time_filter.ts diff --git a/src/legacy/core_plugins/data/public/timefilter/lib/diff_time_picker_vals.test.ts b/src/plugins/data/public/query/timefilter/lib/diff_time_picker_vals.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/timefilter/lib/diff_time_picker_vals.test.ts rename to src/plugins/data/public/query/timefilter/lib/diff_time_picker_vals.test.ts diff --git a/src/legacy/core_plugins/data/public/timefilter/lib/diff_time_picker_vals.ts b/src/plugins/data/public/query/timefilter/lib/diff_time_picker_vals.ts similarity index 100% rename from src/legacy/core_plugins/data/public/timefilter/lib/diff_time_picker_vals.ts rename to src/plugins/data/public/query/timefilter/lib/diff_time_picker_vals.ts diff --git a/src/legacy/core_plugins/data/public/timefilter/lib/extract_time_filter.test.ts b/src/plugins/data/public/query/timefilter/lib/extract_time_filter.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/timefilter/lib/extract_time_filter.test.ts rename to src/plugins/data/public/query/timefilter/lib/extract_time_filter.test.ts diff --git a/src/legacy/core_plugins/data/public/timefilter/lib/extract_time_filter.ts b/src/plugins/data/public/query/timefilter/lib/extract_time_filter.ts similarity index 100% rename from src/legacy/core_plugins/data/public/timefilter/lib/extract_time_filter.ts rename to src/plugins/data/public/query/timefilter/lib/extract_time_filter.ts diff --git a/src/legacy/core_plugins/data/public/timefilter/lib/parse_querystring.ts b/src/plugins/data/public/query/timefilter/lib/parse_querystring.ts similarity index 100% rename from src/legacy/core_plugins/data/public/timefilter/lib/parse_querystring.ts rename to src/plugins/data/public/query/timefilter/lib/parse_querystring.ts diff --git a/src/legacy/core_plugins/data/public/timefilter/time_history.ts b/src/plugins/data/public/query/timefilter/time_history.ts similarity index 97% rename from src/legacy/core_plugins/data/public/timefilter/time_history.ts rename to src/plugins/data/public/query/timefilter/time_history.ts index 36ad1a4427a47e..e14c9ac0bc7ca7 100644 --- a/src/legacy/core_plugins/data/public/timefilter/time_history.ts +++ b/src/plugins/data/public/query/timefilter/time_history.ts @@ -20,7 +20,7 @@ import moment from 'moment'; import { TimeRange } from 'src/plugins/data/public'; import { IStorageWrapper } from 'src/plugins/kibana_utils/public'; -import { PersistedLog } from '../query/persisted_log'; +import { PersistedLog } from '../persisted_log'; export class TimeHistory { private history: PersistedLog; diff --git a/src/legacy/core_plugins/data/public/timefilter/timefilter.test.ts b/src/plugins/data/public/query/timefilter/timefilter.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/timefilter/timefilter.test.ts rename to src/plugins/data/public/query/timefilter/timefilter.test.ts diff --git a/src/legacy/core_plugins/data/public/timefilter/timefilter.ts b/src/plugins/data/public/query/timefilter/timefilter.ts similarity index 97% rename from src/legacy/core_plugins/data/public/timefilter/timefilter.ts rename to src/plugins/data/public/query/timefilter/timefilter.ts index 14e167b0fd56e5..137e5100aa20e9 100644 --- a/src/legacy/core_plugins/data/public/timefilter/timefilter.ts +++ b/src/plugins/data/public/query/timefilter/timefilter.ts @@ -20,13 +20,15 @@ import _ from 'lodash'; import { Subject, BehaviorSubject } from 'rxjs'; import moment from 'moment'; -import { RefreshInterval, TimeRange } from 'src/plugins/data/public'; -import { IndexPattern, TimeHistoryContract } from '../index'; +import { RefreshInterval, TimeRange, TimeHistoryContract } from 'src/plugins/data/public'; +import { IndexPattern } from 'src/legacy/core_plugins/data/public'; import { areRefreshIntervalsDifferent, areTimeRangesDifferent } from './lib/diff_time_picker_vals'; import { parseQueryString } from './lib/parse_querystring'; import { calculateBounds, getTime } from './get_time'; import { TimefilterConfig, InputTimeRange, TimeRangeBounds } from './types'; +// TODO: remove! + export class Timefilter { // Fired when isTimeRangeSelectorEnabled \ isAutoRefreshSelectorEnabled are toggled private enabledUpdated$ = new BehaviorSubject(false); diff --git a/src/legacy/core_plugins/data/public/timefilter/timefilter_service.mock.ts b/src/plugins/data/public/query/timefilter/timefilter_service.mock.ts similarity index 100% rename from src/legacy/core_plugins/data/public/timefilter/timefilter_service.mock.ts rename to src/plugins/data/public/query/timefilter/timefilter_service.mock.ts diff --git a/src/legacy/core_plugins/data/public/timefilter/timefilter_service.ts b/src/plugins/data/public/query/timefilter/timefilter_service.ts similarity index 100% rename from src/legacy/core_plugins/data/public/timefilter/timefilter_service.ts rename to src/plugins/data/public/query/timefilter/timefilter_service.ts diff --git a/src/legacy/core_plugins/data/public/timefilter/types.ts b/src/plugins/data/public/query/timefilter/types.ts similarity index 100% rename from src/legacy/core_plugins/data/public/timefilter/types.ts rename to src/plugins/data/public/query/timefilter/types.ts diff --git a/x-pack/legacy/plugins/apm/dev_docs/github_commands.md b/x-pack/legacy/plugins/apm/dev_docs/github_commands.md new file mode 100644 index 00000000000000..f2c32bafa7539d --- /dev/null +++ b/x-pack/legacy/plugins/apm/dev_docs/github_commands.md @@ -0,0 +1,6 @@ +### Useful Github Pull Request commands + +The following commands can be executed by writing them as comments on a pull request: + +- `@elasticmachine merge upstream`: Will merge the upstream (eg. master or 7.x) into the branch. This is useful if a bug has been fixed upstream and the fix is necessary to pass CI checks +- `retest` Re-run the tests. This is useful if a flaky test caused the build to fail diff --git a/x-pack/legacy/plugins/apm/dev_docs/typescript.md b/x-pack/legacy/plugins/apm/dev_docs/typescript.md new file mode 100644 index 00000000000000..105c6edabf48ff --- /dev/null +++ b/x-pack/legacy/plugins/apm/dev_docs/typescript.md @@ -0,0 +1,11 @@ +#### Optimizing TypeScript + +Kibana and X-Pack are very large TypeScript projects, and it comes at a cost. Editor responsiveness is not great, and the CLI type check for X-Pack takes about a minute. To get faster feedback, we create a smaller APM TypeScript project that only type checks the APM project and the files it uses. This optimization consists of creating a `tsconfig.json` in APM that includes the Kibana/X-Pack typings, and editing the Kibana/X-Pack configurations to not include any files, or removing the configurations altogether. The script configures git to ignore any changes in these files, and has an undo script as well. + +To run the optimization: + +`$ node x-pack/legacy/plugins/apm/scripts/optimize-tsconfig` + +To undo the optimization: + +`$ node x-pack/legacy/plugins/apm/scripts/unoptimize-tsconfig` diff --git a/x-pack/legacy/plugins/apm/dev_docs/vscode_setup.md b/x-pack/legacy/plugins/apm/dev_docs/vscode_setup.md new file mode 100644 index 00000000000000..e1901b3855f735 --- /dev/null +++ b/x-pack/legacy/plugins/apm/dev_docs/vscode_setup.md @@ -0,0 +1,53 @@ +### Visual Studio Code + +When using [Visual Studio Code](https://code.visualstudio.com/) with APM it's best to set up a [multi-root workspace](https://code.visualstudio.com/docs/editor/multi-root-workspaces) and add the `x-pack/legacy/plugins/apm` directory, the `x-pack` directory, and the root of the Kibana repository to the workspace. This makes it so you can navigate and search within APM and use the wider workspace roots when you need to widen your search. + +#### Using the Jest extension + +The [vscode-jest extension](https://marketplace.visualstudio.com/items?itemName=Orta.vscode-jest) is a good way to run your Jest tests inside the editor. + +Some of the benefits of using the extension over just running it in a terminal are: + +• It shows the pass/fail of a test inline in the test file +• It shows the error message in the test file if it fails +• You don’t have to have the terminal process running +• It can automatically update your snapshots when they change +• Coverage mapping + +The extension doesn't really work well if you're trying to use it on all of Kibana or all of X-Pack, but it works well if you configure it to run only on the files in APM. + +If you have a workspace configured as described above you should have: + +```json +"jest.disabledWorkspaceFolders": ["kibana", "x-pack"] +``` + +in your Workspace settings, and: + +```json +"jest.pathToJest": "node scripts/jest.js --testPathPattern=legacy/plugins/apm", +"jest.rootPath": "../../.." +``` + +in the settings for the APM folder. + +#### Jest debugging + +To make the [VSCode debugger](https://vscode.readthedocs.io/en/latest/editor/debugging/) work with Jest (you can set breakpoints in the code and tests and use the VSCode debugger) you'll need the [Node Debug extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.node-debug2) installed and can set up a launch configuration like: + +```json +{ + "type": "node", + "name": "APM Jest", + "request": "launch", + "args": ["--runInBand", "--testPathPattern=legacy/plugins/apm"], + "cwd": "${workspaceFolder}/../../..", + "console": "internalConsole", + "internalConsoleOptions": "openOnSessionStart", + "disableOptimisticBPs": true, + "program": "${workspaceFolder}/../../../scripts/jest.js", + "runtimeVersion": "10.15.2" +} +``` + +(you'll want `runtimeVersion` to match what's in the Kibana root .nvmrc. Depending on your setup, you might be able to remove this line.) diff --git a/x-pack/legacy/plugins/apm/readme.md b/x-pack/legacy/plugins/apm/readme.md index 17a72f07470f26..a46b0c2895fcae 100644 --- a/x-pack/legacy/plugins/apm/readme.md +++ b/x-pack/legacy/plugins/apm/readme.md @@ -29,6 +29,13 @@ cd apm-integration-testing/ _Docker Compose is required_ +### Debugging Elasticsearch queries + +All APM api endpoints accept `_debug=true` as a query param that will result in the underlying ES query being outputted in the Kibana backend process. + +Example: +`/api/apm/services/my_service?_debug=true` + ### Unit testing Note: Run the following commands from `kibana/x-pack`. @@ -45,10 +52,6 @@ node scripts/jest.js plugins/apm --watch node scripts/jest.js plugins/apm --updateSnapshot ``` -### Cypress E2E tests - -See the Cypress-specific [readme.md](cypress/README.md) - ### Linting _Note: Run the following commands from `kibana/`._ @@ -65,63 +68,8 @@ yarn prettier "./x-pack/legacy/plugins/apm/**/*.{tsx,ts,js}" --write yarn eslint ./x-pack/legacy/plugins/apm --fix ``` -### Useful Github Pull Request commands - -The following commands can be executed by writing them as comments on a pull request: - - - `@elasticmachine merge upstream`: Will merge the upstream (eg. master or 7.x) into the branch. This is useful if a bug has been fixed upstream and the fix is necessary to pass CI checks - - `retest` Re-run the tests. This is useful if a flaky test caused the build to fail - -### Visual Studio Code - -When using [Visual Studio Code](https://code.visualstudio.com/) with APM it's best to set up a [multi-root workspace](https://code.visualstudio.com/docs/editor/multi-root-workspaces) and add the `x-pack/legacy/plugins/apm` directory, the `x-pack` directory, and the root of the Kibana repository to the workspace. This makes it so you can navigate and search within APM and use the wider workspace roots when you need to widen your search. - -#### Using the Jest extension - -The [vscode-jest extension](https://marketplace.visualstudio.com/items?itemName=Orta.vscode-jest) is a good way to run your Jest tests inside the editor. - -Some of the benefits of using the extension over just running it in a terminal are: - -• It shows the pass/fail of a test inline in the test file -• It shows the error message in the test file if it fails -• You don’t have to have the terminal process running -• It can automatically update your snapshots when they change -• Coverage mapping - -The extension doesn't really work well if you're trying to use it on all of Kibana or all of X-Pack, but it works well if you configure it to run only on the files in APM. - -If you have a workspace configured as described above you should have: - -```json -"jest.disabledWorkspaceFolders": ["kibana", "x-pack"] -``` - -in your Workspace settings, and: - -```json -"jest.pathToJest": "node scripts/jest.js --testPathPattern=legacy/plugins/apm", -"jest.rootPath": "../../.." -``` - -in the settings for the APM folder. - -#### Jest debugging - -To make the [VSCode debugger](https://vscode.readthedocs.io/en/latest/editor/debugging/) work with Jest (you can set breakpoints in the code and tests and use the VSCode debugger) you'll need the [Node Debug extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.node-debug2) installed and can set up a launch configuration like: - -```json -{ - "type": "node", - "name": "APM Jest", - "request": "launch", - "args": ["--runInBand", "--testPathPattern=legacy/plugins/apm"], - "cwd": "${workspaceFolder}/../../..", - "console": "internalConsole", - "internalConsoleOptions": "openOnSessionStart", - "disableOptimisticBPs": true, - "program": "${workspaceFolder}/../../../scripts/jest.js", - "runtimeVersion": "10.15.2" -} -``` +#### Further resources -(you'll want `runtimeVersion` to match what's in the Kibana root .nvmrc. Depending on your setup, you might be able to remove this line.) +- [Cypress integration tests](cypress/README.md) +- [VSCode setup instructions](./dev_docs/vscode_setup.md) +- [Github PR commands](./dev_docs/github_commands.md) diff --git a/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig.js b/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig.js new file mode 100644 index 00000000000000..c1f1472dc90241 --- /dev/null +++ b/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig.js @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +const { optimizeTsConfig } = require('./optimize-tsconfig/optimize'); + +optimizeTsConfig(); diff --git a/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/optimize.js b/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/optimize.js new file mode 100644 index 00000000000000..ef9e393db3eca7 --- /dev/null +++ b/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/optimize.js @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +/* eslint-disable import/no-extraneous-dependencies */ + +const fs = require('fs'); +const promisify = require('util').promisify; +const path = require('path'); +const json5 = require('json5'); +const execa = require('execa'); + +const copyFile = promisify(fs.copyFile); +const rename = promisify(fs.rename); +const readFile = promisify(fs.readFile); +const writeFile = promisify(fs.writeFile); + +const { + xpackRoot, + kibanaRoot, + apmRoot, + tsconfigTpl, + filesToIgnore +} = require('./paths'); +const { unoptimizeTsConfig } = require('./unoptimize'); + +function updateParentTsConfigs() { + return Promise.all( + [ + path.resolve(xpackRoot, 'apm.tsconfig.json'), + path.resolve(kibanaRoot, 'tsconfig.json') + ].map(async filename => { + const config = json5.parse(await readFile(filename, 'utf-8')); + + await writeFile( + filename, + JSON.stringify( + { + ...config, + include: [] + }, + null, + 2 + ), + { encoding: 'utf-8' } + ); + }) + ); +} + +async function setIgnoreChanges() { + for (const filename of filesToIgnore) { + await execa('git', ['update-index', '--skip-worktree', filename]); + } +} + +const optimizeTsConfig = () => { + return unoptimizeTsConfig() + .then(() => + Promise.all([ + copyFile(tsconfigTpl, path.resolve(apmRoot, './tsconfig.json')), + rename( + path.resolve(xpackRoot, 'tsconfig.json'), + path.resolve(xpackRoot, 'apm.tsconfig.json') + ) + ]) + ) + .then(() => updateParentTsConfigs()) + .then(() => setIgnoreChanges()) + .then(() => { + // eslint-disable-next-line no-console + console.log( + 'Created an optimized tsconfig.json for APM. To undo these changes, run `./scripts/unoptimize-tsconfig.js`' + ); + }); +}; + +module.exports = { + optimizeTsConfig +}; diff --git a/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/paths.js b/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/paths.js new file mode 100644 index 00000000000000..cdb8e4d878ea36 --- /dev/null +++ b/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/paths.js @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +const path = require('path'); + +const apmRoot = path.resolve(__dirname, '../..'); +const xpackRoot = path.resolve(apmRoot, '../../..'); +const kibanaRoot = path.resolve(xpackRoot, '..'); + +const tsconfigTpl = path.resolve(__dirname, './tsconfig.json'); + +const filesToIgnore = [ + path.resolve(xpackRoot, 'tsconfig.json'), + path.resolve(kibanaRoot, 'tsconfig.json') +]; + +module.exports = { + apmRoot, + xpackRoot, + kibanaRoot, + tsconfigTpl, + filesToIgnore +}; diff --git a/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/tsconfig.json b/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/tsconfig.json new file mode 100644 index 00000000000000..e7d9abea65a3ac --- /dev/null +++ b/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../../apm.tsconfig.json", + "include": [ + "./**/*", + "../../../typings/**/*" + ], + "exclude": [ + "**/__fixtures__/**/*", + "./cypress/**/*" + ] +} diff --git a/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/unoptimize.js b/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/unoptimize.js new file mode 100644 index 00000000000000..3fdf2a97363a8c --- /dev/null +++ b/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/unoptimize.js @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +/* eslint-disable import/no-extraneous-dependencies */ + +const path = require('path'); +const execa = require('execa'); +const fs = require('fs'); +const promisify = require('util').promisify; +const removeFile = promisify(fs.unlink); +const exists = promisify(fs.exists); + +const { apmRoot, filesToIgnore } = require('./paths'); + +async function unoptimizeTsConfig() { + for (const filename of filesToIgnore) { + await execa('git', ['update-index', '--no-skip-worktree', filename]); + await execa('git', ['checkout', filename]); + } + + const apmTsConfig = path.join(apmRoot, 'tsconfig.json'); + if (await exists(apmTsConfig)) { + await removeFile(apmTsConfig); + } +} + +module.exports = { + unoptimizeTsConfig: () => { + return unoptimizeTsConfig().then(() => { + // eslint-disable-next-line no-console + console.log('Removed APM TypeScript optimizations'); + }); + } +}; diff --git a/x-pack/legacy/plugins/apm/scripts/unoptimize-tsconfig.js b/x-pack/legacy/plugins/apm/scripts/unoptimize-tsconfig.js new file mode 100644 index 00000000000000..5362b6a6d52e20 --- /dev/null +++ b/x-pack/legacy/plugins/apm/scripts/unoptimize-tsconfig.js @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +const { unoptimizeTsConfig } = require('./optimize-tsconfig/unoptimize'); + +unoptimizeTsConfig(); diff --git a/x-pack/legacy/plugins/apm/typings/common.ts b/x-pack/legacy/plugins/apm/typings/common.d.ts similarity index 77% rename from x-pack/legacy/plugins/apm/typings/common.ts rename to x-pack/legacy/plugins/apm/typings/common.d.ts index 2fafceb32209c1..d79b05ed99b496 100644 --- a/x-pack/legacy/plugins/apm/typings/common.ts +++ b/x-pack/legacy/plugins/apm/typings/common.d.ts @@ -4,6 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ +import '../../infra/types/rison_node'; +import '../../infra/types/eui'; +// EUIBasicTable +import {} from '../../reporting/public/components/report_listing'; +// .svg +import '../../canvas/types/webpack'; + // Allow unknown properties in an object export type AllowUnknownProperties = T extends Array ? Array> diff --git a/x-pack/legacy/plugins/ml/public/util/chart_utils.test.js b/x-pack/legacy/plugins/ml/public/util/chart_utils.test.js index aaec5e412c4cb3..6d13f1bc668089 100644 --- a/x-pack/legacy/plugins/ml/public/util/chart_utils.test.js +++ b/x-pack/legacy/plugins/ml/public/util/chart_utils.test.js @@ -14,19 +14,18 @@ jest.mock('ui/registry/field_formats', () => ({ jest.mock('ui/timefilter', () => { const dateMath = require('@elastic/datemath'); - const { dataPluginMock } = require('../../../../../../src/legacy/core_plugins/data/public/mocks'); - const dataSetup = dataPluginMock.createSetup(); - const { timefilter } = dataSetup.timefilter; let _time = undefined; - timefilter.setTime.mockImplementation((time) => { - _time = time; - }); - timefilter.getActiveBounds.mockImplementation(() => { - return { - min: dateMath.parse(_time.from), - max: dateMath.parse(_time.to), - }; - }); + const timefilter = { + setTime: (time) => { + _time = time; + }, + getActiveBounds: () => { + return { + min: dateMath.parse(_time.from), + max: dateMath.parse(_time.to), + }; + } + }; return { timefilter, }; diff --git a/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx b/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx index c885d001542e58..5b60b625212936 100644 --- a/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx @@ -41,7 +41,6 @@ import { esFilters } from '../../../../../../../src/plugins/data/public'; const { ui: { SearchBar }, search, - timefilter, } = data; export const siemFilterManager = npStart.plugins.data.query.filterManager; @@ -99,10 +98,11 @@ const SearchBarComponent = memo { + const { timefilter } = npStart.plugins.data.query.timefilter; if (fromStr != null && toStr != null) { - timefilter.timefilter.setTime({ from: fromStr, to: toStr }); + timefilter.setTime({ from: fromStr, to: toStr }); } else if (start != null && end != null) { - timefilter.timefilter.setTime({ + timefilter.setTime({ from: new Date(start).toISOString(), to: new Date(end).toISOString(), });