= {
tilemap: true,
regionmap: true,
manifestServiceUrl: true,
+ emsUrl: true,
emsFileApiUrl: true,
emsTileApiUrl: true,
emsLandingPageUrl: true,
diff --git a/src/plugins/telemetry/schema/legacy_plugins.json b/src/plugins/telemetry/schema/legacy_plugins.json
index 1a7c0ccb15082..d5b0514b64918 100644
--- a/src/plugins/telemetry/schema/legacy_plugins.json
+++ b/src/plugins/telemetry/schema/legacy_plugins.json
@@ -1,21 +1,3 @@
{
- "properties": {
- "localization": {
- "properties": {
- "locale": {
- "type": "keyword"
- },
- "integrities": {
- "properties": {
- "DYNAMIC_KEY": {
- "type": "text"
- }
- }
- },
- "labelsCount": {
- "type": "long"
- }
- }
- }
- }
+ "properties": {}
}
diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json
index c840cbe8fc94d..a1eae69ffaed0 100644
--- a/src/plugins/telemetry/schema/oss_plugins.json
+++ b/src/plugins/telemetry/schema/oss_plugins.json
@@ -1581,6 +1581,23 @@
}
}
},
+ "localization": {
+ "properties": {
+ "locale": {
+ "type": "keyword"
+ },
+ "integrities": {
+ "properties": {
+ "DYNAMIC_KEY": {
+ "type": "text"
+ }
+ }
+ },
+ "labelsCount": {
+ "type": "long"
+ }
+ }
+ },
"stack_management": {
"properties": {
"visualize:enableLabs": {
diff --git a/src/plugins/vis_default_editor/public/components/__snapshots__/agg.test.tsx.snap b/src/plugins/vis_default_editor/public/components/__snapshots__/agg.test.tsx.snap
index 2a521bc01219c..26173cddb3716 100644
--- a/src/plugins/vis_default_editor/public/components/__snapshots__/agg.test.tsx.snap
+++ b/src/plugins/vis_default_editor/public/components/__snapshots__/agg.test.tsx.snap
@@ -17,12 +17,12 @@ exports[`DefaultEditorAgg component should init with the default set of props 1`
extraAction={
{
const actionIcons = [];
+ const aggTitle = agg.type?.title?.toLowerCase();
if (showError) {
actionIcons.push({
@@ -170,7 +172,8 @@ function DefaultEditorAgg({
color: 'danger',
type: 'alert',
tooltip: i18n.translate('visDefaultEditor.agg.errorsAriaLabel', {
- defaultMessage: 'Aggregation has errors',
+ defaultMessage: '{schemaTitle} {aggTitle} aggregation has errors',
+ values: { aggTitle, schemaTitle },
}),
dataTestSubj: 'hasErrorsAggregationIcon',
});
@@ -184,7 +187,8 @@ function DefaultEditorAgg({
type: 'eye',
onClick: () => onToggleEnableAgg(agg.id, false),
tooltip: i18n.translate('visDefaultEditor.agg.disableAggButtonTooltip', {
- defaultMessage: 'Disable aggregation',
+ defaultMessage: 'Disable {schemaTitle} {aggTitle} aggregation',
+ values: { aggTitle, schemaTitle },
}),
dataTestSubj: 'toggleDisableAggregationBtn disable',
});
@@ -196,7 +200,8 @@ function DefaultEditorAgg({
type: 'eyeClosed',
onClick: () => onToggleEnableAgg(agg.id, true),
tooltip: i18n.translate('visDefaultEditor.agg.enableAggButtonTooltip', {
- defaultMessage: 'Enable aggregation',
+ defaultMessage: 'Enable {schemaTitle} {aggTitle} aggregation',
+ values: { aggTitle, schemaTitle },
}),
dataTestSubj: 'toggleDisableAggregationBtn enable',
});
@@ -206,7 +211,8 @@ function DefaultEditorAgg({
id: 'dragHandle',
type: 'grab',
tooltip: i18n.translate('visDefaultEditor.agg.modifyPriorityButtonTooltip', {
- defaultMessage: 'Modify priority by dragging',
+ defaultMessage: 'Modify priority of {schemaTitle} {aggTitle} by dragging',
+ values: { aggTitle, schemaTitle },
}),
dataTestSubj: 'dragHandleBtn',
});
@@ -218,7 +224,8 @@ function DefaultEditorAgg({
type: 'cross',
onClick: () => removeAgg(agg.id),
tooltip: i18n.translate('visDefaultEditor.agg.removeDimensionButtonTooltip', {
- defaultMessage: 'Remove dimension',
+ defaultMessage: 'Remove {schemaTitle} {aggTitle} aggregation',
+ values: { aggTitle, schemaTitle },
}),
dataTestSubj: 'removeDimensionBtn',
});
@@ -257,7 +264,7 @@ function DefaultEditorAgg({
);
};
- const schemaTitle = getSchemaByName(schemas, agg.schema).title;
+
const buttonContent = (
<>
{schemaTitle || agg.schema} {showDescription && {aggDescription}}
diff --git a/src/plugins/vis_default_editor/public/components/agg_add.tsx b/src/plugins/vis_default_editor/public/components/agg_add.tsx
index 46d5af8cec680..e78f2fcc4453c 100644
--- a/src/plugins/vis_default_editor/public/components/agg_add.tsx
+++ b/src/plugins/vis_default_editor/public/components/agg_add.tsx
@@ -56,22 +56,26 @@ function DefaultEditorAggAdd({
addSchema(schema);
};
+ const groupNameLabel =
+ groupName === AggGroupNames.Buckets
+ ? i18n.translate('visDefaultEditor.aggAdd.bucketLabel', { defaultMessage: 'bucket' })
+ : i18n.translate('visDefaultEditor.aggAdd.metricLabel', { defaultMessage: 'metric' });
+
const addButton = (
setIsPopoverOpen(!isPopoverOpen)}
+ aria-label={i18n.translate('visDefaultEditor.aggAdd.addGroupButtonLabel', {
+ defaultMessage: 'Add {groupNameLabel}',
+ values: { groupNameLabel },
+ })}
>
);
- const groupNameLabel =
- groupName === AggGroupNames.Buckets
- ? i18n.translate('visDefaultEditor.aggAdd.bucketLabel', { defaultMessage: 'bucket' })
- : i18n.translate('visDefaultEditor.aggAdd.metricLabel', { defaultMessage: 'metric' });
-
const isSchemaDisabled = (schema: Schema): boolean => {
const count = group.filter((agg) => agg.schema === schema.name).length;
return count >= schema.max;
diff --git a/src/plugins/vis_default_editor/public/components/controls/date_ranges.tsx b/src/plugins/vis_default_editor/public/components/controls/date_ranges.tsx
index 785ef1b83a23d..90ee1dd4f02ae 100644
--- a/src/plugins/vis_default_editor/public/components/controls/date_ranges.tsx
+++ b/src/plugins/vis_default_editor/public/components/controls/date_ranges.tsx
@@ -36,7 +36,7 @@ import dateMath from '@elastic/datemath';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { isEqual, omit } from 'lodash';
-import { useMount } from 'react-use';
+import useMount from 'react-use/lib/useMount';
import { DocLinksStart } from 'src/core/public';
import { useKibana } from '../../../../kibana_react/public';
diff --git a/src/plugins/vis_default_editor/public/components/controls/field.tsx b/src/plugins/vis_default_editor/public/components/controls/field.tsx
index 9529adfe12720..cb6e9d9aa7ba8 100644
--- a/src/plugins/vis_default_editor/public/components/controls/field.tsx
+++ b/src/plugins/vis_default_editor/public/components/controls/field.tsx
@@ -19,7 +19,7 @@
import { get } from 'lodash';
import React, { useState, useCallback } from 'react';
-import { useMount } from 'react-use';
+import useMount from 'react-use/lib/useMount';
import { EuiComboBox, EuiComboBoxOptionOption, EuiFormRow } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
diff --git a/src/plugins/vis_default_editor/public/components/controls/filters.tsx b/src/plugins/vis_default_editor/public/components/controls/filters.tsx
index b2e6373edfc10..4c5181ab316d1 100644
--- a/src/plugins/vis_default_editor/public/components/controls/filters.tsx
+++ b/src/plugins/vis_default_editor/public/components/controls/filters.tsx
@@ -21,7 +21,7 @@ import React, { useState, useEffect } from 'react';
import { omit, isEqual } from 'lodash';
import { htmlIdGenerator, EuiButton, EuiSpacer } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
-import { useMount } from 'react-use';
+import useMount from 'react-use/lib/useMount';
import { Query, DataPublicPluginStart } from '../../../../data/public';
import { IUiSettingsClient } from '../../../../../core/public';
diff --git a/src/plugins/vis_default_editor/public/components/controls/order_by.tsx b/src/plugins/vis_default_editor/public/components/controls/order_by.tsx
index 16aeafaab253b..000719318f107 100644
--- a/src/plugins/vis_default_editor/public/components/controls/order_by.tsx
+++ b/src/plugins/vis_default_editor/public/components/controls/order_by.tsx
@@ -20,7 +20,7 @@
import React from 'react';
import { EuiFormRow, EuiSelect } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
-import { useMount } from 'react-use';
+import useMount from 'react-use/lib/useMount';
import {
isCompatibleAggregation,
diff --git a/src/plugins/vis_default_editor/public/components/controls/radius_ratio_option.tsx b/src/plugins/vis_default_editor/public/components/controls/radius_ratio_option.tsx
index c2c21e7c1a058..00e6b6da88b05 100644
--- a/src/plugins/vis_default_editor/public/components/controls/radius_ratio_option.tsx
+++ b/src/plugins/vis_default_editor/public/components/controls/radius_ratio_option.tsx
@@ -21,7 +21,7 @@ import React, { useCallback } from 'react';
import { EuiFormRow, EuiIconTip, EuiRange, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
-import { useMount } from 'react-use';
+import useMount from 'react-use/lib/useMount';
import { AggControlProps } from './agg_control_props';
diff --git a/src/plugins/vis_default_editor/public/components/controls/sub_metric.tsx b/src/plugins/vis_default_editor/public/components/controls/sub_metric.tsx
index fc79ba703c2b4..4b0637edf4055 100644
--- a/src/plugins/vis_default_editor/public/components/controls/sub_metric.tsx
+++ b/src/plugins/vis_default_editor/public/components/controls/sub_metric.tsx
@@ -20,7 +20,7 @@
import React from 'react';
import { EuiFormLabel, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
-import { useMount } from 'react-use';
+import useMount from 'react-use/lib/useMount';
import { AggParamType, IAggConfig, AggGroupNames } from '../../../../data/public';
import { useSubAggParamsHandlers } from './utils';
diff --git a/src/plugins/vis_default_editor/public/components/sidebar/controls.tsx b/src/plugins/vis_default_editor/public/components/sidebar/controls.tsx
index df9818b237962..388ac39f06475 100644
--- a/src/plugins/vis_default_editor/public/components/sidebar/controls.tsx
+++ b/src/plugins/vis_default_editor/public/components/sidebar/controls.tsx
@@ -21,7 +21,7 @@ import React, { useCallback, useState } from 'react';
import { EuiFlexGroup, EuiFlexItem, EuiButton, EuiButtonEmpty, EuiToolTip } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
-import { useDebounce } from 'react-use';
+import useDebounce from 'react-use/lib/useDebounce';
import { Vis } from 'src/plugins/visualizations/public';
import { discardChanges, EditorAction } from './state';
diff --git a/src/plugins/vis_type_timeseries/common/vis_schema.ts b/src/plugins/vis_type_timeseries/common/vis_schema.ts
index 27f09fb574b0f..9ec5ae1424ae3 100644
--- a/src/plugins/vis_type_timeseries/common/vis_schema.ts
+++ b/src/plugins/vis_type_timeseries/common/vis_schema.ts
@@ -120,7 +120,7 @@ export const metricsItems = schema.object({
type: stringRequired,
value: stringOptionalNullable,
values: schema.maybe(schema.nullable(schema.arrayOf(schema.nullable(schema.string())))),
- size: stringOptionalNullable,
+ size: stringOrNumberOptionalNullable,
agg_with: stringOptionalNullable,
order: stringOptionalNullable,
order_by: stringOptionalNullable,
diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/calculation.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/calculation.js
index bb3d39797656f..5bf4fb55ee5e5 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/aggs/calculation.js
+++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/calculation.js
@@ -26,6 +26,7 @@ import { createChangeHandler } from '../lib/create_change_handler';
import { createSelectHandler } from '../lib/create_select_handler';
import { createTextHandler } from '../lib/create_text_handler';
import { CalculationVars, newVariable } from './vars';
+import { METRIC_TYPES } from '../../../../common/metric_types';
import { FormattedMessage } from '@kbn/i18n/react';
import {
@@ -99,6 +100,7 @@ export function CalculationAgg(props) {
onChange={handleChange}
name="variables"
model={model}
+ exclude={[METRIC_TYPES.TOP_HIT]}
/>
diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/cumulative_sum.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/cumulative_sum.js
index 11b3e303e7e00..0b879adbd37ae 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/aggs/cumulative_sum.js
+++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/cumulative_sum.js
@@ -24,6 +24,7 @@ import { AggSelect } from './agg_select';
import { MetricSelect } from './metric_select';
import { createChangeHandler } from '../lib/create_change_handler';
import { createSelectHandler } from '../lib/create_select_handler';
+import { METRIC_TYPES } from '../../../../common/metric_types';
import { FormattedMessage } from '@kbn/i18n/react';
import {
htmlIdGenerator,
@@ -80,6 +81,7 @@ export function CumulativeSumAgg(props) {
metrics={siblings}
metric={model}
value={model.field}
+ exclude={[METRIC_TYPES.TOP_HIT]}
/>
diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/derivative.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/derivative.js
index faf1a59adc4aa..fa1289dc74c72 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/aggs/derivative.js
+++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/derivative.js
@@ -25,6 +25,7 @@ import { AggRow } from './agg_row';
import { createChangeHandler } from '../lib/create_change_handler';
import { createSelectHandler } from '../lib/create_select_handler';
import { createTextHandler } from '../lib/create_text_handler';
+import { METRIC_TYPES } from '../../../../common/metric_types';
import {
htmlIdGenerator,
EuiFlexGroup,
@@ -91,6 +92,7 @@ export const DerivativeAgg = (props) => {
metrics={siblings}
metric={model}
value={model.field}
+ exclude={[METRIC_TYPES.TOP_HIT]}
fullWidth
/>
diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/moving_average.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/moving_average.js
index 316e0f9af43bd..fb945d2606bc8 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/aggs/moving_average.js
+++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/moving_average.js
@@ -25,6 +25,7 @@ import { MetricSelect } from './metric_select';
import { createChangeHandler } from '../lib/create_change_handler';
import { createSelectHandler } from '../lib/create_select_handler';
import { createNumberHandler } from '../lib/create_number_handler';
+import { METRIC_TYPES } from '../../../../common/metric_types';
import {
htmlIdGenerator,
EuiFlexGroup,
@@ -153,6 +154,7 @@ export const MovingAverageAgg = (props) => {
metrics={siblings}
metric={model}
value={model.field}
+ exclude={[METRIC_TYPES.TOP_HIT]}
/>
diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/positive_only.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/positive_only.js
index 1999862f7aa0e..6ca5fa8e7447f 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/aggs/positive_only.js
+++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/positive_only.js
@@ -24,6 +24,7 @@ import { MetricSelect } from './metric_select';
import { AggRow } from './agg_row';
import { createChangeHandler } from '../lib/create_change_handler';
import { createSelectHandler } from '../lib/create_select_handler';
+import { METRIC_TYPES } from '../../../../common/metric_types';
import {
htmlIdGenerator,
EuiFlexGroup,
@@ -85,6 +86,7 @@ export const PositiveOnlyAgg = (props) => {
metrics={siblings}
metric={model}
value={model.field}
+ exclude={[METRIC_TYPES.TOP_HIT]}
/>
diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/serial_diff.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/serial_diff.js
index 10b3d551bb89f..e3a0c74273539 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/aggs/serial_diff.js
+++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/serial_diff.js
@@ -25,6 +25,7 @@ import { AggRow } from './agg_row';
import { createChangeHandler } from '../lib/create_change_handler';
import { createSelectHandler } from '../lib/create_select_handler';
import { createNumberHandler } from '../lib/create_number_handler';
+import { METRIC_TYPES } from '../../../../common/metric_types';
import {
htmlIdGenerator,
EuiFlexGroup,
@@ -87,6 +88,7 @@ export const SerialDiffAgg = (props) => {
metrics={siblings}
metric={model}
value={model.field}
+ exclude={[METRIC_TYPES.TOP_HIT]}
/>
diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/std_sibling.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/std_sibling.js
index 30e5c57ac90ba..bed5e9caa9f87 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/aggs/std_sibling.js
+++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/std_sibling.js
@@ -25,6 +25,8 @@ import { AggSelect } from './agg_select';
import { createChangeHandler } from '../lib/create_change_handler';
import { createSelectHandler } from '../lib/create_select_handler';
import { createTextHandler } from '../lib/create_text_handler';
+import { METRIC_TYPES } from '../../../../common/metric_types';
+
import {
htmlIdGenerator,
EuiFlexGroup,
@@ -154,7 +156,7 @@ const StandardSiblingAggUi = (props) => {
>
diff --git a/src/plugins/vis_type_timeseries/server/lib/get_fields.ts b/src/plugins/vis_type_timeseries/server/lib/get_fields.ts
index b52188129f77f..dc49e280a2bb7 100644
--- a/src/plugins/vis_type_timeseries/server/lib/get_fields.ts
+++ b/src/plugins/vis_type_timeseries/server/lib/get_fields.ts
@@ -62,10 +62,12 @@ export async function getFields(
let indexPatternString = indexPattern;
if (!indexPatternString) {
- const [{ savedObjects }, { data }] = await framework.core.getStartServices();
+ const [{ savedObjects, elasticsearch }, { data }] = await framework.core.getStartServices();
const savedObjectsClient = savedObjects.getScopedClient(request);
+ const clusterClient = elasticsearch.client.asScoped(request).asCurrentUser;
const indexPatternsService = await data.indexPatterns.indexPatternsServiceFactory(
- savedObjectsClient
+ savedObjectsClient,
+ clusterClient
);
const defaultIndexPattern = await indexPatternsService.getDefault();
indexPatternString = get(defaultIndexPattern, 'title', '');
diff --git a/src/plugins/visualizations/public/embeddable/_index.scss b/src/plugins/visualizations/public/embeddable/_index.scss
index c1e3809657bfa..9703e90159f48 100644
--- a/src/plugins/visualizations/public/embeddable/_index.scss
+++ b/src/plugins/visualizations/public/embeddable/_index.scss
@@ -1,2 +1 @@
-@import 'visualize_lab_disabled';
@import 'embeddables';
diff --git a/src/plugins/visualizations/public/embeddable/_visualize_lab_disabled.scss b/src/plugins/visualizations/public/embeddable/_visualize_lab_disabled.scss
deleted file mode 100644
index 914480ff8c777..0000000000000
--- a/src/plugins/visualizations/public/embeddable/_visualize_lab_disabled.scss
+++ /dev/null
@@ -1,13 +0,0 @@
-.visDisabledLabVisualization {
- width: 100%;
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- text-align: center;
-}
-
-.visDisabledLabVisualization__icon {
- font-size: $euiFontSizeXL;
-}
-
diff --git a/src/plugins/visualizations/public/embeddable/disabled_lab_visualization.tsx b/src/plugins/visualizations/public/embeddable/disabled_lab_visualization.tsx
index 3d2af2c591a3c..ea7760f31d54c 100644
--- a/src/plugins/visualizations/public/embeddable/disabled_lab_visualization.tsx
+++ b/src/plugins/visualizations/public/embeddable/disabled_lab_visualization.tsx
@@ -17,29 +17,42 @@
* under the License.
*/
-import { FormattedMessage } from '@kbn/i18n/react';
+import { FormattedMessage, I18nProvider } from '@kbn/i18n/react';
+import { EuiEmptyPrompt, EuiLink } from '@elastic/eui';
import React from 'react';
+import { getDocLinks } from '../services';
export function DisabledLabVisualization({ title }: { title: string }) {
+ const advancedSettingsLink = getDocLinks().links.management.visualizationSettings;
return (
-
-
+
+
+
+ }
+ iconType="beaker"
+ body={
+
+ }
+ actions={
+
+
+
+ }
/>
-
- {title} }}
- />
-
-
-
-
-
+
);
}
diff --git a/src/plugins/visualize/public/application/components/visualize_listing.tsx b/src/plugins/visualize/public/application/components/visualize_listing.tsx
index 2edabbf46f9d8..718bd2ed343ce 100644
--- a/src/plugins/visualize/public/application/components/visualize_listing.tsx
+++ b/src/plugins/visualize/public/application/components/visualize_listing.tsx
@@ -21,7 +21,9 @@ import './visualize_listing.scss';
import React, { useCallback, useRef, useMemo, useEffect } from 'react';
import { i18n } from '@kbn/i18n';
-import { useUnmount, useMount } from 'react-use';
+import useUnmount from 'react-use/lib/useUnmount';
+import useMount from 'react-use/lib/useMount';
+
import { useLocation } from 'react-router-dom';
import { SavedObjectsFindOptionsReference } from '../../../../../core/public';
diff --git a/test/functional/apps/management/_index_patterns_empty.ts b/test/functional/apps/management/_index_patterns_empty.ts
index 4ae2e7836ac37..2a1d723f1a06e 100644
--- a/test/functional/apps/management/_index_patterns_empty.ts
+++ b/test/functional/apps/management/_index_patterns_empty.ts
@@ -22,6 +22,7 @@ import { FtrProviderContext } from '../../ftr_provider_context';
export default function ({ getPageObjects, getService }: FtrProviderContext) {
const esArchiver = getService('esArchiver');
const kibanaServer = getService('kibanaServer');
+ const log = getService('log');
const PageObjects = getPageObjects(['common', 'settings']);
const testSubjects = getService('testSubjects');
const globalNav = getService('globalNav');
@@ -30,6 +31,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
describe('index pattern empty view', () => {
before(async () => {
await esArchiver.load('empty_kibana');
+ await esArchiver.unload('logstash_functional');
+ await esArchiver.unload('makelogs');
await kibanaServer.uiSettings.replace({});
await PageObjects.settings.navigateTo();
});
@@ -37,16 +40,26 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
after(async () => {
await esArchiver.unload('empty_kibana');
await esArchiver.loadIfNeeded('makelogs');
- });
-
- // create index pattern and return to verify list
- it(`shows empty views`, async () => {
// @ts-expect-error
await es.transport.request({
- path: '/_all',
+ path: '/logstash-a',
method: 'DELETE',
});
+ });
+
+ // create index pattern and return to verify list
+ it(`shows empty views`, async () => {
await PageObjects.settings.clickKibanaIndexPatterns();
+ log.debug(
+ `\n\nNOTE: If this test fails make sure there aren't any non-system indices in the _cat/indices output (use esArchiver.unload on them)`
+ );
+ log.debug(
+ // @ts-expect-error
+ await es.transport.request({
+ path: '/_cat/indices',
+ method: 'GET',
+ })
+ );
await testSubjects.existOrFail('createAnyway');
// @ts-expect-error
await es.transport.request({
diff --git a/test/functional/apps/management/_mgmt_import_saved_objects.js b/test/functional/apps/management/_mgmt_import_saved_objects.js
index 3a9f8665fd33b..d479a7006d0f8 100644
--- a/test/functional/apps/management/_mgmt_import_saved_objects.js
+++ b/test/functional/apps/management/_mgmt_import_saved_objects.js
@@ -29,6 +29,7 @@ export default function ({ getService, getPageObjects }) {
describe('mgmt saved objects', function describeIndexTests() {
beforeEach(async function () {
+ await esArchiver.load('empty_kibana');
await esArchiver.load('discover');
await PageObjects.settings.navigateTo();
});
diff --git a/test/functional/services/common/browser.ts b/test/functional/services/common/browser.ts
index f5fb54c72177f..b3b7fd32eae19 100644
--- a/test/functional/services/common/browser.ts
+++ b/test/functional/services/common/browser.ts
@@ -216,13 +216,17 @@ export async function BrowserProvider({ getService }: FtrProviderContext) {
* Does a drag-and-drop action from one point to another
* https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/input_exports_Actions.html#dragAndDrop
*
- * @param {{element: WebElementWrapper | {x: number, y: number}, offset: {x: number, y: number}}} from
- * @param {{element: WebElementWrapper | {x: number, y: number}, offset: {x: number, y: number}}} to
* @return {Promise
}
*/
public async dragAndDrop(
- from: { offset?: { x: any; y: any }; location: any },
- to: { offset?: { x: any; y: any }; location: any }
+ from: {
+ location: WebElementWrapper | { x?: number; y?: number };
+ offset?: { x?: number; y?: number };
+ },
+ to: {
+ location: WebElementWrapper | { x?: number; y?: number };
+ offset?: { x?: number; y?: number };
+ }
) {
// The offset should be specified in pixels relative to the center of the element's bounding box
const getW3CPoint = (data: any) => {
@@ -230,7 +234,11 @@ export async function BrowserProvider({ getService }: FtrProviderContext) {
data.offset = {};
}
return data.location instanceof WebElementWrapper
- ? { x: data.offset.x || 0, y: data.offset.y || 0, origin: data.location._webElement }
+ ? {
+ x: data.offset.x || 0,
+ y: data.offset.y || 0,
+ origin: data.location._webElement,
+ }
: { x: data.location.x, y: data.location.y, origin: Origin.POINTER };
};
@@ -240,6 +248,62 @@ export async function BrowserProvider({ getService }: FtrProviderContext) {
return await this.getActions().move(startPoint).press().move(endPoint).release().perform();
}
+ /**
+ * Performs drag and drop for html5 native drag and drop implementation
+ * There's a bug in Chromedriver for html5 dnd that doesn't allow to use the method `dragAndDrop` defined above
+ * https://github.com/SeleniumHQ/selenium/issues/6235
+ * This implementation simulates user's action by calling the drag and drop specific events directly.
+ *
+ * @param {string} from html selector
+ * @param {string} to html selector
+ * @return {Promise}
+ */
+ public async html5DragAndDrop(from: string, to: string) {
+ await this.execute(
+ `
+ function createEvent(typeOfEvent) {
+ const event = document.createEvent("CustomEvent");
+ event.initCustomEvent(typeOfEvent, true, true, null);
+ event.dataTransfer = {
+ data: {},
+ setData: function (key, value) {
+ this.data[key] = value;
+ },
+ getData: function (key) {
+ return this.data[key];
+ }
+ };
+ return event;
+ }
+ function dispatchEvent(element, event, transferData) {
+ if (transferData !== undefined) {
+ event.dataTransfer = transferData;
+ }
+ if (element.dispatchEvent) {
+ element.dispatchEvent(event);
+ } else if (element.fireEvent) {
+ element.fireEvent("on" + event.type, event);
+ }
+ }
+
+ const origin = document.querySelector(arguments[0]);
+ const target = document.querySelector(arguments[1]);
+
+ const dragStartEvent = createEvent('dragstart');
+ dispatchEvent(origin, dragStartEvent);
+
+ setTimeout(() => {
+ const dropEvent = createEvent('drop');
+ dispatchEvent(target, dropEvent, dragStartEvent.dataTransfer);
+ const dragEndEvent = createEvent('dragend');
+ dispatchEvent(origin, dragEndEvent, dropEvent.dataTransfer);
+ }, 50);
+ `,
+ from,
+ to
+ );
+ }
+
/**
* Reloads the current browser window/frame.
* https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_Navigation.html#refresh
diff --git a/test/plugin_functional/plugins/data_search/server/plugin.ts b/test/plugin_functional/plugins/data_search/server/plugin.ts
index e016ef56802f3..ca22e82188403 100644
--- a/test/plugin_functional/plugins/data_search/server/plugin.ts
+++ b/test/plugin_functional/plugins/data_search/server/plugin.ts
@@ -58,14 +58,16 @@ export class DataSearchTestPlugin
},
},
async (context, req, res) => {
- const [{ savedObjects }, { data }] = await core.getStartServices();
+ const [{ savedObjects, elasticsearch }, { data }] = await core.getStartServices();
const service = await data.search.searchSource.asScoped(req);
+ const clusterClient = elasticsearch.client.asScoped(req).asCurrentUser;
const savedObjectsClient = savedObjects.getScopedClient(req);
// Since the index pattern ID can change on each test run, we need
// to look it up on the fly and insert it into the request.
const indexPatterns = await data.indexPatterns.indexPatternsServiceFactory(
- savedObjectsClient
+ savedObjectsClient,
+ clusterClient
);
const ids = await indexPatterns.getIds();
// @ts-expect-error Force overwriting the request
diff --git a/test/plugin_functional/plugins/index_patterns/server/plugin.ts b/test/plugin_functional/plugins/index_patterns/server/plugin.ts
index a54502b740211..c05b71b834c70 100644
--- a/test/plugin_functional/plugins/index_patterns/server/plugin.ts
+++ b/test/plugin_functional/plugins/index_patterns/server/plugin.ts
@@ -36,13 +36,35 @@ export class IndexPatternsTestPlugin
public setup(core: CoreSetup) {
const router = core.http.createRouter();
+ router.post(
+ {
+ path: '/api/index-patterns-plugin/create',
+ validate: {
+ body: schema.object({}, { unknowns: 'allow' }),
+ },
+ },
+ async (context, req, res) => {
+ const [{ savedObjects, elasticsearch }, { data }] = await core.getStartServices();
+ const savedObjectsClient = savedObjects.getScopedClient(req);
+ const service = await data.indexPatterns.indexPatternsServiceFactory(
+ savedObjectsClient,
+ elasticsearch.client.asScoped(req).asCurrentUser
+ );
+ const ids = await service.createAndSave(req.body);
+ return res.ok({ body: ids });
+ }
+ );
+
router.get(
{ path: '/api/index-patterns-plugin/get-all', validate: false },
async (context, req, res) => {
- const [{ savedObjects }, { data }] = await core.getStartServices();
+ const [{ savedObjects, elasticsearch }, { data }] = await core.getStartServices();
const savedObjectsClient = savedObjects.getScopedClient(req);
- const service = await data.indexPatterns.indexPatternsServiceFactory(savedObjectsClient);
- const ids = await service.getIds();
+ const service = await data.indexPatterns.indexPatternsServiceFactory(
+ savedObjectsClient,
+ elasticsearch.client.asScoped(req).asCurrentUser
+ );
+ const ids = await service.getIds(true);
return res.ok({ body: ids });
}
);
@@ -58,9 +80,12 @@ export class IndexPatternsTestPlugin
},
async (context, req, res) => {
const id = (req.params as Record).id;
- const [{ savedObjects }, { data }] = await core.getStartServices();
+ const [{ savedObjects, elasticsearch }, { data }] = await core.getStartServices();
const savedObjectsClient = savedObjects.getScopedClient(req);
- const service = await data.indexPatterns.indexPatternsServiceFactory(savedObjectsClient);
+ const service = await data.indexPatterns.indexPatternsServiceFactory(
+ savedObjectsClient,
+ elasticsearch.client.asScoped(req).asCurrentUser
+ );
const ip = await service.get(id);
return res.ok({ body: ip.toSpec() });
}
@@ -76,10 +101,13 @@ export class IndexPatternsTestPlugin
},
},
async (context, req, res) => {
- const [{ savedObjects }, { data }] = await core.getStartServices();
+ const [{ savedObjects, elasticsearch }, { data }] = await core.getStartServices();
const id = (req.params as Record).id;
const savedObjectsClient = savedObjects.getScopedClient(req);
- const service = await data.indexPatterns.indexPatternsServiceFactory(savedObjectsClient);
+ const service = await data.indexPatterns.indexPatternsServiceFactory(
+ savedObjectsClient,
+ elasticsearch.client.asScoped(req).asCurrentUser
+ );
const ip = await service.get(id);
await service.updateSavedObject(ip);
return res.ok();
@@ -96,10 +124,13 @@ export class IndexPatternsTestPlugin
},
},
async (context, req, res) => {
- const [{ savedObjects }, { data }] = await core.getStartServices();
+ const [{ savedObjects, elasticsearch }, { data }] = await core.getStartServices();
const id = (req.params as Record).id;
const savedObjectsClient = savedObjects.getScopedClient(req);
- const service = await data.indexPatterns.indexPatternsServiceFactory(savedObjectsClient);
+ const service = await data.indexPatterns.indexPatternsServiceFactory(
+ savedObjectsClient,
+ elasticsearch.client.asScoped(req).asCurrentUser
+ );
await service.delete(id);
return res.ok();
}
diff --git a/test/plugin_functional/test_suites/data_plugin/index_patterns.ts b/test/plugin_functional/test_suites/data_plugin/index_patterns.ts
index 2c846dc780311..2e94f61c7ded8 100644
--- a/test/plugin_functional/test_suites/data_plugin/index_patterns.ts
+++ b/test/plugin_functional/test_suites/data_plugin/index_patterns.ts
@@ -23,16 +23,25 @@ import '../../plugins/core_provider_plugin/types';
export default function ({ getService }: PluginFunctionalProviderContext) {
const supertest = getService('supertest');
- // skipping the tests as it deletes index patterns created by other test causing unexpected failures
- // https://github.com/elastic/kibana/issues/79886
- describe.skip('index patterns', function () {
+ describe('index patterns', function () {
let indexPatternId = '';
- it('can get all ids', async () => {
- const body = await (await supertest.get('/api/index-patterns-plugin/get-all').expect(200))
- .body;
- indexPatternId = body[0];
- expect(body.length > 0).to.equal(true);
+ it('can create an index pattern', async () => {
+ const title = 'shakes*';
+ const fieldFormats = { bytes: { id: 'bytes' } };
+ const body = await (
+ await supertest
+ .post('/api/index-patterns-plugin/create')
+ .set('kbn-xsrf', 'anything')
+ .send({ title, fieldFormats })
+ .expect(200)
+ ).body;
+
+ indexPatternId = body.id;
+ expect(body.id).not.empty();
+ expect(body.title).to.equal(title);
+ expect(body.fields.length).to.equal(15);
+ expect(body.fieldFormatMap).to.eql(fieldFormats);
});
it('can get index pattern by id', async () => {
diff --git a/x-pack/plugins/apm/public/components/app/Home/alerting_popover_flyout/index.tsx b/x-pack/plugins/apm/public/application/action_menu/alerting_popover_flyout.tsx
similarity index 83%
rename from x-pack/plugins/apm/public/components/app/Home/alerting_popover_flyout/index.tsx
rename to x-pack/plugins/apm/public/application/action_menu/alerting_popover_flyout.tsx
index 7e6331c1fa3a8..394b4caea3e7b 100644
--- a/x-pack/plugins/apm/public/components/app/Home/alerting_popover_flyout/index.tsx
+++ b/x-pack/plugins/apm/public/application/action_menu/alerting_popover_flyout.tsx
@@ -5,16 +5,16 @@
*/
import {
- EuiButtonEmpty,
EuiContextMenu,
EuiContextMenuPanelDescriptor,
+ EuiHeaderLink,
EuiPopover,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React, { useState } from 'react';
-import { AlertType } from '../../../../../common/alert_types';
-import { useApmPluginContext } from '../../../../hooks/useApmPluginContext';
-import { AlertingFlyout } from '../../../alerting/AlertingFlyout';
+import { IBasePath } from '../../../../../../src/core/public';
+import { AlertType } from '../../../common/alert_types';
+import { AlertingFlyout } from '../../components/alerting/AlertingFlyout';
const alertLabel = i18n.translate('xpack.apm.home.alertsMenu.alerts', {
defaultMessage: 'Alerts',
@@ -46,28 +46,32 @@ const CREATE_TRANSACTION_ERROR_RATE_ALERT_PANEL_ID =
const CREATE_ERROR_COUNT_ALERT_PANEL_ID = 'create_error_count_panel';
interface Props {
+ basePath: IBasePath;
canReadAlerts: boolean;
canSaveAlerts: boolean;
canReadAnomalies: boolean;
+ includeTransactionDuration: boolean;
}
-export function AlertingPopoverAndFlyout(props: Props) {
- const { canSaveAlerts, canReadAlerts, canReadAnomalies } = props;
-
- const plugin = useApmPluginContext();
-
+export function AlertingPopoverAndFlyout({
+ basePath,
+ canSaveAlerts,
+ canReadAlerts,
+ canReadAnomalies,
+ includeTransactionDuration,
+}: Props) {
const [popoverOpen, setPopoverOpen] = useState(false);
-
const [alertType, setAlertType] = useState(null);
const button = (
- setPopoverOpen(true)}
+ onClick={() => setPopoverOpen((prevState) => !prevState)}
>
{alertLabel}
-
+
);
const panels: EuiContextMenuPanelDescriptor[] = [
@@ -98,7 +102,7 @@ export function AlertingPopoverAndFlyout(props: Props) {
'xpack.apm.home.alertsMenu.viewActiveAlerts',
{ defaultMessage: 'View active alerts' }
),
- href: plugin.core.http.basePath.prepend(
+ href: basePath.prepend(
'/app/management/insightsAndAlerting/triggersActions/alerts'
),
icon: 'tableOfContents',
@@ -113,6 +117,19 @@ export function AlertingPopoverAndFlyout(props: Props) {
id: CREATE_TRANSACTION_DURATION_ALERT_PANEL_ID,
title: transactionDurationLabel,
items: [
+ // threshold alerts
+ ...(includeTransactionDuration
+ ? [
+ {
+ name: createThresholdAlertLabel,
+ onClick: () => {
+ setAlertType(AlertType.TransactionDuration);
+ setPopoverOpen(false);
+ },
+ },
+ ]
+ : []),
+
// anomaly alerts
...(canReadAnomalies
? [
diff --git a/x-pack/plugins/apm/public/components/shared/Links/apm/anomaly_detection_setup_link.test.tsx b/x-pack/plugins/apm/public/application/action_menu/anomaly_detection_setup_link.test.tsx
similarity index 96%
rename from x-pack/plugins/apm/public/components/shared/Links/apm/anomaly_detection_setup_link.test.tsx
rename to x-pack/plugins/apm/public/application/action_menu/anomaly_detection_setup_link.test.tsx
index a53468e2ad06c..b90f606d276eb 100644
--- a/x-pack/plugins/apm/public/components/shared/Links/apm/anomaly_detection_setup_link.test.tsx
+++ b/x-pack/plugins/apm/public/application/action_menu/anomaly_detection_setup_link.test.tsx
@@ -6,8 +6,8 @@
import React from 'react';
import { render, fireEvent, waitFor } from '@testing-library/react';
-import { MissingJobsAlert } from './AnomalyDetectionSetupLink';
-import * as hooks from '../../../../hooks/useFetcher';
+import { MissingJobsAlert } from './anomaly_detection_setup_link';
+import * as hooks from '../../hooks/useFetcher';
async function renderTooltipAnchor({
jobs,
diff --git a/x-pack/plugins/apm/public/components/shared/Links/apm/AnomalyDetectionSetupLink.tsx b/x-pack/plugins/apm/public/application/action_menu/anomaly_detection_setup_link.tsx
similarity index 67%
rename from x-pack/plugins/apm/public/components/shared/Links/apm/AnomalyDetectionSetupLink.tsx
rename to x-pack/plugins/apm/public/application/action_menu/anomaly_detection_setup_link.tsx
index 368837b3c9411..d75446cb0dd48 100644
--- a/x-pack/plugins/apm/public/components/shared/Links/apm/AnomalyDetectionSetupLink.tsx
+++ b/x-pack/plugins/apm/public/application/action_menu/anomaly_detection_setup_link.tsx
@@ -3,19 +3,25 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
-import React from 'react';
-import { EuiButtonEmpty, EuiToolTip, EuiIcon } from '@elastic/eui';
+import {
+ EuiHeaderLink,
+ EuiIcon,
+ EuiLoadingSpinner,
+ EuiToolTip,
+} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
-import { useApmPluginContext } from '../../../../hooks/useApmPluginContext';
-import { APIReturnType } from '../../../../services/rest/createCallApmApi';
-import { APMLink } from './APMLink';
+import React from 'react';
import {
ENVIRONMENT_ALL,
getEnvironmentLabel,
-} from '../../../../../common/environment_filter_values';
-import { useUrlParams } from '../../../../hooks/useUrlParams';
-import { useFetcher, FETCH_STATUS } from '../../../../hooks/useFetcher';
-import { useLicense } from '../../../../hooks/useLicense';
+} from '../../../common/environment_filter_values';
+import { getAPMHref } from '../../components/shared/Links/apm/APMLink';
+import { useApmPluginContext } from '../../hooks/useApmPluginContext';
+import { FETCH_STATUS, useFetcher } from '../../hooks/useFetcher';
+import { useLicense } from '../../hooks/useLicense';
+import { useUrlParams } from '../../hooks/useUrlParams';
+import { APIReturnType } from '../../services/rest/createCallApmApi';
+import { units } from '../../style/variables';
export type AnomalyDetectionApiResponse = APIReturnType<
'/api/apm/settings/anomaly-detection',
@@ -27,24 +33,27 @@ const DEFAULT_DATA = { jobs: [], hasLegacyJobs: false };
export function AnomalyDetectionSetupLink() {
const { uiFilters } = useUrlParams();
const environment = uiFilters.environment;
- const plugin = useApmPluginContext();
- const canGetJobs = !!plugin.core.application.capabilities.ml?.canGetJobs;
+ const { core } = useApmPluginContext();
+ const canGetJobs = !!core.application.capabilities.ml?.canGetJobs;
const license = useLicense();
const hasValidLicense = license?.isActive && license?.hasAtLeast('platinum');
+ const { basePath } = core.http;
return (
-
-
- {ANOMALY_DETECTION_LINK_LABEL}
-
-
{canGetJobs && hasValidLicense ? (
- ) : null}
-
+ ) : (
+
+ )}
+
+ {ANOMALY_DETECTION_LINK_LABEL}
+
+
);
}
@@ -56,8 +65,14 @@ export function MissingJobsAlert({ environment }: { environment?: string }) {
{ preservePreviousData: false, showToastOnError: false }
);
+ const defaultIcon = ;
+
+ if (status === FETCH_STATUS.LOADING) {
+ return ;
+ }
+
if (status !== FETCH_STATUS.SUCCESS) {
- return null;
+ return defaultIcon;
}
const isEnvironmentSelected =
@@ -65,7 +80,7 @@ export function MissingJobsAlert({ environment }: { environment?: string }) {
// there are jobs for at least one environment
if (!isEnvironmentSelected && data.jobs.length > 0) {
- return null;
+ return defaultIcon;
}
// there are jobs for the selected environment
@@ -73,7 +88,7 @@ export function MissingJobsAlert({ environment }: { environment?: string }) {
isEnvironmentSelected &&
data.jobs.some((job) => environment === job.environment)
) {
- return null;
+ return defaultIcon;
}
return (
diff --git a/x-pack/plugins/apm/public/application/action_menu/index.tsx b/x-pack/plugins/apm/public/application/action_menu/index.tsx
new file mode 100644
index 0000000000000..1713ef61fac1e
--- /dev/null
+++ b/x-pack/plugins/apm/public/application/action_menu/index.tsx
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+import { EuiHeaderLink, EuiHeaderLinks } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
+import React from 'react';
+import { useParams } from 'react-router-dom';
+import { getAlertingCapabilities } from '../../components/alerting/get_alert_capabilities';
+import { getAPMHref } from '../../components/shared/Links/apm/APMLink';
+import { useApmPluginContext } from '../../hooks/useApmPluginContext';
+import { AlertingPopoverAndFlyout } from './alerting_popover_flyout';
+import { AnomalyDetectionSetupLink } from './anomaly_detection_setup_link';
+
+export function ActionMenu() {
+ const { core, plugins } = useApmPluginContext();
+ const { serviceName } = useParams<{ serviceName?: string }>();
+ const { search } = window.location;
+ const { application, http } = core;
+ const { basePath } = http;
+ const { capabilities } = application;
+ const canAccessML = !!capabilities.ml?.canAccessML;
+ const {
+ isAlertingAvailable,
+ canReadAlerts,
+ canSaveAlerts,
+ canReadAnomalies,
+ } = getAlertingCapabilities(plugins, capabilities);
+
+ function apmHref(path: string) {
+ return getAPMHref({ basePath, path, search });
+ }
+
+ function kibanaHref(path: string) {
+ return basePath.prepend(path);
+ }
+
+ return (
+
+
+ {i18n.translate('xpack.apm.settingsLinkLabel', {
+ defaultMessage: 'Settings',
+ })}
+
+ {isAlertingAvailable && (
+
+ )}
+ {canAccessML && }
+
+ {i18n.translate('xpack.apm.addDataButtonLabel', {
+ defaultMessage: 'Add data',
+ })}
+
+
+ );
+}
diff --git a/x-pack/plugins/apm/public/application/application.test.tsx b/x-pack/plugins/apm/public/application/application.test.tsx
index 97700b9bc96b7..75b7835c13151 100644
--- a/x-pack/plugins/apm/public/application/application.test.tsx
+++ b/x-pack/plugins/apm/public/application/application.test.tsx
@@ -53,6 +53,7 @@ describe('renderApp', () => {
const params = {
element: document.createElement('div'),
history: createMemoryHistory(),
+ setHeaderActionMenu: () => {},
};
jest.spyOn(window, 'scrollTo').mockReturnValueOnce(undefined);
createCallApmApi((core.http as unknown) as HttpSetup);
diff --git a/x-pack/plugins/apm/public/application/csmApp.tsx b/x-pack/plugins/apm/public/application/csmApp.tsx
index d8f54c7bfc94f..dfc3d6b4b9ec8 100644
--- a/x-pack/plugins/apm/public/application/csmApp.tsx
+++ b/x-pack/plugins/apm/public/application/csmApp.tsx
@@ -66,21 +66,23 @@ function CsmApp() {
}
export function CsmAppRoot({
+ appMountParameters,
core,
deps,
- history,
config,
corePlugins: { embeddable },
}: {
+ appMountParameters: AppMountParameters;
core: CoreStart;
deps: ApmPluginSetupDeps;
- history: AppMountParameters['history'];
config: ConfigSchema;
corePlugins: ApmPluginStartDeps;
}) {
+ const { history } = appMountParameters;
const i18nCore = core.i18n;
const plugins = deps;
const apmPluginContextValue = {
+ appMountParameters,
config,
core,
plugins,
@@ -109,10 +111,12 @@ export function CsmAppRoot({
export const renderApp = (
core: CoreStart,
deps: ApmPluginSetupDeps,
- { element, history }: AppMountParameters,
+ appMountParameters: AppMountParameters,
config: ConfigSchema,
corePlugins: ApmPluginStartDeps
) => {
+ const { element } = appMountParameters;
+
createCallApmApi(core.http);
// Automatically creates static index pattern and stores as saved object
@@ -123,9 +127,9 @@ export const renderApp = (
ReactDOM.render(
,
diff --git a/x-pack/plugins/apm/public/application/index.tsx b/x-pack/plugins/apm/public/application/index.tsx
index 4e3217ce17ed1..2e1f259bd8c42 100644
--- a/x-pack/plugins/apm/public/application/index.tsx
+++ b/x-pack/plugins/apm/public/application/index.tsx
@@ -22,7 +22,10 @@ import {
import { AlertsContextProvider } from '../../../triggers_actions_ui/public';
import { routes } from '../components/app/Main/route_config';
import { ScrollToTopOnPathChange } from '../components/app/Main/ScrollToTopOnPathChange';
-import { ApmPluginContext } from '../context/ApmPluginContext';
+import {
+ ApmPluginContext,
+ ApmPluginContextValue,
+} from '../context/ApmPluginContext';
import { LicenseProvider } from '../context/LicenseContext';
import { UrlParamsProvider } from '../context/UrlParamsContext';
import { useBreadcrumbs } from '../hooks/use_breadcrumbs';
@@ -64,23 +67,14 @@ function App() {
}
export function ApmAppRoot({
- core,
- deps,
- history,
- config,
+ apmPluginContextValue,
}: {
- core: CoreStart;
- deps: ApmPluginSetupDeps;
- history: AppMountParameters['history'];
- config: ConfigSchema;
+ apmPluginContextValue: ApmPluginContextValue;
}) {
+ const { appMountParameters, core, plugins } = apmPluginContextValue;
+ const { history } = appMountParameters;
const i18nCore = core.i18n;
- const plugins = deps;
- const apmPluginContextValue = {
- config,
- core,
- plugins,
- };
+
return (
@@ -117,14 +111,21 @@ export function ApmAppRoot({
export const renderApp = (
core: CoreStart,
- deps: ApmPluginSetupDeps,
- { element, history }: AppMountParameters,
+ setupDeps: ApmPluginSetupDeps,
+ appMountParameters: AppMountParameters,
config: ConfigSchema
) => {
+ const { element } = appMountParameters;
+ const apmPluginContextValue = {
+ appMountParameters,
+ config,
+ core,
+ plugins: setupDeps,
+ };
+
// render APM feedback link in global help menu
setHelpExtension(core);
setReadonlyBadge(core);
-
createCallApmApi(core.http);
// Automatically creates static index pattern and stores as saved object
@@ -134,7 +135,7 @@ export const renderApp = (
});
ReactDOM.render(
- ,
+ ,
element
);
return () => {
diff --git a/x-pack/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap b/x-pack/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap
index 0a22604837b97..82fabff610191 100644
--- a/x-pack/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap
+++ b/x-pack/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap
@@ -4,6 +4,9 @@ exports[`Home component should render services 1`] = `
- {i18n.translate('xpack.apm.home.servicesTabLabel', {
- defaultMessage: 'Services',
- })}
-
- ),
- render: () => ,
- name: 'services',
- },
- {
- link: (
-
- {i18n.translate('xpack.apm.home.tracesTabLabel', {
- defaultMessage: 'Traces',
- })}
-
- ),
- render: () => ,
- name: 'traces',
- },
- ];
-
- if (serviceMapEnabled) {
- homeTabs.push({
- link: (
-
- {i18n.translate('xpack.apm.home.serviceMapTabLabel', {
- defaultMessage: 'Service Map',
- })}
-
- ),
- render: () => ,
- name: 'service-map',
- });
- }
-
- return homeTabs;
-}
-
-const SETTINGS_LINK_LABEL = i18n.translate('xpack.apm.settingsLinkLabel', {
- defaultMessage: 'Settings',
-});
+const homeTabs = [
+ {
+ link: (
+
+ {i18n.translate('xpack.apm.home.servicesTabLabel', {
+ defaultMessage: 'Services',
+ })}
+
+ ),
+ render: () => ,
+ name: 'services',
+ },
+ {
+ link: (
+
+ {i18n.translate('xpack.apm.home.tracesTabLabel', {
+ defaultMessage: 'Traces',
+ })}
+
+ ),
+ render: () => ,
+ name: 'traces',
+ },
+ {
+ link: (
+
+ {i18n.translate('xpack.apm.home.serviceMapTabLabel', {
+ defaultMessage: 'Service Map',
+ })}
+
+ ),
+ render: () => ,
+ name: 'service-map',
+ },
+];
interface Props {
tab: 'traces' | 'services' | 'service-map';
}
export function Home({ tab }: Props) {
- const { config, core, plugins } = useApmPluginContext();
- const capabilities = core.application.capabilities;
- const canAccessML = !!capabilities.ml?.canAccessML;
- const homeTabs = getHomeTabs(config);
const selectedTab = homeTabs.find(
(homeTab) => homeTab.name === tab
) as $ElementType;
- const {
- isAlertingAvailable,
- canReadAlerts,
- canSaveAlerts,
- canReadAnomalies,
- } = getAlertingCapabilities(plugins, core.application.capabilities);
-
return (
-
-
-
- APM
-
-
-
-
-
- {SETTINGS_LINK_LABEL}
-
-
-
- {isAlertingAvailable && (
-
-
-
- )}
- {canAccessML && (
-
-
-
- )}
-
-
-
-
+
+ APM
+
{homeTabs.map((homeTab) => (
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/URLFilter/URLSearch/SelectableUrlList.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/URLFilter/URLSearch/SelectableUrlList.tsx
index 7bd9b2c87814b..1d314e3a0e0d3 100644
--- a/x-pack/plugins/apm/public/components/app/RumDashboard/URLFilter/URLSearch/SelectableUrlList.tsx
+++ b/x-pack/plugins/apm/public/components/app/RumDashboard/URLFilter/URLSearch/SelectableUrlList.tsx
@@ -31,7 +31,7 @@ import { i18n } from '@kbn/i18n';
import styled from 'styled-components';
import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';
import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json';
-import { useEvent } from 'react-use';
+import useEvent from 'react-use/lib/useEvent';
import {
formatOptions,
selectableRenderOptions,
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/EmbeddedMap.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/EmbeddedMap.tsx
index 77afe92a8f521..b757635af1702 100644
--- a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/EmbeddedMap.tsx
+++ b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/EmbeddedMap.tsx
@@ -77,6 +77,7 @@ export function EmbeddedMapComponent() {
);
const input: MapEmbeddableInput = {
+ attributes: { title: '' },
id: uuid.v4(),
filters: mapFilters,
refreshConfig: {
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/__tests__/__mocks__/regions_layer.mock.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/__tests__/__mocks__/regions_layer.mock.ts
index e564332583375..6d259a5a2e48c 100644
--- a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/__tests__/__mocks__/regions_layer.mock.ts
+++ b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/__tests__/__mocks__/regions_layer.mock.ts
@@ -21,6 +21,8 @@ export const mockLayerList = [
{
leftField: 'iso2',
right: {
+ applyGlobalQuery: true,
+ applyGlobalTime: true,
type: 'ES_TERM_SOURCE',
id: '3657625d-17b0-41ef-99ba-3a2b2938655c',
indexPatternTitle: 'apm-*',
@@ -38,7 +40,6 @@ export const mockLayerList = [
},
],
indexPatternId: 'apm_static_index_pattern_id',
- applyGlobalQuery: true,
},
},
],
@@ -46,7 +47,6 @@ export const mockLayerList = [
type: 'EMS_FILE',
id: 'world_countries',
tooltipProperties: ['name'],
- applyGlobalQuery: true,
},
style: {
type: 'VECTOR',
@@ -96,6 +96,8 @@ export const mockLayerList = [
{
leftField: 'region_iso_code',
right: {
+ applyGlobalQuery: true,
+ applyGlobalTime: true,
type: 'ES_TERM_SOURCE',
id: 'e62a1b9c-d7ff-4fd4-a0f6-0fdc44bb9e41',
indexPatternTitle: 'apm-*',
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts
index bc45d58329f49..a1cdf7bb646e5 100644
--- a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts
+++ b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts
@@ -43,6 +43,7 @@ const ES_TERM_SOURCE_COUNTRY: ESTermSourceDescriptor = {
],
indexPatternId: APM_STATIC_INDEX_PATTERN_ID,
applyGlobalQuery: true,
+ applyGlobalTime: true,
};
const ES_TERM_SOURCE_REGION: ESTermSourceDescriptor = {
@@ -56,6 +57,8 @@ const ES_TERM_SOURCE_REGION: ESTermSourceDescriptor = {
language: 'kuery',
},
indexPatternId: APM_STATIC_INDEX_PATTERN_ID,
+ applyGlobalQuery: true,
+ applyGlobalTime: true,
};
const getWhereQuery = (serviceName: string) => {
@@ -158,7 +161,6 @@ export function useLayerList() {
type: 'EMS_FILE',
id: 'world_countries',
tooltipProperties: [COUNTRY_NAME],
- applyGlobalQuery: true,
},
style: getLayerStyle(TRANSACTION_DURATION_COUNTRY),
id: 'e8d1d974-eed8-462f-be2c-f0004b7619b2',
diff --git a/x-pack/plugins/apm/public/components/app/ServiceDetails/alerting_popover_flyout/index.tsx b/x-pack/plugins/apm/public/components/app/ServiceDetails/alerting_popover_flyout/index.tsx
deleted file mode 100644
index 3a8d24f0a8b02..0000000000000
--- a/x-pack/plugins/apm/public/components/app/ServiceDetails/alerting_popover_flyout/index.tsx
+++ /dev/null
@@ -1,197 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import {
- EuiButtonEmpty,
- EuiContextMenu,
- EuiContextMenuPanelDescriptor,
- EuiPopover,
-} from '@elastic/eui';
-import { i18n } from '@kbn/i18n';
-import React, { useState } from 'react';
-import { AlertType } from '../../../../../common/alert_types';
-import { useApmPluginContext } from '../../../../hooks/useApmPluginContext';
-import { AlertingFlyout } from '../../../alerting/AlertingFlyout';
-
-const alertLabel = i18n.translate(
- 'xpack.apm.serviceDetails.alertsMenu.alerts',
- { defaultMessage: 'Alerts' }
-);
-const transactionDurationLabel = i18n.translate(
- 'xpack.apm.serviceDetails.alertsMenu.transactionDuration',
- { defaultMessage: 'Transaction duration' }
-);
-const transactionErrorRateLabel = i18n.translate(
- 'xpack.apm.serviceDetails.alertsMenu.transactionErrorRate',
- { defaultMessage: 'Transaction error rate' }
-);
-const errorCountLabel = i18n.translate(
- 'xpack.apm.serviceDetails.alertsMenu.errorCount',
- { defaultMessage: 'Error count' }
-);
-const createThresholdAlertLabel = i18n.translate(
- 'xpack.apm.serviceDetails.alertsMenu.createThresholdAlert',
- { defaultMessage: 'Create threshold alert' }
-);
-const createAnomalyAlertAlertLabel = i18n.translate(
- 'xpack.apm.serviceDetails.alertsMenu.createAnomalyAlert',
- { defaultMessage: 'Create anomaly alert' }
-);
-
-const CREATE_TRANSACTION_DURATION_ALERT_PANEL_ID =
- 'create_transaction_duration_panel';
-const CREATE_TRANSACTION_ERROR_RATE_ALERT_PANEL_ID =
- 'create_transaction_error_rate_panel';
-const CREATE_ERROR_COUNT_ALERT_PANEL_ID = 'create_error_count_panel';
-
-interface Props {
- canReadAlerts: boolean;
- canSaveAlerts: boolean;
- canReadAnomalies: boolean;
-}
-
-export function AlertingPopoverAndFlyout(props: Props) {
- const { canSaveAlerts, canReadAlerts, canReadAnomalies } = props;
-
- const plugin = useApmPluginContext();
-
- const [popoverOpen, setPopoverOpen] = useState(false);
-
- const [alertType, setAlertType] = useState(null);
-
- const button = (
- setPopoverOpen(true)}
- >
- {alertLabel}
-
- );
-
- const panels: EuiContextMenuPanelDescriptor[] = [
- {
- id: 0,
- title: alertLabel,
- items: [
- ...(canSaveAlerts
- ? [
- {
- name: transactionDurationLabel,
- panel: CREATE_TRANSACTION_DURATION_ALERT_PANEL_ID,
- },
- {
- name: transactionErrorRateLabel,
- panel: CREATE_TRANSACTION_ERROR_RATE_ALERT_PANEL_ID,
- },
- {
- name: errorCountLabel,
- panel: CREATE_ERROR_COUNT_ALERT_PANEL_ID,
- },
- ]
- : []),
- ...(canReadAlerts
- ? [
- {
- name: i18n.translate(
- 'xpack.apm.serviceDetails.alertsMenu.viewActiveAlerts',
- { defaultMessage: 'View active alerts' }
- ),
- href: plugin.core.http.basePath.prepend(
- '/app/management/insightsAndAlerting/triggersActions/alerts'
- ),
- icon: 'tableOfContents',
- },
- ]
- : []),
- ],
- },
-
- // transaction duration panel
- {
- id: CREATE_TRANSACTION_DURATION_ALERT_PANEL_ID,
- title: transactionDurationLabel,
- items: [
- // threshold alerts
- {
- name: createThresholdAlertLabel,
- onClick: () => {
- setAlertType(AlertType.TransactionDuration);
- setPopoverOpen(false);
- },
- },
-
- // anomaly alerts
- ...(canReadAnomalies
- ? [
- {
- name: createAnomalyAlertAlertLabel,
- onClick: () => {
- setAlertType(AlertType.TransactionDurationAnomaly);
- setPopoverOpen(false);
- },
- },
- ]
- : []),
- ],
- },
-
- // transaction error rate panel
- {
- id: CREATE_TRANSACTION_ERROR_RATE_ALERT_PANEL_ID,
- title: transactionErrorRateLabel,
- items: [
- // threshold alerts
- {
- name: createThresholdAlertLabel,
- onClick: () => {
- setAlertType(AlertType.TransactionErrorRate);
- setPopoverOpen(false);
- },
- },
- ],
- },
-
- // error alerts panel
- {
- id: CREATE_ERROR_COUNT_ALERT_PANEL_ID,
- title: errorCountLabel,
- items: [
- {
- name: createThresholdAlertLabel,
- onClick: () => {
- setAlertType(AlertType.ErrorCount);
- setPopoverOpen(false);
- },
- },
- ],
- },
- ];
-
- return (
- <>
-
- {
- if (!visible) {
- setAlertType(null);
- }
- }}
- />
- >
- );
-}
diff --git a/x-pack/plugins/apm/public/components/app/ServiceDetails/index.tsx b/x-pack/plugins/apm/public/components/app/ServiceDetails/index.tsx
index 8825702cafd51..aa5dcd5a5ea18 100644
--- a/x-pack/plugins/apm/public/components/app/ServiceDetails/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/ServiceDetails/index.tsx
@@ -4,19 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import {
- EuiButtonEmpty,
- EuiFlexGroup,
- EuiFlexItem,
- EuiTitle,
-} from '@elastic/eui';
-import { i18n } from '@kbn/i18n';
+import { EuiTitle } from '@elastic/eui';
import React from 'react';
import { RouteComponentProps } from 'react-router-dom';
-import { useApmPluginContext } from '../../../hooks/useApmPluginContext';
-import { getAlertingCapabilities } from '../../alerting/get_alert_capabilities';
import { ApmHeader } from '../../shared/ApmHeader';
-import { AlertingPopoverAndFlyout } from './alerting_popover_flyout';
import { ServiceDetailTabs } from './ServiceDetailTabs';
interface Props extends RouteComponentProps<{ serviceName: string }> {
@@ -24,51 +15,15 @@ interface Props extends RouteComponentProps<{ serviceName: string }> {
}
export function ServiceDetails({ match, tab }: Props) {
- const { core, plugins } = useApmPluginContext();
const { serviceName } = match.params;
- const {
- isAlertingAvailable,
- canReadAlerts,
- canSaveAlerts,
- canReadAnomalies,
- } = getAlertingCapabilities(plugins, core.application.capabilities);
-
- const ADD_DATA_LABEL = i18n.translate('xpack.apm.addDataButtonLabel', {
- defaultMessage: 'Add data',
- });
-
return (
-
-
-
- {serviceName}
-
-
- {isAlertingAvailable && (
-
-
-
- )}
-
-
- {ADD_DATA_LABEL}
-
-
-
+
+ {serviceName}
+
-
);
diff --git a/x-pack/plugins/apm/public/components/app/ServiceMap/useRefDimensions.ts b/x-pack/plugins/apm/public/components/app/ServiceMap/useRefDimensions.ts
index c8639b334f66a..fc478e27ccac3 100644
--- a/x-pack/plugins/apm/public/components/app/ServiceMap/useRefDimensions.ts
+++ b/x-pack/plugins/apm/public/components/app/ServiceMap/useRefDimensions.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { useRef } from 'react';
-import { useWindowSize } from 'react-use';
+import useWindowSize from 'react-use/lib/useWindowSize';
export function useRefDimensions() {
const ref = useRef(null);
diff --git a/x-pack/plugins/apm/public/components/app/Settings/index.tsx b/x-pack/plugins/apm/public/components/app/Settings/index.tsx
index e770116ac2759..c9c577285ee80 100644
--- a/x-pack/plugins/apm/public/components/app/Settings/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/Settings/index.tsx
@@ -14,6 +14,8 @@ import {
import { i18n } from '@kbn/i18n';
import React, { ReactNode } from 'react';
import { RouteComponentProps } from 'react-router-dom';
+import { HeaderMenuPortal } from '../../../../../observability/public';
+import { ActionMenu } from '../../../application/action_menu';
import { useApmPluginContext } from '../../../hooks/useApmPluginContext';
import { getAPMHref } from '../../shared/Links/apm/APMLink';
import { HomeLink } from '../../shared/Links/apm/HomeLink';
@@ -23,7 +25,7 @@ interface SettingsProps extends RouteComponentProps<{}> {
}
export function Settings({ children, location }: SettingsProps) {
- const { core } = useApmPluginContext();
+ const { appMountParameters, core } = useApmPluginContext();
const { basePath } = core.http;
const canAccessML = !!core.application.capabilities.ml?.canAccessML;
const { search, pathname } = location;
@@ -34,6 +36,11 @@ export function Settings({ children, location }: SettingsProps) {
return (
<>
+
+
+
{i18n.translate('xpack.apm.settings.returnLinkLabel', {
diff --git a/x-pack/plugins/apm/public/components/app/service_inventory/service_inventory.test.tsx b/x-pack/plugins/apm/public/components/app/service_inventory/service_inventory.test.tsx
index d394c7db62554..247e91fb438ef 100644
--- a/x-pack/plugins/apm/public/components/app/service_inventory/service_inventory.test.tsx
+++ b/x-pack/plugins/apm/public/components/app/service_inventory/service_inventory.test.tsx
@@ -149,7 +149,7 @@ describe('ServiceInventory', () => {
"Looks like you don't have any APM services installed. Let's add some!"
);
- expect(gettingStartedMessage).not.toBeEmpty();
+ expect(gettingStartedMessage).not.toBeEmptyDOMElement();
});
it('should render empty message, when list is empty and historical data is found', async () => {
@@ -165,7 +165,7 @@ describe('ServiceInventory', () => {
await waitFor(() => expect(httpGet).toHaveBeenCalledTimes(1));
const noServicesText = await findByText('No services found');
- expect(noServicesText).not.toBeEmpty();
+ expect(noServicesText).not.toBeEmptyDOMElement();
});
describe('when legacy data is found', () => {
diff --git a/x-pack/plugins/apm/public/components/shared/ApmHeader/index.tsx b/x-pack/plugins/apm/public/components/shared/ApmHeader/index.tsx
index 6674abe9b8ce5..96f170fa6a093 100644
--- a/x-pack/plugins/apm/public/components/shared/ApmHeader/index.tsx
+++ b/x-pack/plugins/apm/public/components/shared/ApmHeader/index.tsx
@@ -6,13 +6,21 @@
import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
import React, { ReactNode } from 'react';
+import { HeaderMenuPortal } from '../../../../../observability/public';
+import { ActionMenu } from '../../../application/action_menu';
+import { useApmPluginContext } from '../../../hooks/useApmPluginContext';
import { DatePicker } from '../DatePicker';
import { EnvironmentFilter } from '../EnvironmentFilter';
import { KueryBar } from '../KueryBar';
export function ApmHeader({ children }: { children: ReactNode }) {
+ const { setHeaderActionMenu } = useApmPluginContext().appMountParameters;
+
return (
<>
+
+
+
{children}
diff --git a/x-pack/plugins/apm/public/components/shared/KueryBar/get_bool_filter.ts b/x-pack/plugins/apm/public/components/shared/KueryBar/get_bool_filter.ts
index 74d7ace20dae0..e7dd03db6b63c 100644
--- a/x-pack/plugins/apm/public/components/shared/KueryBar/get_bool_filter.ts
+++ b/x-pack/plugins/apm/public/components/shared/KueryBar/get_bool_filter.ts
@@ -4,6 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import { ESFilter } from '../../../../../../typings/elasticsearch';
import {
ERROR_GROUP_ID,
PROCESSOR_EVENT,
@@ -12,7 +13,6 @@ import {
TRANSACTION_TYPE,
} from '../../../../common/elasticsearch_fieldnames';
import { UIProcessorEvent } from '../../../../common/processor_event';
-import { ESFilter } from '../../../../typings/elasticsearch';
import { IUrlParams } from '../../../context/UrlParamsContext/types';
export function getBoolFilter({
@@ -26,23 +26,7 @@ export function getBoolFilter({
serviceName?: string;
urlParams: IUrlParams;
}) {
- const { start, end } = urlParams;
-
- if (!start || !end) {
- throw new Error('Date range was not defined');
- }
-
- const boolFilter: ESFilter[] = [
- {
- range: {
- '@timestamp': {
- gte: new Date(start).getTime(),
- lte: new Date(end).getTime(),
- format: 'epoch_millis',
- },
- },
- },
- ];
+ const boolFilter: ESFilter[] = [];
if (serviceName) {
boolFilter.push({
diff --git a/x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx b/x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx
index 157e014bee424..dce8e49deec41 100644
--- a/x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx
+++ b/x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx
@@ -111,6 +111,7 @@ export function KueryBar() {
query: inputValue,
selectionStart,
selectionEnd: selectionStart,
+ useTimeRange: true,
})) || []
)
.filter((suggestion) => !startsWith(suggestion.text, 'span.'))
diff --git a/x-pack/plugins/apm/public/components/shared/Links/SetupInstructionsLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/SetupInstructionsLink.tsx
index a5bcec1501ad3..0ff73d91d7c5b 100644
--- a/x-pack/plugins/apm/public/components/shared/Links/SetupInstructionsLink.tsx
+++ b/x-pack/plugins/apm/public/components/shared/Links/SetupInstructionsLink.tsx
@@ -34,7 +34,7 @@ export function SetupInstructionsLink({
{SETUP_INSTRUCTIONS_LABEL}
) : (
-
+
{ADD_DATA_LABEL}
)}
diff --git a/x-pack/plugins/apm/public/context/ApmPluginContext/MockApmPluginContext.tsx b/x-pack/plugins/apm/public/context/ApmPluginContext/MockApmPluginContext.tsx
index 3b915045f54b6..25e7f23a00125 100644
--- a/x-pack/plugins/apm/public/context/ApmPluginContext/MockApmPluginContext.tsx
+++ b/x-pack/plugins/apm/public/context/ApmPluginContext/MockApmPluginContext.tsx
@@ -38,6 +38,7 @@ const mockCore = {
application: {
capabilities: {
apm: {},
+ ml: {},
},
currentAppId$: new Observable(),
navigateToUrl: (url: string) => {},
@@ -93,7 +94,13 @@ const mockPlugin = {
},
},
};
+
+const mockAppMountParameters = {
+ setHeaderActionMenu: () => {},
+};
+
export const mockApmPluginContextValue = {
+ appMountParameters: mockAppMountParameters,
config: mockConfig,
core: mockCore,
plugins: mockPlugin,
diff --git a/x-pack/plugins/apm/public/context/ApmPluginContext/index.tsx b/x-pack/plugins/apm/public/context/ApmPluginContext/index.tsx
index 39d961f6a8164..44952e64db59c 100644
--- a/x-pack/plugins/apm/public/context/ApmPluginContext/index.tsx
+++ b/x-pack/plugins/apm/public/context/ApmPluginContext/index.tsx
@@ -4,12 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { CoreStart } from 'kibana/public';
+import { AppMountParameters, CoreStart } from 'kibana/public';
import { createContext } from 'react';
import { ConfigSchema } from '../../';
import { ApmPluginSetupDeps } from '../../plugin';
export interface ApmPluginContextValue {
+ appMountParameters: AppMountParameters;
config: ConfigSchema;
core: CoreStart;
plugins: ApmPluginSetupDeps;
diff --git a/x-pack/plugins/apm/public/utils/testHelpers.tsx b/x-pack/plugins/apm/public/utils/testHelpers.tsx
index f990c4387ddf1..87dfeb95b6326 100644
--- a/x-pack/plugins/apm/public/utils/testHelpers.tsx
+++ b/x-pack/plugins/apm/public/utils/testHelpers.tsx
@@ -6,26 +6,26 @@
/* global jest */
-import React from 'react';
-import { ReactWrapper, mount, MountRendererProps } from 'enzyme';
+import { render, waitFor } from '@testing-library/react';
+import { mount, MountRendererProps, ReactWrapper } from 'enzyme';
import enzymeToJson from 'enzyme-to-json';
import { Location } from 'history';
import moment from 'moment';
import { Moment } from 'moment-timezone';
-import { render, waitFor } from '@testing-library/react';
+import React from 'react';
import { MemoryRouter } from 'react-router-dom';
-// eslint-disable-next-line @kbn/eslint/no-restricted-paths
-import { APMConfig } from '../../server';
-import { PromiseReturnType } from '../../typings/common';
-import { EuiThemeProvider } from '../../../observability/public';
import {
ESFilter,
- ESSearchResponse,
ESSearchRequest,
-} from '../../typings/elasticsearch';
+ ESSearchResponse,
+} from '../../../../typings/elasticsearch';
+import { EuiThemeProvider } from '../../../observability/public';
+import { PromiseReturnType } from '../../../observability/typings/common';
+// eslint-disable-next-line @kbn/eslint/no-restricted-paths
+import { APMConfig } from '../../server';
+import { UIFilters } from '../../typings/ui_filters';
import { MockApmPluginContextWrapper } from '../context/ApmPluginContext/MockApmPluginContext';
import { UrlParamsProvider } from '../context/UrlParamsContext';
-import { UIFilters } from '../../typings/ui_filters';
const originalConsoleWarn = console.warn; // eslint-disable-line no-console
/**
diff --git a/x-pack/plugins/apm/scripts/shared/get_es_client.ts b/x-pack/plugins/apm/scripts/shared/get_es_client.ts
index 86dfd92190fdf..912c8943b1edf 100644
--- a/x-pack/plugins/apm/scripts/shared/get_es_client.ts
+++ b/x-pack/plugins/apm/scripts/shared/get_es_client.ts
@@ -6,7 +6,10 @@
import { Client } from '@elastic/elasticsearch';
import { ApiKeyAuth, BasicAuth } from '@elastic/elasticsearch/lib/pool';
-import { ESSearchResponse, ESSearchRequest } from '../../typings/elasticsearch';
+import {
+ ESSearchResponse,
+ ESSearchRequest,
+} from '../../../../typings/elasticsearch';
export type ESClient = ReturnType;
diff --git a/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts b/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts
index ecda5b0e8504b..464a737c50ea2 100644
--- a/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts
+++ b/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts
@@ -9,6 +9,7 @@ import { isEmpty } from 'lodash';
import { Observable } from 'rxjs';
import { take } from 'rxjs/operators';
import { APMConfig } from '../..';
+import { ESSearchResponse } from '../../../../../typings/elasticsearch';
import { AlertingPlugin } from '../../../../alerts/server';
import { AlertType, ALERT_TYPES_CONFIG } from '../../../common/alert_types';
import {
@@ -17,7 +18,6 @@ import {
SERVICE_NAME,
} from '../../../common/elasticsearch_fieldnames';
import { ProcessorEvent } from '../../../common/processor_event';
-import { ESSearchResponse } from '../../../typings/elasticsearch';
import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es';
import { getApmIndices } from '../settings/apm_indices/get_apm_indices';
import { apmActionVariables } from './action_variables';
diff --git a/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts b/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts
index d9e69c8f3b7d7..602ee99970f8a 100644
--- a/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts
+++ b/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts
@@ -7,21 +7,21 @@
import { schema } from '@kbn/config-schema';
import { Observable } from 'rxjs';
import { take } from 'rxjs/operators';
-import { getDurationFormatter } from '../../../common/utils/formatters';
-import { ProcessorEvent } from '../../../common/processor_event';
+import { APMConfig } from '../..';
+import { ESSearchResponse } from '../../../../../typings/elasticsearch';
+import { AlertingPlugin } from '../../../../alerts/server';
import { AlertType, ALERT_TYPES_CONFIG } from '../../../common/alert_types';
-import { ESSearchResponse } from '../../../typings/elasticsearch';
import {
PROCESSOR_EVENT,
+ SERVICE_ENVIRONMENT,
SERVICE_NAME,
- TRANSACTION_TYPE,
TRANSACTION_DURATION,
- SERVICE_ENVIRONMENT,
+ TRANSACTION_TYPE,
} from '../../../common/elasticsearch_fieldnames';
-import { AlertingPlugin } from '../../../../alerts/server';
-import { getApmIndices } from '../settings/apm_indices/get_apm_indices';
-import { APMConfig } from '../..';
+import { ProcessorEvent } from '../../../common/processor_event';
+import { getDurationFormatter } from '../../../common/utils/formatters';
import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es';
+import { getApmIndices } from '../settings/apm_indices/get_apm_indices';
import { apmActionVariables } from './action_variables';
interface RegisterAlertParams {
diff --git a/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts b/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts
index 06b296db5a485..0506e1b4c3aed 100644
--- a/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts
+++ b/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts
@@ -5,25 +5,25 @@
*/
import { schema } from '@kbn/config-schema';
+import { isEmpty } from 'lodash';
import { Observable } from 'rxjs';
import { take } from 'rxjs/operators';
-import { isEmpty } from 'lodash';
-import { asDecimalOrInteger } from '../../../common/utils/formatters';
-import { ProcessorEvent } from '../../../common/processor_event';
-import { EventOutcome } from '../../../common/event_outcome';
+import { APMConfig } from '../..';
+import { ESSearchResponse } from '../../../../../typings/elasticsearch';
+import { AlertingPlugin } from '../../../../alerts/server';
import { AlertType, ALERT_TYPES_CONFIG } from '../../../common/alert_types';
-import { ESSearchResponse } from '../../../typings/elasticsearch';
import {
+ EVENT_OUTCOME,
PROCESSOR_EVENT,
+ SERVICE_ENVIRONMENT,
SERVICE_NAME,
TRANSACTION_TYPE,
- EVENT_OUTCOME,
- SERVICE_ENVIRONMENT,
} from '../../../common/elasticsearch_fieldnames';
-import { AlertingPlugin } from '../../../../alerts/server';
-import { getApmIndices } from '../settings/apm_indices/get_apm_indices';
-import { APMConfig } from '../..';
+import { EventOutcome } from '../../../common/event_outcome';
+import { ProcessorEvent } from '../../../common/processor_event';
+import { asDecimalOrInteger } from '../../../common/utils/formatters';
import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es';
+import { getApmIndices } from '../settings/apm_indices/get_apm_indices';
import { apmActionVariables } from './action_variables';
interface RegisterAlertParams {
diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/index.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/index.ts
index e53a0e24b4723..730645c609cb6 100644
--- a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/index.ts
+++ b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/index.ts
@@ -9,7 +9,7 @@ import { IndicesStatsParams, Client } from 'elasticsearch';
import {
ESSearchRequest,
ESSearchResponse,
-} from '../../../../typings/elasticsearch';
+} from '../../../../../../typings/elasticsearch';
import { ApmIndicesConfig } from '../../settings/apm_indices/get_apm_indices';
import { tasks } from './tasks';
import { APMDataTelemetry } from '../types';
diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts
index ac82d353417b4..ec2eb7c8dd99a 100644
--- a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts
+++ b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts
@@ -5,7 +5,7 @@
*/
import { ValuesType } from 'utility-types';
import { flatten, merge, sortBy, sum, pickBy } from 'lodash';
-import { AggregationOptionsByType } from '../../../../typings/elasticsearch/aggregations';
+import { AggregationOptionsByType } from '../../../../../../typings/elasticsearch/aggregations';
import { ProcessorEvent } from '../../../../common/processor_event';
import { TelemetryTask } from '.';
import { AGENT_NAMES, RUM_AGENT_NAMES } from '../../../../common/agent_name';
diff --git a/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.ts b/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.ts
index b12dd73a20986..9e18c81e4aaeb 100644
--- a/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.ts
+++ b/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.ts
@@ -4,12 +4,12 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { ProcessorEvent } from '../../../../common/processor_event';
-import { ESFilter } from '../../../../typings/elasticsearch';
+import { ESFilter } from '../../../../../../typings/elasticsearch';
import {
ERROR_GROUP_ID,
SERVICE_NAME,
} from '../../../../common/elasticsearch_fieldnames';
+import { ProcessorEvent } from '../../../../common/processor_event';
import { rangeFilter } from '../../../../common/utils/range_filter';
import { Setup, SetupTimeRange } from '../../helpers/setup_request';
diff --git a/x-pack/plugins/apm/server/lib/errors/distribution/get_distribution.ts b/x-pack/plugins/apm/server/lib/errors/distribution/get_distribution.ts
index dea518cad8e40..7866c99353451 100644
--- a/x-pack/plugins/apm/server/lib/errors/distribution/get_distribution.ts
+++ b/x-pack/plugins/apm/server/lib/errors/distribution/get_distribution.ts
@@ -4,10 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { PromiseReturnType } from '../../../../typings/common';
+import { PromiseReturnType } from '../../../../../observability/typings/common';
import { Setup, SetupTimeRange } from '../../helpers/setup_request';
-import { getBuckets } from './get_buckets';
import { BUCKET_TARGET_COUNT } from '../../transactions/constants';
+import { getBuckets } from './get_buckets';
function getBucketSize({ start, end }: SetupTimeRange) {
return Math.floor((end - start) / BUCKET_TARGET_COUNT);
diff --git a/x-pack/plugins/apm/server/lib/errors/get_error_group.ts b/x-pack/plugins/apm/server/lib/errors/get_error_group.ts
index 0fbc7720f7111..37be72beedeb1 100644
--- a/x-pack/plugins/apm/server/lib/errors/get_error_group.ts
+++ b/x-pack/plugins/apm/server/lib/errors/get_error_group.ts
@@ -4,13 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { ProcessorEvent } from '../../../common/processor_event';
+import { PromiseReturnType } from '../../../../observability/typings/common';
import {
ERROR_GROUP_ID,
SERVICE_NAME,
TRANSACTION_SAMPLED,
} from '../../../common/elasticsearch_fieldnames';
-import { PromiseReturnType } from '../../../typings/common';
+import { ProcessorEvent } from '../../../common/processor_event';
import { rangeFilter } from '../../../common/utils/range_filter';
import { Setup, SetupTimeRange } from '../helpers/setup_request';
import { getTransaction } from '../transactions/get_transaction';
diff --git a/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts b/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts
index 006d2fae3d4fb..d734a1395fc5e 100644
--- a/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts
+++ b/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts
@@ -4,6 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import { SortOptions } from '../../../../../typings/elasticsearch/aggregations';
+import { PromiseReturnType } from '../../../../observability/typings/common';
import {
ERROR_CULPRIT,
ERROR_EXC_HANDLED,
@@ -12,11 +14,9 @@ import {
ERROR_GROUP_ID,
ERROR_LOG_MESSAGE,
} from '../../../common/elasticsearch_fieldnames';
-import { PromiseReturnType } from '../../../typings/common';
-import { Setup, SetupTimeRange } from '../helpers/setup_request';
import { getErrorGroupsProjection } from '../../projections/errors';
import { mergeProjection } from '../../projections/util/merge_projection';
-import { SortOptions } from '../../../typings/elasticsearch/aggregations';
+import { Setup, SetupTimeRange } from '../helpers/setup_request';
export type ErrorGroupListAPIResponse = PromiseReturnType<
typeof getErrorGroups
diff --git a/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_environment_ui_filter_es.ts b/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_environment_ui_filter_es.ts
index ea8d02eb833cf..dd9f0b0333c01 100644
--- a/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_environment_ui_filter_es.ts
+++ b/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_environment_ui_filter_es.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { ESFilter } from '../../../../typings/elasticsearch';
+import { ESFilter } from '../../../../../../typings/elasticsearch';
import {
ENVIRONMENT_NOT_DEFINED,
ENVIRONMENT_ALL,
diff --git a/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_es_filter.ts b/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_es_filter.ts
index 1b8f32d4de8b9..0592f13bdf54f 100644
--- a/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_es_filter.ts
+++ b/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_es_filter.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { ESFilter } from '../../../../typings/elasticsearch';
+import { ESFilter } from '../../../../../../typings/elasticsearch';
import { UIFilters } from '../../../../typings/ui_filters';
import { getEnvironmentUiFilterES } from './get_environment_ui_filter_es';
import {
diff --git a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/add_filter_to_exclude_legacy_data.ts b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/add_filter_to_exclude_legacy_data.ts
index 494cd6cbf0eec..921b46daee2a9 100644
--- a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/add_filter_to_exclude_legacy_data.ts
+++ b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/add_filter_to_exclude_legacy_data.ts
@@ -9,7 +9,7 @@ import { OBSERVER_VERSION_MAJOR } from '../../../../../common/elasticsearch_fiel
import {
ESSearchRequest,
ESFilter,
-} from '../../../../../typings/elasticsearch';
+} from '../../../../../../../typings/elasticsearch';
/*
Adds a range query to the ES request to exclude legacy data
diff --git a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/index.ts b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/index.ts
index 9020cb1b9953a..870997efb77de 100644
--- a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/index.ts
+++ b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/index.ts
@@ -5,7 +5,6 @@
*/
import { ValuesType } from 'utility-types';
-import { APMBaseDoc } from '../../../../../typings/es_schemas/raw/apm_base_doc';
import { APMError } from '../../../../../typings/es_schemas/ui/apm_error';
import {
KibanaRequest,
@@ -15,12 +14,13 @@ import { ProcessorEvent } from '../../../../../common/processor_event';
import {
ESSearchRequest,
ESSearchResponse,
-} from '../../../../../typings/elasticsearch';
+} from '../../../../../../../typings/elasticsearch';
import { ApmIndicesConfig } from '../../../settings/apm_indices/get_apm_indices';
import { addFilterToExcludeLegacyData } from './add_filter_to_exclude_legacy_data';
import { callClientWithDebug } from '../call_client_with_debug';
import { Transaction } from '../../../../../typings/es_schemas/ui/transaction';
import { Span } from '../../../../../typings/es_schemas/ui/span';
+import { Metric } from '../../../../../typings/es_schemas/ui/metric';
import { unpackProcessorEvents } from './unpack_processor_events';
export type APMEventESSearchRequest = Omit & {
@@ -33,7 +33,7 @@ type TypeOfProcessorEvent = {
[ProcessorEvent.error]: APMError;
[ProcessorEvent.transaction]: Transaction;
[ProcessorEvent.span]: Span;
- [ProcessorEvent.metric]: APMBaseDoc;
+ [ProcessorEvent.metric]: Metric;
[ProcessorEvent.onboarding]: unknown;
[ProcessorEvent.sourcemap]: unknown;
}[T];
diff --git a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/unpack_processor_events.ts b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/unpack_processor_events.ts
index 736c7ad2d1089..add522a5c7f84 100644
--- a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/unpack_processor_events.ts
+++ b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/unpack_processor_events.ts
@@ -10,7 +10,7 @@ import { ProcessorEvent } from '../../../../../common/processor_event';
import {
ESSearchRequest,
ESFilter,
-} from '../../../../../typings/elasticsearch';
+} from '../../../../../../../typings/elasticsearch';
import { APMEventESSearchRequest } from '.';
import {
ApmIndicesConfig,
diff --git a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_internal_es_client/index.ts b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_internal_es_client/index.ts
index 072391606d574..8e74a7992e9ea 100644
--- a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_internal_es_client/index.ts
+++ b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_internal_es_client/index.ts
@@ -15,7 +15,7 @@ import { APMRequestHandlerContext } from '../../../../routes/typings';
import {
ESSearchResponse,
ESSearchRequest,
-} from '../../../../../typings/elasticsearch';
+} from '../../../../../../../typings/elasticsearch';
import { callClientWithDebug } from '../call_client_with_debug';
// `type` was deprecated in 7.0
diff --git a/x-pack/plugins/apm/server/lib/helpers/get_internal_saved_objects_client.ts b/x-pack/plugins/apm/server/lib/helpers/get_internal_saved_objects_client.ts
index e0bb9ad354f58..097538076de25 100644
--- a/x-pack/plugins/apm/server/lib/helpers/get_internal_saved_objects_client.ts
+++ b/x-pack/plugins/apm/server/lib/helpers/get_internal_saved_objects_client.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { CoreSetup } from 'src/core/server';
-import { PromiseReturnType } from '../../../typings/common';
+import { PromiseReturnType } from '../../../../observability/typings/common';
export type InternalSavedObjectsClient = PromiseReturnType<
typeof getInternalSavedObjectsClient
diff --git a/x-pack/plugins/apm/server/lib/helpers/setup_request.ts b/x-pack/plugins/apm/server/lib/helpers/setup_request.ts
index 363c4128137e0..65d36c8b36af8 100644
--- a/x-pack/plugins/apm/server/lib/helpers/setup_request.ts
+++ b/x-pack/plugins/apm/server/lib/helpers/setup_request.ts
@@ -4,20 +4,21 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import moment from 'moment';
import { Logger } from 'kibana/server';
-import { isActivePlatinumLicense } from '../../../common/service_map';
-import { UI_SETTINGS } from '../../../../../../src/plugins/data/common';
-import { KibanaRequest } from '../../../../../../src/core/server';
+import moment from 'moment';
import { APMConfig } from '../..';
+import { KibanaRequest } from '../../../../../../src/core/server';
+import { UI_SETTINGS } from '../../../../../../src/plugins/data/common';
+import { ESFilter } from '../../../../../typings/elasticsearch';
+import { ProcessorEvent } from '../../../common/processor_event';
+import { isActivePlatinumLicense } from '../../../common/service_map';
+import { UIFilters } from '../../../typings/ui_filters';
+import { APMRequestHandlerContext } from '../../routes/typings';
import {
- getApmIndices,
ApmIndicesConfig,
+ getApmIndices,
} from '../settings/apm_indices/get_apm_indices';
-import { ESFilter } from '../../../typings/elasticsearch';
import { getEsFilter } from './convert_ui_filters/get_es_filter';
-import { APMRequestHandlerContext } from '../../routes/typings';
-import { ProcessorEvent } from '../../../common/processor_event';
import {
APMEventClient,
createApmEventClient,
@@ -26,7 +27,6 @@ import {
APMInternalClient,
createInternalESClient,
} from './create_es_client/create_internal_es_client';
-import { UIFilters } from '../../../typings/ui_filters';
// Explicitly type Setup to prevent TS initialization errors
// https://github.com/microsoft/TypeScript/issues/34933
diff --git a/x-pack/plugins/apm/server/lib/helpers/transaction_error_rate.ts b/x-pack/plugins/apm/server/lib/helpers/transaction_error_rate.ts
index ccc7ba7e22b50..03a44e77ba2d3 100644
--- a/x-pack/plugins/apm/server/lib/helpers/transaction_error_rate.ts
+++ b/x-pack/plugins/apm/server/lib/helpers/transaction_error_rate.ts
@@ -9,7 +9,7 @@ import { EventOutcome } from '../../../common/event_outcome';
import {
AggregationOptionsByType,
AggregationResultOf,
-} from '../../../typings/elasticsearch/aggregations';
+} from '../../../../../typings/elasticsearch/aggregations';
import { getTransactionDurationFieldForAggregatedTransactions } from './aggregated_transactions';
export function getOutcomeAggregation({
diff --git a/x-pack/plugins/apm/server/lib/metrics/fetch_and_transform_metrics.ts b/x-pack/plugins/apm/server/lib/metrics/fetch_and_transform_metrics.ts
index 3ccba8c7586dc..57eae26593305 100644
--- a/x-pack/plugins/apm/server/lib/metrics/fetch_and_transform_metrics.ts
+++ b/x-pack/plugins/apm/server/lib/metrics/fetch_and_transform_metrics.ts
@@ -4,15 +4,15 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { Unionize, Overwrite } from 'utility-types';
-import { Setup, SetupTimeRange } from '../helpers/setup_request';
-import { getMetricsDateHistogramParams } from '../helpers/metrics';
-import { ChartBase } from './types';
-import { transformDataToMetricsChart } from './transform_metrics_chart';
+import { Overwrite, Unionize } from 'utility-types';
+import { AggregationOptionsByType } from '../../../../../typings/elasticsearch';
import { getMetricsProjection } from '../../projections/metrics';
import { mergeProjection } from '../../projections/util/merge_projection';
-import { AggregationOptionsByType } from '../../../typings/elasticsearch/aggregations';
import { APMEventESSearchRequest } from '../helpers/create_es_client/create_apm_event_client';
+import { getMetricsDateHistogramParams } from '../helpers/metrics';
+import { Setup, SetupTimeRange } from '../helpers/setup_request';
+import { transformDataToMetricsChart } from './transform_metrics_chart';
+import { ChartBase } from './types';
type MetricsAggregationMap = Unionize<{
min: AggregationOptionsByType['min'];
diff --git a/x-pack/plugins/apm/server/lib/metrics/transform_metrics_chart.ts b/x-pack/plugins/apm/server/lib/metrics/transform_metrics_chart.ts
index a191d5400e36c..bcf8b412f350a 100644
--- a/x-pack/plugins/apm/server/lib/metrics/transform_metrics_chart.ts
+++ b/x-pack/plugins/apm/server/lib/metrics/transform_metrics_chart.ts
@@ -4,10 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
import theme from '@elastic/eui/dist/eui_theme_light.json';
-import { ChartBase } from './types';
-import { ESSearchResponse } from '../../../typings/elasticsearch';
+import { ESSearchResponse } from '../../../../../typings/elasticsearch';
import { getVizColorForIndex } from '../../../common/viz_colors';
import { GenericMetricsRequest } from './fetch_and_transform_metrics';
+import { ChartBase } from './types';
export type GenericMetricsChart = ReturnType<
typeof transformDataToMetricsChart
diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts
index 5f4bc61af4c69..8f8d7763970b7 100644
--- a/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts
+++ b/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts
@@ -4,21 +4,21 @@
* you may not use this file except in compliance with the Elastic License.
*/
import Boom from '@hapi/boom';
+import { MlPluginSetup } from '../../../../ml/server';
+import { PromiseReturnType } from '../../../../observability/typings/common';
+import {
+ getSeverity,
+ ML_ERRORS,
+ ServiceAnomalyStats,
+} from '../../../common/anomaly_detection';
+import { ENVIRONMENT_ALL } from '../../../common/environment_filter_values';
import { getServiceHealthStatus } from '../../../common/service_health_status';
-import { Setup, SetupTimeRange } from '../helpers/setup_request';
-import { PromiseReturnType } from '../../../typings/common';
import {
TRANSACTION_PAGE_LOAD,
TRANSACTION_REQUEST,
} from '../../../common/transaction_types';
-import {
- ServiceAnomalyStats,
- getSeverity,
- ML_ERRORS,
-} from '../../../common/anomaly_detection';
import { getMlJobsWithAPMGroup } from '../anomaly_detection/get_ml_jobs_with_apm_group';
-import { ENVIRONMENT_ALL } from '../../../common/environment_filter_values';
-import { MlPluginSetup } from '../../../../ml/server';
+import { Setup, SetupTimeRange } from '../helpers/setup_request';
export const DEFAULT_ANOMALIES = { mlJobIds: [], serviceAnomalies: {} };
diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts
index 330bb936c9e88..ccebbfa44538a 100644
--- a/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts
+++ b/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts
@@ -3,8 +3,9 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
-import { chunk } from 'lodash';
import { Logger } from 'kibana/server';
+import { chunk } from 'lodash';
+import { PromiseReturnType } from '../../../../observability/typings/common';
import {
AGENT_NAME,
SERVICE_ENVIRONMENT,
@@ -12,17 +13,16 @@ import {
} from '../../../common/elasticsearch_fieldnames';
import { getServicesProjection } from '../../projections/services';
import { mergeProjection } from '../../projections/util/merge_projection';
-import { PromiseReturnType } from '../../../typings/common';
-import { Setup, SetupTimeRange } from '../helpers/setup_request';
import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es';
-import { transformServiceMapResponses } from './transform_service_map_responses';
-import { getServiceMapFromTraceIds } from './get_service_map_from_trace_ids';
-import { getTraceSampleIds } from './get_trace_sample_ids';
+import { Setup, SetupTimeRange } from '../helpers/setup_request';
import {
+ DEFAULT_ANOMALIES,
getServiceAnomalies,
ServiceAnomaliesResponse,
- DEFAULT_ANOMALIES,
} from './get_service_anomalies';
+import { getServiceMapFromTraceIds } from './get_service_map_from_trace_ids';
+import { getTraceSampleIds } from './get_trace_sample_ids';
+import { transformServiceMapResponses } from './transform_service_map_responses';
export interface IEnvOptions {
setup: Setup & SetupTimeRange;
diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts
index 37b34641435fb..82d339686f7ec 100644
--- a/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts
+++ b/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts
@@ -4,33 +4,33 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import { ESFilter } from '../../../../../typings/elasticsearch';
import {
- TRANSACTION_REQUEST,
- TRANSACTION_PAGE_LOAD,
-} from '../../../common/transaction_types';
-import {
- SERVICE_NAME,
+ METRIC_CGROUP_MEMORY_USAGE_BYTES,
METRIC_SYSTEM_CPU_PERCENT,
METRIC_SYSTEM_FREE_MEMORY,
METRIC_SYSTEM_TOTAL_MEMORY,
- METRIC_CGROUP_MEMORY_USAGE_BYTES,
+ SERVICE_NAME,
TRANSACTION_TYPE,
} from '../../../common/elasticsearch_fieldnames';
import { ProcessorEvent } from '../../../common/processor_event';
+import {
+ TRANSACTION_PAGE_LOAD,
+ TRANSACTION_REQUEST,
+} from '../../../common/transaction_types';
import { rangeFilter } from '../../../common/utils/range_filter';
-import { ESFilter } from '../../../typings/elasticsearch';
+import {
+ getDocumentTypeFilterForAggregatedTransactions,
+ getProcessorEventForAggregatedTransactions,
+ getTransactionDurationFieldForAggregatedTransactions,
+} from '../helpers/aggregated_transactions';
+import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es';
import { Setup, SetupTimeRange } from '../helpers/setup_request';
import {
percentCgroupMemoryUsedScript,
percentSystemMemoryUsedScript,
} from '../metrics/by_agent/shared/memory';
-import {
- getProcessorEventForAggregatedTransactions,
- getTransactionDurationFieldForAggregatedTransactions,
- getDocumentTypeFilterForAggregatedTransactions,
-} from '../helpers/aggregated_transactions';
import { getErrorRate } from '../transaction_groups/get_error_rate';
-import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es';
interface Options {
setup: Setup & SetupTimeRange;
diff --git a/x-pack/plugins/apm/server/lib/service_map/get_trace_sample_ids.ts b/x-pack/plugins/apm/server/lib/service_map/get_trace_sample_ids.ts
index 22c655bb96f50..db11ab2d9ce3a 100644
--- a/x-pack/plugins/apm/server/lib/service_map/get_trace_sample_ids.ts
+++ b/x-pack/plugins/apm/server/lib/service_map/get_trace_sample_ids.ts
@@ -3,20 +3,20 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
-import { uniq, take, sortBy } from 'lodash';
import Boom from '@hapi/boom';
-import { ProcessorEvent } from '../../../common/processor_event';
-import { Setup, SetupTimeRange } from '../helpers/setup_request';
-import { rangeFilter } from '../../../common/utils/range_filter';
-import { ESFilter } from '../../../typings/elasticsearch';
+import { sortBy, take, uniq } from 'lodash';
+import { ESFilter } from '../../../../../typings/elasticsearch';
import {
- SERVICE_NAME,
SERVICE_ENVIRONMENT,
- TRACE_ID,
+ SERVICE_NAME,
SPAN_DESTINATION_SERVICE_RESOURCE,
+ TRACE_ID,
} from '../../../common/elasticsearch_fieldnames';
-import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es';
+import { ProcessorEvent } from '../../../common/processor_event';
import { SERVICE_MAP_TIMEOUT_ERROR } from '../../../common/service_map';
+import { rangeFilter } from '../../../common/utils/range_filter';
+import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es';
+import { Setup, SetupTimeRange } from '../helpers/setup_request';
const MAX_TRACES_TO_INSPECT = 1000;
diff --git a/x-pack/plugins/apm/server/lib/services/annotations/get_derived_service_annotations.ts b/x-pack/plugins/apm/server/lib/services/annotations/get_derived_service_annotations.ts
index b80e86d53f292..367cf2faf6a8e 100644
--- a/x-pack/plugins/apm/server/lib/services/annotations/get_derived_service_annotations.ts
+++ b/x-pack/plugins/apm/server/lib/services/annotations/get_derived_service_annotations.ts
@@ -4,19 +4,19 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { isNumber } from 'lodash';
+import { ESFilter } from '../../../../../../typings/elasticsearch';
import { Annotation, AnnotationType } from '../../../../common/annotations';
-import { SetupTimeRange, Setup } from '../../helpers/setup_request';
-import { ESFilter } from '../../../../typings/elasticsearch';
-import { rangeFilter } from '../../../../common/utils/range_filter';
import {
SERVICE_NAME,
SERVICE_VERSION,
} from '../../../../common/elasticsearch_fieldnames';
-import { getEnvironmentUiFilterES } from '../../helpers/convert_ui_filters/get_environment_ui_filter_es';
+import { rangeFilter } from '../../../../common/utils/range_filter';
import {
getDocumentTypeFilterForAggregatedTransactions,
getProcessorEventForAggregatedTransactions,
} from '../../helpers/aggregated_transactions';
+import { getEnvironmentUiFilterES } from '../../helpers/convert_ui_filters/get_environment_ui_filter_es';
+import { Setup, SetupTimeRange } from '../../helpers/setup_request';
export async function getDerivedServiceAnnotations({
setup,
diff --git a/x-pack/plugins/apm/server/lib/services/annotations/get_stored_annotations.ts b/x-pack/plugins/apm/server/lib/services/annotations/get_stored_annotations.ts
index 6e3ae0181ddee..623abf6930297 100644
--- a/x-pack/plugins/apm/server/lib/services/annotations/get_stored_annotations.ts
+++ b/x-pack/plugins/apm/server/lib/services/annotations/get_stored_annotations.ts
@@ -5,13 +5,13 @@
*/
import { LegacyAPICaller, Logger } from 'kibana/server';
-import { SERVICE_NAME } from '../../../../common/elasticsearch_fieldnames';
-import { ESSearchResponse } from '../../../../typings/elasticsearch';
+import { ESSearchResponse } from '../../../../../../typings/elasticsearch';
+import { Annotation as ESAnnotation } from '../../../../../observability/common/annotations';
import { ScopedAnnotationsClient } from '../../../../../observability/server';
import { Annotation, AnnotationType } from '../../../../common/annotations';
-import { Annotation as ESAnnotation } from '../../../../../observability/common/annotations';
-import { SetupTimeRange, Setup } from '../../helpers/setup_request';
+import { SERVICE_NAME } from '../../../../common/elasticsearch_fieldnames';
import { getEnvironmentUiFilterES } from '../../helpers/convert_ui_filters/get_environment_ui_filter_es';
+import { Setup, SetupTimeRange } from '../../helpers/setup_request';
export async function getStoredAnnotations({
setup,
diff --git a/x-pack/plugins/apm/server/lib/services/annotations/index.test.ts b/x-pack/plugins/apm/server/lib/services/annotations/index.test.ts
index f30b77f147710..16c46be78cb28 100644
--- a/x-pack/plugins/apm/server/lib/services/annotations/index.test.ts
+++ b/x-pack/plugins/apm/server/lib/services/annotations/index.test.ts
@@ -6,7 +6,7 @@
import {
ESSearchRequest,
ESSearchResponse,
-} from '../../../../typings/elasticsearch';
+} from '../../../../../../typings/elasticsearch';
import {
inspectSearchParams,
SearchParamsMock,
diff --git a/x-pack/plugins/apm/server/lib/services/get_services/get_services_items.ts b/x-pack/plugins/apm/server/lib/services/get_services/get_services_items.ts
index 5ea3714e81b6f..89915e798b7cd 100644
--- a/x-pack/plugins/apm/server/lib/services/get_services/get_services_items.ts
+++ b/x-pack/plugins/apm/server/lib/services/get_services/get_services_items.ts
@@ -4,17 +4,17 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { Logger } from '@kbn/logging';
+import { PromiseReturnType } from '../../../../../observability/typings/common';
import { joinByKey } from '../../../../common/utils/join_by_key';
-import { PromiseReturnType } from '../../../../typings/common';
-import { Setup, SetupTimeRange } from '../../helpers/setup_request';
import { getServicesProjection } from '../../../projections/services';
+import { Setup, SetupTimeRange } from '../../helpers/setup_request';
import {
- getTransactionDurationAverages,
getAgentNames,
- getTransactionRates,
- getTransactionErrorRates,
getEnvironments,
getHealthStatuses,
+ getTransactionDurationAverages,
+ getTransactionErrorRates,
+ getTransactionRates,
} from './get_services_items_stats';
export type ServiceListAPIResponse = PromiseReturnType;
diff --git a/x-pack/plugins/apm/server/lib/services/get_services/index.ts b/x-pack/plugins/apm/server/lib/services/get_services/index.ts
index 5f39d6c836930..9d450804e421d 100644
--- a/x-pack/plugins/apm/server/lib/services/get_services/index.ts
+++ b/x-pack/plugins/apm/server/lib/services/get_services/index.ts
@@ -4,13 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { isEmpty } from 'lodash';
import { Logger } from '@kbn/logging';
-import { PromiseReturnType } from '../../../../typings/common';
+import { isEmpty } from 'lodash';
+import { PromiseReturnType } from '../../../../../observability/typings/common';
import { Setup, SetupTimeRange } from '../../helpers/setup_request';
-import { hasHistoricalAgentData } from './has_historical_agent_data';
import { getLegacyDataStatus } from './get_legacy_data_status';
import { getServicesItems } from './get_services_items';
+import { hasHistoricalAgentData } from './has_historical_agent_data';
export type ServiceListAPIResponse = PromiseReturnType;
diff --git a/x-pack/plugins/apm/server/lib/settings/agent_configuration/convert_settings_to_string.ts b/x-pack/plugins/apm/server/lib/settings/agent_configuration/convert_settings_to_string.ts
index ab01a68733a7a..6791bf85a7b6a 100644
--- a/x-pack/plugins/apm/server/lib/settings/agent_configuration/convert_settings_to_string.ts
+++ b/x-pack/plugins/apm/server/lib/settings/agent_configuration/convert_settings_to_string.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { ESSearchHit } from '../../../../typings/elasticsearch';
+import { ESSearchHit } from '../../../../../../typings/elasticsearch';
import { AgentConfiguration } from '../../../../common/agent_configuration/configuration_types';
// needed for backwards compatability
diff --git a/x-pack/plugins/apm/server/lib/settings/agent_configuration/find_exact_configuration.ts b/x-pack/plugins/apm/server/lib/settings/agent_configuration/find_exact_configuration.ts
index 3a9623c777516..bd10df76b85c7 100644
--- a/x-pack/plugins/apm/server/lib/settings/agent_configuration/find_exact_configuration.ts
+++ b/x-pack/plugins/apm/server/lib/settings/agent_configuration/find_exact_configuration.ts
@@ -4,13 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import { ESSearchHit } from '../../../../../../typings/elasticsearch';
+import { AgentConfiguration } from '../../../../common/agent_configuration/configuration_types';
import {
- SERVICE_NAME,
SERVICE_ENVIRONMENT,
+ SERVICE_NAME,
} from '../../../../common/elasticsearch_fieldnames';
import { Setup } from '../../helpers/setup_request';
-import { AgentConfiguration } from '../../../../common/agent_configuration/configuration_types';
-import { ESSearchHit } from '../../../../typings/elasticsearch';
import { convertConfigSettingsToString } from './convert_settings_to_string';
export async function findExactConfiguration({
diff --git a/x-pack/plugins/apm/server/lib/settings/agent_configuration/search_configurations.ts b/x-pack/plugins/apm/server/lib/settings/agent_configuration/search_configurations.ts
index 2585f88c2aa43..43ae4995ce672 100644
--- a/x-pack/plugins/apm/server/lib/settings/agent_configuration/search_configurations.ts
+++ b/x-pack/plugins/apm/server/lib/settings/agent_configuration/search_configurations.ts
@@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
-import { ESSearchHit } from '../../../../typings/elasticsearch';
+import { ESSearchHit } from '../../../../../../typings/elasticsearch';
import {
SERVICE_NAME,
SERVICE_ENVIRONMENT,
diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_correlations_for_slow_transactions.ts b/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_correlations_for_slow_transactions.ts
index 3efc65afdfd28..76e595c928cf2 100644
--- a/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_correlations_for_slow_transactions.ts
+++ b/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_correlations_for_slow_transactions.ts
@@ -4,9 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { asDuration } from '../../../../common/utils/formatters';
-import { ESFilter } from '../../../../typings/elasticsearch';
-import { rangeFilter } from '../../../../common/utils/range_filter';
+import { ESFilter } from '../../../../../../typings/elasticsearch';
import {
SERVICE_NAME,
TRANSACTION_DURATION,
@@ -14,6 +12,8 @@ import {
TRANSACTION_TYPE,
} from '../../../../common/elasticsearch_fieldnames';
import { ProcessorEvent } from '../../../../common/processor_event';
+import { asDuration } from '../../../../common/utils/formatters';
+import { rangeFilter } from '../../../../common/utils/range_filter';
import { Setup, SetupTimeRange } from '../../helpers/setup_request';
import { getDurationForPercentile } from './get_duration_for_percentile';
import {
diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_duration_for_percentile.ts b/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_duration_for_percentile.ts
index 37ee19ff40f62..a94540df10fff 100644
--- a/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_duration_for_percentile.ts
+++ b/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_duration_for_percentile.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { ESFilter } from '../../../../typings/elasticsearch';
+import { ESFilter } from '../../../../../../typings/elasticsearch';
import { TRANSACTION_DURATION } from '../../../../common/elasticsearch_fieldnames';
import { ProcessorEvent } from '../../../../common/processor_event';
import { Setup, SetupTimeRange } from '../../helpers/setup_request';
diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_significant_terms_agg.ts b/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_significant_terms_agg.ts
index 1cf0787c1d970..c5ab8d8f1d111 100644
--- a/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_significant_terms_agg.ts
+++ b/x-pack/plugins/apm/server/lib/transaction_groups/correlations/get_significant_terms_agg.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { ESFilter } from '../../../../typings/elasticsearch';
+import { ESFilter } from '../../../../../../typings/elasticsearch';
import { SignificantTermsScoring } from './scoring_rt';
export function getSignificantTermsAgg({
diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.ts b/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.ts
index 0a4d9748f2597..89fff260a7d23 100644
--- a/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.ts
+++ b/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.ts
@@ -3,24 +3,24 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
-import { take, sortBy } from 'lodash';
-import { Unionize } from 'utility-types';
+import { sortBy, take } from 'lodash';
import moment from 'moment';
-import { joinByKey } from '../../../common/utils/join_by_key';
+import { Unionize } from 'utility-types';
+import { AggregationOptionsByType } from '../../../../../typings/elasticsearch';
+import { PromiseReturnType } from '../../../../observability/typings/common';
import {
SERVICE_NAME,
TRANSACTION_NAME,
} from '../../../common/elasticsearch_fieldnames';
+import { joinByKey } from '../../../common/utils/join_by_key';
import { getTransactionGroupsProjection } from '../../projections/transaction_groups';
import { mergeProjection } from '../../projections/util/merge_projection';
-import { PromiseReturnType } from '../../../../observability/typings/common';
-import { AggregationOptionsByType } from '../../../typings/elasticsearch/aggregations';
import { Setup, SetupTimeRange } from '../helpers/setup_request';
import {
getAverages,
- getSums,
- getPercentiles,
getCounts,
+ getPercentiles,
+ getSums,
} from './get_transaction_group_stats';
interface TopTransactionOptions {
diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/get_transaction_group_stats.ts b/x-pack/plugins/apm/server/lib/transaction_groups/get_transaction_group_stats.ts
index 2550bd70c527d..cfd3540446172 100644
--- a/x-pack/plugins/apm/server/lib/transaction_groups/get_transaction_group_stats.ts
+++ b/x-pack/plugins/apm/server/lib/transaction_groups/get_transaction_group_stats.ts
@@ -6,7 +6,7 @@
import { merge } from 'lodash';
import { TRANSACTION_TYPE } from '../../../common/elasticsearch_fieldnames';
import { arrayUnionToCallable } from '../../../common/utils/array_union_to_callable';
-import { AggregationInputMap } from '../../../typings/elasticsearch/aggregations';
+import { AggregationInputMap } from '../../../../../typings/elasticsearch';
import { TransactionGroupRequestBase, TransactionGroupSetup } from './fetcher';
import { getTransactionDurationFieldForAggregatedTransactions } from '../helpers/aggregated_transactions';
diff --git a/x-pack/plugins/apm/server/lib/transactions/charts/get_anomaly_data/fetcher.ts b/x-pack/plugins/apm/server/lib/transactions/charts/get_anomaly_data/fetcher.ts
index 8c999b445d799..aad67c43f48e2 100644
--- a/x-pack/plugins/apm/server/lib/transactions/charts/get_anomaly_data/fetcher.ts
+++ b/x-pack/plugins/apm/server/lib/transactions/charts/get_anomaly_data/fetcher.ts
@@ -5,7 +5,7 @@
*/
import { Logger } from 'kibana/server';
-import { ESSearchResponse } from '../../../../../typings/elasticsearch';
+import { ESSearchResponse } from '../../../../../../../typings/elasticsearch';
import { PromiseReturnType } from '../../../../../../observability/typings/common';
import { Setup, SetupTimeRange } from '../../../helpers/setup_request';
diff --git a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts
index e2edbbec63d47..a2da3977b81c7 100644
--- a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts
+++ b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts
@@ -4,22 +4,22 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { ESFilter } from '../../../../../typings/elasticsearch';
+import { ESFilter } from '../../../../../../../typings/elasticsearch';
+import { PromiseReturnType } from '../../../../../../observability/typings/common';
import {
SERVICE_NAME,
TRANSACTION_NAME,
TRANSACTION_RESULT,
TRANSACTION_TYPE,
} from '../../../../../common/elasticsearch_fieldnames';
-import { PromiseReturnType } from '../../../../../../observability/typings/common';
-import { getBucketSize } from '../../../helpers/get_bucket_size';
import { rangeFilter } from '../../../../../common/utils/range_filter';
-import { Setup, SetupTimeRange } from '../../../helpers/setup_request';
import {
+ getDocumentTypeFilterForAggregatedTransactions,
getProcessorEventForAggregatedTransactions,
getTransactionDurationFieldForAggregatedTransactions,
- getDocumentTypeFilterForAggregatedTransactions,
} from '../../../helpers/aggregated_transactions';
+import { getBucketSize } from '../../../helpers/get_bucket_size';
+import { Setup, SetupTimeRange } from '../../../helpers/setup_request';
export type ESResponse = PromiseReturnType;
export function timeseriesFetcher({
diff --git a/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts b/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts
index 34d01627a2869..010acd09239a3 100644
--- a/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts
+++ b/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts
@@ -4,9 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { ValuesType } from 'utility-types';
-import { PromiseReturnType } from '../../../../../typings/common';
-import { joinByKey } from '../../../../../common/utils/join_by_key';
-import { ProcessorEvent } from '../../../../../common/processor_event';
+import { PromiseReturnType } from '../../../../../../observability/typings/common';
import {
SERVICE_NAME,
TRACE_ID,
@@ -16,13 +14,15 @@ import {
TRANSACTION_SAMPLED,
TRANSACTION_TYPE,
} from '../../../../../common/elasticsearch_fieldnames';
+import { ProcessorEvent } from '../../../../../common/processor_event';
+import { joinByKey } from '../../../../../common/utils/join_by_key';
import { rangeFilter } from '../../../../../common/utils/range_filter';
-import { Setup, SetupTimeRange } from '../../../helpers/setup_request';
import {
getDocumentTypeFilterForAggregatedTransactions,
getProcessorEventForAggregatedTransactions,
getTransactionDurationFieldForAggregatedTransactions,
} from '../../../helpers/aggregated_transactions';
+import { Setup, SetupTimeRange } from '../../../helpers/setup_request';
function getHistogramAggOptions({
bucketSize,
diff --git a/x-pack/plugins/apm/server/lib/ui_filters/get_environments.ts b/x-pack/plugins/apm/server/lib/ui_filters/get_environments.ts
index b9f25e20f9f73..8109becbed45e 100644
--- a/x-pack/plugins/apm/server/lib/ui_filters/get_environments.ts
+++ b/x-pack/plugins/apm/server/lib/ui_filters/get_environments.ts
@@ -4,16 +4,16 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { ProcessorEvent } from '../../../common/processor_event';
+import { ESFilter } from '../../../../../typings/elasticsearch';
import {
SERVICE_ENVIRONMENT,
SERVICE_NAME,
} from '../../../common/elasticsearch_fieldnames';
-import { rangeFilter } from '../../../common/utils/range_filter';
-import { Setup, SetupTimeRange } from '../helpers/setup_request';
import { ENVIRONMENT_NOT_DEFINED } from '../../../common/environment_filter_values';
-import { ESFilter } from '../../../typings/elasticsearch';
+import { ProcessorEvent } from '../../../common/processor_event';
+import { rangeFilter } from '../../../common/utils/range_filter';
import { getProcessorEventForAggregatedTransactions } from '../helpers/aggregated_transactions';
+import { Setup, SetupTimeRange } from '../helpers/setup_request';
export async function getEnvironments({
setup,
diff --git a/x-pack/plugins/apm/server/projections/typings.ts b/x-pack/plugins/apm/server/projections/typings.ts
index 332ac533e78c6..b6d6ffbb7ddbf 100644
--- a/x-pack/plugins/apm/server/projections/typings.ts
+++ b/x-pack/plugins/apm/server/projections/typings.ts
@@ -4,11 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { ESSearchBody } from '../../typings/elasticsearch';
import {
AggregationOptionsByType,
AggregationInputMap,
-} from '../../typings/elasticsearch/aggregations';
+ ESSearchBody,
+} from '../../../../typings/elasticsearch';
import { APMEventESSearchRequest } from '../lib/helpers/create_es_client/create_apm_event_client';
export type Projection = Omit & {
diff --git a/x-pack/plugins/apm/server/projections/util/merge_projection/index.ts b/x-pack/plugins/apm/server/projections/util/merge_projection/index.ts
index ea7267dd337c2..2782b039958e1 100644
--- a/x-pack/plugins/apm/server/projections/util/merge_projection/index.ts
+++ b/x-pack/plugins/apm/server/projections/util/merge_projection/index.ts
@@ -3,12 +3,14 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
-import { mergeWith, isPlainObject, cloneDeep } from 'lodash';
+import { cloneDeep, isPlainObject, mergeWith } from 'lodash';
import { DeepPartial } from 'utility-types';
-import { AggregationInputMap } from '../../../../typings/elasticsearch/aggregations';
-import { ESSearchBody } from '../../../../typings/elasticsearch';
-import { Projection } from '../../typings';
+import {
+ AggregationInputMap,
+ ESSearchBody,
+} from '../../../../../../typings/elasticsearch';
import { APMEventESSearchRequest } from '../../../lib/helpers/create_es_client/create_apm_event_client';
+import { Projection } from '../../typings';
type PlainObject = Record;
diff --git a/x-pack/plugins/apm/server/utils/test_helpers.tsx b/x-pack/plugins/apm/server/utils/test_helpers.tsx
index 21b59dc516d06..9093b16fada0d 100644
--- a/x-pack/plugins/apm/server/utils/test_helpers.tsx
+++ b/x-pack/plugins/apm/server/utils/test_helpers.tsx
@@ -3,14 +3,14 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
+import { APMConfig } from '../';
+import { PromiseReturnType } from '../../../observability/typings/common';
import {
ESFilter,
- ESSearchResponse,
ESSearchRequest,
-} from '../../typings/elasticsearch';
-import { PromiseReturnType } from '../../typings/common';
+ ESSearchResponse,
+} from '../../../../typings/elasticsearch';
import { UIFilters } from '../../typings/ui_filters';
-import { APMConfig } from '..';
interface Options {
mockResponse?: (
diff --git a/x-pack/plugins/apm/typings/common.d.ts b/x-pack/plugins/apm/typings/common.d.ts
index 754529a198552..9133315c4c16a 100644
--- a/x-pack/plugins/apm/typings/common.d.ts
+++ b/x-pack/plugins/apm/typings/common.d.ts
@@ -25,10 +25,4 @@ export type PromiseValueType = Value extends Promise
? Value
: Value;
-export type PromiseReturnType = Func extends (
- ...args: any[]
-) => Promise
- ? Value
- : Func;
-
export type Maybe = T | null | undefined;
diff --git a/x-pack/plugins/apm/typings/es_schemas/raw/apm_base_doc.ts b/x-pack/plugins/apm/typings/es_schemas/raw/apm_base_doc.ts
index 19bd1129677dd..91335b39dab0f 100644
--- a/x-pack/plugins/apm/typings/es_schemas/raw/apm_base_doc.ts
+++ b/x-pack/plugins/apm/typings/es_schemas/raw/apm_base_doc.ts
@@ -4,6 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import { Observer } from './fields/observer';
+
// all documents types extend APMBaseDoc and inherit all properties
export interface APMBaseDoc {
'@timestamp': string;
@@ -11,10 +13,10 @@ export interface APMBaseDoc {
name: string;
version: string;
};
- timestamp: { us: number };
parent?: { id: string }; // parent ID is not available on root transactions
trace?: { id: string };
labels?: {
[key: string]: string | number | boolean;
};
+ observer?: Observer;
}
diff --git a/x-pack/plugins/apm/typings/es_schemas/raw/error_raw.ts b/x-pack/plugins/apm/typings/es_schemas/raw/error_raw.ts
index b8eb79aabdcc5..6b366090931cd 100644
--- a/x-pack/plugins/apm/typings/es_schemas/raw/error_raw.ts
+++ b/x-pack/plugins/apm/typings/es_schemas/raw/error_raw.ts
@@ -13,9 +13,9 @@ import { Page } from './fields/page';
import { Process } from './fields/process';
import { Service } from './fields/service';
import { Stackframe } from './fields/stackframe';
+import { TimestampUs } from './fields/timestamp_us';
import { Url } from './fields/url';
import { User } from './fields/user';
-import { Observer } from './fields/observer';
interface Processor {
name: 'error';
@@ -41,6 +41,7 @@ interface Log {
export interface ErrorRaw extends APMBaseDoc {
processor: Processor;
+ timestamp: TimestampUs;
transaction?: {
id: string;
sampled?: boolean;
@@ -66,5 +67,4 @@ export interface ErrorRaw extends APMBaseDoc {
service: Service;
url?: Url;
user?: User;
- observer?: Observer;
}
diff --git a/x-pack/plugins/rollup/server/lib/__tests__/fixtures/index.js b/x-pack/plugins/apm/typings/es_schemas/raw/fields/timestamp_us.ts
similarity index 83%
rename from x-pack/plugins/rollup/server/lib/__tests__/fixtures/index.js
rename to x-pack/plugins/apm/typings/es_schemas/raw/fields/timestamp_us.ts
index e97606c1fadfb..20b35295e9ba5 100644
--- a/x-pack/plugins/rollup/server/lib/__tests__/fixtures/index.js
+++ b/x-pack/plugins/apm/typings/es_schemas/raw/fields/timestamp_us.ts
@@ -4,4 +4,6 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export { jobs } from './jobs';
+export interface TimestampUs {
+ us: number;
+}
diff --git a/x-pack/plugins/apm/typings/es_schemas/raw/metric_raw.ts b/x-pack/plugins/apm/typings/es_schemas/raw/metric_raw.ts
new file mode 100644
index 0000000000000..b4a1954783db0
--- /dev/null
+++ b/x-pack/plugins/apm/typings/es_schemas/raw/metric_raw.ts
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+import { APMBaseDoc } from './apm_base_doc';
+import { Container } from './fields/container';
+import { Kubernetes } from './fields/kubernetes';
+
+type BaseMetric = APMBaseDoc & {
+ processor: {
+ name: 'metric';
+ event: 'metric';
+ };
+};
+
+type BaseBreakdownMetric = BaseMetric & {
+ transaction: {
+ name: string;
+ type: string;
+ };
+ span: {
+ self_time: {
+ count: number;
+ sum: {
+ us: number;
+ };
+ };
+ };
+};
+
+type TransactionBreakdownMetric = BaseBreakdownMetric & {
+ transaction: {
+ duration: {
+ count: number;
+ sum: {
+ us: number;
+ };
+ };
+ breakdown: {
+ count: number;
+ };
+ };
+};
+
+type SpanBreakdownMetric = BaseBreakdownMetric & {
+ span: {
+ type: string;
+ subtype?: string;
+ };
+};
+
+type SystemMetric = BaseMetric & {
+ system: unknown;
+ service: {
+ node?: {
+ name: string;
+ };
+ };
+};
+
+type CGroupMetric = SystemMetric;
+type JVMMetric = SystemMetric & {
+ jvm: unknown;
+};
+
+type TransactionDurationMetric = BaseMetric & {
+ transaction: {
+ name: string;
+ type: string;
+ result?: string;
+ duration: {
+ histogram: {
+ values: number[];
+ counts: number[];
+ };
+ };
+ };
+ service: {
+ name: string;
+ node?: {
+ name: string;
+ };
+ environment?: string;
+ version?: string;
+ };
+ container?: Container;
+ kubernetes?: Kubernetes;
+};
+
+export type MetricRaw =
+ | BaseMetric
+ | TransactionBreakdownMetric
+ | SpanBreakdownMetric
+ | TransactionDurationMetric
+ | SystemMetric
+ | CGroupMetric
+ | JVMMetric;
diff --git a/x-pack/plugins/apm/typings/es_schemas/raw/span_raw.ts b/x-pack/plugins/apm/typings/es_schemas/raw/span_raw.ts
index 5c2e391059783..dcb3dc02f6519 100644
--- a/x-pack/plugins/apm/typings/es_schemas/raw/span_raw.ts
+++ b/x-pack/plugins/apm/typings/es_schemas/raw/span_raw.ts
@@ -6,7 +6,7 @@
import { APMBaseDoc } from './apm_base_doc';
import { Stackframe } from './fields/stackframe';
-import { Observer } from './fields/observer';
+import { TimestampUs } from './fields/timestamp_us';
interface Processor {
name: 'transaction';
@@ -48,9 +48,9 @@ export interface SpanRaw extends APMBaseDoc {
headers?: Record;
};
};
+ timestamp: TimestampUs;
transaction?: {
id: string;
};
- observer?: Observer;
child?: { id: string[] };
}
diff --git a/x-pack/plugins/apm/typings/es_schemas/raw/transaction_raw.ts b/x-pack/plugins/apm/typings/es_schemas/raw/transaction_raw.ts
index cdfe4183c96f5..68db3bca94641 100644
--- a/x-pack/plugins/apm/typings/es_schemas/raw/transaction_raw.ts
+++ b/x-pack/plugins/apm/typings/es_schemas/raw/transaction_raw.ts
@@ -12,10 +12,10 @@ import { Kubernetes } from './fields/kubernetes';
import { Page } from './fields/page';
import { Process } from './fields/process';
import { Service } from './fields/service';
+import { TimestampUs } from './fields/timestamp_us';
import { Url } from './fields/url';
import { User } from './fields/user';
import { UserAgent } from './fields/user_agent';
-import { Observer } from './fields/observer';
interface Processor {
name: 'transaction';
@@ -24,6 +24,7 @@ interface Processor {
export interface TransactionRaw extends APMBaseDoc {
processor: Processor;
+ timestamp: TimestampUs;
trace: { id: string }; // trace is required
transaction: {
duration: { us: number };
@@ -63,5 +64,4 @@ export interface TransactionRaw extends APMBaseDoc {
url?: Url;
user?: User;
user_agent?: UserAgent;
- observer?: Observer;
}
diff --git a/x-pack/plugins/apm/typings/es_schemas/ui/metric.ts b/x-pack/plugins/apm/typings/es_schemas/ui/metric.ts
new file mode 100644
index 0000000000000..eefb0923f16da
--- /dev/null
+++ b/x-pack/plugins/apm/typings/es_schemas/ui/metric.ts
@@ -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.
+ */
+
+import { MetricRaw } from '../raw/metric_raw';
+
+export type Metric = MetricRaw;
diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts
index a64ff7da2aa19..7bb6e43b38d59 100644
--- a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts
+++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts
@@ -83,6 +83,7 @@ export function savedMap(): ExpressionFunctionDefinition<
return {
type: EmbeddableExpressionType,
input: {
+ attributes: { title: '' },
id: args.id,
filters: getQueryFilters(filters),
timeRange: args.timerange || defaultTimeRange,
diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.test.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.test.ts
index d2c803a1ff208..635e0ec2d0dcb 100644
--- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.test.ts
+++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.test.ts
@@ -9,6 +9,7 @@ import { MapEmbeddableInput } from '../../../../../../plugins/maps/public/embedd
import { fromExpression, Ast } from '@kbn/interpreter/common';
const baseSavedMapInput = {
+ attributes: { title: '' },
id: 'embeddableId',
filters: [],
isLayerTOCOpen: false,
diff --git a/x-pack/plugins/cloud/kibana.json b/x-pack/plugins/cloud/kibana.json
index 27b35bcbdd88b..9bca2f30bd23c 100644
--- a/x-pack/plugins/cloud/kibana.json
+++ b/x-pack/plugins/cloud/kibana.json
@@ -3,7 +3,7 @@
"version": "8.0.0",
"kibanaVersion": "kibana",
"configPath": ["xpack", "cloud"],
- "optionalPlugins": ["usageCollection", "home"],
+ "optionalPlugins": ["usageCollection", "home", "security"],
"server": true,
"ui": true
}
diff --git a/x-pack/plugins/cloud/public/index.ts b/x-pack/plugins/cloud/public/index.ts
index 39ef5f452c18b..680b2f1ad2bd6 100644
--- a/x-pack/plugins/cloud/public/index.ts
+++ b/x-pack/plugins/cloud/public/index.ts
@@ -7,7 +7,7 @@
import { PluginInitializerContext } from '../../../../src/core/public';
import { CloudPlugin } from './plugin';
-export { CloudSetup } from './plugin';
+export { CloudSetup, CloudConfigType } from './plugin';
export function plugin(initializerContext: PluginInitializerContext) {
return new CloudPlugin(initializerContext);
}
diff --git a/x-pack/plugins/cloud/public/mocks.ts b/x-pack/plugins/cloud/public/mocks.ts
new file mode 100644
index 0000000000000..bafebbca4ecdd
--- /dev/null
+++ b/x-pack/plugins/cloud/public/mocks.ts
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+function createSetupMock() {
+ return {
+ cloudId: 'mock-cloud-id',
+ isCloudEnabled: true,
+ resetPasswordUrl: 'reset-password-url',
+ accountUrl: 'account-url',
+ };
+}
+
+export const cloudMock = {
+ createSetup: createSetupMock,
+};
diff --git a/x-pack/plugins/cloud/public/plugin.ts b/x-pack/plugins/cloud/public/plugin.ts
index 45005f3f5e422..bc410b89c30e7 100644
--- a/x-pack/plugins/cloud/public/plugin.ts
+++ b/x-pack/plugins/cloud/public/plugin.ts
@@ -6,40 +6,51 @@
import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'src/core/public';
import { i18n } from '@kbn/i18n';
+import { SecurityPluginStart } from '../../security/public';
import { getIsCloudEnabled } from '../common/is_cloud_enabled';
import { ELASTIC_SUPPORT_LINK } from '../common/constants';
import { HomePublicPluginSetup } from '../../../../src/plugins/home/public';
+import { createUserMenuLinks } from './user_menu_links';
-interface CloudConfigType {
+export interface CloudConfigType {
id?: string;
resetPasswordUrl?: string;
deploymentUrl?: string;
+ accountUrl?: string;
}
interface CloudSetupDependencies {
home?: HomePublicPluginSetup;
}
+interface CloudStartDependencies {
+ security?: SecurityPluginStart;
+}
+
export interface CloudSetup {
cloudId?: string;
cloudDeploymentUrl?: string;
isCloudEnabled: boolean;
+ resetPasswordUrl?: string;
+ accountUrl?: string;
}
export class CloudPlugin implements Plugin {
private config!: CloudConfigType;
+ private isCloudEnabled: boolean;
constructor(private readonly initializerContext: PluginInitializerContext) {
this.config = this.initializerContext.config.get();
+ this.isCloudEnabled = false;
}
public async setup(core: CoreSetup, { home }: CloudSetupDependencies) {
const { id, resetPasswordUrl, deploymentUrl } = this.config;
- const isCloudEnabled = getIsCloudEnabled(id);
+ this.isCloudEnabled = getIsCloudEnabled(id);
if (home) {
- home.environment.update({ cloud: isCloudEnabled });
- if (isCloudEnabled) {
+ home.environment.update({ cloud: this.isCloudEnabled });
+ if (this.isCloudEnabled) {
home.tutorials.setVariable('cloud', { id, resetPasswordUrl });
}
}
@@ -47,11 +58,11 @@ export class CloudPlugin implements Plugin {
return {
cloudId: id,
cloudDeploymentUrl: deploymentUrl,
- isCloudEnabled,
+ isCloudEnabled: this.isCloudEnabled,
};
}
- public start(coreStart: CoreStart) {
+ public start(coreStart: CoreStart, { security }: CloudStartDependencies) {
const { deploymentUrl } = this.config;
coreStart.chrome.setHelpSupportUrl(ELASTIC_SUPPORT_LINK);
if (deploymentUrl) {
@@ -63,5 +74,10 @@ export class CloudPlugin implements Plugin {
href: deploymentUrl,
});
}
+
+ if (security && this.isCloudEnabled) {
+ const userMenuLinks = createUserMenuLinks(this.config);
+ security.navControlService.addUserMenuLinks(userMenuLinks);
+ }
}
}
diff --git a/x-pack/plugins/cloud/public/user_menu_links.ts b/x-pack/plugins/cloud/public/user_menu_links.ts
new file mode 100644
index 0000000000000..15e2f14e885ba
--- /dev/null
+++ b/x-pack/plugins/cloud/public/user_menu_links.ts
@@ -0,0 +1,38 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { i18n } from '@kbn/i18n';
+import { UserMenuLink } from '../../security/public';
+import { CloudConfigType } from '.';
+
+export const createUserMenuLinks = (config: CloudConfigType): UserMenuLink[] => {
+ const { resetPasswordUrl, accountUrl } = config;
+ const userMenuLinks = [] as UserMenuLink[];
+
+ if (resetPasswordUrl) {
+ userMenuLinks.push({
+ label: i18n.translate('xpack.cloud.userMenuLinks.profileLinkText', {
+ defaultMessage: 'Cloud profile',
+ }),
+ iconType: 'logoCloud',
+ href: resetPasswordUrl,
+ order: 100,
+ });
+ }
+
+ if (accountUrl) {
+ userMenuLinks.push({
+ label: i18n.translate('xpack.cloud.userMenuLinks.accountLinkText', {
+ defaultMessage: 'Account & Billing',
+ }),
+ iconType: 'gear',
+ href: accountUrl,
+ order: 200,
+ });
+ }
+
+ return userMenuLinks;
+};
diff --git a/x-pack/plugins/cloud/server/config.ts b/x-pack/plugins/cloud/server/config.ts
index ff8a2c5acdf9a..eaa4ab7a482dd 100644
--- a/x-pack/plugins/cloud/server/config.ts
+++ b/x-pack/plugins/cloud/server/config.ts
@@ -23,6 +23,7 @@ const configSchema = schema.object({
apm: schema.maybe(apmConfigSchema),
resetPasswordUrl: schema.maybe(schema.string()),
deploymentUrl: schema.maybe(schema.string()),
+ accountUrl: schema.maybe(schema.string()),
});
export type CloudConfigType = TypeOf;
@@ -32,6 +33,7 @@ export const config: PluginConfigDescriptor = {
id: true,
resetPasswordUrl: true,
deploymentUrl: true,
+ accountUrl: true,
},
schema: configSchema,
};
diff --git a/x-pack/plugins/data_enhanced/public/autocomplete/providers/kql_query_suggestion/value.ts b/x-pack/plugins/data_enhanced/public/autocomplete/providers/kql_query_suggestion/value.ts
index 441e5a6f775dd..cab3a657b7b6b 100644
--- a/x-pack/plugins/data_enhanced/public/autocomplete/providers/kql_query_suggestion/value.ts
+++ b/x-pack/plugins/data_enhanced/public/autocomplete/providers/kql_query_suggestion/value.ts
@@ -27,7 +27,7 @@ const wrapAsSuggestions = (start: number, end: number, query: string, values: st
export const setupGetValueSuggestions: KqlQuerySuggestionProvider = () => {
return async (
- { indexPatterns, boolFilter, signal },
+ { indexPatterns, boolFilter, useTimeRange, signal },
{ start, end, prefix, suffix, fieldName, nestedPath }
): Promise => {
const fullFieldName = nestedPath ? `${nestedPath}.${fieldName}` : fieldName;
@@ -49,6 +49,7 @@ export const setupGetValueSuggestions: KqlQuerySuggestionProvider = () => {
field,
query,
boolFilter,
+ useTimeRange,
signal,
}).then((valueSuggestions) => {
const quotedValues = valueSuggestions.map((value) =>
diff --git a/x-pack/plugins/enterprise_search/common/types/app_search.ts b/x-pack/plugins/enterprise_search/common/types/app_search.ts
index 203b77834bc15..9f754412ec730 100644
--- a/x-pack/plugins/enterprise_search/common/types/app_search.ts
+++ b/x-pack/plugins/enterprise_search/common/types/app_search.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export interface IAccount {
+export interface Account {
accountId: string;
onboardingComplete: boolean;
role: {
@@ -21,7 +21,7 @@ export interface IAccount {
};
}
-export interface IConfiguredLimits {
+export interface ConfiguredLimits {
engine: {
maxDocumentByteSize: number;
maxEnginesPerMetaEngine: number;
diff --git a/x-pack/plugins/enterprise_search/common/types/index.ts b/x-pack/plugins/enterprise_search/common/types/index.ts
index 1006d39138759..39d9aa8607bc2 100644
--- a/x-pack/plugins/enterprise_search/common/types/index.ts
+++ b/x-pack/plugins/enterprise_search/common/types/index.ts
@@ -5,39 +5,39 @@
*/
import {
- IAccount as IAppSearchAccount,
- IConfiguredLimits as IAppSearchConfiguredLimits,
+ Account as AppSearchAccount,
+ ConfiguredLimits as AppSearchConfiguredLimits,
} from './app_search';
import {
- IWorkplaceSearchInitialData,
- IConfiguredLimits as IWorkplaceSearchConfiguredLimits,
+ WorkplaceSearchInitialData,
+ ConfiguredLimits as WorkplaceSearchConfiguredLimits,
} from './workplace_search';
-export interface IInitialAppData {
+export interface InitialAppData {
readOnlyMode?: boolean;
ilmEnabled?: boolean;
isFederatedAuth?: boolean;
- configuredLimits?: IConfiguredLimits;
+ configuredLimits?: ConfiguredLimits;
access?: {
hasAppSearchAccess: boolean;
hasWorkplaceSearchAccess: boolean;
};
- appSearch?: IAppSearchAccount;
- workplaceSearch?: IWorkplaceSearchInitialData;
+ appSearch?: AppSearchAccount;
+ workplaceSearch?: WorkplaceSearchInitialData;
}
-export interface IConfiguredLimits {
- appSearch: IAppSearchConfiguredLimits;
- workplaceSearch: IWorkplaceSearchConfiguredLimits;
+export interface ConfiguredLimits {
+ appSearch: AppSearchConfiguredLimits;
+ workplaceSearch: WorkplaceSearchConfiguredLimits;
}
-export interface IMetaPage {
+export interface MetaPage {
current: number;
size: number;
total_pages: number;
total_results: number;
}
-export interface IMeta {
- page: IMetaPage;
+export interface Meta {
+ page: MetaPage;
}
diff --git a/x-pack/plugins/enterprise_search/common/types/workplace_search.ts b/x-pack/plugins/enterprise_search/common/types/workplace_search.ts
index 886597fcd9891..883cc6939b4bc 100644
--- a/x-pack/plugins/enterprise_search/common/types/workplace_search.ts
+++ b/x-pack/plugins/enterprise_search/common/types/workplace_search.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export interface IAccount {
+export interface Account {
id: string;
groups: string[];
isAdmin: boolean;
@@ -14,65 +14,19 @@ export interface IAccount {
viewedOnboardingPage: boolean;
}
-export interface IOrganization {
+export interface Organization {
name: string;
defaultOrgName: string;
}
-export interface IWorkplaceSearchInitialData {
- organization: IOrganization;
- account: IAccount;
+export interface WorkplaceSearchInitialData {
+ organization: Organization;
+ account: Account;
}
-export interface IConfiguredLimits {
+export interface ConfiguredLimits {
customApiSource: {
maxDocumentByteSize: number;
totalFields: number;
};
}
-
-export interface IGroup {
- id: string;
- name: string;
- createdAt: string;
- updatedAt: string;
- contentSources: IContentSource[];
- users: IUser[];
- usersCount: number;
- color?: string;
-}
-
-export interface IGroupDetails extends IGroup {
- contentSources: IContentSourceDetails[];
- canEditGroup: boolean;
- canDeleteGroup: boolean;
-}
-
-export interface IUser {
- id: string;
- name: string | null;
- initials: string;
- pictureUrl: string | null;
- color: string;
- email: string;
- role?: string;
- groupIds: string[];
-}
-
-export interface IContentSource {
- id: string;
- serviceType: string;
- name: string;
-}
-
-export interface IContentSourceDetails extends IContentSource {
- status: string;
- statusMessage: string;
- documentCount: string;
- isFederatedSource: boolean;
- searchable: boolean;
- supportedByLicense: boolean;
- errorReason: number;
- allowsReauth: boolean;
- boost: number;
-}
diff --git a/x-pack/plugins/enterprise_search/public/applications/__mocks__/enzyme_rerender.mock.ts b/x-pack/plugins/enterprise_search/public/applications/__mocks__/enzyme_rerender.mock.ts
new file mode 100644
index 0000000000000..1508f27c00377
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/__mocks__/enzyme_rerender.mock.ts
@@ -0,0 +1,16 @@
+/*
+ * 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.
+ */
+
+import { ShallowWrapper } from 'enzyme';
+
+/**
+ * Quick and easy helper for re-rendering a React component in Enzyme
+ * after (e.g.) updating Kea values
+ */
+export const rerender = (wrapper: ShallowWrapper) => {
+ wrapper.setProps({}); // Re-renders
+ wrapper.update(); // Just in case
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/__mocks__/index.ts b/x-pack/plugins/enterprise_search/public/applications/__mocks__/index.ts
index bdf555311d154..e8944b15978a9 100644
--- a/x-pack/plugins/enterprise_search/public/applications/__mocks__/index.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/__mocks__/index.ts
@@ -15,4 +15,5 @@ export { mockAllValues, mockAllActions, setMockValues, setMockActions } from './
export { mountAsync } from './mount_async.mock';
export { mountWithIntl } from './mount_with_i18n.mock';
export { shallowWithIntl } from './shallow_with_i18n.mock';
+export { rerender } from './enzyme_rerender.mock';
// Note: shallow_useeffect must be imported directly as a file
diff --git a/x-pack/plugins/enterprise_search/public/applications/__mocks__/mount_async.mock.tsx b/x-pack/plugins/enterprise_search/public/applications/__mocks__/mount_async.mock.tsx
index a33e116c7ca72..a3d817e1da904 100644
--- a/x-pack/plugins/enterprise_search/public/applications/__mocks__/mount_async.mock.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/__mocks__/mount_async.mock.tsx
@@ -20,13 +20,13 @@ import { mountWithIntl } from './';
* const wrapper = mountAsync();
*/
-interface IOptions {
+interface Options {
i18n?: boolean;
}
export const mountAsync = async (
children: React.ReactElement,
- options: IOptions
+ options: Options
): Promise => {
let wrapper: ReactWrapper | undefined;
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/app_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/app_logic.ts
index 932e84af45c2b..2b475073c6ea5 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/app_logic.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/app_logic.ts
@@ -6,24 +6,24 @@
import { kea, MakeLogicType } from 'kea';
-import { IInitialAppData } from '../../../common/types';
-import { IConfiguredLimits, IAccount, IRole } from './types';
+import { InitialAppData } from '../../../common/types';
+import { ConfiguredLimits, Account, Role } from './types';
import { getRoleAbilities } from './utils/role';
-export interface IAppValues {
+interface AppValues {
hasInitialized: boolean;
ilmEnabled: boolean;
- configuredLimits: Partial;
- account: Partial;
- myRole: Partial;
+ configuredLimits: Partial;
+ account: Partial;
+ myRole: Partial;
}
-export interface IAppActions {
- initializeAppData(props: IInitialAppData): Required;
+interface AppActions {
+ initializeAppData(props: InitialAppData): Required;
setOnboardingComplete(): boolean;
}
-export const AppLogic = kea>({
+export const AppLogic = kea>({
path: ['enterprise_search', 'app_search', 'app_logic'],
actions: {
initializeAppData: (props) => props,
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/constants.ts
index decf1e2158744..ea4906ec08946 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/constants.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/constants.ts
@@ -3,8 +3,14 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
+
import { i18n } from '@kbn/i18n';
+export const CREDENTIALS_TITLE = i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.credentials.title',
+ { defaultMessage: 'Credentials' }
+);
+
export enum ApiTokenTypes {
Admin = 'admin',
Private = 'private',
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials.tsx
index c8eae8cc13f5f..72b02dfdc1f61 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials.tsx
@@ -28,6 +28,7 @@ import { FlashMessages } from '../../../shared/flash_messages';
import { CredentialsLogic } from './credentials_logic';
import { externalUrl } from '../../../shared/enterprise_search_url/external_url';
+import { CREDENTIALS_TITLE } from './constants';
import { CredentialsList } from './credentials_list';
import { CredentialsFlyout } from './credentials_flyout';
@@ -47,21 +48,11 @@ export const Credentials: React.FC = () => {
return (
<>
-
+
-
- {i18n.translate('xpack.enterpriseSearch.appSearch.credentials.title', {
- defaultMessage: 'Credentials',
- })}
-
+ {CREDENTIALS_TITLE}
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_engine_access.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_engine_access.test.tsx
index b4b092f17a6aa..d0bbf868aa90c 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_engine_access.test.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_engine_access.test.tsx
@@ -5,6 +5,7 @@
*/
import { setMockValues, setMockActions } from '../../../../../__mocks__/kea.mock';
+import { rerender } from '../../../../../__mocks__';
import React from 'react';
import { shallow } from 'enzyme';
@@ -60,7 +61,7 @@ describe('FormKeyEngineAccess', () => {
...values,
fullEngineAccessChecked: false,
});
- wrapper.setProps({}); // Re-render
+ rerender(wrapper);
expect(wrapper.find('#all_engines').prop('checked')).toEqual(false);
expect(wrapper.find('#all_engines').prop('value')).toEqual('false');
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_read_write_access.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_read_write_access.tsx
index a02b00b6ad377..d96c57b3c8bc3 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_read_write_access.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_read_write_access.tsx
@@ -10,7 +10,7 @@ import { EuiCheckbox, EuiText, EuiTitle, EuiSpacer, EuiPanel } from '@elastic/eu
import { i18n } from '@kbn/i18n';
import { CredentialsLogic } from '../../credentials_logic';
-import { ITokenReadWrite } from '../../types';
+import { TokenReadWrite } from '../../types';
export const FormKeyReadWriteAccess: React.FC = () => {
const { setTokenReadWrite } = useActions(CredentialsLogic);
@@ -37,7 +37,7 @@ export const FormKeyReadWriteAccess: React.FC = () => {
name="read"
id="read"
checked={activeApiToken.read}
- onChange={(e) => setTokenReadWrite(e.target as ITokenReadWrite)}
+ onChange={(e) => setTokenReadWrite(e.target as TokenReadWrite)}
label={i18n.translate(
'xpack.enterpriseSearch.appSearch.credentials.formReadWrite.readLabel',
{ defaultMessage: 'Read Access' }
@@ -47,7 +47,7 @@ export const FormKeyReadWriteAccess: React.FC = () => {
name="write"
id="write"
checked={activeApiToken.write}
- onChange={(e) => setTokenReadWrite(e.target as ITokenReadWrite)}
+ onChange={(e) => setTokenReadWrite(e.target as TokenReadWrite)}
label={i18n.translate(
'xpack.enterpriseSearch.appSearch.credentials.formReadWrite.writeLabel',
{ defaultMessage: 'Write Access' }
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/header.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/header.test.tsx
index a8d9505136faa..803789ebee568 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/header.test.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/header.test.tsx
@@ -11,12 +11,12 @@ import { shallow } from 'enzyme';
import { EuiFlyoutHeader } from '@elastic/eui';
import { ApiTokenTypes } from '../constants';
-import { IApiToken } from '../types';
+import { ApiToken } from '../types';
import { CredentialsFlyoutHeader } from './header';
describe('CredentialsFlyoutHeader', () => {
- const apiToken: IApiToken = {
+ const apiToken: ApiToken = {
name: '',
type: ApiTokenTypes.Private,
read: true,
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/credentials_list.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/credentials_list.test.tsx
index 97d29b9333f4b..4f5ded0a3ccc1 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/credentials_list.test.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/credentials_list.test.tsx
@@ -10,7 +10,7 @@ import React from 'react';
import { shallow } from 'enzyme';
import { EuiBasicTable, EuiCopy, EuiEmptyPrompt } from '@elastic/eui';
-import { IApiToken } from '../types';
+import { ApiToken } from '../types';
import { ApiTokenTypes } from '../constants';
import { HiddenText } from '../../../../shared/hidden_text';
@@ -18,7 +18,7 @@ import { Key } from './key';
import { CredentialsList } from './credentials_list';
describe('Credentials', () => {
- const apiToken: IApiToken = {
+ const apiToken: ApiToken = {
name: '',
type: ApiTokenTypes.Private,
read: true,
@@ -77,7 +77,7 @@ describe('Credentials', () => {
});
const wrapper = shallow();
const { items } = wrapper.find(EuiBasicTable).props();
- expect(items.map((i: IApiToken) => i.id)).toEqual([undefined, 1, 2]);
+ expect(items.map((i: ApiToken) => i.id)).toEqual([undefined, 1, 2]);
});
});
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/credentials_list.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/credentials_list.tsx
index f9752dca582e1..9240bade4975e 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/credentials_list.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/credentials_list.tsx
@@ -14,7 +14,7 @@ import { i18n } from '@kbn/i18n';
import { CredentialsLogic } from '../credentials_logic';
import { Key } from './key';
import { HiddenText } from '../../../../shared/hidden_text';
-import { IApiToken } from '../types';
+import { ApiToken } from '../types';
import { TOKEN_TYPE_DISPLAY_NAMES } from '../constants';
import { apiTokenSort } from '../utils/api_token_sort';
import { getModeDisplayText, getEnginesDisplayText } from '../utils';
@@ -26,21 +26,21 @@ export const CredentialsList: React.FC = () => {
const items = useMemo(() => apiTokens.slice().sort(apiTokenSort), [apiTokens]);
- const columns: Array> = [
+ const columns: Array> = [
{
name: 'Name',
width: '12%',
- render: (token: IApiToken) => token.name,
+ render: (token: ApiToken) => token.name,
},
{
name: 'Type',
width: '15%',
- render: (token: IApiToken) => TOKEN_TYPE_DISPLAY_NAMES[token.type],
+ render: (token: ApiToken) => TOKEN_TYPE_DISPLAY_NAMES[token.type],
},
{
name: 'Key',
width: '36%',
- render: (token: IApiToken) => {
+ render: (token: ApiToken) => {
const { key } = token;
if (!key) return null;
return (
@@ -64,12 +64,12 @@ export const CredentialsList: React.FC = () => {
{
name: 'Modes',
width: '10%',
- render: (token: IApiToken) => getModeDisplayText(token),
+ render: (token: ApiToken) => getModeDisplayText(token),
},
{
name: 'Engines',
width: '18%',
- render: (token: IApiToken) => getEnginesDisplayText(token),
+ render: (token: ApiToken) => getEnginesDisplayText(token),
},
{
actions: [
@@ -83,7 +83,7 @@ export const CredentialsList: React.FC = () => {
type: 'icon',
icon: 'pencil',
color: 'primary',
- onClick: (token: IApiToken) => showCredentialsForm(token),
+ onClick: (token: ApiToken) => showCredentialsForm(token),
},
{
name: i18n.translate('xpack.enterpriseSearch.actions.delete', {
@@ -95,7 +95,7 @@ export const CredentialsList: React.FC = () => {
type: 'icon',
icon: 'trash',
color: 'danger',
- onClick: (token: IApiToken) => deleteApiKey(token.name),
+ onClick: (token: ApiToken) => deleteApiKey(token.name),
},
],
},
@@ -108,7 +108,7 @@ export const CredentialsList: React.FC = () => {
hidePerPageOptions: true,
};
- const onTableChange = ({ page }: CriteriaWithPagination) => {
+ const onTableChange = ({ page }: CriteriaWithPagination) => {
const { index: current } = page;
fetchCredentials(current + 1);
};
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/key.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/key.tsx
index 5c0c24ec733a4..fa2d124cbccdf 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/key.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/key.tsx
@@ -8,14 +8,14 @@ import React from 'react';
import { EuiButtonIcon } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
-interface IProps {
+interface Props {
copy: () => void;
toggleIsHidden: () => void;
isHidden: boolean;
text: React.ReactNode;
}
-export const Key: React.FC = ({ copy, toggleIsHidden, isHidden, text }) => {
+export const Key: React.FC = ({ copy, toggleIsHidden, isHidden, text }) => {
const hideIcon = isHidden ? 'eye' : 'eyeClosed';
const hideIconLabel = isHidden
? i18n.translate('xpack.enterpriseSearch.appSearch.credentials.showApiKey', {
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_logic.test.ts
index de79862b540ba..6523b4fb110b0 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_logic.test.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_logic.test.ts
@@ -88,8 +88,8 @@ describe('CredentialsLogic', () => {
const credentialsDetails = {
engines: [
- { name: 'engine1', type: 'indexed', language: 'english', result_fields: [] },
- { name: 'engine1', type: 'indexed', language: 'english', result_fields: [] },
+ { name: 'engine1', type: 'indexed', language: 'english', result_fields: {} },
+ { name: 'engine1', type: 'indexed', language: 'english', result_fields: {} },
],
};
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_logic.ts
index 7b8b864b3a317..166cbae9a4512 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_logic.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_logic.ts
@@ -17,11 +17,11 @@ import {
} from '../../../shared/flash_messages';
import { AppLogic } from '../../app_logic';
-import { IMeta } from '../../../../../common/types';
-import { IEngine } from '../../types';
-import { IApiToken, ICredentialsDetails, ITokenReadWrite } from './types';
+import { Meta } from '../../../../../common/types';
+import { Engine } from '../../types';
+import { ApiToken, CredentialsDetails, TokenReadWrite } from './types';
-export const defaultApiToken: IApiToken = {
+export const defaultApiToken: ApiToken = {
name: '',
type: ApiTokenTypes.Private,
read: true,
@@ -29,21 +29,21 @@ export const defaultApiToken: IApiToken = {
access_all_engines: true,
};
-interface ICredentialsLogicActions {
+interface CredentialsLogicActions {
addEngineName(engineName: string): string;
onApiKeyDelete(tokenName: string): string;
- onApiTokenCreateSuccess(apiToken: IApiToken): IApiToken;
+ onApiTokenCreateSuccess(apiToken: ApiToken): ApiToken;
onApiTokenError(formErrors: string[]): string[];
- onApiTokenUpdateSuccess(apiToken: IApiToken): IApiToken;
+ onApiTokenUpdateSuccess(apiToken: ApiToken): ApiToken;
removeEngineName(engineName: string): string;
setAccessAllEngines(accessAll: boolean): boolean;
- setCredentialsData(meta: IMeta, apiTokens: IApiToken[]): { meta: IMeta; apiTokens: IApiToken[] };
- setCredentialsDetails(details: ICredentialsDetails): ICredentialsDetails;
+ setCredentialsData(meta: Meta, apiTokens: ApiToken[]): { meta: Meta; apiTokens: ApiToken[] };
+ setCredentialsDetails(details: CredentialsDetails): CredentialsDetails;
setNameInputBlurred(isBlurred: boolean): boolean;
- setTokenReadWrite(tokenReadWrite: ITokenReadWrite): ITokenReadWrite;
+ setTokenReadWrite(tokenReadWrite: TokenReadWrite): TokenReadWrite;
setTokenName(name: string): string;
setTokenType(tokenType: string): string;
- showCredentialsForm(apiToken?: IApiToken): IApiToken;
+ showCredentialsForm(apiToken?: ApiToken): ApiToken;
hideCredentialsForm(): { value: boolean };
resetCredentials(): { value: boolean };
initializeCredentialsData(): { value: boolean };
@@ -54,25 +54,25 @@ interface ICredentialsLogicActions {
onEngineSelect(engineName: string): string;
}
-interface ICredentialsLogicValues {
- activeApiToken: IApiToken;
+interface CredentialsLogicValues {
+ activeApiToken: ApiToken;
activeApiTokenExists: boolean;
activeApiTokenRawName: string;
- apiTokens: IApiToken[];
+ apiTokens: ApiToken[];
dataLoading: boolean;
- engines: IEngine[];
+ engines: Engine[];
formErrors: string[];
isCredentialsDataComplete: boolean;
isCredentialsDetailsComplete: boolean;
fullEngineAccessChecked: boolean;
- meta: Partial;
+ meta: Partial;
nameInputBlurred: boolean;
shouldShowCredentialsForm: boolean;
}
-export const CredentialsLogic = kea<
- MakeLogicType
->({
+type CredentialsLogicType = MakeLogicType; // If we leave this inline, Prettier does some horrifying indenting nonsense :/
+
+export const CredentialsLogic = kea({
path: ['enterprise_search', 'app_search', 'credentials_logic'],
actions: () => ({
addEngineName: (engineName) => engineName,
@@ -267,7 +267,7 @@ export const CredentialsLogic = kea<
onApiTokenChange: async () => {
const { id, name, engines, type, read, write } = values.activeApiToken;
- const data: IApiToken = {
+ const data: ApiToken = {
name,
type,
};
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/index.ts
index bceda234175a7..0fc64a43ffa85 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/index.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/index.ts
@@ -5,3 +5,4 @@
*/
export { Credentials } from './credentials';
+export { CREDENTIALS_TITLE } from './constants';
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/types.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/types.ts
index 9ca4d086d55c8..23f78b44c0db5 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/types.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/types.ts
@@ -4,14 +4,14 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { IEngine } from '../../types';
+import { Engine } from '../../types';
import { ApiTokenTypes } from './constants';
-export interface ICredentialsDetails {
- engines: IEngine[];
+export interface CredentialsDetails {
+ engines: Engine[];
}
-export interface IApiToken {
+export interface ApiToken {
access_all_engines?: boolean;
key?: string;
engines?: string[];
@@ -22,7 +22,7 @@ export interface IApiToken {
write?: boolean;
}
-export interface ITokenReadWrite {
+export interface TokenReadWrite {
name: 'read' | 'write';
checked: boolean;
}
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/api_token_sort.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/api_token_sort.test.ts
index 84818322b3570..2287125bb5eb8 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/api_token_sort.test.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/api_token_sort.test.ts
@@ -7,10 +7,10 @@
import { apiTokenSort } from '.';
import { ApiTokenTypes } from '../constants';
-import { IApiToken } from '../types';
+import { ApiToken } from '../types';
describe('apiTokenSort', () => {
- const apiToken: IApiToken = {
+ const apiToken: ApiToken = {
name: '',
type: ApiTokenTypes.Private,
read: true,
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/api_token_sort.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/api_token_sort.ts
index 80a46f30e0930..b9fb501ccabe2 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/api_token_sort.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/api_token_sort.ts
@@ -4,9 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { IApiToken } from '../types';
+import { ApiToken } from '../types';
-export const apiTokenSort = (apiTokenA: IApiToken, apiTokenB: IApiToken): number => {
+export const apiTokenSort = (apiTokenA: ApiToken, apiTokenB: ApiToken): number => {
if (!apiTokenA.id) {
return -1;
}
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_engines_display_text.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_engines_display_text.test.tsx
index b06ed63f8616c..bee19a44facd3 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_engines_display_text.test.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_engines_display_text.test.tsx
@@ -8,10 +8,10 @@ import React from 'react';
import { shallow } from 'enzyme';
import { getEnginesDisplayText } from './get_engines_display_text';
-import { IApiToken } from '../types';
+import { ApiToken } from '../types';
import { ApiTokenTypes } from '../constants';
-const apiToken: IApiToken = {
+const apiToken: ApiToken = {
name: '',
type: ApiTokenTypes.Private,
read: true,
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_engines_display_text.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_engines_display_text.tsx
index 1b216c46307db..fb23551302f3b 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_engines_display_text.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_engines_display_text.tsx
@@ -6,9 +6,9 @@
import React from 'react';
import { ApiTokenTypes, ALL } from '../constants';
-import { IApiToken } from '../types';
+import { ApiToken } from '../types';
-export const getEnginesDisplayText = (apiToken: IApiToken): JSX.Element | string => {
+export const getEnginesDisplayText = (apiToken: ApiToken): JSX.Element | string => {
const { type, access_all_engines: accessAll, engines = [] } = apiToken;
if (type === ApiTokenTypes.Admin) {
return '--';
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_mode_display_text.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_mode_display_text.test.ts
index b2083f22c8e1c..46b4c9b2c786c 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_mode_display_text.test.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_mode_display_text.test.ts
@@ -5,11 +5,11 @@
*/
import { ApiTokenTypes } from '../constants';
-import { IApiToken } from '../types';
+import { ApiToken } from '../types';
import { getModeDisplayText } from './get_mode_display_text';
-const apiToken: IApiToken = {
+const apiToken: ApiToken = {
name: '',
type: ApiTokenTypes.Private,
read: true,
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_mode_display_text.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_mode_display_text.ts
index 9c8758d83882d..b150aa2cfc3be 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_mode_display_text.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_mode_display_text.ts
@@ -5,9 +5,9 @@
*/
import { ApiTokenTypes, READ_ONLY, READ_WRITE, SEARCH_DISPLAY, WRITE_ONLY } from '../constants';
-import { IApiToken } from '../types';
+import { ApiToken } from '../types';
-export const getModeDisplayText = (apiToken: IApiToken): string => {
+export const getModeDisplayText = (apiToken: ApiToken): string => {
const { read = false, write = false, type } = apiToken;
switch (type) {
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/constants.ts
index ee5b47eda490e..3c963e415f33b 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/constants.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/constants.ts
@@ -9,10 +9,6 @@ import { i18n } from '@kbn/i18n';
// TODO: It's very likely that we'll move these i18n constants to their respective component
// folders once those are migrated over. This is a temporary way of DRYing them out for now.
-export const ENGINES_TITLE = i18n.translate('xpack.enterpriseSearch.appSearch.engines.title', {
- defaultMessage: 'Engines',
-});
-
export const OVERVIEW_TITLE = i18n.translate(
'xpack.enterpriseSearch.appSearch.engine.overview.title',
{ defaultMessage: 'Overview' }
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.test.ts
new file mode 100644
index 0000000000000..13db440df739e
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.test.ts
@@ -0,0 +1,266 @@
+/*
+ * 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.
+ */
+
+import { resetContext } from 'kea';
+
+import { mockHttpValues } from '../../../__mocks__';
+jest.mock('../../../shared/http', () => ({
+ HttpLogic: { values: mockHttpValues },
+}));
+const { http } = mockHttpValues;
+
+import { EngineLogic } from './';
+
+describe('EngineLogic', () => {
+ const mockEngineData = {
+ name: 'some-engine',
+ type: 'default',
+ created_at: 'some date timestamp',
+ language: null,
+ document_count: 1,
+ field_count: 1,
+ result_fields: {
+ id: { raw: {} },
+ },
+ unconfirmedFields: [],
+ unsearchedUnconfirmedFields: false,
+ sample: false,
+ isMeta: false,
+ invalidBoosts: false,
+ schema: {},
+ apiTokens: [],
+ apiKey: 'some-key',
+ };
+
+ const DEFAULT_VALUES = {
+ dataLoading: true,
+ engine: {},
+ engineName: '',
+ isMetaEngine: false,
+ isSampleEngine: false,
+ hasSchemaConflicts: false,
+ hasUnconfirmedSchemaFields: false,
+ engineNotFound: false,
+ };
+
+ const mount = (values?: object) => {
+ if (!values) {
+ resetContext({});
+ } else {
+ resetContext({
+ defaults: {
+ enterprise_search: {
+ app_search: {
+ engine_logic: {
+ ...values,
+ },
+ },
+ },
+ },
+ });
+ }
+ EngineLogic.mount();
+ };
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('has expected default values', () => {
+ mount();
+ expect(EngineLogic.values).toEqual(DEFAULT_VALUES);
+ });
+
+ describe('actions', () => {
+ describe('setEngineData', () => {
+ describe('engine & dataLoading', () => {
+ it('should set engine to the provided value and dataLoading to false', () => {
+ mount();
+ EngineLogic.actions.setEngineData(mockEngineData);
+
+ expect(EngineLogic.values).toEqual({
+ ...DEFAULT_VALUES,
+ engine: mockEngineData,
+ dataLoading: false,
+ });
+ });
+ });
+ });
+
+ describe('setEngineName', () => {
+ describe('engineName', () => {
+ it('should be set to the provided value', () => {
+ mount();
+ EngineLogic.actions.setEngineName('some-new-engine');
+
+ expect(EngineLogic.values).toEqual({
+ ...DEFAULT_VALUES,
+ engineName: 'some-new-engine',
+ });
+ });
+ });
+ });
+
+ describe('setIndexingStatus', () => {
+ describe('engine', () => {
+ it('should set the nested obj property to the provided value', () => {
+ mount({ engine: mockEngineData });
+ const mockReindexJob = {
+ percentageComplete: 50,
+ numDocumentsWithErrors: 2,
+ activeReindexJobId: 123,
+ };
+ EngineLogic.actions.setIndexingStatus(mockReindexJob);
+
+ expect(EngineLogic.values).toEqual({
+ ...DEFAULT_VALUES,
+ engine: {
+ ...mockEngineData,
+ activeReindexJob: mockReindexJob,
+ },
+ });
+ });
+ });
+ });
+
+ describe('setEngineNotFound', () => {
+ describe('engineNotFound', () => {
+ it('should be set to the provided value', () => {
+ mount();
+ EngineLogic.actions.setEngineNotFound(true);
+
+ expect(EngineLogic.values).toEqual({
+ ...DEFAULT_VALUES,
+ engineNotFound: true,
+ });
+ });
+ });
+ });
+
+ describe('clearEngine', () => {
+ describe('engine', () => {
+ it('should be reset to an empty obj', () => {
+ mount({ engine: mockEngineData });
+ EngineLogic.actions.clearEngine();
+
+ expect(EngineLogic.values).toEqual({
+ ...DEFAULT_VALUES,
+ engine: {},
+ });
+ });
+ });
+
+ describe('dataLoading', () => {
+ it('should be set to true', () => {
+ mount({ dataLoading: false });
+ EngineLogic.actions.clearEngine();
+
+ expect(EngineLogic.values).toEqual({
+ ...DEFAULT_VALUES,
+ dataLoading: true,
+ });
+ });
+ });
+ });
+
+ describe('initializeEngine', () => {
+ it('fetches and sets engine data', async () => {
+ mount({ engineName: 'some-engine' });
+ jest.spyOn(EngineLogic.actions, 'setEngineData');
+ const promise = Promise.resolve(mockEngineData);
+ http.get.mockReturnValueOnce(promise);
+
+ EngineLogic.actions.initializeEngine();
+ await promise;
+
+ expect(http.get).toHaveBeenCalledWith('/api/app_search/engines/some-engine');
+ expect(EngineLogic.actions.setEngineData).toHaveBeenCalledWith(mockEngineData);
+ });
+
+ it('handles errors', async () => {
+ mount();
+ jest.spyOn(EngineLogic.actions, 'setEngineNotFound');
+ const promise = Promise.reject('An error occured');
+ http.get.mockReturnValue(promise);
+
+ try {
+ EngineLogic.actions.initializeEngine();
+ await promise;
+ } catch {
+ // Do nothing
+ }
+ expect(EngineLogic.actions.setEngineNotFound).toHaveBeenCalledWith(true);
+ });
+ });
+ });
+
+ describe('selectors', () => {
+ describe('isSampleEngine', () => {
+ it('should be set based on engine.sample', () => {
+ const mockSampleEngine = { ...mockEngineData, sample: true };
+ mount({ engine: mockSampleEngine });
+
+ expect(EngineLogic.values).toEqual({
+ ...DEFAULT_VALUES,
+ engine: mockSampleEngine,
+ isSampleEngine: true,
+ });
+ });
+ });
+
+ describe('isMetaEngine', () => {
+ it('should be set based on engine.type', () => {
+ const mockMetaEngine = { ...mockEngineData, type: 'meta' };
+ mount({ engine: mockMetaEngine });
+
+ expect(EngineLogic.values).toEqual({
+ ...DEFAULT_VALUES,
+ engine: mockMetaEngine,
+ isMetaEngine: true,
+ });
+ });
+ });
+
+ describe('hasSchemaConflicts', () => {
+ it('should be set based on engine.schemaConflicts', () => {
+ const mockSchemaEngine = {
+ ...mockEngineData,
+ schemaConflicts: {
+ someSchemaField: {
+ fieldTypes: {
+ number: ['some-engine'],
+ date: ['another-engine'],
+ },
+ },
+ },
+ };
+ mount({ engine: mockSchemaEngine });
+
+ expect(EngineLogic.values).toEqual({
+ ...DEFAULT_VALUES,
+ engine: mockSchemaEngine,
+ hasSchemaConflicts: true,
+ });
+ });
+ });
+
+ describe('hasUnconfirmedSchemaFields', () => {
+ it('should be set based on engine.unconfirmedFields', () => {
+ const mockUnconfirmedFieldsEngine = {
+ ...mockEngineData,
+ unconfirmedFields: ['new_field_1', 'new_field_2'],
+ };
+ mount({ engine: mockUnconfirmedFieldsEngine });
+
+ expect(EngineLogic.values).toEqual({
+ ...DEFAULT_VALUES,
+ engine: mockUnconfirmedFieldsEngine,
+ hasUnconfirmedSchemaFields: true,
+ });
+ });
+ });
+ });
+});
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.ts
new file mode 100644
index 0000000000000..2e7595e3ee87b
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.ts
@@ -0,0 +1,101 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { kea, MakeLogicType } from 'kea';
+
+import { HttpLogic } from '../../../shared/http';
+
+import { IndexingStatus } from '../schema/types';
+import { EngineDetails } from './types';
+
+interface EngineValues {
+ dataLoading: boolean;
+ engine: EngineDetails | {};
+ engineName: string;
+ isMetaEngine: boolean;
+ isSampleEngine: boolean;
+ hasSchemaConflicts: boolean;
+ hasUnconfirmedSchemaFields: boolean;
+ engineNotFound: boolean;
+}
+
+interface EngineActions {
+ setEngineData(engine: EngineDetails): { engine: EngineDetails };
+ setEngineName(engineName: string): { engineName: string };
+ setIndexingStatus(activeReindexJob: IndexingStatus): { activeReindexJob: IndexingStatus };
+ setEngineNotFound(notFound: boolean): { notFound: boolean };
+ clearEngine(): void;
+ initializeEngine(): void;
+}
+
+export const EngineLogic = kea>({
+ path: ['enterprise_search', 'app_search', 'engine_logic'],
+ actions: {
+ setEngineData: (engine) => ({ engine }),
+ setEngineName: (engineName) => ({ engineName }),
+ setIndexingStatus: (activeReindexJob) => ({ activeReindexJob }),
+ setEngineNotFound: (notFound) => ({ notFound }),
+ clearEngine: true,
+ initializeEngine: true,
+ },
+ reducers: {
+ dataLoading: [
+ true,
+ {
+ setEngineData: () => false,
+ clearEngine: () => true,
+ },
+ ],
+ engine: [
+ {},
+ {
+ setEngineData: (_, { engine }) => engine,
+ clearEngine: () => ({}),
+ setIndexingStatus: (state, { activeReindexJob }) => ({
+ ...state,
+ activeReindexJob,
+ }),
+ },
+ ],
+ engineName: [
+ '',
+ {
+ setEngineName: (_, { engineName }) => engineName,
+ },
+ ],
+ engineNotFound: [
+ false,
+ {
+ setEngineNotFound: (_, { notFound }) => notFound,
+ },
+ ],
+ },
+ selectors: ({ selectors }) => ({
+ isMetaEngine: [() => [selectors.engine], (engine) => engine?.type === 'meta'],
+ isSampleEngine: [() => [selectors.engine], (engine) => !!engine?.sample],
+ hasSchemaConflicts: [
+ () => [selectors.engine],
+ (engine) => !!(engine?.schemaConflicts && Object.keys(engine.schemaConflicts).length > 0),
+ ],
+ hasUnconfirmedSchemaFields: [
+ () => [selectors.engine],
+ (engine) => engine?.unconfirmedFields?.length > 0,
+ ],
+ }),
+ listeners: ({ actions, values }) => ({
+ initializeEngine: async () => {
+ const { engineName } = values;
+ const { http } = HttpLogic.values;
+
+ try {
+ const response = await http.get(`/api/app_search/engines/${engineName}`);
+ actions.setEngineData(response);
+ } catch (error) {
+ actions.setEngineNotFound(true);
+ }
+ },
+ }),
+});
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.scss b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.scss
index d7740724204a7..529fb9c4bd63e 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.scss
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.scss
@@ -15,3 +15,11 @@
margin-top: $euiSizeXS;
}
}
+
+.appSearchNavIcons {
+ // EUI override
+ &.euiFlexItem {
+ flex-grow: 0;
+ flex-direction: row;
+ }
+}
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.test.tsx
index 7bdc3c86a50d6..0d2ce654d4a0a 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.test.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.test.tsx
@@ -4,134 +4,189 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import '../../../__mocks__/react_router_history.mock';
import { setMockValues } from '../../../__mocks__/kea.mock';
+import { rerender } from '../../../__mocks__';
import React from 'react';
-import { shallow, mount } from 'enzyme';
-import { Switch, useParams } from 'react-router-dom';
-import { EuiBadge } from '@elastic/eui';
+import { shallow } from 'enzyme';
+import { EuiBadge, EuiIcon } from '@elastic/eui';
-import { EngineRouter, EngineNav } from './';
+import { EngineNav } from './';
-describe('EngineRouter', () => {
- it('renders a default engine overview', () => {
- setMockValues({ myRole: {} });
- const wrapper = shallow();
-
- expect(wrapper.find(Switch)).toHaveLength(1);
- expect(wrapper.find('[data-test-subj="EngineOverviewTODO"]')).toHaveLength(1);
- });
-
- it('renders an analytics view', () => {
- setMockValues({ myRole: { canViewEngineAnalytics: true } });
- const wrapper = shallow();
+describe('EngineNav', () => {
+ const values = { myRole: {}, engineName: 'some-engine', dataLoading: false, engine: {} };
- expect(wrapper.find('[data-test-subj="AnalyticsTODO"]')).toHaveLength(1);
+ beforeEach(() => {
+ setMockValues(values);
});
-});
-describe('EngineNav', () => {
- beforeEach(() => {
- (useParams as jest.Mock).mockReturnValue({ engineName: 'some-engine' });
+ it('does not render if async data is still loading', () => {
+ setMockValues({ ...values, dataLoading: true });
+ const wrapper = shallow();
+ expect(wrapper.isEmptyRender()).toBe(true);
});
it('does not render without an engine name', () => {
- setMockValues({ myRole: {} });
- (useParams as jest.Mock).mockReturnValue({ engineName: '' });
+ setMockValues({ ...values, engineName: '' });
const wrapper = shallow();
expect(wrapper.isEmptyRender()).toBe(true);
});
- it('renders an engine label', () => {
- setMockValues({ myRole: {} });
- const wrapper = mount();
+ it('renders an engine label and badges', () => {
+ setMockValues({ ...values, isSampleEngine: false, isMetaEngine: false });
+ const wrapper = shallow();
+ const label = wrapper.find('[data-test-subj="EngineLabel"]').find('.eui-textTruncate');
+
+ expect(label.text()).toEqual('SOME-ENGINE');
+ expect(wrapper.find(EuiBadge)).toHaveLength(0);
- const label = wrapper.find('[data-test-subj="EngineLabel"]').last();
- expect(label.text()).toEqual(expect.stringContaining('SOME-ENGINE'));
+ setMockValues({ ...values, isSampleEngine: true });
+ rerender(wrapper);
+ expect(wrapper.find(EuiBadge).prop('children')).toEqual('SAMPLE ENGINE');
- // TODO: Test sample & meta engine conditional rendering
- expect(label.find(EuiBadge).text()).toEqual('SAMPLE ENGINE');
+ setMockValues({ ...values, isMetaEngine: true });
+ rerender(wrapper);
+ expect(wrapper.find(EuiBadge).prop('children')).toEqual('META ENGINE');
});
it('renders a default engine overview link', () => {
- setMockValues({ myRole: {} });
const wrapper = shallow();
expect(wrapper.find('[data-test-subj="EngineOverviewLink"]')).toHaveLength(1);
});
it('renders an analytics link', () => {
- setMockValues({ myRole: { canViewEngineAnalytics: true } });
+ setMockValues({ ...values, myRole: { canViewEngineAnalytics: true } });
const wrapper = shallow();
expect(wrapper.find('[data-test-subj="EngineAnalyticsLink"]')).toHaveLength(1);
});
it('renders a documents link', () => {
- setMockValues({ myRole: { canViewEngineDocuments: true } });
+ setMockValues({ ...values, myRole: { canViewEngineDocuments: true } });
const wrapper = shallow();
expect(wrapper.find('[data-test-subj="EngineDocumentsLink"]')).toHaveLength(1);
});
it('renders a schema link', () => {
- setMockValues({ myRole: { canViewEngineSchema: true } });
+ setMockValues({ ...values, myRole: { canViewEngineSchema: true } });
const wrapper = shallow();
expect(wrapper.find('[data-test-subj="EngineSchemaLink"]')).toHaveLength(1);
+ });
+
+ describe('schema nav icons', () => {
+ const myRole = { canViewEngineSchema: true };
+
+ it('renders unconfirmed schema fields info icon', () => {
+ setMockValues({ ...values, myRole, hasUnconfirmedSchemaFields: true });
+ const wrapper = shallow();
+ expect(wrapper.find('[data-test-subj="EngineNavSchemaUnconfirmedFields"]')).toHaveLength(1);
+ });
- // TODO: Schema warning icon
+ it('renders schema conflicts alert icon', () => {
+ setMockValues({ ...values, myRole, hasSchemaConflicts: true });
+ const wrapper = shallow();
+ expect(wrapper.find('[data-test-subj="EngineNavSchemaConflicts"]')).toHaveLength(1);
+ });
});
- // TODO: Unskip when EngineLogic is migrated
- it.skip('renders a crawler link', () => {
- setMockValues({ myRole: { canViewEngineCrawler: true } });
- const wrapper = shallow();
- expect(wrapper.find('[data-test-subj="EngineCrawlerLink"]')).toHaveLength(1);
+ describe('crawler link', () => {
+ const myRole = { canViewEngineCrawler: true };
+
+ it('renders', () => {
+ setMockValues({ ...values, myRole });
+ const wrapper = shallow();
+ expect(wrapper.find('[data-test-subj="EngineCrawlerLink"]')).toHaveLength(1);
+ });
+
+ it('does not render for meta engines', () => {
+ setMockValues({ ...values, myRole, isMetaEngine: true });
+ const wrapper = shallow();
+ expect(wrapper.find('[data-test-subj="EngineCrawlerLink"]')).toHaveLength(0);
+ });
- // TODO: Test that the crawler link does NOT show up for meta/sample engines
+ it('does not render for sample engine', () => {
+ setMockValues({ ...values, myRole, isSampleEngine: true });
+ const wrapper = shallow();
+ expect(wrapper.find('[data-test-subj="EngineCrawlerLink"]')).toHaveLength(0);
+ });
});
- // TODO: Unskip when EngineLogic is migrated
- it.skip('renders a meta engine source engines link', () => {
- setMockValues({ myRole: { canViewMetaEngineSourceEngines: true } });
- const wrapper = shallow();
- expect(wrapper.find('[data-test-subj="MetaEngineEnginesLink"]')).toHaveLength(1);
+ describe('meta engine source engines link', () => {
+ const myRole = { canViewMetaEngineSourceEngines: true };
+
+ it('renders', () => {
+ setMockValues({ ...values, myRole, isMetaEngine: true });
+ const wrapper = shallow();
+ expect(wrapper.find('[data-test-subj="MetaEngineEnginesLink"]')).toHaveLength(1);
+ });
- // TODO: Test that the crawler link does NOT show up for non-meta engines
+ it('does not render for non meta engines', () => {
+ setMockValues({ ...values, myRole, isMetaEngine: false });
+ const wrapper = shallow();
+ expect(wrapper.find('[data-test-subj="MetaEngineEnginesLink"]')).toHaveLength(0);
+ });
});
it('renders a relevance tuning link', () => {
- setMockValues({ myRole: { canManageEngineRelevanceTuning: true } });
+ setMockValues({ ...values, myRole: { canManageEngineRelevanceTuning: true } });
const wrapper = shallow();
expect(wrapper.find('[data-test-subj="EngineRelevanceTuningLink"]')).toHaveLength(1);
+ });
+
+ describe('relevance tuning nav icons', () => {
+ const myRole = { canManageEngineRelevanceTuning: true };
+
+ it('renders unconfirmed schema fields info icon', () => {
+ const engine = { unsearchedUnconfirmedFields: true };
+ setMockValues({ ...values, myRole, engine });
+ const wrapper = shallow();
+ expect(
+ wrapper.find('[data-test-subj="EngineNavRelevanceTuningUnsearchedFields"]')
+ ).toHaveLength(1);
+ });
+
+ it('renders schema conflicts alert icon', () => {
+ const engine = { invalidBoosts: true };
+ setMockValues({ ...values, myRole, engine });
+ const wrapper = shallow();
+ expect(wrapper.find('[data-test-subj="EngineNavRelevanceTuningInvalidBoosts"]')).toHaveLength(
+ 1
+ );
+ });
- // TODO: Boost error icon
+ it('can render multiple icons', () => {
+ const engine = { invalidBoosts: true, unsearchedUnconfirmedFields: true };
+ setMockValues({ ...values, myRole, engine });
+ const wrapper = shallow();
+ expect(wrapper.find(EuiIcon)).toHaveLength(2);
+ });
});
it('renders a synonyms link', () => {
- setMockValues({ myRole: { canManageEngineSynonyms: true } });
+ setMockValues({ ...values, myRole: { canManageEngineSynonyms: true } });
const wrapper = shallow();
expect(wrapper.find('[data-test-subj="EngineSynonymsLink"]')).toHaveLength(1);
});
it('renders a curations link', () => {
- setMockValues({ myRole: { canManageEngineCurations: true } });
+ setMockValues({ ...values, myRole: { canManageEngineCurations: true } });
const wrapper = shallow();
expect(wrapper.find('[data-test-subj="EngineCurationsLink"]')).toHaveLength(1);
});
it('renders a results settings link', () => {
- setMockValues({ myRole: { canManageEngineResultSettings: true } });
+ setMockValues({ ...values, myRole: { canManageEngineResultSettings: true } });
const wrapper = shallow();
expect(wrapper.find('[data-test-subj="EngineResultSettingsLink"]')).toHaveLength(1);
});
it('renders a Search UI link', () => {
- setMockValues({ myRole: { canManageEngineSearchUi: true } });
+ setMockValues({ ...values, myRole: { canManageEngineSearchUi: true } });
const wrapper = shallow();
expect(wrapper.find('[data-test-subj="EngineSearchUILink"]')).toHaveLength(1);
});
it('renders an API logs link', () => {
- setMockValues({ myRole: { canViewEngineApiLogs: true } });
+ setMockValues({ ...values, myRole: { canViewEngineApiLogs: true } });
const wrapper = shallow();
expect(wrapper.find('[data-test-subj="EngineAPILogsLink"]')).toHaveLength(1);
});
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx
index e5ee392b34c01..77aca8a71994d 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx
@@ -5,18 +5,15 @@
*/
import React from 'react';
-import { Route, Switch, useParams } from 'react-router-dom';
import { useValues } from 'kea';
-import { EuiText, EuiBadge } from '@elastic/eui';
+import { EuiText, EuiBadge, EuiIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { SideNavLink, SideNavItem } from '../../../shared/layout';
-import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome';
import { AppLogic } from '../../app_logic';
import {
getEngineRoute,
- ENGINE_PATH,
ENGINE_ANALYTICS_PATH,
ENGINE_DOCUMENTS_PATH,
ENGINE_SCHEMA_PATH,
@@ -30,8 +27,8 @@ import {
ENGINE_API_LOGS_PATH,
} from '../../routes';
import { getAppSearchUrl } from '../../../shared/enterprise_search_url';
+import { ENGINES_TITLE } from '../engines';
import {
- ENGINES_TITLE,
OVERVIEW_TITLE,
ANALYTICS_TITLE,
DOCUMENTS_TITLE,
@@ -45,34 +42,10 @@ import {
API_LOGS_TITLE,
} from './constants';
-import './engine_nav.scss';
-
-export const EngineRouter: React.FC = () => {
- const {
- myRole: { canViewEngineAnalytics },
- } = useValues(AppLogic);
+import { EngineLogic } from './';
+import { EngineDetails } from './types';
- // TODO: EngineLogic
-
- const { engineName } = useParams() as { engineName: string };
- const engineBreadcrumb = [ENGINES_TITLE, engineName];
-
- return (
- // TODO: Add more routes as we migrate them
-
- {canViewEngineAnalytics && (
-
-
- Just testing right now
-
- )}
-
-
- Overview
-
-
- );
-};
+import './engine_nav.scss';
export const EngineNav: React.FC = () => {
const {
@@ -91,14 +64,22 @@ export const EngineNav: React.FC = () => {
},
} = useValues(AppLogic);
- // TODO: Use EngineLogic
- const isSampleEngine = true;
- const isMetaEngine = false;
- const { engineName } = useParams() as { engineName: string };
- const engineRoute = engineName && getEngineRoute(engineName);
+ const {
+ engineName,
+ dataLoading,
+ isSampleEngine,
+ isMetaEngine,
+ hasSchemaConflicts,
+ hasUnconfirmedSchemaFields,
+ engine,
+ } = useValues(EngineLogic);
+ if (dataLoading) return null;
if (!engineName) return null;
+ const engineRoute = getEngineRoute(engineName);
+ const { invalidBoosts, unsearchedUnconfirmedFields } = engine as Required;
+
return (
<>
@@ -143,8 +124,33 @@ export const EngineNav: React.FC = () => {
to={getAppSearchUrl(engineRoute + ENGINE_SCHEMA_PATH)}
data-test-subj="EngineSchemaLink"
>
- {SCHEMA_TITLE}
- {/* TODO: Engine schema warning icon */}
+
+ {SCHEMA_TITLE}
+
+ {hasUnconfirmedSchemaFields && (
+
+ )}
+ {hasSchemaConflicts && (
+
+ )}
+
+
)}
{canViewEngineCrawler && !isMetaEngine && !isSampleEngine && (
@@ -171,8 +177,33 @@ export const EngineNav: React.FC = () => {
to={getAppSearchUrl(engineRoute + ENGINE_RELEVANCE_TUNING_PATH)}
data-test-subj="EngineRelevanceTuningLink"
>
- {RELEVANCE_TUNING_TITLE}
- {/* TODO: invalid boosts error icon */}
+
+ {RELEVANCE_TUNING_TITLE}
+
+ {invalidBoosts && (
+
+ )}
+ {unsearchedUnconfirmedFields && (
+
+ )}
+
+
)}
{canManageEngineSynonyms && (
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx
new file mode 100644
index 0000000000000..e38381cad32ba
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+import '../../../__mocks__/react_router_history.mock';
+import { unmountHandler } from '../../../__mocks__/shallow_useeffect.mock';
+import { setMockValues, setMockActions } from '../../../__mocks__/kea.mock';
+
+import React from 'react';
+import { shallow } from 'enzyme';
+import { Switch, Redirect, useParams } from 'react-router-dom';
+
+jest.mock('../../../shared/flash_messages', () => ({
+ setQueuedErrorMessage: jest.fn(),
+}));
+import { setQueuedErrorMessage } from '../../../shared/flash_messages';
+
+import { EngineRouter } from './';
+
+describe('EngineRouter', () => {
+ const values = { dataLoading: false, engineNotFound: false, myRole: {} };
+ const actions = { setEngineName: jest.fn(), initializeEngine: jest.fn(), clearEngine: jest.fn() };
+
+ beforeEach(() => {
+ setMockValues(values);
+ setMockActions(actions);
+ });
+
+ describe('useEffect', () => {
+ beforeEach(() => {
+ (useParams as jest.Mock).mockReturnValue({ engineName: 'some-engine' });
+ shallow();
+ });
+
+ it('sets engineName based on the current route parameters', () => {
+ expect(actions.setEngineName).toHaveBeenCalledWith('some-engine');
+ });
+
+ it('initializes/fetches engine API data', () => {
+ expect(actions.initializeEngine).toHaveBeenCalled();
+ });
+
+ it('clears engine on unmount', () => {
+ unmountHandler();
+ expect(actions.clearEngine).toHaveBeenCalled();
+ });
+ });
+
+ it('redirects to engines list and flashes an error if the engine param was not found', () => {
+ (useParams as jest.Mock).mockReturnValue({ engineName: '404-engine' });
+ setMockValues({ ...values, engineNotFound: true });
+ const wrapper = shallow();
+
+ expect(wrapper.find(Redirect).prop('to')).toEqual('/engines');
+ expect(setQueuedErrorMessage).toHaveBeenCalledWith(
+ "No engine with name '404-engine' could be found."
+ );
+ });
+
+ it('does not render if async data is still loading', () => {
+ setMockValues({ ...values, dataLoading: true });
+ const wrapper = shallow();
+ expect(wrapper.isEmptyRender()).toBe(true);
+ });
+
+ it('renders a default engine overview', () => {
+ const wrapper = shallow();
+
+ expect(wrapper.find(Switch)).toHaveLength(1);
+ expect(wrapper.find('[data-test-subj="EngineOverviewTODO"]')).toHaveLength(1);
+ });
+
+ it('renders an analytics view', () => {
+ setMockValues({ myRole: { canViewEngineAnalytics: true } });
+ const wrapper = shallow();
+
+ expect(wrapper.find('[data-test-subj="AnalyticsTODO"]')).toHaveLength(1);
+ });
+});
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx
new file mode 100644
index 0000000000000..3e6856771f7d9
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+import React, { useEffect } from 'react';
+import { Route, Switch, Redirect, useParams } from 'react-router-dom';
+import { useValues, useActions } from 'kea';
+
+import { i18n } from '@kbn/i18n';
+
+import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome';
+import { setQueuedErrorMessage } from '../../../shared/flash_messages';
+import { AppLogic } from '../../app_logic';
+
+// TODO: Uncomment and add more routes as we migrate them
+import {
+ ENGINES_PATH,
+ ENGINE_PATH,
+ ENGINE_ANALYTICS_PATH,
+ // ENGINE_DOCUMENTS_PATH,
+ // ENGINE_SCHEMA_PATH,
+ // ENGINE_CRAWLER_PATH,
+ // META_ENGINE_SOURCE_ENGINES_PATH,
+ // ENGINE_RELEVANCE_TUNING_PATH,
+ // ENGINE_SYNONYMS_PATH,
+ // ENGINE_CURATIONS_PATH,
+ // ENGINE_RESULT_SETTINGS_PATH,
+ // ENGINE_SEARCH_UI_PATH,
+ // ENGINE_API_LOGS_PATH,
+} from '../../routes';
+import { ENGINES_TITLE } from '../engines';
+import {
+ OVERVIEW_TITLE,
+ ANALYTICS_TITLE,
+ // DOCUMENTS_TITLE,
+ // SCHEMA_TITLE,
+ // CRAWLER_TITLE,
+ // RELEVANCE_TUNING_TITLE,
+ // SYNONYMS_TITLE,
+ // CURATIONS_TITLE,
+ // RESULT_SETTINGS_TITLE,
+ // SEARCH_UI_TITLE,
+ // API_LOGS_TITLE,
+} from './constants';
+
+import { EngineLogic } from './';
+
+export const EngineRouter: React.FC = () => {
+ const {
+ myRole: {
+ canViewEngineAnalytics,
+ // canViewEngineDocuments,
+ // canViewEngineSchema,
+ // canViewEngineCrawler,
+ // canViewMetaEngineSourceEngines,
+ // canManageEngineSynonyms,
+ // canManageEngineCurations,
+ // canManageEngineRelevanceTuning,
+ // canManageEngineResultSettings,
+ // canManageEngineSearchUi,
+ // canViewEngineApiLogs,
+ },
+ } = useValues(AppLogic);
+
+ const { dataLoading, engineNotFound } = useValues(EngineLogic);
+ const { setEngineName, initializeEngine, clearEngine } = useActions(EngineLogic);
+
+ const { engineName } = useParams() as { engineName: string };
+ const engineBreadcrumb = [ENGINES_TITLE, engineName];
+
+ useEffect(() => {
+ setEngineName(engineName);
+ initializeEngine();
+ return clearEngine;
+ }, [engineName]);
+
+ if (engineNotFound) {
+ setQueuedErrorMessage(
+ i18n.translate('xpack.enterpriseSearch.appSearch.engine.notFound', {
+ defaultMessage: "No engine with name '{engineName}' could be found.",
+ values: { engineName },
+ })
+ );
+ return ;
+ }
+
+ if (dataLoading) return null;
+
+ return (
+
+ {canViewEngineAnalytics && (
+
+
+ Just testing right now
+
+ )}
+
+
+ Overview
+
+
+ );
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/index.ts
index a3320ba5024ca..4e7d81f73fb8d 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/index.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/index.ts
@@ -4,4 +4,6 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export { EngineRouter, EngineNav } from './engine_nav';
+export { EngineRouter } from './engine_router';
+export { EngineNav } from './engine_nav';
+export { EngineLogic } from './engine_logic';
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/types.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/types.ts
new file mode 100644
index 0000000000000..635d1136291aa
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/types.ts
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+import { ApiToken } from '../credentials/types';
+import { Schema, SchemaConflicts, IndexingStatus } from '../schema/types';
+
+export interface Engine {
+ name: string;
+ type: string;
+ language: string | null;
+ result_fields: {
+ [key: string]: ResultField;
+ };
+}
+
+export interface EngineDetails extends Engine {
+ created_at: string;
+ document_count: number;
+ field_count: number;
+ unsearchedUnconfirmedFields: boolean;
+ apiTokens: ApiToken[];
+ apiKey: string;
+ schema: Schema;
+ schemaConflicts?: SchemaConflicts;
+ unconfirmedFields?: string[];
+ activeReindexJob?: IndexingStatus;
+ invalidBoosts: boolean;
+ sample?: boolean;
+ isMeta: boolean;
+ engine_count?: number;
+ includedEngines?: EngineDetails[];
+}
+
+interface ResultField {
+ raw: object;
+ snippet?: {
+ size: number;
+ fallback: boolean;
+ };
+}
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/assets/engine_icon.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/assets/engine_icon.tsx
similarity index 100%
rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/assets/engine_icon.tsx
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/assets/engine_icon.tsx
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/assets/meta_engine_icon.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/assets/meta_engine_icon.tsx
similarity index 100%
rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/assets/meta_engine_icon.tsx
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/assets/meta_engine_icon.tsx
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/empty_state.scss b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.scss
similarity index 100%
rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/empty_state.scss
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.scss
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/empty_state.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.test.tsx
similarity index 100%
rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/empty_state.test.tsx
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.test.tsx
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/empty_state.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.tsx
similarity index 96%
rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/empty_state.tsx
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.tsx
index b7ed1cc895097..95142782d2272 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/empty_state.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.tsx
@@ -14,7 +14,7 @@ import { getAppSearchUrl } from '../../../../shared/enterprise_search_url';
import { SetAppSearchChrome as SetPageChrome } from '../../../../shared/kibana_chrome';
import { CREATE_ENGINES_PATH } from '../../../routes';
-import { EngineOverviewHeader } from './header';
+import { EnginesOverviewHeader } from './header';
import './empty_state.scss';
@@ -34,7 +34,7 @@ export const EmptyState: React.FC = () => {
return (
<>
-
+
{
+describe('EnginesOverviewHeader', () => {
it('renders', () => {
- const wrapper = shallow();
+ const wrapper = shallow();
expect(wrapper.find('h1')).toHaveLength(1);
});
it('renders a launch app search button that sends telemetry on click', () => {
- const wrapper = shallow();
+ const wrapper = shallow();
const button = wrapper.find('[data-test-subj="launchButton"]');
expect(button.prop('href')).toBe('http://localhost:3002/as');
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/header.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/header.tsx
similarity index 93%
rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/header.tsx
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/header.tsx
index 4bb69bafa0996..3faa74be11e98 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/header.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/header.tsx
@@ -19,7 +19,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
import { TelemetryLogic } from '../../../../shared/telemetry';
import { getAppSearchUrl } from '../../../../shared/enterprise_search_url';
-export const EngineOverviewHeader: React.FC = () => {
+export const EnginesOverviewHeader: React.FC = () => {
const { sendAppSearchTelemetry } = useActions(TelemetryLogic);
const buttonProps = {
@@ -42,7 +42,7 @@ export const EngineOverviewHeader: React.FC = () => {
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/index.ts
similarity index 87%
rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/index.ts
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/index.ts
index 794053f184f8c..cb2e0f825d455 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/index.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/index.ts
@@ -4,6 +4,6 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export { EngineOverviewHeader } from './header';
+export { EnginesOverviewHeader } from './header';
export { LoadingState } from './loading_state';
export { EmptyState } from './empty_state';
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/loading_state.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.test.tsx
similarity index 100%
rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/loading_state.test.tsx
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.test.tsx
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/loading_state.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.tsx
similarity index 89%
rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/loading_state.tsx
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.tsx
index 832a133ed43c7..8e2166d2ef105 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/loading_state.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.tsx
@@ -8,13 +8,13 @@ import React from 'react';
import { EuiPageContent, EuiSpacer, EuiLoadingContent } from '@elastic/eui';
import { SetAppSearchChrome as SetPageChrome } from '../../../../shared/kibana_chrome';
-import { EngineOverviewHeader } from './header';
+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
new file mode 100644
index 0000000000000..12545c59b40a0
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/constants.ts
@@ -0,0 +1,16 @@
+/*
+ * 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.
+ */
+
+import { i18n } from '@kbn/i18n';
+
+export const ENGINES_TITLE = i18n.translate('xpack.enterpriseSearch.appSearch.engines.title', {
+ defaultMessage: 'Engines',
+});
+
+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/engine_overview/engine_overview.scss b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.scss
similarity index 96%
rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.scss
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.scss
index 5e8a20ba425ad..c956f3da562f6 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.scss
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.scss
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-.engineOverview {
+.enginesOverview {
padding: $euiSize;
@include euiBreakpoint('m', 'l', 'xl') {
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.test.tsx
similarity index 80%
rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.test.tsx
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.test.tsx
index f87ea2d422780..61f783a8b6c2e 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.test.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.test.tsx
@@ -14,14 +14,14 @@ import { shallow, ReactWrapper } from 'enzyme';
import { mountAsync, mockHttpValues, setMockValues } from '../../../__mocks__';
import { LoadingState, EmptyState } from './components';
-import { EngineTable } from './engine_table';
+import { EnginesTable } from './engines_table';
-import { EngineOverview } from './';
+import { EnginesOverview } from './';
-describe('EngineOverview', () => {
+describe('EnginesOverview', () => {
describe('non-happy-path states', () => {
it('isLoading', () => {
- const wrapper = shallow();
+ const wrapper = shallow();
expect(wrapper.find(LoadingState)).toHaveLength(1);
});
@@ -36,7 +36,7 @@ describe('EngineOverview', () => {
}),
},
});
- const wrapper = await mountAsync(, { i18n: true });
+ const wrapper = await mountAsync(, { i18n: true });
expect(wrapper.find(EmptyState)).toHaveLength(1);
});
@@ -69,9 +69,9 @@ describe('EngineOverview', () => {
});
it('renders and calls the engines API', async () => {
- const wrapper = await mountAsync(, { i18n: true });
+ const wrapper = await mountAsync(, { i18n: true });
- expect(wrapper.find(EngineTable)).toHaveLength(1);
+ expect(wrapper.find(EnginesTable)).toHaveLength(1);
expect(mockApi).toHaveBeenNthCalledWith(1, '/api/app_search/engines', {
query: {
type: 'indexed',
@@ -86,9 +86,9 @@ describe('EngineOverview', () => {
hasPlatinumLicense: true,
http: { ...mockHttpValues.http, get: mockApi },
});
- const wrapper = await mountAsync(, { i18n: true });
+ const wrapper = await mountAsync(, { i18n: true });
- expect(wrapper.find(EngineTable)).toHaveLength(2);
+ expect(wrapper.find(EnginesTable)).toHaveLength(2);
expect(mockApi).toHaveBeenNthCalledWith(2, '/api/app_search/engines', {
query: {
type: 'meta',
@@ -100,10 +100,10 @@ describe('EngineOverview', () => {
describe('pagination', () => {
const getTablePagination = (wrapper: ReactWrapper) =>
- wrapper.find(EngineTable).prop('pagination');
+ wrapper.find(EnginesTable).prop('pagination');
it('passes down page data from the API', async () => {
- const wrapper = await mountAsync(, { i18n: true });
+ const wrapper = await mountAsync(, { i18n: true });
const pagination = getTablePagination(wrapper);
expect(pagination.totalEngines).toEqual(100);
@@ -111,7 +111,7 @@ describe('EngineOverview', () => {
});
it('re-polls the API on page change', async () => {
- const wrapper = await mountAsync(, { i18n: true });
+ const wrapper = await mountAsync(, { i18n: true });
await act(async () => getTablePagination(wrapper).onPaginate(5));
wrapper.update();
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx
similarity index 78%
rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx
index c0fd254567910..0381c3806fec7 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx
@@ -13,7 +13,6 @@ import {
EuiTitle,
EuiSpacer,
} from '@elastic/eui';
-import { i18n } from '@kbn/i18n';
import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome';
import { SendAppSearchTelemetry as SendTelemetry } from '../../../shared/telemetry';
@@ -23,22 +22,22 @@ import { LicensingLogic } from '../../../shared/licensing';
import { EngineIcon } from './assets/engine_icon';
import { MetaEngineIcon } from './assets/meta_engine_icon';
+import { ENGINES_TITLE, META_ENGINES_TITLE } from './constants';
+import { EnginesOverviewHeader, LoadingState, EmptyState } from './components';
+import { EnginesTable } from './engines_table';
-import { EngineOverviewHeader, LoadingState, EmptyState } from './components';
-import { EngineTable } from './engine_table';
+import './engines_overview.scss';
-import './engine_overview.scss';
-
-interface IGetEnginesParams {
+interface GetEnginesParams {
type: string;
pageIndex: number;
}
-interface ISetEnginesCallbacks {
+interface SetEnginesCallbacks {
setResults: React.Dispatch>;
setResultsTotal: React.Dispatch>;
}
-export const EngineOverview: React.FC = () => {
+export const EnginesOverview: React.FC = () => {
const { http } = useValues(HttpLogic);
const { hasPlatinumLicense } = useValues(LicensingLogic);
@@ -50,12 +49,12 @@ export const EngineOverview: React.FC = () => {
const [metaEnginesPage, setMetaEnginesPage] = useState(1);
const [metaEnginesTotal, setMetaEnginesTotal] = useState(0);
- const getEnginesData = async ({ type, pageIndex }: IGetEnginesParams) => {
+ const getEnginesData = async ({ type, pageIndex }: GetEnginesParams) => {
return await http.get('/api/app_search/engines', {
query: { type, pageIndex },
});
};
- const setEnginesData = async (params: IGetEnginesParams, callbacks: ISetEnginesCallbacks) => {
+ const setEnginesData = async (params: GetEnginesParams, callbacks: SetEnginesCallbacks) => {
const response = await getEnginesData(params);
callbacks.setResults(response.results);
@@ -88,21 +87,18 @@ export const EngineOverview: React.FC = () => {
-
-
+
+
-
- {i18n.translate('xpack.enterpriseSearch.appSearch.enginesOverview.engines', {
- defaultMessage: 'Engines',
- })}
+ {ENGINES_TITLE}
- {
-
- {i18n.translate('xpack.enterpriseSearch.appSearch.enginesOverview.metaEngines', {
- defaultMessage: 'Meta Engines',
- })}
+ {META_ENGINES_TITLE}
- {
+describe('EnginesTable', () => {
const onPaginate = jest.fn(); // onPaginate updates the engines API call upstream
const wrapper = mountWithIntl(
- {
it('handles empty data', () => {
const emptyWrapper = mountWithIntl(
- {} }} />
+ {} }}
+ />
);
const emptyTable = emptyWrapper.find(EuiBasicTable);
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_table.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.tsx
similarity index 91%
rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_table.tsx
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.tsx
index abeaf45e6aee8..9591bbda1f7c2 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_table.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.tsx
@@ -16,28 +16,28 @@ import { getEngineRoute } from '../../routes';
import { ENGINES_PAGE_SIZE } from '../../../../../common/constants';
-export interface IEngineTableData {
+interface EnginesTableData {
name: string;
created_at: string;
document_count: number;
field_count: number;
}
-export interface IEngineTablePagination {
+interface EnginesTablePagination {
totalEngines: number;
pageIndex: number;
onPaginate(pageIndex: number): void;
}
-export interface IEngineTableProps {
- data: IEngineTableData[];
- pagination: IEngineTablePagination;
+interface EnginesTableProps {
+ data: EnginesTableData[];
+ pagination: EnginesTablePagination;
}
-export interface IOnChange {
+interface OnChange {
page: {
index: number;
};
}
-export const EngineTable: React.FC = ({
+export const EnginesTable: React.FC = ({
data,
pagination: { totalEngines, pageIndex, onPaginate },
}) => {
@@ -52,7 +52,7 @@ export const EngineTable: React.FC = ({
}),
});
- const columns: Array> = [
+ const columns: Array> = [
{
field: 'name',
name: i18n.translate('xpack.enterpriseSearch.appSearch.enginesOverview.table.column.name', {
@@ -144,7 +144,7 @@ export const EngineTable: React.FC = ({
totalItemCount: totalEngines,
hidePerPageOptions: true,
}}
- onChange={({ page }: IOnChange) => {
+ onChange={({ page }: OnChange) => {
const { index } = page;
onPaginate(index + 1); // Note on paging - App Search's API pages start at 1, EuiBasicTables' pages start at 0
}}
diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_search_bar/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/index.ts
similarity index 67%
rename from x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_search_bar/index.ts
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/index.ts
index 2748764d7f46e..76ca9239a3c7e 100644
--- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_search_bar/index.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/index.ts
@@ -4,4 +4,5 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export { AnalyticsSearchBar, filterAnalytics, filterAnalyticsModels } from './analytics_search_bar';
+export { EnginesOverview } from './engines_overview';
+export { ENGINES_TITLE, META_ENGINES_TITLE } from './constants';
diff --git a/x-pack/plugins/maps/public/embeddable/merge_input_with_saved_map.d.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/constants.ts
similarity index 57%
rename from x-pack/plugins/maps/public/embeddable/merge_input_with_saved_map.d.ts
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/constants.ts
index 4ce4df02f6a39..133d8b604381b 100644
--- a/x-pack/plugins/maps/public/embeddable/merge_input_with_saved_map.d.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/constants.ts
@@ -4,9 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { MapEmbeddableInput } from './map_embeddable';
+import { i18n } from '@kbn/i18n';
-export function mergeInputWithSavedMap(
- input: MapEmbeddableInput,
- savedmap: unknown
-): Partial;
+export const ROLE_MAPPINGS_TITLE = i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.roleMappings.title',
+ { defaultMessage: 'Role Mappings' }
+);
diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/types.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/index.ts
similarity index 82%
rename from x-pack/plugins/enterprise_search/public/applications/shared/types.ts
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/index.ts
index 3fd1dcad0066e..662b91bb3e925 100644
--- a/x-pack/plugins/enterprise_search/public/applications/shared/types.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/index.ts
@@ -4,4 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export { IFlashMessage } from './flash_messages';
+export { ROLE_MAPPINGS_TITLE } from './constants';
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/schema/types.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/schema/types.ts
new file mode 100644
index 0000000000000..84f402dd3b95f
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/schema/types.ts
@@ -0,0 +1,34 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export type SchemaTypes = 'text' | 'number' | 'geolocation' | 'date';
+
+export interface Schema {
+ [key: string]: SchemaTypes;
+}
+
+// this is a mapping of schema field types ("string", "number", "geolocation", "date") to the names
+// of source engines which utilize that type
+export type SchemaConflictFieldTypes = {
+ [key in SchemaTypes]: string[];
+};
+
+export interface SchemaConflict {
+ fieldTypes: SchemaConflictFieldTypes;
+ resolution?: string;
+}
+
+// For now these values are ISchemaConflictFieldTypes, but in the near future will be ISchemaConflict
+// once we implement schema conflict resolution
+export interface SchemaConflicts {
+ [key: string]: SchemaConflictFieldTypes;
+}
+
+export interface IndexingStatus {
+ percentageComplete: number;
+ numDocumentsWithErrors: number;
+ activeReindexJobId: number;
+}
diff --git a/x-pack/plugins/maps/public/routing/store_operations.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/constants.ts
similarity index 59%
rename from x-pack/plugins/maps/public/routing/store_operations.ts
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/constants.ts
index 53ebbb3328ff9..c7b22d740341c 100644
--- a/x-pack/plugins/maps/public/routing/store_operations.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/constants.ts
@@ -4,8 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { createMapStore } from '../reducers/store';
+import { i18n } from '@kbn/i18n';
-const store = createMapStore();
-
-export const getStore = () => store;
+export const SETTINGS_TITLE = i18n.translate('xpack.enterpriseSearch.appSearch.settings.title', {
+ defaultMessage: 'Settings',
+});
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/index.ts
index db74dcb1a1846..3e162a4a2a1bc 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/index.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/index.ts
@@ -5,3 +5,4 @@
*/
export { Settings } from './settings';
+export { SETTINGS_TITLE } from './constants';
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/generic_confirmation_modal.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/generic_confirmation_modal.test.tsx
new file mode 100644
index 0000000000000..f1eac1a009ecf
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/generic_confirmation_modal.test.tsx
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+import React from 'react';
+import { shallow } from 'enzyme';
+
+import { GenericConfirmationModal } from './generic_confirmation_modal';
+
+describe('GenericConfirmationModal', () => {
+ let wrapper: any;
+ const onClose = jest.fn();
+ const onSave = jest.fn();
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ wrapper = shallow(
+
+ );
+ });
+
+ it('calls onSave callback when save is pressed', () => {
+ const button = wrapper.find('[data-test-subj="GenericConfirmationModalSave"]');
+ button.simulate('click');
+ expect(onSave).toHaveBeenCalled();
+ });
+
+ it('calls onClose callback when Cancel is pressed', () => {
+ const button = wrapper.find('[data-test-subj="GenericConfirmationModalCancel"]');
+ button.simulate('click');
+ expect(onClose).toHaveBeenCalled();
+ });
+
+ it('disables the Save button when the input is empty', () => {
+ const button = wrapper.find('[data-test-subj="GenericConfirmationModalSave"]');
+ expect(button.prop('disabled')).toEqual(true);
+ });
+
+ it('disables the Save button when the input is not equal to the target', () => {
+ const input = wrapper.find('[data-test-subj="GenericConfirmationModalInput"]');
+ input.prop('onChange')({
+ target: {
+ value: 'NOT_GOOD',
+ },
+ });
+
+ const button = wrapper.find('[data-test-subj="GenericConfirmationModalSave"]');
+ expect(button.prop('disabled')).toEqual(true);
+ });
+
+ it('enables the Save button when the current input equals the target prop', () => {
+ const input = wrapper.find('[data-test-subj="GenericConfirmationModalInput"]');
+ input.prop('onChange')({
+ target: {
+ value: 'DISABLE',
+ },
+ });
+ const button = wrapper.find('[data-test-subj="GenericConfirmationModalSave"]');
+ expect(button.prop('disabled')).toEqual(false);
+ });
+
+ it('is not case sensitive', () => {
+ const input = wrapper.find('[data-test-subj="GenericConfirmationModalInput"]');
+ input.prop('onChange')({
+ target: {
+ value: 'diSable',
+ },
+ });
+ const button = wrapper.find('[data-test-subj="GenericConfirmationModalSave"]');
+ expect(button.prop('disabled')).toEqual(false);
+ });
+});
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/generic_confirmation_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/generic_confirmation_modal.tsx
new file mode 100644
index 0000000000000..6d802b0c5cfaf
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/generic_confirmation_modal.tsx
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+import React, { ReactNode, useState } from 'react';
+import { i18n } from '@kbn/i18n';
+
+import {
+ EuiButton,
+ EuiButtonEmpty,
+ EuiFieldText,
+ EuiFormRow,
+ EuiModal,
+ EuiModalBody,
+ EuiModalFooter,
+ EuiModalHeader,
+ EuiModalHeaderTitle,
+ EuiSpacer,
+ EuiText,
+} from '@elastic/eui';
+
+interface GenericConfirmationModalProps {
+ description: ReactNode;
+ subheading: ReactNode;
+ target: string;
+ title: string;
+ onClose(): void;
+ onSave(): void;
+}
+
+export const GenericConfirmationModal: React.FC = ({
+ description,
+ onClose,
+ onSave,
+ subheading,
+ target,
+ title,
+}) => {
+ const [inputValue, setInputValue] = useState('');
+
+ const onConfirm = () => {
+ setInputValue('');
+ onSave();
+ };
+
+ return (
+
+
+ {title}
+
+
+
+
+ {subheading}
+
+ {description}
+
+
+
+ setInputValue(e.target.value)}
+ />
+
+
+
+
+ {i18n.translate('xpack.enterpriseSearch.appSearch.settings.logRetention.modal.cancel', {
+ defaultMessage: 'Cancel',
+ })}
+
+
+ {i18n.translate('xpack.enterpriseSearch.appSearch.settings.logRetention.modal.save', {
+ defaultMessage: 'Save setting',
+ })}
+
+
+
+ );
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.test.tsx
new file mode 100644
index 0000000000000..d77089d52fbdd
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.test.tsx
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+import '../../../../__mocks__/kea.mock';
+import { setMockActions, setMockValues } from '../../../../__mocks__';
+
+import React from 'react';
+import { shallow } from 'enzyme';
+
+import { LogRetentionConfirmationModal } from './log_retention_confirmation_modal';
+import { LogRetentionOptions } from './types';
+import { GenericConfirmationModal } from './generic_confirmation_modal';
+
+describe('', () => {
+ const actions = {
+ closeModals: jest.fn(),
+ saveLogRetention: jest.fn(),
+ };
+
+ const values = {
+ openedModal: null,
+ logRetention: {
+ analytics: {
+ enabled: true,
+ retentionPolicy: {
+ isDefault: true,
+ minAgeDays: 180,
+ },
+ },
+ api: {
+ enabled: true,
+ retentionPolicy: {
+ isDefault: true,
+ minAgeDays: 7,
+ },
+ },
+ },
+ };
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ setMockActions(actions);
+ setMockValues(values);
+ });
+
+ it('renders nothing by default', () => {
+ const logRetentionPanel = shallow();
+ expect(logRetentionPanel.isEmptyRender()).toBe(true);
+ });
+
+ describe('analytics', () => {
+ it('renders the Analytics panel when openedModal is set to Analytics', () => {
+ setMockValues({
+ ...values,
+ openedModal: LogRetentionOptions.Analytics,
+ });
+
+ const logRetentionPanel = shallow();
+ expect(
+ logRetentionPanel.find('[data-test-subj="AnalyticsLogRetentionConfirmationModal"]').length
+ ).toBe(1);
+ });
+
+ it('calls saveLogRetention on save when showing analytics', () => {
+ setMockValues({
+ ...values,
+ openedModal: LogRetentionOptions.Analytics,
+ });
+
+ const logRetentionPanel = shallow();
+ const genericConfirmationModal = logRetentionPanel.find(GenericConfirmationModal);
+ genericConfirmationModal.prop('onSave')();
+ expect(actions.saveLogRetention).toHaveBeenCalledWith(LogRetentionOptions.Analytics, false);
+ });
+
+ it('calls closeModals on close', () => {
+ setMockValues({
+ ...values,
+ openedModal: LogRetentionOptions.Analytics,
+ });
+
+ const logRetentionPanel = shallow();
+ const genericConfirmationModal = logRetentionPanel.find(GenericConfirmationModal);
+ genericConfirmationModal.prop('onClose')();
+ expect(actions.closeModals).toHaveBeenCalled();
+ });
+ });
+
+ describe('api', () => {
+ it('renders the API panel when openedModal is set to API', () => {
+ setMockValues({
+ ...values,
+ openedModal: LogRetentionOptions.API,
+ });
+
+ const logRetentionPanel = shallow();
+ expect(
+ logRetentionPanel.find('[data-test-subj="APILogRetentionConfirmationModal"]').length
+ ).toBe(1);
+ });
+
+ it('calls saveLogRetention on save when showing api', () => {
+ setMockValues({
+ ...values,
+ openedModal: LogRetentionOptions.API,
+ });
+
+ const logRetentionPanel = shallow();
+ const genericConfirmationModal = logRetentionPanel.find(GenericConfirmationModal);
+ genericConfirmationModal.prop('onSave')();
+ expect(actions.saveLogRetention).toHaveBeenCalledWith(LogRetentionOptions.API, false);
+ });
+
+ it('calls closeModals on close', () => {
+ setMockValues({
+ ...values,
+ openedModal: LogRetentionOptions.API,
+ });
+
+ const logRetentionPanel = shallow();
+ const genericConfirmationModal = logRetentionPanel.find(GenericConfirmationModal);
+ genericConfirmationModal.prop('onClose')();
+ expect(actions.closeModals).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.tsx
new file mode 100644
index 0000000000000..67421bb78fa71
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.tsx
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+import React from 'react';
+import { i18n } from '@kbn/i18n';
+
+import { EuiTextColor, EuiOverlayMask } from '@elastic/eui';
+import { useActions, useValues } from 'kea';
+
+import { GenericConfirmationModal } from './generic_confirmation_modal';
+import { LogRetentionLogic } from './log_retention_logic';
+
+import { LogRetentionOptions } from './types';
+
+export const LogRetentionConfirmationModal: React.FC = () => {
+ const CANNOT_BE_RECOVERED_TEXT = i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.modal.recovery',
+ {
+ defaultMessage: 'Once your data has been removed, it cannot be recovered.',
+ }
+ );
+
+ const DISABLE_TEXT = i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.modal.disable',
+ {
+ defaultMessage: 'DISABLE',
+ }
+ );
+
+ const { closeModals, saveLogRetention } = useActions(LogRetentionLogic);
+
+ const { logRetention, openedModal } = useValues(LogRetentionLogic);
+
+ if (openedModal === null) {
+ return null;
+ }
+
+ return (
+
+ {openedModal === LogRetentionOptions.Analytics && (
+
+
+ {i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.modal.analytics.description',
+ {
+ defaultMessage:
+ 'When disabling Analytics Logs, all your engines will immediately stop indexing Analytics Logs. Your existing data will be deleted in accordance with the storage timeframes outlined above.',
+ }
+ )}
+
+
+
+ {CANNOT_BE_RECOVERED_TEXT}
+
+
+ >
+ }
+ target={DISABLE_TEXT}
+ onClose={closeModals}
+ onSave={() => saveLogRetention(LogRetentionOptions.Analytics, false)}
+ />
+ )}
+ {openedModal === LogRetentionOptions.API && (
+
+
+ {i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.modal.api.description',
+ {
+ defaultMessage:
+ 'When disabling API Logs, all your engines will immediately stop indexing API Logs. Your existing data will be deleted in accordance with the storage timeframes outlined above.',
+ }
+ )}
+
+
+
+ {CANNOT_BE_RECOVERED_TEXT}
+
+
+ >
+ }
+ target={DISABLE_TEXT}
+ onClose={closeModals}
+ onSave={() => saveLogRetention(LogRetentionOptions.API, false)}
+ />
+ )}
+
+ );
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_logic.test.ts
index 367c7b085123f..c86d7e3e915e2 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_logic.test.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_logic.test.ts
@@ -17,7 +17,7 @@ jest.mock('../../../../shared/flash_messages', () => ({
}));
import { flashAPIErrors } from '../../../../shared/flash_messages';
-import { ELogRetentionOptions } from './types';
+import { LogRetentionOptions } from './types';
import { LogRetentionLogic } from './log_retention_logic';
describe('LogRetentionLogic', () => {
@@ -87,11 +87,11 @@ describe('LogRetentionLogic', () => {
it('should be set to the provided value', () => {
mount();
- LogRetentionLogic.actions.setOpenedModal(ELogRetentionOptions.Analytics);
+ LogRetentionLogic.actions.setOpenedModal(LogRetentionOptions.Analytics);
expect(LogRetentionLogic.values).toEqual({
...DEFAULT_VALUES,
- openedModal: ELogRetentionOptions.Analytics,
+ openedModal: LogRetentionOptions.Analytics,
});
});
});
@@ -194,10 +194,10 @@ describe('LogRetentionLogic', () => {
describe('openedModal', () => {
it('should be reset to null', () => {
mount({
- openedModal: ELogRetentionOptions.Analytics,
+ openedModal: LogRetentionOptions.Analytics,
});
- LogRetentionLogic.actions.saveLogRetention(ELogRetentionOptions.Analytics, true);
+ LogRetentionLogic.actions.saveLogRetention(LogRetentionOptions.Analytics, true);
expect(LogRetentionLogic.values).toEqual({
...DEFAULT_VALUES,
@@ -211,7 +211,7 @@ describe('LogRetentionLogic', () => {
const promise = Promise.resolve(TYPICAL_SERVER_LOG_RETENTION);
http.put.mockReturnValue(promise);
- LogRetentionLogic.actions.saveLogRetention(ELogRetentionOptions.Analytics, true);
+ LogRetentionLogic.actions.saveLogRetention(LogRetentionOptions.Analytics, true);
expect(http.put).toHaveBeenCalledWith('/api/app_search/log_settings', {
body: JSON.stringify({
@@ -233,7 +233,7 @@ describe('LogRetentionLogic', () => {
const promise = Promise.reject('An error occured');
http.put.mockReturnValue(promise);
- LogRetentionLogic.actions.saveLogRetention(ELogRetentionOptions.Analytics, true);
+ LogRetentionLogic.actions.saveLogRetention(LogRetentionOptions.Analytics, true);
try {
await promise;
@@ -252,7 +252,7 @@ describe('LogRetentionLogic', () => {
isLogRetentionUpdating: false,
});
- LogRetentionLogic.actions.toggleLogRetention(ELogRetentionOptions.Analytics);
+ LogRetentionLogic.actions.toggleLogRetention(LogRetentionOptions.Analytics);
expect(LogRetentionLogic.values).toEqual({
...DEFAULT_VALUES,
@@ -264,17 +264,17 @@ describe('LogRetentionLogic', () => {
it('will call setOpenedModal if already enabled', () => {
mount({
logRetention: {
- [ELogRetentionOptions.Analytics]: {
+ [LogRetentionOptions.Analytics]: {
enabled: true,
},
},
});
jest.spyOn(LogRetentionLogic.actions, 'setOpenedModal');
- LogRetentionLogic.actions.toggleLogRetention(ELogRetentionOptions.Analytics);
+ LogRetentionLogic.actions.toggleLogRetention(LogRetentionOptions.Analytics);
expect(LogRetentionLogic.actions.setOpenedModal).toHaveBeenCalledWith(
- ELogRetentionOptions.Analytics
+ LogRetentionOptions.Analytics
);
});
});
@@ -337,17 +337,17 @@ describe('LogRetentionLogic', () => {
it('will call saveLogRetention if NOT already enabled', () => {
mount({
logRetention: {
- [ELogRetentionOptions.Analytics]: {
+ [LogRetentionOptions.Analytics]: {
enabled: false,
},
},
});
jest.spyOn(LogRetentionLogic.actions, 'saveLogRetention');
- LogRetentionLogic.actions.toggleLogRetention(ELogRetentionOptions.Analytics);
+ LogRetentionLogic.actions.toggleLogRetention(LogRetentionOptions.Analytics);
expect(LogRetentionLogic.actions.saveLogRetention).toHaveBeenCalledWith(
- ELogRetentionOptions.Analytics,
+ LogRetentionOptions.Analytics,
true
);
});
@@ -359,7 +359,7 @@ describe('LogRetentionLogic', () => {
jest.spyOn(LogRetentionLogic.actions, 'saveLogRetention');
jest.spyOn(LogRetentionLogic.actions, 'setOpenedModal');
- LogRetentionLogic.actions.toggleLogRetention(ELogRetentionOptions.API);
+ LogRetentionLogic.actions.toggleLogRetention(LogRetentionOptions.API);
expect(LogRetentionLogic.actions.saveLogRetention).not.toHaveBeenCalled();
expect(LogRetentionLogic.actions.setOpenedModal).not.toHaveBeenCalled();
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_logic.ts
index 28830f2edb1d9..31fc41213492d 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_logic.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_logic.ts
@@ -6,31 +6,31 @@
import { kea, MakeLogicType } from 'kea';
-import { ELogRetentionOptions, ILogRetention, ILogRetentionServer } from './types';
+import { LogRetentionOptions, LogRetention, LogRetentionServer } from './types';
import { HttpLogic } from '../../../../shared/http';
import { flashAPIErrors } from '../../../../shared/flash_messages';
import { convertLogRetentionFromServerToClient } from './utils/convert_log_retention';
-interface ILogRetentionActions {
+interface LogRetentionActions {
clearLogRetentionUpdating(): { value: boolean };
closeModals(): { value: boolean };
fetchLogRetention(): { value: boolean };
saveLogRetention(
- option: ELogRetentionOptions,
+ option: LogRetentionOptions,
enabled: boolean
- ): { option: ELogRetentionOptions; enabled: boolean };
- setOpenedModal(option: ELogRetentionOptions): { option: ELogRetentionOptions };
- toggleLogRetention(option: ELogRetentionOptions): { option: ELogRetentionOptions };
- updateLogRetention(logRetention: ILogRetention): { logRetention: ILogRetention };
+ ): { option: LogRetentionOptions; enabled: boolean };
+ setOpenedModal(option: LogRetentionOptions): { option: LogRetentionOptions };
+ toggleLogRetention(option: LogRetentionOptions): { option: LogRetentionOptions };
+ updateLogRetention(logRetention: LogRetention): { logRetention: LogRetention };
}
-interface ILogRetentionValues {
- logRetention: ILogRetention | null;
+interface LogRetentionValues {
+ logRetention: LogRetention | null;
isLogRetentionUpdating: boolean;
- openedModal: ELogRetentionOptions | null;
+ openedModal: LogRetentionOptions | null;
}
-export const LogRetentionLogic = kea>({
+export const LogRetentionLogic = kea>({
path: ['enterprise_search', 'app_search', 'log_retention_logic'],
actions: () => ({
clearLogRetentionUpdating: true,
@@ -72,7 +72,7 @@ export const LogRetentionLogic = kea', () => {
+ const actions = {
+ fetchLogRetention: jest.fn(),
+ toggleLogRetention: jest.fn(),
+ };
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ setMockActions(actions);
+ });
+
+ it('renders', () => {
+ const logRetentionPanel = shallow();
+ expect(logRetentionPanel.find('[data-test-subj="LogRetentionPanel"]')).toHaveLength(1);
+ });
+
+ it('initializes data on mount', () => {
+ shallow();
+ expect(actions.fetchLogRetention).toHaveBeenCalledTimes(1);
+ });
+
+ it('renders Analytics switch off when analytics log retention is false in LogRetentionLogic ', () => {
+ setMockValues({
+ isLogRetentionUpdating: false,
+ logRetention: mockLogRetention({
+ analytics: {
+ enabled: false,
+ },
+ }),
+ });
+
+ const logRetentionPanel = shallow();
+ expect(
+ logRetentionPanel.find('[data-test-subj="LogRetentionPanelAnalyticsSwitch"]').prop('checked')
+ ).toEqual(false);
+ });
+
+ it('renders Analytics switch on when analyticsLogRetention is true in LogRetentionLogic ', () => {
+ setMockValues({
+ isLogRetentionUpdating: false,
+ logRetention: mockLogRetention({
+ analytics: {
+ enabled: true,
+ },
+ }),
+ });
+
+ const logRetentionPanel = shallow();
+ expect(
+ logRetentionPanel.find('[data-test-subj="LogRetentionPanelAnalyticsSwitch"]').prop('checked')
+ ).toEqual(true);
+ });
+
+ it('renders API switch off when apiLogRetention is false in LogRetentionLogic ', () => {
+ setMockValues({
+ isLogRetentionUpdating: false,
+ logRetention: mockLogRetention({
+ api: {
+ enabled: false,
+ },
+ }),
+ });
+
+ const logRetentionPanel = shallow();
+ expect(
+ logRetentionPanel.find('[data-test-subj="LogRetentionPanelAPISwitch"]').prop('checked')
+ ).toEqual(false);
+ });
+
+ it('renders API switch on when apiLogRetention is true in LogRetentionLogic ', () => {
+ setMockValues({
+ isLogRetentionUpdating: false,
+ logRetention: mockLogRetention({
+ api: {
+ enabled: true,
+ },
+ }),
+ });
+
+ const logRetentionPanel = shallow();
+ expect(
+ logRetentionPanel.find('[data-test-subj="LogRetentionPanelAPISwitch"]').prop('checked')
+ ).toEqual(true);
+ });
+
+ it('enables both switches when isLogRetentionUpdating is false', () => {
+ setMockValues({
+ isLogRetentionUpdating: false,
+ logRetention: mockLogRetention({}),
+ });
+ const logRetentionPanel = shallow();
+ expect(
+ logRetentionPanel.find('[data-test-subj="LogRetentionPanelAnalyticsSwitch"]').prop('disabled')
+ ).toEqual(false);
+ expect(
+ logRetentionPanel.find('[data-test-subj="LogRetentionPanelAPISwitch"]').prop('disabled')
+ ).toEqual(false);
+ });
+
+ it('disables both switches when isLogRetentionUpdating is true', () => {
+ setMockValues({
+ isLogRetentionUpdating: true,
+ logRetention: mockLogRetention({}),
+ });
+ const logRetentionPanel = shallow();
+
+ expect(
+ logRetentionPanel.find('[data-test-subj="LogRetentionPanelAnalyticsSwitch"]').prop('disabled')
+ ).toEqual(true);
+ expect(
+ logRetentionPanel.find('[data-test-subj="LogRetentionPanelAPISwitch"]').prop('disabled')
+ ).toEqual(true);
+ });
+
+ it('calls toggleLogRetention when analytics log retention option is changed', () => {
+ setMockValues({
+ isLogRetentionUpdating: false,
+ logRetention: mockLogRetention({
+ analytics: {
+ enabled: false,
+ },
+ }),
+ });
+ const logRetentionPanel = shallow();
+ logRetentionPanel
+ .find('[data-test-subj="LogRetentionPanelAnalyticsSwitch"]')
+ .simulate('change');
+ expect(actions.toggleLogRetention).toHaveBeenCalledWith('analytics');
+ });
+
+ it('calls toggleLogRetention when api log retention option is changed', () => {
+ setMockValues({
+ isLogRetentionUpdating: false,
+ logRetention: mockLogRetention({
+ analytics: {
+ enabled: false,
+ },
+ }),
+ });
+ const logRetentionPanel = shallow();
+ logRetentionPanel.find('[data-test-subj="LogRetentionPanelAPISwitch"]').simulate('change');
+ expect(actions.toggleLogRetention).toHaveBeenCalledWith('api');
+ });
+});
+
+const mockLogRetention = (logRetention: Partial) => {
+ const baseLogRetention = {
+ analytics: {
+ disabledAt: null,
+ enabled: true,
+ retentionPolicy: { isDefault: true, minAgeDays: 180 },
+ },
+ api: {
+ disabledAt: null,
+ enabled: true,
+ retentionPolicy: { isDefault: true, minAgeDays: 180 },
+ },
+ };
+
+ return {
+ analytics: {
+ ...baseLogRetention.analytics,
+ ...logRetention.analytics,
+ },
+ api: {
+ ...baseLogRetention.api,
+ ...logRetention.api,
+ },
+ };
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_panel.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_panel.tsx
new file mode 100644
index 0000000000000..23572074b3c69
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_panel.tsx
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+import React, { useEffect } from 'react';
+import { i18n } from '@kbn/i18n';
+
+import { EuiLink, EuiSpacer, EuiSwitch, EuiText, EuiTextColor, EuiTitle } from '@elastic/eui';
+import { useActions, useValues } from 'kea';
+
+import { LogRetentionLogic } from './log_retention_logic';
+import { AnalyticsLogRetentionMessage, ApiLogRetentionMessage } from './messaging';
+import { LogRetentionOptions } from './types';
+
+export const LogRetentionPanel: React.FC = () => {
+ const { toggleLogRetention, fetchLogRetention } = useActions(LogRetentionLogic);
+
+ const { logRetention, isLogRetentionUpdating } = useValues(LogRetentionLogic);
+
+ const hasILM = logRetention !== null;
+ const analyticsLogRetentionSettings = logRetention?.[LogRetentionOptions.Analytics];
+ const apiLogRetentionSettings = logRetention?.[LogRetentionOptions.API];
+
+ useEffect(() => {
+ fetchLogRetention();
+ }, []);
+
+ return (
+
+
+
+ {i18n.translate('xpack.enterpriseSearch.appSearch.settings.logRetention.title', {
+ defaultMessage: 'Log Retention',
+ })}
+
+
+
+
+ {i18n.translate('xpack.enterpriseSearch.appSearch.settings.logRetention.description', {
+ defaultMessage: 'Manage the default write settings for API Logs and Analytics.',
+ })}{' '}
+
+ {i18n.translate('xpack.enterpriseSearch.appSearch.settings.logRetention.learnMore', {
+ defaultMessage: 'Learn more about retention settings.',
+ })}
+
+
+
+
+
+
+
+ {i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.analytics.label',
+ {
+ defaultMessage: 'Analytics Logs',
+ }
+ )}
+
+ {': '}
+ {hasILM && (
+
+
+
+ )}
+ >
+ }
+ checked={!!analyticsLogRetentionSettings?.enabled}
+ onChange={() => toggleLogRetention(LogRetentionOptions.Analytics)}
+ disabled={isLogRetentionUpdating}
+ data-test-subj="LogRetentionPanelAnalyticsSwitch"
+ />
+
+
+
+
+
+ {i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.api.label',
+ {
+ defaultMessage: 'API Logs',
+ }
+ )}
+
+ {': '}
+ {hasILM && (
+
+
+
+ )}
+ >
+ }
+ checked={!!apiLogRetentionSettings?.enabled}
+ onChange={() => toggleLogRetention(LogRetentionOptions.API)}
+ disabled={isLogRetentionUpdating}
+ data-test-subj="LogRetentionPanelAPISwitch"
+ />
+
+
+ );
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/constants.ts
new file mode 100644
index 0000000000000..6db087e092697
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/constants.ts
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+import { i18n } from '@kbn/i18n';
+
+import { LogRetentionMessages } from './types';
+import { renderLogRetentionDate } from '.';
+
+const ANALYTICS_NO_LOGGING = i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.analytics.noLogging',
+ {
+ defaultMessage: 'Analytics collection has been disabled for all engines.',
+ }
+);
+
+const ANALYTICS_NO_LOGGING_COLLECTED = (disabledAt: string) =>
+ i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.analytics.noLogging.collected',
+ {
+ defaultMessage: 'The last date analytics were collected was {disabledAt}.',
+ values: { disabledAt },
+ }
+ );
+
+const ANALYTICS_NO_LOGGING_NOT_COLLECTED = i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.analytics.noLogging.notCollected',
+ {
+ defaultMessage: 'There are no analytics collected.',
+ }
+);
+
+const ANALYTICS_ILM_DISABLED = i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.analytics.ilmDisabled',
+ {
+ defaultMessage: "App Search isn't managing analytics retention.",
+ }
+);
+
+const ANALYTICS_CUSTOM_POLICY = i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.analytics.customPolicy',
+ {
+ defaultMessage: 'You have a custom analytics retention policy.',
+ }
+);
+
+const ANALYTICS_STORED = (minAgeDays: number | null | undefined) =>
+ i18n.translate('xpack.enterpriseSearch.appSearch.settings.logRetention.analytics.stored', {
+ defaultMessage: 'Your analytics are being stored for at least {minAgeDays} days.',
+ values: { minAgeDays },
+ });
+
+const API_NO_LOGGING = i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.api.noLogging',
+ {
+ defaultMessage: 'API logging has been disabled for all engines.',
+ }
+);
+
+const API_NO_LOGGING_COLLECTED = (disabledAt: string) =>
+ i18n.translate('xpack.enterpriseSearch.appSearch.settings.logRetention.api.noLogging.collected', {
+ defaultMessage: 'The last date logs were collected was {disabledAt}.',
+ values: { disabledAt },
+ });
+
+const API_NO_LOGGING_NOT_COLLECTED = i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.api.noLogging.notCollected',
+ {
+ defaultMessage: 'There are no logs collected.',
+ }
+);
+
+const API_ILM_DISABLED = i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.api.ilmDisabled',
+ {
+ defaultMessage: "App Search isn't managing API log retention.",
+ }
+);
+
+const API_CUSTOM_POLICY = i18n.translate(
+ 'xpack.enterpriseSearch.appSearch.settings.logRetention.api.customPolicy',
+ {
+ defaultMessage: 'You have a custom API log retention policy.',
+ }
+);
+
+const API_STORED = (minAgeDays: number | null | undefined) =>
+ i18n.translate('xpack.enterpriseSearch.appSearch.settings.logRetention.api.stored', {
+ defaultMessage: 'Your logs are being stored for at least {minAgeDays} days.',
+ values: { minAgeDays },
+ });
+
+export const ANALYTICS_MESSAGES: LogRetentionMessages = {
+ noLogging: (_, logRetentionSettings) =>
+ `${ANALYTICS_NO_LOGGING} ${
+ logRetentionSettings.disabledAt
+ ? ANALYTICS_NO_LOGGING_COLLECTED(renderLogRetentionDate(logRetentionSettings.disabledAt))
+ : ANALYTICS_NO_LOGGING_NOT_COLLECTED
+ }`,
+ ilmDisabled: ANALYTICS_ILM_DISABLED,
+ customPolicy: ANALYTICS_CUSTOM_POLICY,
+ defaultPolicy: (_, logRetentionSettings) =>
+ ANALYTICS_STORED(logRetentionSettings.retentionPolicy?.minAgeDays),
+};
+
+export const API_MESSAGES: LogRetentionMessages = {
+ noLogging: (_, logRetentionSettings) =>
+ `${API_NO_LOGGING} ${
+ logRetentionSettings.disabledAt
+ ? API_NO_LOGGING_COLLECTED(renderLogRetentionDate(logRetentionSettings.disabledAt))
+ : API_NO_LOGGING_NOT_COLLECTED
+ }`,
+ ilmDisabled: API_ILM_DISABLED,
+ customPolicy: API_CUSTOM_POLICY,
+ defaultPolicy: (_, logRetentionSettings) =>
+ API_STORED(logRetentionSettings.retentionPolicy?.minAgeDays),
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/determine_tooltip_content.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/determine_tooltip_content.test.ts
new file mode 100644
index 0000000000000..fbc2ccfbc8a52
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/determine_tooltip_content.test.ts
@@ -0,0 +1,168 @@
+/*
+ * 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.
+ */
+
+import { determineTooltipContent } from './determine_tooltip_content';
+import { ANALYTICS_MESSAGES, API_MESSAGES } from './constants';
+
+describe('determineTooltipContent', () => {
+ const BASE_SETTINGS = {
+ disabledAt: null,
+ enabled: true,
+ retentionPolicy: null,
+ };
+
+ it('will return nothing if settings are not provided', () => {
+ expect(determineTooltipContent(ANALYTICS_MESSAGES, true)).toBeUndefined();
+ });
+
+ describe('analytics messages', () => {
+ describe('when analytics logs are enabled', () => {
+ describe("and they're using the default policy", () => {
+ it('will render a retention policy message', () => {
+ expect(
+ determineTooltipContent(ANALYTICS_MESSAGES, true, {
+ ...BASE_SETTINGS,
+ enabled: true,
+ retentionPolicy: {
+ isDefault: true,
+ minAgeDays: 7,
+ },
+ })
+ ).toEqual('Your analytics are being stored for at least 7 days.');
+ });
+ });
+
+ describe('and there is a custom policy', () => {
+ it('will render a retention policy message', () => {
+ expect(
+ determineTooltipContent(ANALYTICS_MESSAGES, true, {
+ ...BASE_SETTINGS,
+ enabled: true,
+ retentionPolicy: {
+ isDefault: false,
+ minAgeDays: 7,
+ },
+ })
+ ).toEqual('You have a custom analytics retention policy.');
+ });
+ });
+ });
+
+ describe('when analytics logs are disabled', () => {
+ describe('and there is no disabledAt date', () => {
+ it('will render a no logging message', () => {
+ expect(
+ determineTooltipContent(ANALYTICS_MESSAGES, true, {
+ ...BASE_SETTINGS,
+ enabled: false,
+ disabledAt: null,
+ })
+ ).toEqual(
+ 'Analytics collection has been disabled for all engines. There are no analytics collected.'
+ );
+ });
+ });
+
+ describe('and there is a disabledAt date', () => {
+ it('will render a no logging message', () => {
+ expect(
+ determineTooltipContent(ANALYTICS_MESSAGES, true, {
+ ...BASE_SETTINGS,
+ enabled: false,
+ disabledAt: 'Thu, 05 Nov 2020 18:57:28 +0000',
+ })
+ ).toEqual(
+ 'Analytics collection has been disabled for all engines. The last date analytics were collected was November 5, 2020.'
+ );
+ });
+ });
+ });
+
+ describe('when ilm is disabled entirely', () => {
+ it('will render a no logging message', () => {
+ expect(
+ determineTooltipContent(ANALYTICS_MESSAGES, false, {
+ ...BASE_SETTINGS,
+ enabled: true,
+ })
+ ).toEqual("App Search isn't managing analytics retention.");
+ });
+ });
+ });
+
+ describe('api messages', () => {
+ describe('when analytics logs are enabled', () => {
+ describe("and they're using the default policy", () => {
+ it('will render a retention policy message', () => {
+ expect(
+ determineTooltipContent(API_MESSAGES, true, {
+ ...BASE_SETTINGS,
+ enabled: true,
+ retentionPolicy: {
+ isDefault: true,
+ minAgeDays: 7,
+ },
+ })
+ ).toEqual('Your logs are being stored for at least 7 days.');
+ });
+ });
+
+ describe('and there is a custom policy', () => {
+ it('will render a retention policy message', () => {
+ expect(
+ determineTooltipContent(API_MESSAGES, true, {
+ ...BASE_SETTINGS,
+ enabled: true,
+ retentionPolicy: {
+ isDefault: false,
+ minAgeDays: 7,
+ },
+ })
+ ).toEqual('You have a custom API log retention policy.');
+ });
+ });
+ });
+
+ describe('when analytics logs are disabled', () => {
+ describe('and there is no disabledAt date', () => {
+ it('will render a no logging message', () => {
+ expect(
+ determineTooltipContent(API_MESSAGES, true, {
+ ...BASE_SETTINGS,
+ enabled: false,
+ disabledAt: null,
+ })
+ ).toEqual('API logging has been disabled for all engines. There are no logs collected.');
+ });
+ });
+
+ describe('and there is a disabledAt date', () => {
+ it('will render a no logging message', () => {
+ expect(
+ determineTooltipContent(API_MESSAGES, true, {
+ ...BASE_SETTINGS,
+ enabled: false,
+ disabledAt: 'Thu, 05 Nov 2020 18:57:28 +0000',
+ })
+ ).toEqual(
+ 'API logging has been disabled for all engines. The last date logs were collected was November 5, 2020.'
+ );
+ });
+ });
+ });
+
+ describe('when ilm is disabled entirely', () => {
+ it('will render a no logging message', () => {
+ expect(
+ determineTooltipContent(API_MESSAGES, false, {
+ ...BASE_SETTINGS,
+ enabled: true,
+ })
+ ).toEqual("App Search isn't managing API log retention.");
+ });
+ });
+ });
+});
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/determine_tooltip_content.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/determine_tooltip_content.ts
new file mode 100644
index 0000000000000..385831dc511da
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/determine_tooltip_content.ts
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+import { LogRetentionSettings } from '../types';
+import { TMessageStringOrFunction, LogRetentionMessages } from './types';
+
+export const determineTooltipContent = (
+ messages: LogRetentionMessages,
+ ilmEnabled: boolean,
+ logRetentionSettings?: LogRetentionSettings
+) => {
+ if (typeof logRetentionSettings === 'undefined') {
+ return;
+ }
+
+ const renderOrReturnMessage = (message: TMessageStringOrFunction) => {
+ if (typeof message === 'function') {
+ return message(ilmEnabled, logRetentionSettings);
+ }
+ return message;
+ };
+
+ if (!logRetentionSettings.enabled) {
+ return renderOrReturnMessage(messages.noLogging);
+ }
+ if (logRetentionSettings.enabled && !ilmEnabled) {
+ return renderOrReturnMessage(messages.ilmDisabled);
+ }
+ if (
+ logRetentionSettings.enabled &&
+ ilmEnabled &&
+ !logRetentionSettings.retentionPolicy?.isDefault
+ ) {
+ return renderOrReturnMessage(messages.customPolicy);
+ }
+ if (
+ logRetentionSettings.enabled &&
+ ilmEnabled &&
+ logRetentionSettings.retentionPolicy?.isDefault
+ ) {
+ return renderOrReturnMessage(messages.defaultPolicy);
+ }
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/index.test.tsx
new file mode 100644
index 0000000000000..b65ffc04ad700
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/index.test.tsx
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+import '../../../../../__mocks__/kea.mock';
+import { setMockValues } from '../../../../../__mocks__';
+
+import React from 'react';
+import { shallow } from 'enzyme';
+
+import { AnalyticsLogRetentionMessage, ApiLogRetentionMessage, renderLogRetentionDate } from '.';
+
+describe('LogRetentionMessaging', () => {
+ const LOG_RETENTION = {
+ analytics: {
+ disabledAt: null,
+ enabled: true,
+ retentionPolicy: { isDefault: true, minAgeDays: 180 },
+ },
+ api: {
+ disabledAt: null,
+ enabled: true,
+ retentionPolicy: { isDefault: true, minAgeDays: 180 },
+ },
+ };
+
+ describe('renderLogRetentionDate', () => {
+ it('renders a formatted date', () => {
+ expect(renderLogRetentionDate('Thu, 05 Nov 2020 18:57:28 +0000')).toEqual('November 5, 2020');
+ });
+ });
+
+ describe('AnalyticsLogRetentionMessage', () => {
+ it('renders', () => {
+ setMockValues({
+ ilmEnabled: true,
+ logRetention: LOG_RETENTION,
+ });
+ const wrapper = shallow();
+ expect(wrapper.text()).toEqual('Your analytics are being stored for at least 180 days.');
+ });
+
+ it('renders nothing if logRetention is null', () => {
+ setMockValues({
+ ilmEnabled: true,
+ logRetention: null,
+ });
+ const wrapper = shallow();
+ expect(wrapper.isEmptyRender()).toEqual(true);
+ });
+ });
+
+ describe('ApiLogRetentionMessage', () => {
+ it('renders', () => {
+ setMockValues({
+ ilmEnabled: true,
+ logRetention: LOG_RETENTION,
+ });
+ const wrapper = shallow();
+ expect(wrapper.text()).toEqual('Your logs are being stored for at least 180 days.');
+ });
+
+ it('renders nothing if logRetention is null', () => {
+ setMockValues({
+ ilmEnabled: true,
+ logRetention: null,
+ });
+ const wrapper = shallow();
+ expect(wrapper.isEmptyRender()).toEqual(true);
+ });
+ });
+});
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/index.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/index.tsx
new file mode 100644
index 0000000000000..21267738f61ad
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/index.tsx
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+import React from 'react';
+
+import { useValues } from 'kea';
+import moment from 'moment';
+
+import { AppLogic } from '../../../../app_logic';
+import { LogRetentionLogic } from '../log_retention_logic';
+import { LogRetentionOptions } from '../types';
+
+import { determineTooltipContent } from './determine_tooltip_content';
+import { ANALYTICS_MESSAGES, API_MESSAGES } from './constants';
+
+export const renderLogRetentionDate = (dateString: string) =>
+ moment(dateString).format('MMMM D, YYYY');
+
+export const AnalyticsLogRetentionMessage: React.FC = () => {
+ const { ilmEnabled } = useValues(AppLogic);
+ const { logRetention } = useValues(LogRetentionLogic);
+ if (!logRetention) return null;
+
+ return (
+ <>
+ {determineTooltipContent(
+ ANALYTICS_MESSAGES,
+ ilmEnabled,
+ logRetention[LogRetentionOptions.Analytics]
+ )}
+ >
+ );
+};
+
+export const ApiLogRetentionMessage: React.FC = () => {
+ const { ilmEnabled } = useValues(AppLogic);
+ const { logRetention } = useValues(LogRetentionLogic);
+ if (!logRetention) return null;
+
+ return (
+ <>{determineTooltipContent(API_MESSAGES, ilmEnabled, logRetention[LogRetentionOptions.API])}>
+ );
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/types.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/types.ts
new file mode 100644
index 0000000000000..8f86e397dfe26
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/messaging/types.ts
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+import { LogRetentionSettings } from '../types';
+
+export type TMessageStringOrFunction =
+ | string
+ | ((ilmEnabled: boolean, logRetentionSettings: LogRetentionSettings) => string);
+
+export interface LogRetentionMessages {
+ noLogging: TMessageStringOrFunction;
+ ilmDisabled: TMessageStringOrFunction;
+ customPolicy: TMessageStringOrFunction;
+ defaultPolicy: TMessageStringOrFunction;
+}
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/types.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/types.ts
index 7d4f30f88f38f..f802efc72ac4d 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/types.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/types.ts
@@ -4,39 +4,39 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export enum ELogRetentionOptions {
+export enum LogRetentionOptions {
Analytics = 'analytics',
API = 'api',
}
-export interface ILogRetention {
- [ELogRetentionOptions.Analytics]: ILogRetentionSettings;
- [ELogRetentionOptions.API]: ILogRetentionSettings;
+export interface LogRetention {
+ [LogRetentionOptions.Analytics]: LogRetentionSettings;
+ [LogRetentionOptions.API]: LogRetentionSettings;
}
-export interface ILogRetentionPolicy {
+export interface LogRetentionPolicy {
isDefault: boolean;
minAgeDays: number | null;
}
-export interface ILogRetentionSettings {
+export interface LogRetentionSettings {
disabledAt?: string | null;
enabled?: boolean;
- retentionPolicy?: ILogRetentionPolicy | null;
+ retentionPolicy?: LogRetentionPolicy | null;
}
-export interface ILogRetentionServer {
- [ELogRetentionOptions.Analytics]: ILogRetentionServerSettings;
- [ELogRetentionOptions.API]: ILogRetentionServerSettings;
+export interface LogRetentionServer {
+ [LogRetentionOptions.Analytics]: LogRetentionServerSettings;
+ [LogRetentionOptions.API]: LogRetentionServerSettings;
}
-export interface ILogRetentionServerPolicy {
+export interface LogRetentionServerPolicy {
is_default: boolean;
min_age_days: number | null;
}
-export interface ILogRetentionServerSettings {
+export interface LogRetentionServerSettings {
disabled_at: string | null;
enabled: boolean;
- retention_policy: ILogRetentionServerPolicy | null;
+ retention_policy: LogRetentionServerPolicy | null;
}
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/utils/convert_log_retention.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/utils/convert_log_retention.ts
index 1c0818fc286f2..f960bb8f193b4 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/utils/convert_log_retention.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/utils/convert_log_retention.ts
@@ -5,23 +5,23 @@
*/
import {
- ELogRetentionOptions,
- ILogRetention,
- ILogRetentionPolicy,
- ILogRetentionServer,
- ILogRetentionServerPolicy,
- ILogRetentionServerSettings,
- ILogRetentionSettings,
+ LogRetentionOptions,
+ LogRetention,
+ LogRetentionPolicy,
+ LogRetentionServer,
+ LogRetentionServerPolicy,
+ LogRetentionServerSettings,
+ LogRetentionSettings,
} from '../types';
export const convertLogRetentionFromServerToClient = (
- logRetention: ILogRetentionServer
-): ILogRetention => ({
- [ELogRetentionOptions.Analytics]: convertLogRetentionSettingsFromServerToClient(
- logRetention[ELogRetentionOptions.Analytics]
+ logRetention: LogRetentionServer
+): LogRetention => ({
+ [LogRetentionOptions.Analytics]: convertLogRetentionSettingsFromServerToClient(
+ logRetention[LogRetentionOptions.Analytics]
),
- [ELogRetentionOptions.API]: convertLogRetentionSettingsFromServerToClient(
- logRetention[ELogRetentionOptions.API]
+ [LogRetentionOptions.API]: convertLogRetentionSettingsFromServerToClient(
+ logRetention[LogRetentionOptions.API]
),
});
@@ -29,7 +29,7 @@ const convertLogRetentionSettingsFromServerToClient = ({
disabled_at: disabledAt,
enabled,
retention_policy: retentionPolicy,
-}: ILogRetentionServerSettings): ILogRetentionSettings => ({
+}: LogRetentionServerSettings): LogRetentionSettings => ({
disabledAt,
enabled,
retentionPolicy:
@@ -39,7 +39,7 @@ const convertLogRetentionSettingsFromServerToClient = ({
const convertLogRetentionPolicyFromServerToClient = ({
min_age_days: minAgeDays,
is_default: isDefault,
-}: ILogRetentionServerPolicy): ILogRetentionPolicy => ({
+}: LogRetentionServerPolicy): LogRetentionPolicy => ({
isDefault,
minAgeDays,
});
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/settings.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/settings.tsx
index e5e86f3e39734..dbd6627a3b9ce 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/settings.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/settings.tsx
@@ -6,36 +6,39 @@
import React from 'react';
-import { i18n } from '@kbn/i18n';
-import { EuiPageHeader, EuiPageHeaderSection, EuiPageContentBody, EuiTitle } from '@elastic/eui';
+import {
+ EuiPageHeader,
+ EuiPageHeaderSection,
+ EuiPageContent,
+ EuiPageContentBody,
+ EuiTitle,
+} from '@elastic/eui';
import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome';
import { FlashMessages } from '../../../shared/flash_messages';
+import { LogRetentionPanel } from './log_retention/log_retention_panel';
+import { LogRetentionConfirmationModal } from './log_retention/log_retention_confirmation_modal';
+
+import { SETTINGS_TITLE } from './';
export const Settings: React.FC = () => {
return (
<>
-
+
-
- {i18n.translate('xpack.enterpriseSearch.appSearch.settings.title', {
- defaultMessage: 'Settings',
- })}
-
+ {SETTINGS_TITLE}
-
-
-
+
+
+
+
+
+
+
>
);
};
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx
index 700b903efe59b..11387734e9f9e 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx
@@ -16,7 +16,7 @@ import { shallow } from 'enzyme';
import { Layout, SideNav, SideNavLink } from '../shared/layout';
import { SetupGuide } from './components/setup_guide';
import { ErrorConnecting } from './components/error_connecting';
-import { EngineOverview } from './components/engine_overview';
+import { EnginesOverview } from './components/engines';
import { EngineRouter } from './components/engine';
import { AppSearch, AppSearchUnconfigured, AppSearchConfigured, AppSearchNav } from './';
@@ -57,7 +57,7 @@ describe('AppSearchConfigured', () => {
expect(wrapper.find(Layout)).toHaveLength(2);
expect(wrapper.find(Layout).last().prop('readOnlyMode')).toBeFalsy();
- expect(wrapper.find(EngineOverview)).toHaveLength(1);
+ expect(wrapper.find(EnginesOverview)).toHaveLength(1);
expect(wrapper.find(EngineRouter)).toHaveLength(1);
});
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 f32b0b256b898..743cf63fb4bc3 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
@@ -8,13 +8,11 @@ import React, { useEffect } from 'react';
import { Route, Redirect, Switch } from 'react-router-dom';
import { useActions, useValues } from 'kea';
-import { i18n } from '@kbn/i18n';
-
import { getAppSearchUrl } from '../shared/enterprise_search_url';
import { KibanaLogic } from '../shared/kibana';
import { HttpLogic } from '../shared/http';
import { AppLogic } from './app_logic';
-import { IInitialAppData } from '../../../common/types';
+import { InitialAppData } from '../../../common/types';
import { APP_SEARCH_PLUGIN } from '../../../common/constants';
import { Layout, SideNav, SideNavLink } from '../shared/layout';
@@ -33,11 +31,12 @@ import {
import { SetupGuide } from './components/setup_guide';
import { ErrorConnecting } from './components/error_connecting';
import { NotFound } from '../shared/not_found';
-import { EngineOverview } from './components/engine_overview';
-import { Settings } from './components/settings';
-import { Credentials } from './components/credentials';
+import { EnginesOverview, ENGINES_TITLE } from './components/engines';
+import { Settings, SETTINGS_TITLE } from './components/settings';
+import { Credentials, CREDENTIALS_TITLE } from './components/credentials';
+import { ROLE_MAPPINGS_TITLE } from './components/role_mappings';
-export const AppSearch: React.FC = (props) => {
+export const AppSearch: React.FC = (props) => {
const { config } = useValues(KibanaLogic);
return !config.host ? : ;
};
@@ -53,7 +52,7 @@ export const AppSearchUnconfigured: React.FC = () => (
);
-export const AppSearchConfigured: React.FC = (props) => {
+export const AppSearchConfigured: React.FC = (props) => {
const { initializeAppData } = useActions(AppLogic);
const { hasInitialized } = useValues(AppLogic);
const { errorConnecting, readOnlyMode } = useValues(HttpLogic);
@@ -82,7 +81,7 @@ export const AppSearchConfigured: React.FC = (props) => {
-
+
@@ -101,11 +100,11 @@ export const AppSearchConfigured: React.FC = (props) => {
);
};
-interface IAppSearchNavProps {
+interface AppSearchNavProps {
subNav?: React.ReactNode;
}
-export const AppSearchNav: React.FC = ({ subNav }) => {
+export const AppSearchNav: React.FC = ({ subNav }) => {
const {
myRole: { canViewSettings, canViewAccountCredentials, canViewRoleMappings },
} = useValues(AppLogic);
@@ -113,29 +112,15 @@ export const AppSearchNav: React.FC = ({ subNav }) => {
return (