diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggconfigs.getresolvedtimerange.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggconfigs.getresolvedtimerange.md new file mode 100644 index 00000000000000..2af44037292a23 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggconfigs.getresolvedtimerange.md @@ -0,0 +1,19 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [AggConfigs](./kibana-plugin-plugins-data-public.aggconfigs.md) > [getResolvedTimeRange](./kibana-plugin-plugins-data-public.aggconfigs.getresolvedtimerange.md) + +## AggConfigs.getResolvedTimeRange() method + +Returns the current time range as moment instance (date math will get resolved using the current "now" value or system time if not set) + +Signature: + +```typescript +getResolvedTimeRange(): import("../..").TimeRangeBounds | undefined; +``` +Returns: + +`import("../..").TimeRangeBounds | undefined` + +Current time range as resolved date. + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggconfigs.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggconfigs.md index 45333b6767cace..9e671675b0b29f 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggconfigs.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggconfigs.md @@ -42,6 +42,7 @@ export declare class AggConfigs | [getAll()](./kibana-plugin-plugins-data-public.aggconfigs.getall.md) | | | | [getRequestAggById(id)](./kibana-plugin-plugins-data-public.aggconfigs.getrequestaggbyid.md) | | | | [getRequestAggs()](./kibana-plugin-plugins-data-public.aggconfigs.getrequestaggs.md) | | | +| [getResolvedTimeRange()](./kibana-plugin-plugins-data-public.aggconfigs.getresolvedtimerange.md) | | Returns the current time range as moment instance (date math will get resolved using the current "now" value or system time if not set) | | [getResponseAggById(id)](./kibana-plugin-plugins-data-public.aggconfigs.getresponseaggbyid.md) | | Find a response agg by it's id. This may be an agg in the aggConfigs, or one created specifically for a response value | | [getResponseAggs()](./kibana-plugin-plugins-data-public.aggconfigs.getresponseaggs.md) | | Gets the AggConfigs (and possibly ResponseAggConfigs) that represent the values that will be produced when all aggs are run.With multi-value metric aggs it is possible for a single agg request to result in multiple agg values, which is why the length of a vis' responseValuesAggs may be different than the vis' aggs {array\[AggConfig\]} | | [getSearchSourceTimeFilter(forceNow)](./kibana-plugin-plugins-data-public.aggconfigs.getsearchsourcetimefilter.md) | | | diff --git a/src/plugins/data/common/search/aggs/agg_config.ts b/src/plugins/data/common/search/aggs/agg_config.ts index 3c83b5bdf6084b..9a35cf983c8057 100644 --- a/src/plugins/data/common/search/aggs/agg_config.ts +++ b/src/plugins/data/common/search/aggs/agg_config.ts @@ -192,9 +192,8 @@ export class AggConfig { } else if (!this.aggConfigs.timeRange) { return; } - return moment.duration( - moment(this.aggConfigs.timeRange.to).diff(this.aggConfigs.timeRange.from) - ); + const resolvedBounds = this.aggConfigs.getResolvedTimeRange()!; + return moment.duration(moment(resolvedBounds.max).diff(resolvedBounds.min)); } return parsedTimeShift; } diff --git a/src/plugins/data/common/search/aggs/agg_configs.ts b/src/plugins/data/common/search/aggs/agg_configs.ts index 8593a0b0ed0fa3..c205b46e077f03 100644 --- a/src/plugins/data/common/search/aggs/agg_configs.ts +++ b/src/plugins/data/common/search/aggs/agg_configs.ts @@ -23,7 +23,7 @@ import { IAggType } from './agg_type'; import { AggTypesRegistryStart } from './agg_types_registry'; import { AggGroupNames } from './agg_groups'; import { IndexPattern } from '../../index_patterns/index_patterns/index_pattern'; -import { TimeRange, getTime, isRangeFilter } from '../../../common'; +import { TimeRange, getTime, isRangeFilter, calculateBounds } from '../../../common'; import { IBucketAggConfig } from './buckets'; import { insertTimeShiftSplit, mergeTimeShifts } from './utils/time_splits'; @@ -127,6 +127,19 @@ export class AggConfigs { this.aggs.forEach(updateAggTimeRange); } + /** + * Returns the current time range as moment instance (date math will get resolved using the current "now" value or system time if not set) + * @returns Current time range as resolved date. + */ + getResolvedTimeRange() { + return ( + this.timeRange && + calculateBounds(this.timeRange, { + forceNow: this.forceNow, + }) + ); + } + // clone method will reuse existing AggConfig in the list (will not create new instances) clone({ enabledOnly = true } = {}) { const filterAggs = (agg: AggConfig) => { diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index d56727b468da6f..4d9c69b137a3e0 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -259,6 +259,7 @@ export class AggConfigs { getRequestAggById(id: string): AggConfig | undefined; // (undocumented) getRequestAggs(): AggConfig[]; + getResolvedTimeRange(): import("../..").TimeRangeBounds | undefined; getResponseAggById(id: string): AggConfig | undefined; getResponseAggs(): AggConfig[]; // (undocumented) diff --git a/test/interpreter_functional/test_suites/run_pipeline/esaggs_timeshift.ts b/test/interpreter_functional/test_suites/run_pipeline/esaggs_timeshift.ts index c750602f735bd9..8fc09ce2d73424 100644 --- a/test/interpreter_functional/test_suites/run_pipeline/esaggs_timeshift.ts +++ b/test/interpreter_functional/test_suites/run_pipeline/esaggs_timeshift.ts @@ -71,6 +71,21 @@ export default function ({ expect(getCell(result, 0, 2)).to.be(4618); }); + it('shifts multiple metrics with relative time range and previous', async () => { + const expression = ` + kibana_context timeRange={timerange from='${timeRange.from}' to='now'} + | esaggs index={indexPatternLoad id='logstash-*'} + aggs={aggCount id="1" enabled=true schema="metric"} + aggs={aggCount id="2" enabled=true schema="metric" timeShift="previous"} + `; + const result = await expectExpression( + 'esaggs_shift_multi_metric_previous', + expression + ).getResponse(); + expect(getCell(result, 0, 0)).to.be(9247); + expect(getCell(result, 0, 1)).to.be(4763); + }); + it('shifts single percentile', async () => { const expression = ` kibana_context timeRange={timerange from='${timeRange.from}' to='${timeRange.to}'} @@ -137,7 +152,7 @@ export default function ({ customMetric={aggAvg id="3" field="bytes" enabled=true - schema="metric" + schema="metric" } enabled=true schema="metric" @@ -154,7 +169,7 @@ export default function ({ customMetric={aggAvg id="5" field="bytes" enabled=true - schema="metric" + schema="metric" } enabled=true schema="metric" diff --git a/x-pack/plugins/canvas/public/components/workpad_header/view_menu/view_menu.component.tsx b/x-pack/plugins/canvas/public/components/workpad_header/view_menu/view_menu.component.tsx index 8f92db4e7f3f46..8fb24c1f3c62e9 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/view_menu/view_menu.component.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/view_menu/view_menu.component.tsx @@ -85,10 +85,6 @@ export interface Props { * Current autoplay interval */ autoplayInterval: number; - /** - * Enables autoplay - */ - enableAutoplay: (autoplay: boolean) => void; /** * Sets autoplay interval */ @@ -110,7 +106,6 @@ export const ViewMenu: FunctionComponent = ({ setRefreshInterval, autoplayEnabled, autoplayInterval, - enableAutoplay, setAutoplayInterval, }) => { const setRefresh = (val: number) => setRefreshInterval(val); @@ -259,6 +254,5 @@ ViewMenu.propTypes = { setRefreshInterval: PropTypes.func.isRequired, autoplayEnabled: PropTypes.bool.isRequired, autoplayInterval: PropTypes.number.isRequired, - enableAutoplay: PropTypes.func.isRequired, setAutoplayInterval: PropTypes.func.isRequired, }; diff --git a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_history.test.ts b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_history.test.ts index b5b9c038cfd2d8..515da36ddbb361 100644 --- a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_history.test.ts +++ b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_history.test.ts @@ -26,76 +26,234 @@ describe('useRestoreHistory', () => { jest.resetAllMocks(); }); - test('replaces undefined state with current state', () => { - const history = { - location: { - state: undefined, - pathname: 'somepath', - }, - push: jest.fn(), - replace: jest.fn(), - }; - - const state = { - persistent: { some: 'state' }, - }; - - mockGetState.mockReturnValue(state); - mockGetHistory.mockReturnValue(history); - - renderHook(() => useWorkpadHistory()); - - expect(history.replace).toBeCalledWith(history.location.pathname, encode(state.persistent)); + describe('initial run', () => { + test('with undefined location state ', () => { + const history = { + location: { + state: undefined, + pathname: 'somepath', + }, + push: jest.fn(), + replace: jest.fn(), + }; + + const state = { + persistent: { some: 'state' }, + }; + + mockGetState.mockReturnValue(state); + mockGetHistory.mockReturnValue(history); + + renderHook(() => useWorkpadHistory()); + + expect(history.replace).toBeCalledWith(history.location.pathname, encode(state.persistent)); + expect(history.push).not.toBeCalled(); + }); + + test('with location state not matching store state', () => { + const history = { + location: { + state: encode({ prior: 'state' }), + pathname: 'somepath', + }, + push: jest.fn(), + replace: jest.fn(), + }; + + const state = { + persistent: { some: 'state' }, + }; + + mockGetState.mockReturnValue(state); + mockGetHistory.mockReturnValue(history); + + renderHook(() => useWorkpadHistory()); + + expect(history.push).not.toBeCalled(); + expect(history.replace).not.toBeCalled(); + }); + + test('with location state matching store state', () => { + const state = { some: 'state' }; + const history = { + location: { + state: encode(state), + pathname: 'somepath', + }, + push: jest.fn(), + replace: jest.fn(), + }; + mockGetState.mockReturnValue(state); + mockGetHistory.mockReturnValue(history); + + renderHook(() => useWorkpadHistory()); + + expect(history.push).not.toBeCalled(); + expect(history.replace).not.toBeCalled(); + }); }); - test('does not do a push on initial render if states do not match', () => { - const history = { - location: { - state: encode({ old: 'state' }), - pathname: 'somepath', - }, - push: jest.fn(), - replace: jest.fn(), - }; + describe('state changes', () => { + it('does a replace if location state is undefined', () => { + const push = jest.fn(); + const replace = jest.fn(); + + const history = { + location: { + state: encode({ old: 'state' }), + pathname: 'somepath', + search: '', + }, + push, + replace, + }; + + const state = { + persistent: { some: 'state' }, + }; + + const newState = { + persistent: { new: 'state' }, + }; + + mockGetState.mockReturnValue(state); + mockGetHistory.mockReturnValue(history); + + const { rerender } = renderHook(() => useWorkpadHistory()); + + mockGetState.mockReturnValue(newState); + // History object from react router will not change, so just modifying here + history.location.state = undefined; + history.location.pathname = 'newpath'; + rerender(); - const state = { - persistent: { some: 'state' }, - }; + expect(history.replace).toBeCalledWith('newpath', encode(newState.persistent)); + }); - mockGetState.mockReturnValue(state); - mockGetHistory.mockReturnValue(history); + test('does a push if location state does not match store state', () => { + const history = { + location: { + state: encode({ old: 'state' }), + pathname: 'somepath', + }, + push: jest.fn(), + replace: jest.fn(), + }; - renderHook(() => useWorkpadHistory()); + const oldState = { + persistent: { some: 'state' }, + }; - expect(history.push).not.toBeCalled(); + const newState = { + persistent: { new: 'state' }, + }; + + mockGetState.mockReturnValue(oldState); + mockGetHistory.mockReturnValue(history); + + const { rerender } = renderHook(() => useWorkpadHistory()); + + mockGetState.mockReturnValue(newState); + rerender(); + + expect(history.push).toBeCalledWith(history.location.pathname, encode(newState.persistent)); + }); + + test('does nothing if new state matches location state', () => { + const state = { + persistent: { some: 'state' }, + }; + + const newState = { ...state }; + + const history = { + location: { + state: encode(state.persistent), + pathname: 'somepath', + }, + push: jest.fn(), + replace: jest.fn(), + }; + + mockGetState.mockReturnValue(state); + mockGetHistory.mockReturnValue(history); + + const { rerender } = renderHook(() => useWorkpadHistory()); + + mockGetState.mockReturnValue(newState); + rerender(); + + expect(history.push).not.toBeCalled(); + expect(history.replace).not.toBeCalled(); + }); }); - test('rerender does a push if location state does not match store state', () => { - const history = { - location: { - state: encode({ old: 'state' }), - pathname: 'somepath', - }, - push: jest.fn(), - replace: jest.fn(), - }; + describe('changes to location', () => { + test('changes to pathname have no effect', () => { + // This is equivalent of navigating to a new page. + // The location state will initially be undefined, but + // we don't want to take any action because it will cause a state change + // and that will be picked up and do the replace + const state = { + persistent: { some: 'state' }, + }; + + const history = { + location: { + state: encode(state.persistent), + pathname: 'somepath', + }, + push: jest.fn(), + replace: jest.fn(), + }; + + mockGetState.mockReturnValue(state); + mockGetHistory.mockReturnValue(history); + + const { rerender } = renderHook(() => useWorkpadHistory()); + + history.location.state = undefined; + history.location.pathname = 'newpath'; + + rerender(); + + expect(history.push).not.toBeCalled(); + expect(history.replace).not.toBeCalled(); + }); - const oldState = { - persistent: { some: 'state' }, - }; + test('changes to search does a replace', () => { + // This is equivalent of going from full screen to not full screen + // There is no state change that will occur, but we still need to update + // the location state + const state = { + persistent: { some: 'state' }, + }; - const newState = { - persistent: { new: 'state' }, - }; + const history = { + location: { + state: encode(state.persistent), + pathname: 'somepath', + search: '', + }, + push: jest.fn(), + replace: jest.fn(), + }; - mockGetState.mockReturnValue(oldState); - mockGetHistory.mockReturnValue(history); + mockGetState.mockReturnValue(state); + mockGetHistory.mockReturnValue(history); - const { rerender } = renderHook(() => useWorkpadHistory()); + const { rerender } = renderHook(() => useWorkpadHistory()); + history.location.pathname = 'somepath'; + history.location.search = 'newsearch'; + history.location.state = undefined; - mockGetState.mockReturnValue(newState); - rerender(); + rerender(); - expect(history.push).toBeCalledWith(history.location.pathname, encode(newState.persistent)); + expect(history.push).not.toBeCalled(); + expect(history.replace).toBeCalledWith( + `somepath?${history.location.search}`, + encode(state.persistent) + ); + }); }); }); diff --git a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_history.ts b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_history.ts index 1f563f71473301..b8880be60e36ad 100644 --- a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_history.ts +++ b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_history.ts @@ -31,11 +31,10 @@ export const useWorkpadHistory = () => { // This will happen when navigating directly to a url (there will be no state on that link click) if (locationState === undefined) { history.replace(fullPath, encode(historyState)); - } else if (!doesStateMatchLocationState && !isInitialRun) { + } else if (!isInitialRun && !doesStateMatchLocationState) { // There was a state change here - // If the state of the route that we are on does not match this new state, then we are going to push history.push(fullPath, encode(historyState)); } - }, [history, historyState]); + }, [history, historyState, history.location.search]); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/__mocks__/engine_logic.mock.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/__mocks__/engine_logic.mock.ts index 23d638d5f25f3d..b38659b7a9a797 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/__mocks__/engine_logic.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/__mocks__/engine_logic.mock.ts @@ -6,7 +6,7 @@ */ import { EngineDetails } from '../components/engine/types'; -import { ENGINES_TITLE } from '../components/engines'; +import { ENGINES_TITLE } from '../components/engines/constants'; import { generateEncodedPath } from '../utils/encode_path_params'; export const mockEngineValues = { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_creation/engine_creation.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_creation/engine_creation.tsx index 250c941009ecb9..913aa4f0ec8452 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_creation/engine_creation.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_creation/engine_creation.tsx @@ -16,15 +16,13 @@ import { EuiFlexItem, EuiFieldText, EuiSelect, - EuiPageHeader, - EuiPageContent, + EuiPanel, EuiSpacer, EuiTitle, EuiButton, } from '@elastic/eui'; -import { FlashMessages } from '../../../shared/flash_messages'; -import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; +import { AppSearchPageTemplate } from '../layout'; import { ALLOWED_CHARS_NOTE, @@ -44,77 +42,77 @@ export const EngineCreation: React.FC = () => { const { setLanguage, setRawName, submitEngine } = useActions(EngineCreationLogic); return ( -
- - - - - -
{ - e.preventDefault(); - submitEngine(); - }} - > - -

{ENGINE_CREATION_FORM_TITLE}

-
- - - - 0 && rawName !== name ? ( - <> - {SANITIZED_NAME_NOTE} {name} - - ) : ( - ALLOWED_CHARS_NOTE - ) - } + + + { + e.preventDefault(); + submitEngine(); + }} + > + +

{ENGINE_CREATION_FORM_TITLE}

+
+ + + + 0 && rawName !== name ? ( + <> + {SANITIZED_NAME_NOTE} {name} + + ) : ( + ALLOWED_CHARS_NOTE + ) + } + fullWidth + > + setRawName(event.currentTarget.value)} + autoComplete="off" fullWidth - > - setRawName(event.currentTarget.value)} - autoComplete="off" - fullWidth - data-test-subj="EngineCreationNameInput" - placeholder={ENGINE_CREATION_FORM_ENGINE_NAME_PLACEHOLDER} - autoFocus - /> - - - - - setLanguage(event.currentTarget.value)} - /> - - - - - - {ENGINE_CREATION_FORM_SUBMIT_BUTTON_LABEL} - - + data-test-subj="EngineCreationNameInput" + placeholder={ENGINE_CREATION_FORM_ENGINE_NAME_PLACEHOLDER} + autoFocus + /> +
+
+ + + setLanguage(event.currentTarget.value)} + /> + + +
+ + + {ENGINE_CREATION_FORM_SUBMIT_BUTTON_LABEL} +
-
-
+ + ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.tsx index e6a7c03d2aab48..df17d22d387d90 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { useValues, useActions } from 'kea'; -import { EuiPageContent, EuiEmptyPrompt, EuiSpacer } from '@elastic/eui'; +import { EuiEmptyPrompt, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { EuiButtonTo } from '../../../../shared/react_router_helpers'; @@ -20,86 +20,72 @@ import { ENGINE_CREATION_PATH } from '../../../routes'; import { SampleEngineCreationCta } from '../../sample_engine_creation_cta/sample_engine_creation_cta'; -import { EnginesOverviewHeader } from './header'; - export const EmptyState: React.FC = () => { const { myRole: { canManageEngines }, } = useValues(AppLogic); const { sendAppSearchTelemetry } = useActions(TelemetryLogic); - return ( - <> - - - {canManageEngines ? ( - - {i18n.translate('xpack.enterpriseSearch.appSearch.emptyState.title', { - defaultMessage: 'Create your first engine', - })} - - } - titleSize="l" - body={ -

- {i18n.translate('xpack.enterpriseSearch.appSearch.emptyState.description1', { - defaultMessage: - 'An App Search engine stores the documents for your search experience.', - })} -

- } - actions={ - <> - - sendAppSearchTelemetry({ - action: 'clicked', - metric: 'create_first_engine_button', - }) - } - > - {i18n.translate( - 'xpack.enterpriseSearch.appSearch.emptyState.createFirstEngineCta', - { defaultMessage: 'Create an engine' } - )} - - - - - } - /> - ) : ( - - {i18n.translate('xpack.enterpriseSearch.appSearch.emptyState.nonAdmin.title', { - defaultMessage: 'No engines available', - })} - - } - body={ -

- {i18n.translate( - 'xpack.enterpriseSearch.appSearch.emptyState.nonAdmin.description', - { - defaultMessage: - 'Contact your App Search administrator to either create or grant you access to an engine.', - } - )} -

+ return canManageEngines ? ( + + {i18n.translate('xpack.enterpriseSearch.appSearch.emptyState.title', { + defaultMessage: 'Create your first engine', + })} + + } + titleSize="l" + body={ +

+ {i18n.translate('xpack.enterpriseSearch.appSearch.emptyState.description1', { + defaultMessage: 'An App Search engine stores the documents for your search experience.', + })} +

+ } + actions={ + <> + + sendAppSearchTelemetry({ + action: 'clicked', + metric: 'create_first_engine_button', + }) } - /> - )} -
- + > + {i18n.translate('xpack.enterpriseSearch.appSearch.emptyState.createFirstEngineCta', { + defaultMessage: 'Create an engine', + })} + + + + + } + /> + ) : ( + + {i18n.translate('xpack.enterpriseSearch.appSearch.emptyState.nonAdmin.title', { + defaultMessage: 'No engines available', + })} + + } + body={ +

+ {i18n.translate('xpack.enterpriseSearch.appSearch.emptyState.nonAdmin.description', { + defaultMessage: + 'Contact your App Search administrator to either create or grant you access to an engine.', + })} +

+ } + /> ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/header.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/header.tsx deleted file mode 100644 index bab67fd0e4bb50..00000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/header.tsx +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { useActions } from 'kea'; - -import { EuiPageHeader, EuiButton } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -import { getAppSearchUrl } from '../../../../shared/enterprise_search_url'; -import { SetAppSearchChrome as SetPageChrome } from '../../../../shared/kibana_chrome'; -import { TelemetryLogic } from '../../../../shared/telemetry'; - -import { ENGINES_TITLE } from '../constants'; - -export const EnginesOverviewHeader: React.FC = () => { - const { sendAppSearchTelemetry } = useActions(TelemetryLogic); - - return ( - <> - - - sendAppSearchTelemetry({ - action: 'clicked', - metric: 'header_launch_button', - }) - } - data-test-subj="launchButton" - > - {i18n.translate('xpack.enterpriseSearch.appSearch.productCta', { - defaultMessage: 'Launch App Search', - })} - , - ]} - /> - - ); -}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/index.ts index 234d3ba31f44bc..1d8e578e0edf20 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/index.ts @@ -5,7 +5,6 @@ * 2.0. */ -export { EnginesOverviewHeader } from './header'; -export { LoadingState } from './loading_state'; +export { LaunchAppSearchButton } from './launch_as_button'; export { EmptyState } from './empty_state'; export { EmptyMetaEnginesState } from './empty_meta_engines_state'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/header.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/launch_as_button.test.tsx similarity index 64% rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/header.test.tsx rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/launch_as_button.test.tsx index 9b245a468b0838..93c91cc3830f4e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/header.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/launch_as_button.test.tsx @@ -12,23 +12,11 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { EuiPageHeader } from '@elastic/eui'; - -import { EnginesOverviewHeader } from './'; - -describe('EnginesOverviewHeader', () => { - const wrapper = shallow() - .find(EuiPageHeader) - .dive() - .children() - .dive(); - - it('renders', () => { - expect(wrapper.find('h1').text()).toEqual('Engines overview'); - }); +import { LaunchAppSearchButton } from './'; +describe('LaunchAppSearchButton', () => { it('renders a launch app search button that sends telemetry on click', () => { - const button = wrapper.find('[data-test-subj="launchButton"]'); + const button = shallow(); expect(button.prop('href')).toBe('http://localhost:3002/as'); expect(button.prop('isDisabled')).toBeFalsy(); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/launch_as_button.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/launch_as_button.tsx new file mode 100644 index 00000000000000..41102cb4fba2ec --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/launch_as_button.tsx @@ -0,0 +1,41 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { useActions } from 'kea'; + +import { EuiButton } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { getAppSearchUrl } from '../../../../shared/enterprise_search_url'; +import { TelemetryLogic } from '../../../../shared/telemetry'; + +export const LaunchAppSearchButton: React.FC = () => { + const { sendAppSearchTelemetry } = useActions(TelemetryLogic); + + return ( + // eslint-disable-next-line @elastic/eui/href-or-on-click + + sendAppSearchTelemetry({ + action: 'clicked', + metric: 'header_launch_button', + }) + } + data-test-subj="launchButton" + > + {i18n.translate('xpack.enterpriseSearch.appSearch.productCta', { + defaultMessage: 'Launch App Search', + })} + + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.test.tsx deleted file mode 100644 index f7ccfea4bb4d46..00000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.test.tsx +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { shallow } from 'enzyme'; - -import { EuiLoadingContent } from '@elastic/eui'; - -import { LoadingState } from './'; - -describe('LoadingState', () => { - it('renders', () => { - const wrapper = shallow(); - - expect(wrapper.find(EuiLoadingContent)).toHaveLength(2); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.tsx deleted file mode 100644 index 875c47378d1fb0..00000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.tsx +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { EuiPageContent, EuiSpacer, EuiLoadingContent } from '@elastic/eui'; - -import { EnginesOverviewHeader } from './header'; - -export const LoadingState: React.FC = () => { - return ( - <> - - - - - - - - ); -}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/constants.ts index 8d03e3d23ae237..d01e89e004d28d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/constants.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/constants.ts @@ -11,6 +11,11 @@ export const ENGINES_TITLE = i18n.translate('xpack.enterpriseSearch.appSearch.en defaultMessage: 'Engines', }); +export const ENGINES_OVERVIEW_TITLE = i18n.translate( + 'xpack.enterpriseSearch.appSearch.enginesOverview.title', + { defaultMessage: 'Engines overview' } +); + export const META_ENGINES_TITLE = i18n.translate( 'xpack.enterpriseSearch.appSearch.metaEngines.title', { defaultMessage: 'Meta Engines' } diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.test.tsx index 27fe65fe518ebc..8825c322fb8d5f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.test.tsx @@ -14,7 +14,6 @@ import { shallow, ShallowWrapper } from 'enzyme'; import { rerender } from '../../../test_helpers'; -import { LoadingState, EmptyState } from './components'; import { EnginesTable } from './components/tables/engines_table'; import { MetaEnginesTable } from './components/tables/meta_engines_table'; @@ -61,135 +60,117 @@ describe('EnginesOverview', () => { setMockActions(actions); }); - describe('non-happy-path states', () => { - it('isLoading', () => { - setMockValues({ ...values, dataLoading: true }); - const wrapper = shallow(); + const valuesWithEngines = { + ...values, + dataLoading: false, + engines: ['test-engine'], + enginesMeta: { + page: { + current: 1, + size: 10, + total_results: 100, + }, + }, + }; - expect(wrapper.find(LoadingState)).toHaveLength(1); - }); + beforeEach(() => { + jest.clearAllMocks(); + setMockValues(valuesWithEngines); + }); - it('isEmpty', () => { - setMockValues({ ...values, engines: [] }); - const wrapper = shallow(); + it('renders and calls the engines API', () => { + const wrapper = shallow(); - expect(wrapper.find(EmptyState)).toHaveLength(1); - }); + expect(wrapper.find(EnginesTable)).toHaveLength(1); + expect(actions.loadEngines).toHaveBeenCalled(); }); - describe('happy-path states', () => { - const valuesWithEngines = { - ...values, - dataLoading: false, - engines: ['test-engine'], - enginesMeta: { - page: { - current: 1, - size: 10, - total_results: 100, - }, - }, - }; + describe('when the user can manage/create engines', () => { + it('renders a create engine button which takes users to the create engine page', () => { + setMockValues({ + ...valuesWithEngines, + myRole: { canManageEngines: true }, + }); + const wrapper = shallow(); - beforeEach(() => { - jest.clearAllMocks(); - setMockValues(valuesWithEngines); + expect( + wrapper.find('[data-test-subj="appSearchEnginesEngineCreationButton"]').prop('to') + ).toEqual('/engine_creation'); }); + }); - it('renders and calls the engines API', () => { + describe('when the account has a platinum license', () => { + it('renders a 2nd meta engines table & makes a 2nd meta engines call', () => { + setMockValues({ + ...valuesWithEngines, + hasPlatinumLicense: true, + }); const wrapper = shallow(); - expect(wrapper.find(EnginesTable)).toHaveLength(1); - expect(actions.loadEngines).toHaveBeenCalled(); + expect(wrapper.find(MetaEnginesTable)).toHaveLength(1); + expect(actions.loadMetaEngines).toHaveBeenCalled(); }); describe('when the user can manage/create engines', () => { - it('renders a create engine button which takes users to the create engine page', () => { + it('renders a create engine button which takes users to the create meta engine page', () => { setMockValues({ ...valuesWithEngines, + hasPlatinumLicense: true, myRole: { canManageEngines: true }, }); const wrapper = shallow(); expect( - wrapper.find('[data-test-subj="appSearchEnginesEngineCreationButton"]').prop('to') - ).toEqual('/engine_creation'); + wrapper.find('[data-test-subj="appSearchEnginesMetaEngineCreationButton"]').prop('to') + ).toEqual('/meta_engine_creation'); }); }); + }); - describe('when the account has a platinum license', () => { - it('renders a 2nd meta engines table & makes a 2nd meta engines call', () => { - setMockValues({ - ...valuesWithEngines, - hasPlatinumLicense: true, - }); - const wrapper = shallow(); + describe('pagination', () => { + const getTablePagination = (wrapper: ShallowWrapper) => + wrapper.find(EnginesTable).prop('pagination'); - expect(wrapper.find(MetaEnginesTable)).toHaveLength(1); - expect(actions.loadMetaEngines).toHaveBeenCalled(); - }); + it('passes down page data from the API', () => { + const wrapper = shallow(); + const pagination = getTablePagination(wrapper); - describe('when the user can manage/create engines', () => { - it('renders a create engine button which takes users to the create meta engine page', () => { - setMockValues({ - ...valuesWithEngines, - hasPlatinumLicense: true, - myRole: { canManageEngines: true }, - }); - const wrapper = shallow(); - - expect( - wrapper.find('[data-test-subj="appSearchEnginesMetaEngineCreationButton"]').prop('to') - ).toEqual('/meta_engine_creation'); - }); - }); + expect(pagination.totalItemCount).toEqual(100); + expect(pagination.pageIndex).toEqual(0); }); - describe('pagination', () => { - const getTablePagination = (wrapper: ShallowWrapper) => - wrapper.find(EnginesTable).prop('pagination'); - - it('passes down page data from the API', () => { - const wrapper = shallow(); - const pagination = getTablePagination(wrapper); + it('re-polls the API on page change', () => { + const wrapper = shallow(); - expect(pagination.totalItemCount).toEqual(100); - expect(pagination.pageIndex).toEqual(0); + setMockValues({ + ...valuesWithEngines, + enginesMeta: { + page: { + ...valuesWithEngines.enginesMeta.page, + current: 51, + }, + }, }); + rerender(wrapper); - it('re-polls the API on page change', () => { - const wrapper = shallow(); - - setMockValues({ - ...valuesWithEngines, - enginesMeta: { - page: { - ...valuesWithEngines.enginesMeta.page, - current: 51, - }, - }, - }); - rerender(wrapper); + expect(actions.loadEngines).toHaveBeenCalledTimes(2); + expect(getTablePagination(wrapper).pageIndex).toEqual(50); + }); - expect(actions.loadEngines).toHaveBeenCalledTimes(2); - expect(getTablePagination(wrapper).pageIndex).toEqual(50); + it('calls onPagination handlers', () => { + setMockValues({ + ...valuesWithEngines, + hasPlatinumLicense: true, + metaEngines: ['test-meta-engine'], }); + const wrapper = shallow(); + const pageEvent = { page: { index: 0 } }; - it('calls onPagination handlers', () => { - setMockValues({ - ...valuesWithEngines, - hasPlatinumLicense: true, - metaEngines: ['test-meta-engine'], - }); - const wrapper = shallow(); - const pageEvent = { page: { index: 0 } }; - - wrapper.find(EnginesTable).simulate('change', pageEvent); - expect(actions.onEnginesPagination).toHaveBeenCalledWith(1); + wrapper.find(EnginesTable).simulate('change', pageEvent); + expect(actions.onEnginesPagination).toHaveBeenCalledWith(1); - wrapper.find(MetaEnginesTable).simulate('change', pageEvent); - expect(actions.onMetaEnginesPagination).toHaveBeenCalledWith(1); - }); + wrapper.find(MetaEnginesTable).simulate('change', pageEvent); + expect(actions.onMetaEnginesPagination).toHaveBeenCalledWith(1); }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx index 7001ecada999a9..44111a5ecbe66f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx @@ -12,7 +12,7 @@ import { useValues, useActions } from 'kea'; import { EuiFlexGroup, EuiFlexItem, - EuiPageContent, + EuiPanel, EuiPageContentHeader, EuiPageContentHeaderSection, EuiPageContentBody, @@ -20,24 +20,19 @@ import { EuiSpacer, } from '@elastic/eui'; -import { FlashMessages } from '../../../shared/flash_messages'; import { LicensingLogic } from '../../../shared/licensing'; import { EuiButtonTo } from '../../../shared/react_router_helpers'; import { convertMetaToPagination, handlePageChange } from '../../../shared/table_pagination'; -import { SendAppSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; import { AppLogic } from '../../app_logic'; import { EngineIcon, MetaEngineIcon } from '../../icons'; import { ENGINE_CREATION_PATH, META_ENGINE_CREATION_PATH } from '../../routes'; +import { AppSearchPageTemplate } from '../layout'; -import { - EnginesOverviewHeader, - LoadingState, - EmptyState, - EmptyMetaEnginesState, -} from './components'; +import { LaunchAppSearchButton, EmptyState, EmptyMetaEnginesState } from './components'; import { EnginesTable } from './components/tables/engines_table'; import { MetaEnginesTable } from './components/tables/meta_engines_table'; import { + ENGINES_OVERVIEW_TITLE, CREATE_AN_ENGINE_BUTTON_LABEL, CREATE_A_META_ENGINE_BUTTON_LABEL, ENGINES_TITLE, @@ -73,16 +68,19 @@ export const EnginesOverview: React.FC = () => { if (hasPlatinumLicense) loadMetaEngines(); }, [hasPlatinumLicense, metaEnginesMeta.page.current]); - if (dataLoading) return ; - if (!engines.length) return ; - return ( - <> - - - - - + ], + }} + isLoading={dataLoading} + isEmptyState={!engines.length} + emptyState={} + > + @@ -168,7 +166,7 @@ export const EnginesOverview: React.FC = () => { )} - - + + ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation.tsx index 02a1768a7528ea..325e557acec0cd 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation.tsx @@ -18,16 +18,14 @@ import { EuiFormRow, EuiFlexItem, EuiFieldText, - EuiPageContent, - EuiPageHeader, + EuiPanel, EuiSpacer, EuiTitle, EuiButton, } from '@elastic/eui'; -import { FlashMessages } from '../../../shared/flash_messages'; -import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { AppLogic } from '../../app_logic'; +import { AppSearchPageTemplate } from '../layout'; import { ALLOWED_CHARS_NOTE, @@ -74,20 +72,21 @@ export const MetaEngineCreation: React.FC = () => { }, []); return ( -
- - {META_ENGINE_CREATION_FORM_META_ENGINE_DESCRIPTION}
{META_ENGINE_CREATION_FORM_DOCUMENTATION_DESCRIPTION} - } - /> - - + ), + }} + data-test-subj="MetaEngineCreation" + > + { {META_ENGINE_CREATION_FORM_SUBMIT_BUTTON_LABEL} - -
+ + ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx index e66e64b3399daf..d724371cf1dc6e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx @@ -92,9 +92,25 @@ export const AppSearchConfigured: React.FC> = (props) = )} + + + + + + + {canManageEngines && ( + + + + )} + {canManageMetaEngines && ( + + + + )} {canViewRoleMappings && ( @@ -103,28 +119,12 @@ export const AppSearchConfigured: React.FC> = (props) = } readOnlyMode={readOnlyMode}> - - - - - - - {canManageEngines && ( - - - - )} - {canManageMetaEngines && ( - - - - )} diff --git a/x-pack/plugins/fleet/public/applications/integrations/layouts/default.tsx b/x-pack/plugins/fleet/public/applications/integrations/layouts/default.tsx index 98b8e9515e689c..66b88c020f163e 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/layouts/default.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/layouts/default.tsx @@ -5,13 +5,19 @@ * 2.0. */ import React, { memo } from 'react'; -import { EuiText } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiImage, EuiSpacer, EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; + +import styled, { useTheme } from 'styled-components'; + +import type { EuiTheme } from 'src/plugins/kibana_react/common'; + import { useLink } from '../../../hooks'; import type { Section } from '../sections'; -import { HeroImage } from '../sections/epm/screens/home/header'; +import { useLinks } from '../hooks'; import { WithHeaderLayout } from './'; @@ -20,6 +26,30 @@ interface Props { children?: React.ReactNode; } +const Illustration = styled(EuiImage)` + margin-bottom: -68px; + width: 80%; +`; + +const HeroImage = memo(() => { + const { toAssets } = useLinks(); + const theme = useTheme() as EuiTheme; + const IS_DARK_THEME = theme.darkMode; + + return ( + + ); +}); + export const DefaultLayout: React.FunctionComponent = memo(({ section, children }) => { const { getHref } = useLink(); @@ -27,11 +57,29 @@ export const DefaultLayout: React.FunctionComponent = memo(({ section, ch } leftColumn={ - -

- {' '} -

-
+ + +

+ +

+
+ + + + + +

+ +

+
+
+
} tabs={[ { diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/header.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/header.tsx deleted file mode 100644 index 55d058a2d7900e..00000000000000 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/header.tsx +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { memo } from 'react'; -import { i18n } from '@kbn/i18n'; -import styled from 'styled-components'; -import { EuiFlexGroup, EuiFlexItem, EuiImage, EuiText } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; - -import { useLinks, useStartServices } from '../../../../hooks'; - -export const HeroCopy = memo(() => { - return ( - - - -

- -

-
-
- - -

- -

-
-
-
- ); -}); - -const Illustration = styled(EuiImage)` - margin-bottom: -68px; - width: 80%; -`; - -export const HeroImage = memo(() => { - const { toAssets } = useLinks(); - const { uiSettings } = useStartServices(); - const IS_DARK_THEME = uiSettings.get('theme:darkMode'); - - return ( - - ); -}); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/circle.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/circle.test.tsx index e29bb2ac6e92ec..b8c8f6c58f711f 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/circle.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/circle.test.tsx @@ -54,9 +54,10 @@ describe('Processor: Circle', () => { // Click submit button with only the type defined await saveNewProcessor(); - // Expect form error as "field" and "shape_type" are required parameters + // Expect form error as "field", "shape_type" and "error_distance" are required parameters expect(form.getErrorsMessages()).toEqual([ 'A field value is required.', + 'An error distance value is required.', 'A shape type value is required.', ]); }); @@ -91,15 +92,15 @@ describe('Processor: Circle', () => { form, } = testBed; - // Add "field" value (required) + // Set required parameters form.setInputValue('fieldNameField.input', 'field_1'); - // Select the shape form.setSelectValue('shapeSelectorField', 'geo_shape'); - // Add "target_field" value - form.setInputValue('targetField.input', 'target_field'); - form.setInputValue('errorDistanceField.input', '10'); + // Set optional parameters + form.setInputValue('targetField.input', 'target_field'); + form.toggleEuiSwitch('ignoreMissingSwitch.input'); + // Save the field with new changes await saveNewProcessor(); @@ -109,6 +110,7 @@ describe('Processor: Circle', () => { error_distance: 10, shape_type: 'geo_shape', target_field: 'target_field', + ignore_missing: true, }); }); }); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/circle.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/circle.tsx index 74a7f37d841aee..87e08eaeea6e64 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/circle.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/circle.tsx @@ -13,6 +13,7 @@ import { EuiCode } from '@elastic/eui'; import { FIELD_TYPES, fieldValidators, + fieldFormatters, UseField, SelectField, NumericField, @@ -24,13 +25,13 @@ import { FieldNameField } from './common_fields/field_name_field'; import { TargetField } from './common_fields/target_field'; const { emptyField } = fieldValidators; +const { toInt } = fieldFormatters; const fieldsConfig: FieldsConfig = { /* Required fields config */ error_distance: { type: FIELD_TYPES.NUMBER, - deserializer: (v) => (typeof v === 'number' && !isNaN(v) ? v : 1.0), - serializer: Number, + formatters: [toInt], label: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.circleForm.errorDistanceFieldLabel', { @@ -49,18 +50,11 @@ const fieldsConfig: FieldsConfig = { ), validations: [ { - validator: ({ value }) => { - return isNaN(Number(value)) - ? { - message: i18n.translate( - 'xpack.ingestPipelines.pipelineEditor.circleForm.errorDistanceError', - { - defaultMessage: 'An error distance value is required.', - } - ), - } - : undefined; - }, + validator: emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.circleForm.errorDistanceError', { + defaultMessage: 'An error distance value is required.', + }) + ), }, ], }, @@ -110,14 +104,14 @@ export const Circle: FunctionComponent = () => { options: [ { value: 'shape', - label: i18n.translate( + text: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.circleForm.shapeTypeShape', { defaultMessage: 'Shape' } ), }, { value: 'geo_shape', - label: i18n.translate( + text: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.circleForm.shapeTypeGeoShape', { defaultMessage: 'Geo-shape' } ), diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 6b1b8091ec926c..b6e22dc4a519b0 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -9064,7 +9064,6 @@ "xpack.fleet.epm.categoryLabel": "カテゴリー", "xpack.fleet.epm.detailsTitle": "詳細", "xpack.fleet.epm.featuresLabel": "機能", - "xpack.fleet.epm.illustrationAltText": "統合の例", "xpack.fleet.epm.licenseLabel": "ライセンス", "xpack.fleet.epm.loadingIntegrationErrorTitle": "統合詳細の読み込みエラー", "xpack.fleet.epm.packageDetails.integrationList.agentCount": "エージェント", @@ -9079,7 +9078,6 @@ "xpack.fleet.epm.packageDetailsNav.packagePoliciesLinkText": "ポリシー", "xpack.fleet.epm.packageDetailsNav.settingsLinkText": "設定", "xpack.fleet.epm.pageSubtitle": "一般的なアプリやサービスの統合を参照する", - "xpack.fleet.epm.pageTitle": "統合", "xpack.fleet.epm.releaseBadge.betaDescription": "この統合は本番環境用ではありません。", "xpack.fleet.epm.releaseBadge.betaLabel": "ベータ", "xpack.fleet.epm.releaseBadge.experimentalDescription": "この統合は、急に変更されたり、将来のリリースで削除されたりする可能性があります。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 014ebabbe783ff..6ad4e7da082932 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -9150,7 +9150,6 @@ "xpack.fleet.epm.categoryLabel": "类别", "xpack.fleet.epm.detailsTitle": "详情", "xpack.fleet.epm.featuresLabel": "功能", - "xpack.fleet.epm.illustrationAltText": "集成的图示", "xpack.fleet.epm.licenseLabel": "许可证", "xpack.fleet.epm.loadingIntegrationErrorTitle": "加载集成详情时出错", "xpack.fleet.epm.packageDetails.integrationList.agentCount": "代理", @@ -9165,7 +9164,6 @@ "xpack.fleet.epm.packageDetailsNav.packagePoliciesLinkText": "策略", "xpack.fleet.epm.packageDetailsNav.settingsLinkText": "设置", "xpack.fleet.epm.pageSubtitle": "浏览集成以了解热门应用和服务。", - "xpack.fleet.epm.pageTitle": "集成", "xpack.fleet.epm.releaseBadge.betaDescription": "在生产环境中不推荐使用此集成。", "xpack.fleet.epm.releaseBadge.betaLabel": "公测版", "xpack.fleet.epm.releaseBadge.experimentalDescription": "此集成可能有重大更改或将在未来版本中移除。", diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/common/comments/post_comment.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/common/comments/post_comment.ts index e30e276c7b7171..f22ce54de193a4 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/common/comments/post_comment.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/common/comments/post_comment.ts @@ -386,6 +386,8 @@ export default ({ getService }: FtrProviderContext): void => { }, }); + await es.indices.refresh({ index: alert._index }); + const { body: updatedAlert } = await supertest .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) .set('kbn-xsrf', 'true') @@ -439,6 +441,8 @@ export default ({ getService }: FtrProviderContext): void => { }, }); + await es.indices.refresh({ index: alert._index }); + const { body: updatedAlert } = await supertest .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) .set('kbn-xsrf', 'true')