diff --git a/.backportrc.json b/.backportrc.json index 89eefb2e3c442..24e08d4768d9a 100644 --- a/.backportrc.json +++ b/.backportrc.json @@ -2,6 +2,7 @@ "upstream": "elastic/kibana", "targetBranchChoices": [ { "name": "master", "checked": true }, + "8.0", "7.16", "7.15", "7.14", @@ -32,7 +33,7 @@ ], "targetPRLabels": ["backport"], "branchLabelMapping": { - "^v8.0.0$": "master", + "^v8.1.0$": "master", "^v(\\d+).(\\d+).\\d+$": "$1.$2" }, "autoMerge": true, diff --git a/.buildkite/pipelines/hourly.yml b/.buildkite/pipelines/hourly.yml index 3337cfb5dfcdd..b03a46b5b5c66 100644 --- a/.buildkite/pipelines/hourly.yml +++ b/.buildkite/pipelines/hourly.yml @@ -21,7 +21,7 @@ steps: agents: queue: ci-group-6 depends_on: build - timeout_in_minutes: 150 + timeout_in_minutes: 250 key: default-cigroup retry: automatic: diff --git a/.buildkite/scripts/pipelines/pull_request/pipeline.js b/.buildkite/scripts/pipelines/pull_request/pipeline.js index 02d6fc270ddb0..c5ed216042b68 100644 --- a/.buildkite/scripts/pipelines/pull_request/pipeline.js +++ b/.buildkite/scripts/pipelines/pull_request/pipeline.js @@ -57,6 +57,9 @@ const uploadPipeline = (pipelineContent) => { if ( (await doAnyChangesMatch([ /^x-pack\/plugins\/security_solution/, + /^x-pack\/plugins\/cases/, + /^x-pack\/plugins\/lists/, + /^x-pack\/plugins\/timelines/, /^x-pack\/test\/security_solution_cypress/, /^x-pack\/plugins\/triggers_actions_ui\/public\/application\/sections\/action_connector_form/, /^x-pack\/plugins\/triggers_actions_ui\/public\/application\/context\/actions_connectors_context\.tsx/, diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000000000..31bd822640359 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,58 @@ +# Configuration for probot-stale - https://github.com/probot/stale + +# Number of days of inactivity before an Issue or Pull Request becomes stale +daysUntilStale: 180 + +# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. +# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. +daysUntilClose: false + +# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) +onlyLabels: ["Team:apm"] + +# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable +exemptLabels: ["technical debt", "prevent stale"] + +# Set to true to ignore issues in a project (defaults to false) +exemptProjects: false + +# Set to true to ignore issues in a milestone (defaults to false) +exemptMilestones: false + +# Set to true to ignore issues with an assignee (defaults to false) +exemptAssignees: false + +# Label to use when marking as stale +staleLabel: stale + +# Comment to post when marking as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. + +# Comment to post when removing the stale label. +# unmarkComment: > +# Your comment here. + +# Comment to post when closing a stale Issue or Pull Request. +# closeComment: > +# Your comment here. + +# Limit the number of actions per hour, from 1-30. Default is 30 +limitPerRun: 30 + +# Limit to only `issues` or `pulls` +only: issues + +# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': +# pulls: +# daysUntilStale: 30 +# markComment: > +# This pull request has been automatically marked as stale because it has not had +# recent activity. It will be closed if no further activity occurs. Thank you +# for your contributions. + +# issues: +# exemptLabels: +# - confirmed diff --git a/dev_docs/tutorials/saved_objects.mdx b/dev_docs/tutorials/saved_objects.mdx index 29a0b60983d90..9583e195d1c82 100644 --- a/dev_docs/tutorials/saved_objects.mdx +++ b/dev_docs/tutorials/saved_objects.mdx @@ -254,4 +254,4 @@ the error should be verbose and informative so that the corrupt document can be ### Testing Migrations -Bugs in a migration function cause downtime for our users and therefore have a very high impact. Follow the . +Bugs in a migration function cause downtime for our users and therefore have a very high impact. Follow the . diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index 6bac5e7940dbb..f2da704760f3b 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -516,6 +516,9 @@ Enables the legacy charts library for timelion charts in Visualize. **This setting is deprecated and will not be supported as of 8.0.** Maps values to specific colors in charts using the *Compatibility* palette. +[[visualization-uselegacytimeaxis]]`visualization:useLegacyTimeAxis`:: +Enables the legacy time axis for charts in Lens, Discover, Visualize and TSVB + [[visualization-heatmap-maxbuckets]]`visualization:heatmap:maxBuckets`:: The maximum number of buckets a datasource can return. High numbers can have a negative impact on your browser rendering performance. diff --git a/docs/settings/spaces-settings.asciidoc b/docs/settings/spaces-settings.asciidoc index 5483912387cec..dd37943101145 100644 --- a/docs/settings/spaces-settings.asciidoc +++ b/docs/settings/spaces-settings.asciidoc @@ -13,7 +13,7 @@ return all spaces using a single `_search` from {es}, so you must configure this setting lower than the `index.max_result_window` in {es}. The default is `1000`. -`monitoring.cluster_alerts-allowedSpaces` {ess-icon}:: +`monitoring.cluster_alerts.allowedSpaces` {ess-icon}:: Specifies the spaces where cluster alerts are automatically generated. You must specify all spaces where you want to generate alerts, including the default space. When the default space is unspecified, {kib} is unable to generate an alert for the default space. diff --git a/package.json b/package.json index b2065ddc1d608..0e5c042e4236d 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "dashboarding" ], "private": true, - "version": "8.0.0", + "version": "8.1.0", "branch": "master", "types": "./kibana.d.ts", "tsdocMetadata": "./build/tsdoc-metadata.json", @@ -98,7 +98,7 @@ "@elastic/apm-synthtrace": "link:bazel-bin/packages/elastic-apm-synthtrace", "@elastic/apm-rum": "^5.9.1", "@elastic/apm-rum-react": "^1.3.1", - "@elastic/charts": "38.0.1", + "@elastic/charts": "38.1.0", "@elastic/datemath": "link:bazel-bin/packages/elastic-datemath", "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@^8.0.0-canary.35", "@elastic/ems-client": "8.0.0", diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index 453e5c174452d..99f9c04069b72 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -8,7 +8,7 @@ pageLoadAssetSize: console: 46091 core: 435325 crossClusterReplication: 65408 - dashboard: 186763 + dashboard: 82025 dashboardEnhanced: 65646 devTools: 38637 discover: 99999 @@ -76,7 +76,7 @@ pageLoadAssetSize: watcher: 43598 runtimeFields: 41752 stackAlerts: 29684 - presentationUtil: 94301 + presentationUtil: 84606 osquery: 107090 fileUpload: 25664 dataVisualizer: 27530 diff --git a/src/core/server/saved_objects/migrationsv2/actions/integration_tests/actions.test.ts b/src/core/server/saved_objects/migrationsv2/actions/integration_tests/actions.test.ts index 3ca3a8505338b..8cf49440f76b8 100644 --- a/src/core/server/saved_objects/migrationsv2/actions/integration_tests/actions.test.ts +++ b/src/core/server/saved_objects/migrationsv2/actions/integration_tests/actions.test.ts @@ -55,8 +55,7 @@ const { startES } = kbnTestServer.createTestServers({ }); let esServer: kbnTestServer.TestElasticsearchUtils; -// Failing: See https://github.com/elastic/kibana/issues/113697 -describe.skip('migration actions', () => { +describe('migration actions', () => { let client: ElasticsearchClient; beforeAll(async () => { @@ -1158,7 +1157,7 @@ describe.skip('migration actions', () => { it('resolves left wait_for_task_completion_timeout when the task does not complete within the timeout', async () => { const res = (await pickupUpdatedMappings( client, - 'existing_index_with_docs' + '.kibana_1' )()) as Either.Right; const task = waitForPickupUpdatedMappingsTask({ @@ -1539,7 +1538,8 @@ describe.skip('migration actions', () => { } `); }); - it('resolves left request_entity_too_large_exception when the payload is too large', async () => { + // TODO: unskip after https://github.com/elastic/kibana/issues/116111 + it.skip('resolves left request_entity_too_large_exception when the payload is too large', async () => { const newDocs = new Array(10000).fill({ _source: { title: diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/corrupt_outdated_docs.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/corrupt_outdated_docs.test.ts index 348cbe88cd8a7..ebc632f059ced 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/corrupt_outdated_docs.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/corrupt_outdated_docs.test.ts @@ -40,7 +40,7 @@ describe('migration v2 with corrupt saved object documents', () => { await new Promise((resolve) => setTimeout(resolve, 10000)); }); - it('collects corrupt saved object documents across batches', async () => { + it.skip('collects corrupt saved object documents across batches', async () => { const { startES } = kbnTestServer.createTestServers({ adjustTimeout: (t: number) => jest.setTimeout(t), settings: { diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/outdated_docs.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/outdated_docs.test.ts index 506f42cb2e402..9fd8f3884c4ae 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/outdated_docs.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/outdated_docs.test.ts @@ -41,7 +41,7 @@ describe('migration v2', () => { await new Promise((resolve) => setTimeout(resolve, 10000)); }); - it('migrates the documents to the highest version', async () => { + it.skip('migrates the documents to the highest version', async () => { const migratedIndex = `.kibana_${pkg.version}_001`; const { startES } = kbnTestServer.createTestServers({ adjustTimeout: (t: number) => jest.setTimeout(t), diff --git a/src/plugins/charts/common/index.ts b/src/plugins/charts/common/index.ts index 618466212f5bb..d06dbc73e29b1 100644 --- a/src/plugins/charts/common/index.ts +++ b/src/plugins/charts/common/index.ts @@ -7,6 +7,7 @@ */ export const COLOR_MAPPING_SETTING = 'visualization:colorMapping'; +export const LEGACY_TIME_AXIS = 'visualization:useLegacyTimeAxis'; export { CustomPaletteArguments, diff --git a/src/plugins/charts/server/plugin.ts b/src/plugins/charts/server/plugin.ts index 63b703e6b7538..c7559b525cd22 100644 --- a/src/plugins/charts/server/plugin.ts +++ b/src/plugins/charts/server/plugin.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import { schema } from '@kbn/config-schema'; import { CoreSetup, Plugin } from 'kibana/server'; -import { COLOR_MAPPING_SETTING, palette, systemPalette } from '../common'; +import { COLOR_MAPPING_SETTING, LEGACY_TIME_AXIS, palette, systemPalette } from '../common'; import { ExpressionsServerSetup } from '../../expressions/server'; interface SetupDependencies { @@ -45,6 +45,21 @@ export class ChartsServerPlugin implements Plugin { category: ['visualization'], schema: schema.string(), }, + [LEGACY_TIME_AXIS]: { + name: i18n.translate('charts.advancedSettings.visualization.useLegacyTimeAxis.name', { + defaultMessage: 'Legacy chart time axis', + }), + value: false, + description: i18n.translate( + 'charts.advancedSettings.visualization.useLegacyTimeAxis.description', + { + defaultMessage: + 'Enables the legacy time axis for charts in Lens, Discover, Visualize and TSVB', + } + ), + category: ['visualization'], + schema: schema.boolean(), + }, }); return {}; diff --git a/src/plugins/dashboard/public/application/top_nav/editor_menu.tsx b/src/plugins/dashboard/public/application/top_nav/editor_menu.tsx index effbf8ce980d7..8a46a16c1bf0c 100644 --- a/src/plugins/dashboard/public/application/top_nav/editor_menu.tsx +++ b/src/plugins/dashboard/public/application/top_nav/editor_menu.tsx @@ -231,7 +231,7 @@ export const EditorMenu = ({ dashboardContainer, createNewVisType }: Props) => { - {showViewModeToggle && ( )} - {timefield && ( = useLegacyTimeAxis + ? {} + : { strokeWidth: 0.1, stroke: isDarkMode ? 'white' : 'black' }; + const verticalAxisStyle: RecursivePartial = useLegacyTimeAxis + ? {} + : { + axisLine: { + visible: false, + }, + tickLabel: { + fontSize: 11, + }, + }; + const xAxisStyle: RecursivePartial = useLegacyTimeAxis + ? {} + : { + axisLine: { + stroke: isDarkMode ? 'lightgray' : 'darkgray', + strokeWidth: 1, + }, + tickLine: { + size: 12, + strokeWidth: 0.15, + stroke: isDarkMode ? 'white' : 'black', + padding: -10, + visible: true, + }, + tickLabel: { + fontSize: 11, + padding: 0, + alignment: { + vertical: Position.Bottom, + horizontal: Position.Left, + }, + offset: { + x: 1.5, + y: 0, + }, + }, + }; + return (
@@ -195,15 +241,19 @@ export function DiscoverHistogram({ xAxisFormatter.convert(value)} + gridLine={gridLineStyle} + style={verticalAxisStyle} /> diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts index 007d3a99cb1dd..d8d0215fd751f 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts @@ -64,6 +64,10 @@ export const stackManagementSchema: MakeSchemaFrom = { type: 'text', _meta: { description: 'Non-default value of setting.' }, }, + 'visualization:useLegacyTimeAxis': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, 'visualization:regionmap:showWarnings': { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, @@ -436,10 +440,6 @@ export const stackManagementSchema: MakeSchemaFrom = { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, }, - 'labs:canvas:byValueEmbeddable': { - type: 'boolean', - _meta: { description: 'Non-default value of setting.' }, - }, 'labs:canvas:useDataService': { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts index d35a05fe04780..9dcd2038edb9d 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts @@ -40,6 +40,7 @@ export interface UsageStats { 'visualize:enableLabs': boolean; 'visualization:heatmap:maxBuckets': number; 'visualization:colorMapping': string; + 'visualization:useLegacyTimeAxis': boolean; 'visualization:regionmap:showWarnings': boolean; 'visualization:tileMap:maxPrecision': number; 'csv:separator': string; @@ -120,7 +121,6 @@ export interface UsageStats { 'banners:textColor': string; 'banners:backgroundColor': string; 'labs:canvas:enable_ui': boolean; - 'labs:canvas:byValueEmbeddable': boolean; 'labs:canvas:useDataService': boolean; 'labs:presentation:timeToPresent': boolean; 'labs:dashboard:enable_ui': boolean; diff --git a/src/plugins/presentation_util/common/labs.ts b/src/plugins/presentation_util/common/labs.ts index 8eefbd6981280..cb976e73b5edf 100644 --- a/src/plugins/presentation_util/common/labs.ts +++ b/src/plugins/presentation_util/common/labs.ts @@ -11,9 +11,7 @@ import { i18n } from '@kbn/i18n'; export const LABS_PROJECT_PREFIX = 'labs:'; export const DEFER_BELOW_FOLD = `${LABS_PROJECT_PREFIX}dashboard:deferBelowFold` as const; export const DASHBOARD_CONTROLS = `${LABS_PROJECT_PREFIX}dashboard:dashboardControls` as const; -export const BY_VALUE_EMBEDDABLE = `${LABS_PROJECT_PREFIX}canvas:byValueEmbeddable` as const; - -export const projectIDs = [DEFER_BELOW_FOLD, DASHBOARD_CONTROLS, BY_VALUE_EMBEDDABLE] as const; +export const projectIDs = [DEFER_BELOW_FOLD, DASHBOARD_CONTROLS] as const; export const environmentNames = ['kibana', 'browser', 'session'] as const; export const solutionNames = ['canvas', 'dashboard', 'presentation'] as const; @@ -50,19 +48,6 @@ export const projects: { [ID in ProjectID]: ProjectConfig & { id: ID } } = { }), solutions: ['dashboard'], }, - [BY_VALUE_EMBEDDABLE]: { - id: BY_VALUE_EMBEDDABLE, - isActive: true, - isDisplayed: true, - environments: ['kibana', 'browser', 'session'], - name: i18n.translate('presentationUtil.labs.enableByValueEmbeddableName', { - defaultMessage: 'By-Value Embeddables', - }), - description: i18n.translate('presentationUtil.labs.enableByValueEmbeddableDescription', { - defaultMessage: 'Enables support for by-value embeddables in Canvas', - }), - solutions: ['canvas'], - }, }; export type ProjectID = typeof projectIDs[number]; diff --git a/src/plugins/presentation_util/public/components/solution_toolbar/items/quick_group.scss b/src/plugins/presentation_util/public/components/solution_toolbar/items/quick_group.scss index c70e317546d40..535570a51d777 100644 --- a/src/plugins/presentation_util/public/components/solution_toolbar/items/quick_group.scss +++ b/src/plugins/presentation_util/public/components/solution_toolbar/items/quick_group.scss @@ -1,31 +1,11 @@ .quickButtonGroup { - .euiButtonGroup__buttons { - border-radius: $euiBorderRadius; - - .quickButtonGroup__button { - background-color: $euiColorEmptyShade; - @include kbnThemeStyle('v8') { - // sass-lint:disable-block no-important - border-width: $euiBorderWidthThin !important; - border-style: solid !important; - border-color: $euiBorderColor !important; - } - } - - .quickButtonGroup__button:first-of-type { - @include kbnThemeStyle('v8') { - // sass-lint:disable-block no-important - border-top-left-radius: $euiBorderRadius !important; - border-bottom-left-radius: $euiBorderRadius !important; - } - } - - .quickButtonGroup__button:last-of-type { - @include kbnThemeStyle('v8') { - // sass-lint:disable-block no-important - border-top-right-radius: $euiBorderRadius !important; - border-bottom-right-radius: $euiBorderRadius !important; - } + .quickButtonGroup__button { + background-color: $euiColorEmptyShade; + @include kbnThemeStyle('v8') { + // sass-lint:disable-block no-important + border-width: $euiBorderWidthThin !important; + border-style: solid !important; + border-color: $euiBorderColor !important; } } } diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json index 138ce3f097ce9..251fed955788e 100644 --- a/src/plugins/telemetry/schema/oss_plugins.json +++ b/src/plugins/telemetry/schema/oss_plugins.json @@ -7110,6 +7110,12 @@ "description": "Non-default value of setting." } }, + "visualization:useLegacyTimeAxis": { + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } + }, "visualization:regionmap:showWarnings": { "type": "boolean", "_meta": { @@ -7671,12 +7677,6 @@ "description": "Non-default value of setting." } }, - "labs:canvas:byValueEmbeddable": { - "type": "boolean", - "_meta": { - "description": "Non-default value of setting." - } - }, "labs:canvas:useDataService": { "type": "boolean", "_meta": { diff --git a/src/plugins/vis_types/timeseries/public/application/components/vis_types/timeseries/vis.js b/src/plugins/vis_types/timeseries/public/application/components/vis_types/timeseries/vis.js index b4fe39c522de7..b177ef632e210 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/vis_types/timeseries/vis.js +++ b/src/plugins/vis_types/timeseries/public/application/components/vis_types/timeseries/vis.js @@ -19,6 +19,7 @@ import { createFieldFormatter } from '../../lib/create_field_formatter'; import { checkIfSeriesHaveSameFormatters } from '../../lib/check_if_series_have_same_formatters'; import { TimeSeries } from '../../../visualizations/views/timeseries'; import { MarkdownSimple } from '../../../../../../../../plugins/kibana_react/public'; +import { LEGACY_TIME_AXIS } from '../../../../../../../../plugins/charts/common'; import { replaceVars } from '../../lib/replace_vars'; import { getInterval } from '../../lib/get_interval'; import { createIntervalBasedFormatter } from '../../lib/create_interval_based_formatter'; @@ -272,6 +273,7 @@ class TimeseriesVisualization extends Component { syncColors={syncColors} palettesService={palettesService} interval={interval} + useLegacyTimeAxis={getConfig(LEGACY_TIME_AXIS, false)} isLastBucketDropped={Boolean( model.drop_last_bucket || model.series.some((series) => series.series_drop_last_bucket) diff --git a/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/index.js b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/index.js index 2158283bb80d5..5e98b74c0caa5 100644 --- a/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/index.js +++ b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/index.js @@ -72,6 +72,7 @@ export const TimeSeries = ({ palettesService, interval, isLastBucketDropped, + useLegacyTimeAxis, }) => { // If the color isn't configured by the user, use the color mapping service // to assign a color from the Kibana palette. Colors will be shared across the @@ -138,6 +139,51 @@ export const TimeSeries = ({ }, [palettesService, series, syncColors] ); + + const darkMode = uiSettings.get('theme:darkMode'); + const gridLineStyle = !useLegacyTimeAxis + ? { + visible: showGrid, + strokeWidth: 0.1, + stroke: darkMode ? 'white' : 'black', + } + : { + ...GRID_LINE_CONFIG, + visible: showGrid, + }; + const xAxisStyle = !useLegacyTimeAxis + ? { + tickLabel: { + visible: true, + fontSize: 11, + padding: 0, + alignment: { + vertical: Position.Bottom, + horizontal: Position.Left, + }, + offset: { + x: 1.5, + y: 0, + }, + }, + axisLine: { + stroke: darkMode ? 'lightgray' : 'darkgray', + strokeWidth: 1, + }, + tickLine: { + size: 12, + strokeWidth: 0.15, + stroke: darkMode ? 'white' : 'black', + padding: -10, + visible: true, + }, + axisTitle: { + visible: true, + padding: 0, + }, + } + : {}; + return ( ); @@ -357,4 +402,5 @@ TimeSeries.propTypes = { annotations: PropTypes.array, interval: PropTypes.number, isLastBucketDropped: PropTypes.bool, + useLegacyTimeAxis: PropTypes.bool, }; diff --git a/src/plugins/vis_types/xy/public/components/xy_axis.tsx b/src/plugins/vis_types/xy/public/components/xy_axis.tsx index 30e1dbbff673e..b224639bdbff3 100644 --- a/src/plugins/vis_types/xy/public/components/xy_axis.tsx +++ b/src/plugins/vis_types/xy/public/components/xy_axis.tsx @@ -25,6 +25,7 @@ export const XYAxis: FC = ({ domain, style, integersOnly, + timeAxisLayerCount, }) => ( = ({ labelFormat={ticks?.labelFormatter} showOverlappingLabels={ticks?.showOverlappingLabels} showDuplicatedTicks={ticks?.showDuplicates} + timeAxisLayerCount={timeAxisLayerCount} /> ); diff --git a/src/plugins/vis_types/xy/public/config/get_axis.ts b/src/plugins/vis_types/xy/public/config/get_axis.ts index 0d6c67d064cf8..796636ef2cb61 100644 --- a/src/plugins/vis_types/xy/public/config/get_axis.ts +++ b/src/plugins/vis_types/xy/public/config/get_axis.ts @@ -8,7 +8,13 @@ import { identity } from 'lodash'; -import { AxisSpec, TickFormatter, YDomainRange, ScaleType as ECScaleType } from '@elastic/charts'; +import { + AxisSpec, + TickFormatter, + YDomainRange, + ScaleType as ECScaleType, + Position, +} from '@elastic/charts'; import { LabelRotation } from '../../../../charts/public'; import { BUCKET_TYPES } from '../../../../data/public'; @@ -33,7 +39,9 @@ export function getAxis( { categoryLines, valueAxis }: Grid, { params, format, formatter, title: fallbackTitle = '', aggType }: Aspect, seriesParams: SeriesParam[], - isDateHistogram = false + isDateHistogram = false, + useMultiLayerTimeAxis = false, + darkMode = false ): AxisConfig { const isCategoryAxis = type === AxisType.Category; // Hide unassigned axis, not supported in elastic charts @@ -74,9 +82,10 @@ export function getAxis( ticks, grid, scale, - style: getAxisStyle(ticks, title, fallbackRotation), + style: getAxisStyle(useMultiLayerTimeAxis, darkMode, ticks, title, fallbackRotation), domain: getAxisDomain(scale, isCategoryAxis), integersOnly: aggType === 'count', + timeAxisLayerCount: useMultiLayerTimeAxis ? 3 : 0, }; } @@ -147,19 +156,52 @@ export function getScale( } function getAxisStyle( + isMultiLayerTimeAxis: boolean, + darkMode: boolean, ticks?: TickOptions, title?: string, rotationFallback: LabelRotation = LabelRotation.Vertical ): AxisSpec['style'] { - return { - axisTitle: { - visible: (title ?? '').trim().length > 0, - }, - tickLabel: { - visible: ticks?.show, - rotation: -(ticks?.rotation ?? rotationFallback), - }, - }; + return isMultiLayerTimeAxis + ? { + tickLabel: { + visible: Boolean(ticks?.show), + rotation: 0, // rotation is disabled on new time axis + fontSize: 11, + padding: 0, + alignment: { + vertical: Position.Bottom, + horizontal: Position.Left, + }, + offset: { + x: 1.5, + y: 0, + }, + }, + axisLine: { + stroke: darkMode ? 'lightgray' : 'darkgray', + strokeWidth: 1, + }, + tickLine: { + size: 12, + strokeWidth: 0.15, + stroke: darkMode ? 'white' : 'black', + padding: -10, + visible: Boolean(ticks?.show), + }, + axisTitle: { + visible: (title ?? '').trim().length > 0, + }, + } + : { + axisTitle: { + visible: (title ?? '').trim().length > 0, + }, + tickLabel: { + visible: ticks?.show, + rotation: -(ticks?.rotation ?? rotationFallback), + }, + }; } function getAxisDomain( diff --git a/src/plugins/vis_types/xy/public/config/get_config.ts b/src/plugins/vis_types/xy/public/config/get_config.ts index d2a3b9ad2a103..bd79b915be917 100644 --- a/src/plugins/vis_types/xy/public/config/get_config.ts +++ b/src/plugins/vis_types/xy/public/config/get_config.ts @@ -29,7 +29,12 @@ import { getAxis } from './get_axis'; import { getAspects } from './get_aspects'; import { ChartType } from '../index'; -export function getConfig(table: Datatable, params: VisParams): VisConfig { +export function getConfig( + table: Datatable, + params: VisParams, + useLegacyTimeAxis = false, + darkMode = false +): VisConfig { const { thresholdLine, orderBucketsBySum, @@ -42,13 +47,6 @@ export function getConfig(table: Datatable, params: VisParams): VisConfig { fillOpacity, } = params; const aspects = getAspects(table.columns, params.dimensions); - const xAxis = getAxis( - params.categoryAxes[0], - params.grid, - aspects.x, - params.seriesParams, - params.dimensions.x?.aggType === BUCKET_TYPES.DATE_HISTOGRAM - ); const tooltip = getTooltip(aspects, params); const yAxes = params.valueAxes.map((a) => { // find the correct aspect for each value axis @@ -60,10 +58,28 @@ export function getConfig(table: Datatable, params: VisParams): VisConfig { params.seriesParams ); }); + + const rotation = getRotation(params.categoryAxes[0]); + + const isDateHistogram = params.dimensions.x?.aggType === BUCKET_TYPES.DATE_HISTOGRAM; + const isHistogram = params.dimensions.x?.aggType === BUCKET_TYPES.HISTOGRAM; const enableHistogramMode = - (params.dimensions.x?.aggType === BUCKET_TYPES.DATE_HISTOGRAM || - params.dimensions.x?.aggType === BUCKET_TYPES.HISTOGRAM) && + (isDateHistogram || isHistogram) && shouldEnableHistogramMode(params.seriesParams, aspects.y, yAxes); + + const useMultiLayerTimeAxis = + enableHistogramMode && isDateHistogram && !useLegacyTimeAxis && rotation === 0; + + const xAxis = getAxis( + params.categoryAxes[0], + params.grid, + aspects.x, + params.seriesParams, + isDateHistogram, + useMultiLayerTimeAxis, + darkMode + ); + const isTimeChart = (aspects.x.params as DateHistogramParams).date ?? false; return { @@ -83,7 +99,7 @@ export function getConfig(table: Datatable, params: VisParams): VisConfig { xAxis, yAxes, legend: getLegend(params), - rotation: getRotation(params.categoryAxes[0]), + rotation, thresholdLine: getThresholdLine(thresholdLine, yAxes, params.seriesParams), }; } diff --git a/src/plugins/vis_types/xy/public/plugin.ts b/src/plugins/vis_types/xy/public/plugin.ts index c79ead242e35b..0f1de387161e3 100644 --- a/src/plugins/vis_types/xy/public/plugin.ts +++ b/src/plugins/vis_types/xy/public/plugin.ts @@ -24,7 +24,7 @@ import { } from './services'; import { visTypesDefinitions } from './vis_types'; -import { xyVisRenderer } from './vis_renderer'; +import { getXYVisRenderer } from './vis_renderer'; import * as expressionFunctions from './expression_functions'; @@ -69,7 +69,11 @@ export class VisTypeXyPlugin setThemeService(charts.theme); setPalettesService(charts.palettes); - expressions.registerRenderer(xyVisRenderer); + expressions.registerRenderer( + getXYVisRenderer({ + uiSettings: core.uiSettings, + }) + ); expressions.registerFunction(expressionFunctions.visTypeXyVisFn); expressions.registerFunction(expressionFunctions.categoryAxis); expressions.registerFunction(expressionFunctions.timeMarker); diff --git a/src/plugins/vis_types/xy/public/types/config.ts b/src/plugins/vis_types/xy/public/types/config.ts index e52b47366bc85..287787193bd20 100644 --- a/src/plugins/vis_types/xy/public/types/config.ts +++ b/src/plugins/vis_types/xy/public/types/config.ts @@ -85,6 +85,7 @@ export interface AxisConfig { title?: string; grid?: AxisGrid; integersOnly: boolean; + timeAxisLayerCount?: number; } export interface LegendOptions { diff --git a/src/plugins/vis_types/xy/public/vis_component.tsx b/src/plugins/vis_types/xy/public/vis_component.tsx index 515ad3e7eaf6f..8574e86a23096 100644 --- a/src/plugins/vis_types/xy/public/vis_component.tsx +++ b/src/plugins/vis_types/xy/public/vis_component.tsx @@ -66,6 +66,7 @@ export interface VisComponentProps { fireEvent: IInterpreterRenderHandlers['event']; renderComplete: IInterpreterRenderHandlers['done']; syncColors: boolean; + useLegacyTimeAxis: boolean; } export type VisComponentType = typeof VisComponent; @@ -211,8 +212,9 @@ const VisComponent = (props: VisComponentProps) => { ); const { visData, visParams, syncColors } = props; + const isDarkMode = getThemeService().useDarkMode(); - const config = getConfig(visData, visParams); + const config = getConfig(visData, visParams, props.useLegacyTimeAxis, isDarkMode); const timeZone = getTimeZone(); const xDomain = config.xAxis.scale.type === ScaleType.Ordinal ? undefined : getXDomain(config.aspects.x.params); @@ -229,7 +231,7 @@ const VisComponent = (props: VisComponentProps) => { () => config.legend.position ?? Position.Right, [config.legend.position] ); - const isDarkMode = getThemeService().useDarkMode(); + const getSeriesName = getSeriesNameFn(config.aspects, config.aspects.y.length > 1); const splitAccessors = config.aspects.series?.map(({ accessor, formatter }) => { diff --git a/src/plugins/vis_types/xy/public/vis_renderer.tsx b/src/plugins/vis_types/xy/public/vis_renderer.tsx index 093671307d538..77727761015a7 100644 --- a/src/plugins/vis_types/xy/public/vis_renderer.tsx +++ b/src/plugins/vis_types/xy/public/vis_renderer.tsx @@ -9,6 +9,7 @@ import React, { lazy } from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { I18nProvider } from '@kbn/i18n/react'; +import { IUiSettingsClient } from 'kibana/public'; import { VisualizationContainer } from '../../../visualizations/public'; import type { PersistedState } from '../../../visualizations/public'; @@ -17,6 +18,7 @@ import type { ExpressionRenderDefinition } from '../../../expressions/public'; import type { XyVisType } from '../common'; import type { VisComponentType } from './vis_component'; import { RenderValue, visName } from './expression_functions/xy_vis_fn'; +import { LEGACY_TIME_AXIS } from '../../../charts/common'; // @ts-ignore const VisComponent = lazy(() => import('./vis_component')); @@ -28,7 +30,9 @@ function shouldShowNoResultsMessage(visData: any, visType: XyVisType): boolean { return Boolean(isZeroHits); } -export const xyVisRenderer: ExpressionRenderDefinition = { +export const getXYVisRenderer: (deps: { + uiSettings: IUiSettingsClient; +}) => ExpressionRenderDefinition = ({ uiSettings }) => ({ name: visName, displayName: 'XY visualization', reuseDomNode: true, @@ -46,10 +50,11 @@ export const xyVisRenderer: ExpressionRenderDefinition = { fireEvent={handlers.event} uiState={handlers.uiState as PersistedState} syncColors={syncColors} + useLegacyTimeAxis={uiSettings.get(LEGACY_TIME_AXIS, false)} /> , domNode ); }, -}; +}); diff --git a/test/common/services/bsearch.ts b/test/common/services/bsearch.ts new file mode 100644 index 0000000000000..d9fe89d9e4b9c --- /dev/null +++ b/test/common/services/bsearch.ts @@ -0,0 +1,122 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import expect from '@kbn/expect'; +import request from 'superagent'; +import type SuperTest from 'supertest'; +import { IEsSearchResponse } from 'src/plugins/data/common'; +import { FtrProviderContext } from '../ftr_provider_context'; +import { RetryService } from './retry/retry'; + +/** + * Function copied from here: + * test/api_integration/apis/search/bsearch.ts without the compress + * + * Splits the JSON lines from bsearch + */ +const parseBfetchResponse = (resp: request.Response): Array> => { + return resp.text + .trim() + .split('\n') + .map((item) => JSON.parse(item)); +}; + +/** + * Function copied from here: + * x-pack/test/rule_registry/common/lib/authentication/spaces.ts + * @param spaceId The space id we want to utilize + */ +const getSpaceUrlPrefix = (spaceId?: string): string => { + return spaceId && spaceId !== 'default' ? `/s/${spaceId}` : ``; +}; + +/** + * Options for the send method + */ +interface SendOptions { + supertest: SuperTest.SuperTest; + options: object; + strategy: string; + space?: string; +} + +/** + * Bsearch factory which will return a new bsearch capable service that can reduce flake + * on the CI systems when they are under pressure and bsearch returns an async search + * response or a sync response. + * + * @example + * const supertest = getService('supertest'); + * const bsearch = getService('bsearch'); + * const response = await bsearch.send({ + * supertest, + * options: { + * defaultIndex: ['large_volume_dns_data'], + * } + * strategy: 'securitySolutionSearchStrategy', + * }); + * expect(response).eql({ ... your value ... }); + */ +export const BSearchFactory = (retry: RetryService) => ({ + /** Send method to send in your supertest, url, options, and strategy name */ + send: async ({ + supertest, + options, + strategy, + space, + }: SendOptions): Promise => { + const spaceUrl = getSpaceUrlPrefix(space); + const { body } = await retry.try(async () => { + return supertest + .post(`${spaceUrl}/internal/search/${strategy}`) + .set('kbn-xsrf', 'true') + .send(options) + .expect(200); + }); + + if (body.isRunning) { + const result = await retry.try(async () => { + const resp = await supertest + .post(`${spaceUrl}/internal/bsearch`) + .set('kbn-xsrf', 'true') + .send({ + batch: [ + { + request: { + id: body.id, + ...options, + }, + options: { + strategy, + }, + }, + ], + }) + .expect(200); + const [parsedResponse] = parseBfetchResponse(resp); + expect(parsedResponse.result.isRunning).equal(false); + return parsedResponse.result; + }); + return result; + } else { + return body; + } + }, +}); + +/** + * Bsearch provider which will return a new bsearch capable service that can reduce flake + * on the CI systems when they are under pressure and bsearch returns an async search response + * or a sync response. + */ +export function BSearchProvider({ + getService, +}: FtrProviderContext): ReturnType { + const retry = getService('retry'); + return BSearchFactory(retry); +} diff --git a/test/common/services/index.ts b/test/common/services/index.ts index c04bd778468a9..91d17ce1bb3e8 100644 --- a/test/common/services/index.ts +++ b/test/common/services/index.ts @@ -16,6 +16,7 @@ import { SecurityServiceProvider } from './security'; import { EsDeleteAllIndicesProvider } from './es_delete_all_indices'; import { SavedObjectInfoService } from './saved_object_info'; import { IndexPatternsService } from './index_patterns'; +import { BSearchProvider } from './bsearch'; export const services = { deployment: DeploymentService, @@ -28,4 +29,5 @@ export const services = { esDeleteAllIndices: EsDeleteAllIndicesProvider, savedObjectInfo: SavedObjectInfoService, indexPatterns: IndexPatternsService, + bsearch: BSearchProvider, }; diff --git a/test/examples/index_pattern_field_editor_example/index_pattern_field_editor_example.ts b/test/examples/index_pattern_field_editor_example/index_pattern_field_editor_example.ts index 5744c8e64f5c1..fa4308ae72883 100644 --- a/test/examples/index_pattern_field_editor_example/index_pattern_field_editor_example.ts +++ b/test/examples/index_pattern_field_editor_example/index_pattern_field_editor_example.ts @@ -12,7 +12,8 @@ import { PluginFunctionalProviderContext } from 'test/plugin_functional/services export default function ({ getService }: PluginFunctionalProviderContext) { const testSubjects = getService('testSubjects'); - describe('', () => { + // FAILING: https://github.com/elastic/kibana/issues/116463 + describe.skip('', () => { it('finds an index pattern', async () => { await testSubjects.existOrFail('indexPatternTitle'); }); diff --git a/test/functional/apps/dashboard/dashboard_snapshots.ts b/test/functional/apps/dashboard/dashboard_snapshots.ts index 3aba671c0a4b2..9279bbd5806e7 100644 --- a/test/functional/apps/dashboard/dashboard_snapshots.ts +++ b/test/functional/apps/dashboard/dashboard_snapshots.ts @@ -59,7 +59,7 @@ export default function ({ ); await PageObjects.dashboard.clickExitFullScreenLogoButton(); - expect(percentDifference).to.be.lessThan(0.02); + expect(percentDifference).to.be.lessThan(0.022); }); it('compare area chart snapshot', async () => { @@ -81,7 +81,7 @@ export default function ({ ); await PageObjects.dashboard.clickExitFullScreenLogoButton(); - expect(percentDifference).to.be.lessThan(0.02); + expect(percentDifference).to.be.lessThan(0.022); }); }); } diff --git a/test/functional/apps/visualize/_timelion.ts b/test/functional/apps/visualize/_timelion.ts index c531ada8a2573..631d2148d73c3 100644 --- a/test/functional/apps/visualize/_timelion.ts +++ b/test/functional/apps/visualize/_timelion.ts @@ -167,7 +167,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { expect(firstAreaChartData).to.eql(firstAreaExpectedChartData); expect(secondAreaChartData).to.eql(secondAreaExpectedChartData); expect(thirdAreaChartData).to.eql(thirdAreaExpectedChartData); - expect(firstAxesLabels).to.eql(['12.19GB', '12.2GB', '12.21GB']); + expect(firstAxesLabels).to.eql(['12.2GB', '12.21GB']); expect(secondAxesLabels).to.eql(['5.59KB', '5.6KB']); expect(thirdAxesLabels.toString()).to.be( 'BYTES_5721,BYTES_5722,BYTES_5723,BYTES_5724,BYTES_5725,BYTES_5726,BYTES_5727,BYTES_5728,BYTES_5729,BYTES_5730,BYTES_5731,BYTES_5732,BYTES_5733' @@ -257,8 +257,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { expect(value).to.eql('.es()'); }); - // FLAKY: https://github.com/elastic/kibana/issues/116033 - describe.skip('dynamic suggestions for argument values', () => { + describe('dynamic suggestions for argument values', () => { describe('.es()', () => { it('should show index pattern suggestions for index argument', async () => { await monacoEditor.setCodeEditorValue(''); diff --git a/test/functional/config.js b/test/functional/config.js index 5b0b79e84e8df..09eccc863a0e5 100644 --- a/test/functional/config.js +++ b/test/functional/config.js @@ -54,6 +54,7 @@ export default async function ({ readConfigFile }) { 'accessibility:disableAnimations': true, 'dateFormat:tz': 'UTC', 'visualization:visualize:legacyPieChartsLibrary': true, + 'visualization:useLegacyTimeAxis': true, }, }, diff --git a/test/functional/page_objects/timelion_page.ts b/test/functional/page_objects/timelion_page.ts index bdfde3c8145e5..ba1db60bc6350 100644 --- a/test/functional/page_objects/timelion_page.ts +++ b/test/functional/page_objects/timelion_page.ts @@ -7,13 +7,21 @@ */ import { FtrService } from '../ftr_provider_context'; +import type { WebElementWrapper } from '../services/lib/web_element_wrapper'; export class TimelionPageObject extends FtrService { private readonly testSubjects = this.ctx.getService('testSubjects'); + private readonly retry = this.ctx.getService('retry'); public async getSuggestionItemsText() { - const timelionCodeEditor = await this.testSubjects.find('timelionCodeEditor'); - const lists = await timelionCodeEditor.findAllByClassName('monaco-list-row'); + let lists: WebElementWrapper[] = []; + await this.retry.try(async () => { + const timelionCodeEditor = await this.testSubjects.find('timelionCodeEditor'); + lists = await timelionCodeEditor.findAllByClassName('monaco-list-row'); + if (lists.length === 0) { + throw new Error('suggestion list not populated'); + } + }); return await Promise.all(lists.map(async (element) => await element.getVisibleText())); } diff --git a/test/plugin_functional/test_suites/saved_objects_management/hidden_types.ts b/test/plugin_functional/test_suites/saved_objects_management/hidden_types.ts index 8e7adb504ebee..b384c3fbbbb1e 100644 --- a/test/plugin_functional/test_suites/saved_objects_management/hidden_types.ts +++ b/test/plugin_functional/test_suites/saved_objects_management/hidden_types.ts @@ -68,7 +68,8 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide }); }); - describe('Delete modal', () => { + // FLAKY: https://github.com/elastic/kibana/issues/116059 + describe.skip('Delete modal', () => { it('should display a warning then trying to delete hidden saved objects', async () => { await PageObjects.savedObjects.clickCheckboxByTitle('A Pie'); await PageObjects.savedObjects.clickCheckboxByTitle('A Dashboard'); diff --git a/vars/tasks.groovy b/vars/tasks.groovy index 0f509fa8ba132..050b62646fb3b 100644 --- a/vars/tasks.groovy +++ b/vars/tasks.groovy @@ -137,6 +137,7 @@ def functionalXpack(Map params = [:]) { 'x-pack/plugins/security_solution/', 'x-pack/plugins/cases/', 'x-pack/plugins/timelines/', + 'x-pack/plugins/lists/', 'x-pack/test/security_solution_cypress/', 'x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/', 'x-pack/plugins/triggers_actions_ui/public/application/context/actions_connectors_context.tsx', diff --git a/x-pack/package.json b/x-pack/package.json index 805d8555bf453..8fb7a3483e5ef 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -1,6 +1,6 @@ { "name": "x-pack", - "version": "8.0.0", + "version": "8.1.0", "author": "Elastic", "private": true, "license": "Elastic-License", diff --git a/x-pack/plugins/apm/ftr_e2e/README.md b/x-pack/plugins/apm/ftr_e2e/README.md index 2df4e837d2e55..96d6671bb3699 100644 --- a/x-pack/plugins/apm/ftr_e2e/README.md +++ b/x-pack/plugins/apm/ftr_e2e/README.md @@ -4,4 +4,4 @@ APM uses [FTR](../../../../packages/kbn-test/README.md) (functional test runner) ## Running tests -Go to [tests documentation](../scripts/test#e2e-tests-cypress/README.md) \ No newline at end of file +Go to [tests documentation](../dev_docs/testing.md#e2e-tests-cypress) diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/dependencies.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/dependencies.spec.ts new file mode 100644 index 0000000000000..0ab2d5682a900 --- /dev/null +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/dependencies.spec.ts @@ -0,0 +1,80 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +const timeRange = { + rangeFrom: Cypress.env('START_DATE'), + rangeTo: Cypress.env('END_DATE'), +}; + +describe('Dependencies', () => { + beforeEach(() => { + cy.loginAsReadOnlyUser(); + }); + + describe('top-level dependencies page', () => { + it('has a list of dependencies and you can navigate to the page for one', () => { + cy.visit(`/app/apm/services?${new URLSearchParams(timeRange)}`); + cy.contains('nav a', 'Dependencies').click(); + + // `force: true` because Cypress says the element is 0x0 + cy.contains('postgresql').click({ force: true }); + + cy.contains('h1', 'postgresql'); + }); + }); + + describe('dependency overview page', () => { + it('shows dependency information and you can navigate to a page for an upstream service', () => { + cy.visit( + `/app/apm/backends/overview?${new URLSearchParams({ + ...timeRange, + backendName: 'postgresql', + })}` + ); + + cy.get('[data-test-subj="latencyChart"]'); + cy.get('[data-test-subj="throughputChart"]'); + cy.get('[data-test-subj="errorRateChart"]'); + + cy.contains('opbeans-python').click({ force: true }); + + cy.contains('h1', 'opbeans-python'); + }); + }); + + describe('service overview page', () => { + it('shows dependency information and you can navigate to a page for a dependency', () => { + cy.visit( + `/app/apm/services/opbeans-python/overview?${new URLSearchParams( + timeRange + )}` + ); + + cy.contains('postgresql').click({ force: true }); + + cy.contains('h1', 'postgresql'); + }); + }); + + describe('service dependencies tab', () => { + it('shows dependency information and you can navigate to a page for a dependency', () => { + cy.visit( + `/app/apm/services/opbeans-python/overview?${new URLSearchParams( + timeRange + )}` + ); + + cy.contains('a[role="tab"]', 'Dependencies').click(); + + cy.contains('Time spent by dependency'); + + cy.contains('postgresql').click({ force: true }); + + cy.contains('h1', 'postgresql'); + }); + }); +}); diff --git a/x-pack/plugins/canvas/canvas_plugin_src/expression_types/embeddable.ts b/x-pack/plugins/canvas/canvas_plugin_src/expression_types/embeddable.ts index f1ede936c6ace..ac2e8e8babee1 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/expression_types/embeddable.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/expression_types/embeddable.ts @@ -6,11 +6,12 @@ */ import { ExpressionTypeDefinition } from '../../../../../src/plugins/expressions'; -import { EmbeddableInput } from '../../types'; +import { EmbeddableInput } from '../../../../../src/plugins/embeddable/common/'; import { EmbeddableTypes } from './embeddable_types'; export const EmbeddableExpressionType = 'embeddable'; export { EmbeddableTypes, EmbeddableInput }; + export interface EmbeddableExpression { /** * The type of the expression result diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/index.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/index.ts index d6d7a0f867849..2cfdebafb70df 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/index.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/index.ts @@ -6,6 +6,7 @@ */ import { functions as commonFunctions } from '../common'; +import { functions as externalFunctions } from '../external'; import { location } from './location'; import { markdown } from './markdown'; import { urlparam } from './urlparam'; @@ -13,4 +14,13 @@ import { escount } from './escount'; import { esdocs } from './esdocs'; import { essql } from './essql'; -export const functions = [location, markdown, urlparam, escount, esdocs, essql, ...commonFunctions]; +export const functions = [ + location, + markdown, + urlparam, + escount, + esdocs, + essql, + ...commonFunctions, + ...externalFunctions, +]; diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.test.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.test.ts deleted file mode 100644 index 001fb0e3f62e3..0000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.test.ts +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { embeddableFunctionFactory } from './embeddable'; -import { getQueryFilters } from '../../../common/lib/build_embeddable_filters'; -import { ExpressionValueFilter } from '../../../types'; -import { encode } from '../../../common/lib/embeddable_dataurl'; -import { InitializeArguments } from '.'; - -const filterContext: ExpressionValueFilter = { - type: 'filter', - and: [ - { - type: 'filter', - and: [], - value: 'filter-value', - column: 'filter-column', - filterType: 'exactly', - }, - { - type: 'filter', - and: [], - column: 'time-column', - filterType: 'time', - from: '2019-06-04T04:00:00.000Z', - to: '2019-06-05T04:00:00.000Z', - }, - ], -}; - -describe('embeddable', () => { - const fn = embeddableFunctionFactory({} as InitializeArguments)().fn; - const config = { - id: 'some-id', - timerange: { from: '15m', to: 'now' }, - title: 'test embeddable', - }; - - const args = { - config: encode(config), - type: 'visualization', - }; - - it('accepts null context', () => { - const expression = fn(null, args, {} as any); - - expect(expression.input.filters).toEqual([]); - }); - - it('accepts filter context', () => { - const expression = fn(filterContext, args, {} as any); - const embeddableFilters = getQueryFilters(filterContext.and); - - expect(expression.input.filters).toEqual(embeddableFilters); - }); -}); diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.ts deleted file mode 100644 index 7ef8f0a09eb90..0000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/embeddable.ts +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ExpressionFunctionDefinition } from 'src/plugins/expressions/common'; -import { ExpressionValueFilter, EmbeddableInput } from '../../../types'; -import { EmbeddableExpressionType, EmbeddableExpression } from '../../expression_types'; -import { getFunctionHelp } from '../../../i18n'; -import { SavedObjectReference } from '../../../../../../src/core/types'; -import { getQueryFilters } from '../../../common/lib/build_embeddable_filters'; -import { decode, encode } from '../../../common/lib/embeddable_dataurl'; -import { InitializeArguments } from '.'; - -export interface Arguments { - config: string; - type: string; -} - -const defaultTimeRange = { - from: 'now-15m', - to: 'now', -}; - -const baseEmbeddableInput = { - timeRange: defaultTimeRange, - disableTriggers: true, - renderMode: 'noInteractivity', -}; - -type Return = EmbeddableExpression; - -type EmbeddableFunction = ExpressionFunctionDefinition< - 'embeddable', - ExpressionValueFilter | null, - Arguments, - Return ->; - -export function embeddableFunctionFactory({ - embeddablePersistableStateService, -}: InitializeArguments): () => EmbeddableFunction { - return function embeddable(): EmbeddableFunction { - const { help, args: argHelp } = getFunctionHelp().embeddable; - - return { - name: 'embeddable', - help, - args: { - config: { - aliases: ['_'], - types: ['string'], - required: true, - help: argHelp.config, - }, - type: { - types: ['string'], - required: true, - help: argHelp.type, - }, - }, - context: { - types: ['filter'], - }, - type: EmbeddableExpressionType, - fn: (input, args) => { - const filters = input ? input.and : []; - - const embeddableInput = decode(args.config) as EmbeddableInput; - - return { - type: EmbeddableExpressionType, - input: { - ...baseEmbeddableInput, - ...embeddableInput, - filters: getQueryFilters(filters), - }, - generatedAt: Date.now(), - embeddableType: args.type, - }; - }, - - extract(state) { - const input = decode(state.config[0] as string); - - // extracts references for by-reference embeddables - if (input.savedObjectId) { - const refName = 'embeddable.savedObjectId'; - - const references: SavedObjectReference[] = [ - { - name: refName, - type: state.type[0] as string, - id: input.savedObjectId as string, - }, - ]; - - return { - state, - references, - }; - } - - // extracts references for by-value embeddables - const { state: extractedState, references: extractedReferences } = - embeddablePersistableStateService.extract({ - ...input, - type: state.type[0], - }); - - const { type, ...extractedInput } = extractedState; - - return { - state: { ...state, config: [encode(extractedInput)], type: [type] }, - references: extractedReferences, - }; - }, - - inject(state, references) { - const input = decode(state.config[0] as string); - const savedObjectReference = references.find( - (ref) => ref.name === 'embeddable.savedObjectId' - ); - - // injects saved object id for by-references embeddable - if (savedObjectReference) { - input.savedObjectId = savedObjectReference.id; - state.config[0] = encode(input); - state.type[0] = savedObjectReference.type; - } else { - // injects references for by-value embeddables - const { type, ...injectedInput } = embeddablePersistableStateService.inject( - { ...input, type: state.type[0] }, - references - ); - state.config[0] = encode(injectedInput); - state.type[0] = type; - } - return state; - }, - }; - }; -} diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/index.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/index.ts index 1d69e181b5fd9..407a0e2ebfe05 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/index.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/index.ts @@ -5,26 +5,9 @@ * 2.0. */ -import { EmbeddableStart } from 'src/plugins/embeddable/public'; -import { embeddableFunctionFactory } from './embeddable'; import { savedLens } from './saved_lens'; import { savedMap } from './saved_map'; import { savedSearch } from './saved_search'; import { savedVisualization } from './saved_visualization'; -export interface InitializeArguments { - embeddablePersistableStateService: { - extract: EmbeddableStart['extract']; - inject: EmbeddableStart['inject']; - }; -} - -export function initFunctions(initialize: InitializeArguments) { - return [ - embeddableFunctionFactory(initialize), - savedLens, - savedMap, - savedSearch, - savedVisualization, - ]; -} +export const functions = [savedLens, savedMap, savedVisualization, savedSearch]; diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_lens.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_lens.ts index 67947691f7757..082a69a874cae 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_lens.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_lens.ts @@ -9,8 +9,9 @@ import { ExpressionFunctionDefinition } from 'src/plugins/expressions/common'; import { PaletteOutput } from 'src/plugins/charts/common'; import { Filter as DataFilter } from '@kbn/es-query'; import { TimeRange } from 'src/plugins/data/common'; +import { EmbeddableInput } from 'src/plugins/embeddable/common'; import { getQueryFilters } from '../../../common/lib/build_embeddable_filters'; -import { ExpressionValueFilter, EmbeddableInput, TimeRange as TimeRangeArg } from '../../../types'; +import { ExpressionValueFilter, TimeRange as TimeRangeArg } from '../../../types'; import { EmbeddableTypes, EmbeddableExpressionType, @@ -26,7 +27,7 @@ interface Arguments { } export type SavedLensInput = EmbeddableInput & { - savedObjectId: string; + id: string; timeRange?: TimeRange; filters: DataFilter[]; palette?: PaletteOutput; @@ -72,19 +73,18 @@ export function savedLens(): ExpressionFunctionDefinition< }, }, type: EmbeddableExpressionType, - fn: (input, { id, timerange, title, palette }) => { + fn: (input, args) => { const filters = input ? input.and : []; return { type: EmbeddableExpressionType, input: { - id, - savedObjectId: id, + id: args.id, filters: getQueryFilters(filters), - timeRange: timerange || defaultTimeRange, - title: title === null ? undefined : title, + timeRange: args.timerange || defaultTimeRange, + title: args.title === null ? undefined : args.title, disableTriggers: true, - palette, + palette: args.palette, }, embeddableType: EmbeddableTypes.lens, generatedAt: Date.now(), 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 a7471c755155c..538ed3f919823 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 @@ -30,7 +30,7 @@ const defaultTimeRange = { to: 'now', }; -type Output = EmbeddableExpression; +type Output = EmbeddableExpression; export function savedMap(): ExpressionFunctionDefinition< 'savedMap', @@ -85,9 +85,8 @@ export function savedMap(): ExpressionFunctionDefinition< return { type: EmbeddableExpressionType, input: { - id: args.id, attributes: { title: '' }, - savedObjectId: args.id, + id: args.id, filters: getQueryFilters(filters), timeRange: args.timerange || defaultTimeRange, refreshConfig: { diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_visualization.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_visualization.ts index 31e3fb2a8c564..5c0442b43250c 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_visualization.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_visualization.ts @@ -25,7 +25,7 @@ interface Arguments { title: string | null; } -type Output = EmbeddableExpression; +type Output = EmbeddableExpression; const defaultTimeRange = { from: 'now-15m', @@ -94,7 +94,6 @@ export function savedVisualization(): ExpressionFunctionDefinition< type: EmbeddableExpressionType, input: { id, - savedObjectId: id, disableTriggers: true, timeRange: timerange || defaultTimeRange, filters: getQueryFilters(filters), diff --git a/x-pack/plugins/canvas/canvas_plugin_src/plugin.ts b/x-pack/plugins/canvas/canvas_plugin_src/plugin.ts index 591795637aebe..91c573fc4148b 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/plugin.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/plugin.ts @@ -7,14 +7,12 @@ import { CoreSetup, CoreStart, Plugin } from 'src/core/public'; import { ChartsPluginStart } from 'src/plugins/charts/public'; -import { PresentationUtilPluginStart } from 'src/plugins/presentation_util/public'; import { CanvasSetup } from '../public'; import { EmbeddableStart } from '../../../../src/plugins/embeddable/public'; import { UiActionsStart } from '../../../../src/plugins/ui_actions/public'; import { Start as InspectorStart } from '../../../../src/plugins/inspector/public'; import { functions } from './functions/browser'; -import { initFunctions } from './functions/external'; import { typeFunctions } from './expression_types'; import { renderFunctions, renderFunctionFactories } from './renderers'; @@ -27,7 +25,6 @@ export interface StartDeps { uiActions: UiActionsStart; inspector: InspectorStart; charts: ChartsPluginStart; - presentationUtil: PresentationUtilPluginStart; } export type SetupInitializer = (core: CoreSetup, plugins: SetupDeps) => T; @@ -42,13 +39,6 @@ export class CanvasSrcPlugin implements Plugin plugins.canvas.addRenderers(renderFunctions); core.getStartServices().then(([coreStart, depsStart]) => { - const externalFunctions = initFunctions({ - embeddablePersistableStateService: { - extract: depsStart.embeddable.extract, - inject: depsStart.embeddable.inject, - }, - }); - plugins.canvas.addFunctions(externalFunctions); plugins.canvas.addRenderers( renderFunctionFactories.map((factory: any) => factory(coreStart, depsStart)) ); diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx index 953746c280840..73e839433c25e 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx @@ -13,17 +13,16 @@ import { IEmbeddable, EmbeddableFactory, EmbeddableFactoryNotFoundError, - isErrorEmbeddable, } from '../../../../../../src/plugins/embeddable/public'; import { EmbeddableExpression } from '../../expression_types/embeddable'; import { RendererStrings } from '../../../i18n'; import { embeddableInputToExpression } from './embeddable_input_to_expression'; -import { RendererFactory, EmbeddableInput } from '../../../types'; +import { EmbeddableInput } from '../../expression_types'; +import { RendererFactory } from '../../../types'; import { CANVAS_EMBEDDABLE_CLASSNAME } from '../../../common/lib'; const { embeddable: strings } = RendererStrings; -// registry of references to embeddables on the workpad const embeddablesRegistry: { [key: string]: IEmbeddable | Promise; } = {}; @@ -31,11 +30,11 @@ const embeddablesRegistry: { const renderEmbeddableFactory = (core: CoreStart, plugins: StartDeps) => { const I18nContext = core.i18n.Context; - return (embeddableObject: IEmbeddable) => { + return (embeddableObject: IEmbeddable, domNode: HTMLElement) => { return (
@@ -57,9 +56,6 @@ export const embeddableRendererFactory = ( reuseDomNode: true, render: async (domNode, { input, embeddableType }, handlers) => { const uniqueId = handlers.getElementId(); - const isByValueEnabled = plugins.presentationUtil.labsService.isProjectEnabled( - 'labs:canvas:byValueEmbeddable' - ); if (!embeddablesRegistry[uniqueId]) { const factory = Array.from(plugins.embeddable.getEmbeddableFactories()).find( @@ -71,27 +67,15 @@ export const embeddableRendererFactory = ( throw new EmbeddableFactoryNotFoundError(embeddableType); } - const embeddableInput = { ...input, id: uniqueId }; - - const embeddablePromise = input.savedObjectId - ? factory - .createFromSavedObject(input.savedObjectId, embeddableInput) - .then((embeddable) => { - // stores embeddable in registrey - embeddablesRegistry[uniqueId] = embeddable; - return embeddable; - }) - : factory.create(embeddableInput).then((embeddable) => { - if (!embeddable || isErrorEmbeddable(embeddable)) { - return; - } - // stores embeddable in registry - embeddablesRegistry[uniqueId] = embeddable as IEmbeddable; - return embeddable; - }); - embeddablesRegistry[uniqueId] = embeddablePromise as Promise; - - const embeddableObject = (await (async () => embeddablePromise)()) as IEmbeddable; + const embeddablePromise = factory + .createFromSavedObject(input.id, input) + .then((embeddable) => { + embeddablesRegistry[uniqueId] = embeddable; + return embeddable; + }); + embeddablesRegistry[uniqueId] = embeddablePromise; + + const embeddableObject = await (async () => embeddablePromise)(); const palettes = await plugins.charts.palettes.getPalettes(); @@ -102,8 +86,7 @@ export const embeddableRendererFactory = ( const updatedExpression = embeddableInputToExpression( updatedInput, embeddableType, - palettes, - isByValueEnabled + palettes ); if (updatedExpression) { @@ -111,7 +94,15 @@ export const embeddableRendererFactory = ( } }); - ReactDOM.render(renderEmbeddable(embeddableObject), domNode, () => handlers.done()); + ReactDOM.render(renderEmbeddable(embeddableObject, domNode), domNode, () => + handlers.done() + ); + + handlers.onResize(() => { + ReactDOM.render(renderEmbeddable(embeddableObject, domNode), domNode, () => + handlers.done() + ); + }); handlers.onDestroy(() => { subscription.unsubscribe(); @@ -124,7 +115,6 @@ export const embeddableRendererFactory = ( } else { const embeddable = embeddablesRegistry[uniqueId]; - // updating embeddable input with changes made to expression or filters if ('updateInput' in embeddable) { embeddable.updateInput(input); embeddable.reload(); diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable_input_to_expression.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable_input_to_expression.ts index 80830eac24021..41cefad6a470f 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable_input_to_expression.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable_input_to_expression.ts @@ -10,7 +10,6 @@ import { EmbeddableTypes, EmbeddableInput } from '../../expression_types'; import { toExpression as mapToExpression } from './input_type_to_expression/map'; import { toExpression as visualizationToExpression } from './input_type_to_expression/visualization'; import { toExpression as lensToExpression } from './input_type_to_expression/lens'; -import { toExpression as genericToExpression } from './input_type_to_expression/embeddable'; export const inputToExpressionTypeMap = { [EmbeddableTypes.map]: mapToExpression, @@ -24,13 +23,8 @@ export const inputToExpressionTypeMap = { export function embeddableInputToExpression( input: EmbeddableInput, embeddableType: string, - palettes: PaletteRegistry, - useGenericEmbeddable?: boolean + palettes: PaletteRegistry ): string | undefined { - if (useGenericEmbeddable) { - return genericToExpression(input, embeddableType); - } - if (inputToExpressionTypeMap[embeddableType]) { return inputToExpressionTypeMap[embeddableType](input as any, palettes); } diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/embeddable.test.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/embeddable.test.ts deleted file mode 100644 index 4b78acec8750a..0000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/embeddable.test.ts +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { toExpression } from './embeddable'; -import { EmbeddableInput } from '../../../../types'; -import { decode } from '../../../../common/lib/embeddable_dataurl'; -import { fromExpression } from '@kbn/interpreter/common'; - -describe('toExpression', () => { - describe('by-reference embeddable input', () => { - const baseEmbeddableInput = { - id: 'elementId', - savedObjectId: 'embeddableId', - filters: [], - }; - - it('converts to an embeddable expression', () => { - const input: EmbeddableInput = baseEmbeddableInput; - - const expression = toExpression(input, 'visualization'); - const ast = fromExpression(expression); - - expect(ast.type).toBe('expression'); - expect(ast.chain[0].function).toBe('embeddable'); - expect(ast.chain[0].arguments.type[0]).toBe('visualization'); - - const config = decode(ast.chain[0].arguments.config[0] as string); - - expect(config.savedObjectId).toStrictEqual(input.savedObjectId); - }); - - it('includes optional input values', () => { - const input: EmbeddableInput = { - ...baseEmbeddableInput, - title: 'title', - timeRange: { - from: 'now-1h', - to: 'now', - }, - }; - - const expression = toExpression(input, 'visualization'); - const ast = fromExpression(expression); - - const config = decode(ast.chain[0].arguments.config[0] as string); - - expect(config).toHaveProperty('title', input.title); - expect(config).toHaveProperty('timeRange'); - expect(config.timeRange).toHaveProperty('from', input.timeRange?.from); - expect(config.timeRange).toHaveProperty('to', input.timeRange?.to); - }); - - it('includes empty panel title', () => { - const input: EmbeddableInput = { - ...baseEmbeddableInput, - title: '', - }; - - const expression = toExpression(input, 'visualization'); - const ast = fromExpression(expression); - - const config = decode(ast.chain[0].arguments.config[0] as string); - - expect(config).toHaveProperty('title', input.title); - }); - }); - - describe('by-value embeddable input', () => { - const baseEmbeddableInput = { - id: 'elementId', - disableTriggers: true, - filters: [], - }; - it('converts to an embeddable expression', () => { - const input: EmbeddableInput = baseEmbeddableInput; - - const expression = toExpression(input, 'visualization'); - const ast = fromExpression(expression); - - expect(ast.type).toBe('expression'); - expect(ast.chain[0].function).toBe('embeddable'); - expect(ast.chain[0].arguments.type[0]).toBe('visualization'); - - const config = decode(ast.chain[0].arguments.config[0] as string); - expect(config.filters).toStrictEqual(input.filters); - expect(config.disableTriggers).toStrictEqual(input.disableTriggers); - }); - - it('includes optional input values', () => { - const input: EmbeddableInput = { - ...baseEmbeddableInput, - title: 'title', - timeRange: { - from: 'now-1h', - to: 'now', - }, - }; - - const expression = toExpression(input, 'visualization'); - const ast = fromExpression(expression); - - const config = decode(ast.chain[0].arguments.config[0] as string); - - expect(config).toHaveProperty('title', input.title); - expect(config).toHaveProperty('timeRange'); - expect(config.timeRange).toHaveProperty('from', input.timeRange?.from); - expect(config.timeRange).toHaveProperty('to', input.timeRange?.to); - }); - - it('includes empty panel title', () => { - const input: EmbeddableInput = { - ...baseEmbeddableInput, - title: '', - }; - - const expression = toExpression(input, 'visualization'); - const ast = fromExpression(expression); - - const config = decode(ast.chain[0].arguments.config[0] as string); - - expect(config).toHaveProperty('title', input.title); - }); - }); -}); diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/embeddable.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/embeddable.ts deleted file mode 100644 index 94d86f6640be1..0000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/embeddable.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { encode } from '../../../../common/lib/embeddable_dataurl'; -import { EmbeddableInput } from '../../../expression_types'; - -export function toExpression(input: EmbeddableInput, embeddableType: string): string { - return `embeddable config="${encode(input)}" type="${embeddableType}"`; -} diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.test.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.test.ts index 224cdfba389d7..24da7238bcee9 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.test.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.test.ts @@ -11,8 +11,7 @@ import { fromExpression, Ast } from '@kbn/interpreter/common'; import { chartPluginMock } from 'src/plugins/charts/public/mocks'; const baseEmbeddableInput = { - id: 'elementId', - savedObjectId: 'embeddableId', + id: 'embeddableId', filters: [], }; @@ -28,7 +27,7 @@ describe('toExpression', () => { expect(ast.type).toBe('expression'); expect(ast.chain[0].function).toBe('savedLens'); - expect(ast.chain[0].arguments.id).toStrictEqual([input.savedObjectId]); + expect(ast.chain[0].arguments.id).toStrictEqual([input.id]); expect(ast.chain[0].arguments).not.toHaveProperty('title'); expect(ast.chain[0].arguments).not.toHaveProperty('timerange'); diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.ts index 5a13b73b3fe74..35e106f234fa4 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/lens.ts @@ -14,7 +14,7 @@ export function toExpression(input: SavedLensInput, palettes: PaletteRegistry): expressionParts.push('savedLens'); - expressionParts.push(`id="${input.savedObjectId}"`); + expressionParts.push(`id="${input.id}"`); if (input.title !== undefined) { expressionParts.push(`title="${input.title}"`); 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 af7b40a9b283d..804d0d849cc7f 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 @@ -6,12 +6,12 @@ */ import { toExpression } from './map'; +import { MapEmbeddableInput } from '../../../../../../plugins/maps/public/embeddable'; import { fromExpression, Ast } from '@kbn/interpreter/common'; const baseSavedMapInput = { - id: 'elementId', attributes: { title: '' }, - savedObjectId: 'embeddableId', + id: 'embeddableId', filters: [], isLayerTOCOpen: false, refreshConfig: { @@ -23,7 +23,7 @@ const baseSavedMapInput = { describe('toExpression', () => { it('converts to a savedMap expression', () => { - const input = { + const input: MapEmbeddableInput = { ...baseSavedMapInput, }; @@ -33,7 +33,7 @@ describe('toExpression', () => { expect(ast.type).toBe('expression'); expect(ast.chain[0].function).toBe('savedMap'); - expect(ast.chain[0].arguments.id).toStrictEqual([input.savedObjectId]); + expect(ast.chain[0].arguments.id).toStrictEqual([input.id]); expect(ast.chain[0].arguments).not.toHaveProperty('title'); expect(ast.chain[0].arguments).not.toHaveProperty('center'); @@ -41,7 +41,7 @@ describe('toExpression', () => { }); it('includes optional input values', () => { - const input = { + const input: MapEmbeddableInput = { ...baseSavedMapInput, mapCenter: { lat: 1, @@ -73,7 +73,7 @@ describe('toExpression', () => { }); it('includes empty panel title', () => { - const input = { + const input: MapEmbeddableInput = { ...baseSavedMapInput, title: '', }; diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.ts index 03746f38b4696..3fd6a68a327c6 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.ts @@ -5,14 +5,13 @@ * 2.0. */ -import { MapEmbeddableInput } from '../../../../../../plugins/maps/public'; +import { MapEmbeddableInput } from '../../../../../../plugins/maps/public/embeddable'; -export function toExpression(input: MapEmbeddableInput & { savedObjectId: string }): string { +export function toExpression(input: MapEmbeddableInput): string { const expressionParts = [] as string[]; expressionParts.push('savedMap'); - - expressionParts.push(`id="${input.savedObjectId}"`); + expressionParts.push(`id="${input.id}"`); if (input.title !== undefined) { expressionParts.push(`title="${input.title}"`); diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.test.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.test.ts index 4c61a130f3c95..c5106b9a102b4 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.test.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.test.ts @@ -9,8 +9,7 @@ import { toExpression } from './visualization'; import { fromExpression, Ast } from '@kbn/interpreter/common'; const baseInput = { - id: 'elementId', - savedObjectId: 'embeddableId', + id: 'embeddableId', }; describe('toExpression', () => { @@ -25,7 +24,7 @@ describe('toExpression', () => { expect(ast.type).toBe('expression'); expect(ast.chain[0].function).toBe('savedVisualization'); - expect(ast.chain[0].arguments.id).toStrictEqual([input.savedObjectId]); + expect(ast.chain[0].arguments.id).toStrictEqual([input.id]); }); it('includes timerange if given', () => { diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.ts index 364d7cd0755db..bcb73b2081fee 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/visualization.ts @@ -7,11 +7,11 @@ import { VisualizeInput } from 'src/plugins/visualizations/public'; -export function toExpression(input: VisualizeInput & { savedObjectId: string }): string { +export function toExpression(input: VisualizeInput): string { const expressionParts = [] as string[]; expressionParts.push('savedVisualization'); - expressionParts.push(`id="${input.savedObjectId}"`); + expressionParts.push(`id="${input.id}"`); if (input.title !== undefined) { expressionParts.push(`title="${input.title}"`); diff --git a/x-pack/plugins/canvas/common/lib/embeddable_dataurl.ts b/x-pack/plugins/canvas/common/lib/embeddable_dataurl.ts deleted file mode 100644 index e76dedfe63b14..0000000000000 --- a/x-pack/plugins/canvas/common/lib/embeddable_dataurl.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EmbeddableInput } from '../../types'; - -export const encode = (input: Partial) => - Buffer.from(JSON.stringify(input)).toString('base64'); -export const decode = (serializedInput: string) => - JSON.parse(Buffer.from(serializedInput, 'base64').toString()); diff --git a/x-pack/plugins/canvas/i18n/functions/dict/embeddable.ts b/x-pack/plugins/canvas/i18n/functions/dict/embeddable.ts deleted file mode 100644 index 279f58799e8c0..0000000000000 --- a/x-pack/plugins/canvas/i18n/functions/dict/embeddable.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { embeddableFunctionFactory } from '../../../canvas_plugin_src/functions/external/embeddable'; -import { FunctionHelp } from '../function_help'; -import { FunctionFactory } from '../../../types'; - -export const help: FunctionHelp>> = { - help: i18n.translate('xpack.canvas.functions.embeddableHelpText', { - defaultMessage: `Returns an embeddable with the provided configuration`, - }), - args: { - config: i18n.translate('xpack.canvas.functions.embeddable.args.idHelpText', { - defaultMessage: `The base64 encoded embeddable input object`, - }), - type: i18n.translate('xpack.canvas.functions.embeddable.args.typeHelpText', { - defaultMessage: `The embeddable type`, - }), - }, -}; diff --git a/x-pack/plugins/canvas/i18n/functions/function_help.ts b/x-pack/plugins/canvas/i18n/functions/function_help.ts index 520d32af1c272..5eae785fefa2e 100644 --- a/x-pack/plugins/canvas/i18n/functions/function_help.ts +++ b/x-pack/plugins/canvas/i18n/functions/function_help.ts @@ -27,7 +27,6 @@ import { help as demodata } from './dict/demodata'; import { help as doFn } from './dict/do'; import { help as dropdownControl } from './dict/dropdown_control'; import { help as eq } from './dict/eq'; -import { help as embeddable } from './dict/embeddable'; import { help as escount } from './dict/escount'; import { help as esdocs } from './dict/esdocs'; import { help as essql } from './dict/essql'; @@ -183,7 +182,6 @@ export const getFunctionHelp = (): FunctionHelpDict => ({ do: doFn, dropdownControl, eq, - embeddable, escount, esdocs, essql, diff --git a/x-pack/plugins/canvas/kibana.json b/x-pack/plugins/canvas/kibana.json index 2fd312502a3c7..9c4d1b2179d82 100644 --- a/x-pack/plugins/canvas/kibana.json +++ b/x-pack/plugins/canvas/kibana.json @@ -25,7 +25,6 @@ "features", "inspector", "presentationUtil", - "visualizations", "uiActions", "share" ], diff --git a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx index 57f52fcf21f0f..bf731876bf8c8 100644 --- a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx +++ b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC, useCallback } from 'react'; +import React, { FC } from 'react'; import { EuiFlyout, EuiFlyoutHeader, EuiFlyoutBody, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -27,44 +27,38 @@ const strings = { }; export interface Props { onClose: () => void; - onSelect: (id: string, embeddableType: string, isByValueEnabled?: boolean) => void; + onSelect: (id: string, embeddableType: string) => void; availableEmbeddables: string[]; - isByValueEnabled?: boolean; } -export const AddEmbeddableFlyout: FC = ({ - onSelect, - availableEmbeddables, - onClose, - isByValueEnabled, -}) => { +export const AddEmbeddableFlyout: FC = ({ onSelect, availableEmbeddables, onClose }) => { const embeddablesService = useEmbeddablesService(); const platformService = usePlatformService(); const { getEmbeddableFactories } = embeddablesService; const { getSavedObjects, getUISettings } = platformService; - const onAddPanel = useCallback( - (id: string, savedObjectType: string) => { - const embeddableFactories = getEmbeddableFactories(); - // Find the embeddable type from the saved object type - const found = Array.from(embeddableFactories).find((embeddableFactory) => { - return Boolean( - embeddableFactory.savedObjectMetaData && - embeddableFactory.savedObjectMetaData.type === savedObjectType - ); - }); + const onAddPanel = (id: string, savedObjectType: string, name: string) => { + const embeddableFactories = getEmbeddableFactories(); - const foundEmbeddableType = found ? found.type : 'unknown'; + // Find the embeddable type from the saved object type + const found = Array.from(embeddableFactories).find((embeddableFactory) => { + return Boolean( + embeddableFactory.savedObjectMetaData && + embeddableFactory.savedObjectMetaData.type === savedObjectType + ); + }); - onSelect(id, foundEmbeddableType, isByValueEnabled); - }, - [isByValueEnabled, getEmbeddableFactories, onSelect] - ); + const foundEmbeddableType = found ? found.type : 'unknown'; + + onSelect(id, foundEmbeddableType); + }; const embeddableFactories = getEmbeddableFactories(); const availableSavedObjects = Array.from(embeddableFactories) - .filter((factory) => isByValueEnabled || availableEmbeddables.includes(factory.type)) + .filter((factory) => { + return availableEmbeddables.includes(factory.type); + }) .map((factory) => factory.savedObjectMetaData) .filter>(function ( maybeSavedObjectMetaData diff --git a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.tsx b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.tsx index 4dc8d963932d8..770a4cac606b0 100644 --- a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.tsx +++ b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.tsx @@ -8,14 +8,12 @@ import React, { useMemo, useEffect, useCallback } from 'react'; import { createPortal } from 'react-dom'; import { useSelector, useDispatch } from 'react-redux'; -import { encode } from '../../../common/lib/embeddable_dataurl'; import { AddEmbeddableFlyout as Component, Props as ComponentProps } from './flyout.component'; // @ts-expect-error untyped local import { addElement } from '../../state/actions/elements'; import { getSelectedPage } from '../../state/selectors/workpad'; import { EmbeddableTypes } from '../../../canvas_plugin_src/expression_types/embeddable'; import { State } from '../../../types'; -import { useLabsService } from '../../services'; const allowedEmbeddables = { [EmbeddableTypes.map]: (id: string) => { @@ -67,9 +65,6 @@ export const AddEmbeddablePanel: React.FunctionComponent = ({ availableEmbeddables, ...restProps }) => { - const labsService = useLabsService(); - const isByValueEnabled = labsService.isProjectEnabled('labs:canvas:byValueEmbeddable'); - const dispatch = useDispatch(); const pageId = useSelector((state) => getSelectedPage(state)); @@ -79,27 +74,18 @@ export const AddEmbeddablePanel: React.FunctionComponent = ({ ); const onSelect = useCallback( - (id: string, type: string): void => { + (id: string, type: string) => { const partialElement = { expression: `markdown "Could not find embeddable for type ${type}" | render`, }; - - // If by-value is enabled, we'll handle both by-reference and by-value embeddables - // with the new generic `embeddable` function. - // Otherwise we fallback to the embeddable type specific expressions. - if (isByValueEnabled) { - const config = encode({ savedObjectId: id }); - partialElement.expression = `embeddable config="${config}" - type="${type}" -| render`; - } else if (allowedEmbeddables[type]) { + if (allowedEmbeddables[type]) { partialElement.expression = allowedEmbeddables[type](id); } addEmbeddable(pageId, partialElement); restProps.onClose(); }, - [addEmbeddable, pageId, restProps, isByValueEnabled] + [addEmbeddable, pageId, restProps] ); return ( @@ -107,7 +93,6 @@ export const AddEmbeddablePanel: React.FunctionComponent = ({ {...restProps} availableEmbeddables={availableEmbeddables || []} onSelect={onSelect} - isByValueEnabled={isByValueEnabled} /> ); }; diff --git a/x-pack/plugins/canvas/public/components/hooks/workpad/index.tsx b/x-pack/plugins/canvas/public/components/hooks/workpad/index.tsx index ffd5b095b12e5..50d527036560a 100644 --- a/x-pack/plugins/canvas/public/components/hooks/workpad/index.tsx +++ b/x-pack/plugins/canvas/public/components/hooks/workpad/index.tsx @@ -6,5 +6,3 @@ */ export { useDownloadWorkpad, useDownloadRenderedWorkpad } from './use_download_workpad'; - -export { useIncomingEmbeddable } from './use_incoming_embeddable'; diff --git a/x-pack/plugins/canvas/public/components/hooks/workpad/use_incoming_embeddable.ts b/x-pack/plugins/canvas/public/components/hooks/workpad/use_incoming_embeddable.ts deleted file mode 100644 index 2f8e2503ea57e..0000000000000 --- a/x-pack/plugins/canvas/public/components/hooks/workpad/use_incoming_embeddable.ts +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useEffect } from 'react'; -import { useDispatch } from 'react-redux'; -import { fromExpression } from '@kbn/interpreter/common'; -import { CANVAS_APP } from '../../../../common/lib'; -import { decode, encode } from '../../../../common/lib/embeddable_dataurl'; -import { CanvasElement, CanvasPage } from '../../../../types'; -import { useEmbeddablesService, useLabsService } from '../../../services'; -// @ts-expect-error unconverted file -import { addElement } from '../../../state/actions/elements'; -// @ts-expect-error unconverted file -import { selectToplevelNodes } from '../../../state/actions/transient'; - -import { - updateEmbeddableExpression, - fetchEmbeddableRenderable, -} from '../../../state/actions/embeddable'; -import { clearValue } from '../../../state/actions/resolved_args'; - -export const useIncomingEmbeddable = (selectedPage: CanvasPage) => { - const embeddablesService = useEmbeddablesService(); - const labsService = useLabsService(); - const dispatch = useDispatch(); - const isByValueEnabled = labsService.isProjectEnabled('labs:canvas:byValueEmbeddable'); - const stateTransferService = embeddablesService.getStateTransfer(); - - // fetch incoming embeddable from state transfer service. - const incomingEmbeddable = stateTransferService.getIncomingEmbeddablePackage(CANVAS_APP, true); - - useEffect(() => { - if (isByValueEnabled && incomingEmbeddable) { - const { embeddableId, input: incomingInput, type } = incomingEmbeddable; - - // retrieve existing element - const originalElement = selectedPage.elements.find( - ({ id }: CanvasElement) => id === embeddableId - ); - - if (originalElement) { - const originalAst = fromExpression(originalElement!.expression); - - const functionIndex = originalAst.chain.findIndex( - ({ function: fn }) => fn === 'embeddable' - ); - - const originalInput = decode( - originalAst.chain[functionIndex].arguments.config[0] as string - ); - - // clear out resolved arg for old embeddable - const argumentPath = [embeddableId, 'expressionRenderable']; - dispatch(clearValue({ path: argumentPath })); - - const updatedInput = { ...originalInput, ...incomingInput }; - - const expression = `embeddable config="${encode(updatedInput)}" - type="${type}" -| render`; - - dispatch( - updateEmbeddableExpression({ - elementId: originalElement.id, - embeddableExpression: expression, - }) - ); - - // update resolved args - dispatch(fetchEmbeddableRenderable(originalElement.id)); - - // select new embeddable element - dispatch(selectToplevelNodes([embeddableId])); - } else { - const expression = `embeddable config="${encode(incomingInput)}" - type="${type}" -| render`; - dispatch(addElement(selectedPage.id, { expression })); - } - } - }, [dispatch, selectedPage, incomingEmbeddable, isByValueEnabled]); -}; diff --git a/x-pack/plugins/canvas/public/components/workpad/workpad.tsx b/x-pack/plugins/canvas/public/components/workpad/workpad.tsx index 7cc077203c737..622c885b6ef28 100644 --- a/x-pack/plugins/canvas/public/components/workpad/workpad.tsx +++ b/x-pack/plugins/canvas/public/components/workpad/workpad.tsx @@ -27,7 +27,6 @@ import { WorkpadRoutingContext } from '../../routes/workpad'; import { usePlatformService } from '../../services'; import { Workpad as WorkpadComponent, Props } from './workpad.component'; import { State } from '../../../types'; -import { useIncomingEmbeddable } from '../hooks'; type ContainerProps = Pick; @@ -59,9 +58,6 @@ export const Workpad: FC = (props) => { }; }); - const selectedPage = propsFromState.pages[propsFromState.selectedPageNumber - 1]; - useIncomingEmbeddable(selectedPage); - const fetchAllRenderables = useCallback(() => { dispatch(fetchAllRenderablesAction()); }, [dispatch]); diff --git a/x-pack/plugins/canvas/public/components/workpad_app/workpad_app.scss b/x-pack/plugins/canvas/public/components/workpad_app/workpad_app.scss index 0ddd44ed8f9a8..4acdca10d61cc 100644 --- a/x-pack/plugins/canvas/public/components/workpad_app/workpad_app.scss +++ b/x-pack/plugins/canvas/public/components/workpad_app/workpad_app.scss @@ -31,7 +31,7 @@ $canvasLayoutFontSize: $euiFontSizeS; .canvasLayout__stageHeader { flex-grow: 0; flex-basis: auto; - padding: $euiSizeS $euiSize; + padding: $euiSizeS; font-size: $canvasLayoutFontSize; border-bottom: $euiBorderThin; background: $euiColorLightestShade; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/__stories__/__snapshots__/editor_menu.stories.storyshot b/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/__stories__/__snapshots__/editor_menu.stories.storyshot deleted file mode 100644 index f4aab0e59e7ee..0000000000000 --- a/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/__stories__/__snapshots__/editor_menu.stories.storyshot +++ /dev/null @@ -1,81 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Storyshots components/WorkpadHeader/EditorMenu dark mode 1`] = ` -
-
- -
-
-`; - -exports[`Storyshots components/WorkpadHeader/EditorMenu default 1`] = ` -
-
- -
-
-`; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/__stories__/editor_menu.stories.tsx b/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/__stories__/editor_menu.stories.tsx deleted file mode 100644 index 01048bc0af301..0000000000000 --- a/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/__stories__/editor_menu.stories.tsx +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { storiesOf } from '@storybook/react'; -import { action } from '@storybook/addon-actions'; -import React from 'react'; -import { EmbeddableFactoryDefinition, IEmbeddable } from 'src/plugins/embeddable/public'; -import { BaseVisType, VisTypeAlias } from 'src/plugins/visualizations/public'; -import { EditorMenu } from '../editor_menu.component'; - -const testFactories: EmbeddableFactoryDefinition[] = [ - { - type: 'ml_anomaly_swimlane', - getDisplayName: () => 'Anomaly swimlane', - getIconType: () => '', - getDescription: () => 'Description for anomaly swimlane', - isEditable: () => Promise.resolve(true), - create: () => Promise.resolve({ id: 'swimlane_embeddable' } as IEmbeddable), - grouping: [ - { - id: 'ml', - getDisplayName: () => 'machine learning', - getIconType: () => 'machineLearningApp', - }, - ], - }, - { - type: 'ml_anomaly_chart', - getDisplayName: () => 'Anomaly chart', - getIconType: () => '', - getDescription: () => 'Description for anomaly chart', - isEditable: () => Promise.resolve(true), - create: () => Promise.resolve({ id: 'anomaly_chart_embeddable' } as IEmbeddable), - grouping: [ - { - id: 'ml', - getDisplayName: () => 'machine learning', - getIconType: () => 'machineLearningApp', - }, - ], - }, - { - type: 'log_stream', - getDisplayName: () => 'Log stream', - getIconType: () => '', - getDescription: () => 'Description for log stream', - isEditable: () => Promise.resolve(true), - create: () => Promise.resolve({ id: 'anomaly_chart_embeddable' } as IEmbeddable), - }, -]; - -const testVisTypes: BaseVisType[] = [ - { title: 'TSVB', icon: '', description: 'Description of TSVB', name: 'tsvb' } as BaseVisType, - { - titleInWizard: 'Custom visualization', - title: 'Vega', - icon: '', - description: 'Description of Vega', - name: 'vega', - } as BaseVisType, -]; - -const testVisTypeAliases: VisTypeAlias[] = [ - { - title: 'Lens', - aliasApp: 'lens', - aliasPath: 'path/to/lens', - icon: 'lensApp', - name: 'lens', - description: 'Description of Lens app', - stage: 'production', - }, - { - title: 'Maps', - aliasApp: 'maps', - aliasPath: 'path/to/maps', - icon: 'gisApp', - name: 'maps', - description: 'Description of Maps app', - stage: 'production', - }, -]; - -storiesOf('components/WorkpadHeader/EditorMenu', module) - .add('default', () => ( - action('createNewVisType')} - createNewEmbeddable={() => action('createNewEmbeddable')} - /> - )) - .add('dark mode', () => ( - action('createNewVisType')} - createNewEmbeddable={() => action('createNewEmbeddable')} - /> - )); diff --git a/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.component.tsx b/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.component.tsx deleted file mode 100644 index e8f762f9731a1..0000000000000 --- a/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.component.tsx +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { FC } from 'react'; -import { - EuiContextMenu, - EuiContextMenuPanelItemDescriptor, - EuiContextMenuItemIcon, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { EmbeddableFactoryDefinition } from '../../../../../../../src/plugins/embeddable/public'; -import { BaseVisType, VisTypeAlias } from '../../../../../../../src/plugins/visualizations/public'; -import { SolutionToolbarPopover } from '../../../../../../../src/plugins/presentation_util/public'; - -const strings = { - getEditorMenuButtonLabel: () => - i18n.translate('xpack.canvas.solutionToolbar.editorMenuButtonLabel', { - defaultMessage: 'Select type', - }), -}; - -interface FactoryGroup { - id: string; - appName: string; - icon: EuiContextMenuItemIcon; - panelId: number; - factories: EmbeddableFactoryDefinition[]; -} - -interface Props { - factories: EmbeddableFactoryDefinition[]; - isDarkThemeEnabled?: boolean; - promotedVisTypes: BaseVisType[]; - visTypeAliases: VisTypeAlias[]; - createNewVisType: (visType?: BaseVisType | VisTypeAlias) => () => void; - createNewEmbeddable: (factory: EmbeddableFactoryDefinition) => () => void; -} - -export const EditorMenu: FC = ({ - factories, - isDarkThemeEnabled, - promotedVisTypes, - visTypeAliases, - createNewVisType, - createNewEmbeddable, -}: Props) => { - const factoryGroupMap: Record = {}; - const ungroupedFactories: EmbeddableFactoryDefinition[] = []; - - let panelCount = 1; - - // Maps factories with a group to create nested context menus for each group type - // and pushes ungrouped factories into a separate array - factories.forEach((factory: EmbeddableFactoryDefinition, index) => { - const { grouping } = factory; - - if (grouping) { - grouping.forEach((group) => { - if (factoryGroupMap[group.id]) { - factoryGroupMap[group.id].factories.push(factory); - } else { - factoryGroupMap[group.id] = { - id: group.id, - appName: group.getDisplayName ? group.getDisplayName({}) : group.id, - icon: (group.getIconType ? group.getIconType({}) : 'empty') as EuiContextMenuItemIcon, - factories: [factory], - panelId: panelCount, - }; - - panelCount++; - } - }); - } else { - ungroupedFactories.push(factory); - } - }); - - const getVisTypeMenuItem = (visType: BaseVisType): EuiContextMenuPanelItemDescriptor => { - const { name, title, titleInWizard, description, icon = 'empty' } = visType; - return { - name: titleInWizard || title, - icon: icon as string, - onClick: createNewVisType(visType), - 'data-test-subj': `visType-${name}`, - toolTipContent: description, - }; - }; - - const getVisTypeAliasMenuItem = ( - visTypeAlias: VisTypeAlias - ): EuiContextMenuPanelItemDescriptor => { - const { name, title, description, icon = 'empty' } = visTypeAlias; - - return { - name: title, - icon, - onClick: createNewVisType(visTypeAlias), - 'data-test-subj': `visType-${name}`, - toolTipContent: description, - }; - }; - - const getEmbeddableFactoryMenuItem = ( - factory: EmbeddableFactoryDefinition - ): EuiContextMenuPanelItemDescriptor => { - const icon = factory?.getIconType ? factory.getIconType() : 'empty'; - - const toolTipContent = factory?.getDescription ? factory.getDescription() : undefined; - - return { - name: factory.getDisplayName(), - icon, - toolTipContent, - onClick: createNewEmbeddable(factory), - 'data-test-subj': `createNew-${factory.type}`, - }; - }; - - const editorMenuPanels = [ - { - id: 0, - items: [ - ...visTypeAliases.map(getVisTypeAliasMenuItem), - ...Object.values(factoryGroupMap).map(({ id, appName, icon, panelId }) => ({ - name: appName, - icon, - panel: panelId, - 'data-test-subj': `canvasEditorMenu-${id}Group`, - })), - ...ungroupedFactories.map(getEmbeddableFactoryMenuItem), - ...promotedVisTypes.map(getVisTypeMenuItem), - ], - }, - ...Object.values(factoryGroupMap).map( - ({ appName, panelId, factories: groupFactories }: FactoryGroup) => ({ - id: panelId, - title: appName, - items: groupFactories.map(getEmbeddableFactoryMenuItem), - }) - ), - ]; - - return ( - - {() => ( - - )} - - ); -}; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.tsx b/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.tsx deleted file mode 100644 index dad34e6983c5d..0000000000000 --- a/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.tsx +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { FC, useCallback } from 'react'; -import { useLocation } from 'react-router-dom'; -import { trackCanvasUiMetric, METRIC_TYPE } from '../../../../public/lib/ui_metric'; -import { - useEmbeddablesService, - usePlatformService, - useVisualizationsService, -} from '../../../services'; -import { - BaseVisType, - VisGroups, - VisTypeAlias, -} from '../../../../../../../src/plugins/visualizations/public'; -import { - EmbeddableFactoryDefinition, - EmbeddableInput, -} from '../../../../../../../src/plugins/embeddable/public'; -import { CANVAS_APP } from '../../../../common/lib'; -import { encode } from '../../../../common/lib/embeddable_dataurl'; -import { ElementSpec } from '../../../../types'; -import { EditorMenu as Component } from './editor_menu.component'; - -interface Props { - /** - * Handler for adding a selected element to the workpad - */ - addElement: (element: Partial) => void; -} - -export const EditorMenu: FC = ({ addElement }) => { - const embeddablesService = useEmbeddablesService(); - const { pathname, search } = useLocation(); - const platformService = usePlatformService(); - const stateTransferService = embeddablesService.getStateTransfer(); - const visualizationsService = useVisualizationsService(); - const IS_DARK_THEME = platformService.getUISetting('theme:darkMode'); - - const createNewVisType = useCallback( - (visType?: BaseVisType | VisTypeAlias) => () => { - let path = ''; - let appId = ''; - - if (visType) { - if (trackCanvasUiMetric) { - trackCanvasUiMetric(METRIC_TYPE.CLICK, `${visType.name}:create`); - } - - if ('aliasPath' in visType) { - appId = visType.aliasApp; - path = visType.aliasPath; - } else { - appId = 'visualize'; - path = `#/create?type=${encodeURIComponent(visType.name)}`; - } - } else { - appId = 'visualize'; - path = '#/create?'; - } - - stateTransferService.navigateToEditor(appId, { - path, - state: { - originatingApp: CANVAS_APP, - originatingPath: `#/${pathname}${search}`, - }, - }); - }, - [stateTransferService, pathname, search] - ); - - const createNewEmbeddable = useCallback( - (factory: EmbeddableFactoryDefinition) => async () => { - if (trackCanvasUiMetric) { - trackCanvasUiMetric(METRIC_TYPE.CLICK, factory.type); - } - let embeddableInput; - if (factory.getExplicitInput) { - embeddableInput = await factory.getExplicitInput(); - } else { - const newEmbeddable = await factory.create({} as EmbeddableInput); - embeddableInput = newEmbeddable?.getInput(); - } - - if (embeddableInput) { - const config = encode(embeddableInput); - const expression = `embeddable config="${config}" - type="${factory.type}" -| render`; - - addElement({ expression }); - } - }, - [addElement] - ); - - const getVisTypesByGroup = (group: VisGroups): BaseVisType[] => - visualizationsService - .getByGroup(group) - .sort(({ name: a }: BaseVisType | VisTypeAlias, { name: b }: BaseVisType | VisTypeAlias) => { - if (a < b) { - return -1; - } - if (a > b) { - return 1; - } - return 0; - }) - .filter(({ hidden }: BaseVisType) => !hidden); - - const visTypeAliases = visualizationsService - .getAliases() - .sort(({ promotion: a = false }: VisTypeAlias, { promotion: b = false }: VisTypeAlias) => - a === b ? 0 : a ? -1 : 1 - ); - - const factories = embeddablesService - ? Array.from(embeddablesService.getEmbeddableFactories()).filter( - ({ type, isEditable, canCreateNew, isContainerType }) => - isEditable() && - !isContainerType && - canCreateNew() && - !['visualization', 'ml'].some((factoryType) => { - return type.includes(factoryType); - }) - ) - : []; - - const promotedVisTypes = getVisTypesByGroup(VisGroups.PROMOTED); - - return ( - - ); -}; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/index.ts b/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/index.ts deleted file mode 100644 index 0f903b1bbbe2e..0000000000000 --- a/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { EditorMenu } from './editor_menu'; -export { EditorMenu as EditorMenuComponent } from './editor_menu.component'; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/element_menu/element_menu.component.tsx b/x-pack/plugins/canvas/public/components/workpad_header/element_menu/element_menu.component.tsx index 1cfab236d9a9c..8ac581b0866a4 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/element_menu/element_menu.component.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/element_menu/element_menu.component.tsx @@ -12,11 +12,11 @@ import { EuiContextMenu, EuiIcon, EuiContextMenuPanelItemDescriptor } from '@ela import { i18n } from '@kbn/i18n'; import { PrimaryActionPopover } from '../../../../../../../src/plugins/presentation_util/public'; import { getId } from '../../../lib/get_id'; +import { ClosePopoverFn } from '../../popover'; import { CONTEXT_MENU_TOP_BORDER_CLASSNAME } from '../../../../common/lib'; import { ElementSpec } from '../../../../types'; import { flattenPanelTree } from '../../../lib/flatten_panel_tree'; import { AssetManager } from '../../asset_manager'; -import { ClosePopoverFn } from '../../popover'; import { SavedElementsModal } from '../../saved_elements_modal'; interface CategorizedElementLists { @@ -112,7 +112,7 @@ const categorizeElementsByType = (elements: ElementSpec[]): { [key: string]: Ele return categories; }; -export interface Props { +interface Props { /** * Dictionary of elements from elements registry */ @@ -120,7 +120,7 @@ export interface Props { /** * Handler for adding a selected element to the workpad */ - addElement: (element: Partial) => void; + addElement: (element: ElementSpec) => void; } export const ElementMenu: FunctionComponent = ({ elements, addElement }) => { diff --git a/x-pack/plugins/canvas/public/components/workpad_header/element_menu/index.ts b/x-pack/plugins/canvas/public/components/workpad_header/element_menu/index.ts index 037bb84b0cdba..52c8daece7690 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/element_menu/index.ts +++ b/x-pack/plugins/canvas/public/components/workpad_header/element_menu/index.ts @@ -5,4 +5,5 @@ * 2.0. */ -export { ElementMenu } from './element_menu.component'; +export { ElementMenu } from './element_menu'; +export { ElementMenu as ElementMenuComponent } from './element_menu.component'; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/workpad_header.component.tsx b/x-pack/plugins/canvas/public/components/workpad_header/workpad_header.component.tsx index b84e4faf2925e..f031d7c263199 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/workpad_header.component.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/workpad_header.component.tsx @@ -27,7 +27,6 @@ import { ElementMenu } from './element_menu'; import { ShareMenu } from './share_menu'; import { ViewMenu } from './view_menu'; import { LabsControl } from './labs_control'; -import { EditorMenu } from './editor_menu'; const strings = { getFullScreenButtonAriaLabel: () => @@ -161,22 +160,24 @@ export const WorkpadHeader: FC = ({ - {isWriteable && ( - - - {{ - primaryActionButton: , - quickButtonGroup: , - addFromLibraryButton: , - extraButtons: [], - }} - - - )} + {isWriteable && ( + + + {{ + primaryActionButton: ( + + ), + quickButtonGroup: , + addFromLibraryButton: , + }} + + + )} @@ -191,7 +192,6 @@ export const WorkpadHeader: FC = ({ - diff --git a/x-pack/plugins/canvas/public/plugin.tsx b/x-pack/plugins/canvas/public/plugin.tsx index 912055dd47a62..723d1afea2860 100644 --- a/x-pack/plugins/canvas/public/plugin.tsx +++ b/x-pack/plugins/canvas/public/plugin.tsx @@ -8,7 +8,6 @@ import { BehaviorSubject } from 'rxjs'; import type { SharePluginSetup } from 'src/plugins/share/public'; import { ChartsPluginSetup, ChartsPluginStart } from 'src/plugins/charts/public'; -import { VisualizationsStart } from 'src/plugins/visualizations/public'; import { ReportingStart } from '../../reporting/public'; import { CoreSetup, @@ -64,7 +63,6 @@ export interface CanvasStartDeps { charts: ChartsPluginStart; data: DataPublicPluginStart; presentationUtil: PresentationUtilPluginStart; - visualizations: VisualizationsStart; spaces?: SpacesPluginStart; } @@ -124,12 +122,7 @@ export class CanvasPlugin const { pluginServices } = await import('./services'); pluginServices.setRegistry( - pluginServiceRegistry.start({ - coreStart, - startPlugins, - appUpdater: this.appUpdater, - initContext: this.initContext, - }) + pluginServiceRegistry.start({ coreStart, startPlugins, initContext: this.initContext }) ); // Load application bundle diff --git a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.ts b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.ts index bd9a4e7141c27..35e79b442a15d 100644 --- a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.ts +++ b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.ts @@ -53,24 +53,14 @@ export const useWorkpad = ( workpad.aliasId = aliasId; } - if (storedWorkpad.id !== workpadId || storedWorkpad.aliasId !== aliasId) { - dispatch(setAssets(assets)); - dispatch(setWorkpad(workpad, { loadPages })); - dispatch(setZoomScale(1)); - } + dispatch(setAssets(assets)); + dispatch(setWorkpad(workpad, { loadPages })); + dispatch(setZoomScale(1)); } catch (e) { setError(e as Error | string); } })(); - }, [ - workpadId, - dispatch, - setError, - loadPages, - workpadResolve, - storedWorkpad.id, - storedWorkpad.aliasId, - ]); + }, [workpadId, dispatch, setError, loadPages, workpadResolve]); useEffect(() => { (() => { diff --git a/x-pack/plugins/canvas/public/services/embeddables.ts b/x-pack/plugins/canvas/public/services/embeddables.ts index 26b150b7a5349..24d7a57e086f2 100644 --- a/x-pack/plugins/canvas/public/services/embeddables.ts +++ b/x-pack/plugins/canvas/public/services/embeddables.ts @@ -5,12 +5,8 @@ * 2.0. */ -import { - EmbeddableFactory, - EmbeddableStateTransfer, -} from '../../../../../src/plugins/embeddable/public'; +import { EmbeddableFactory } from '../../../../../src/plugins/embeddable/public'; export interface CanvasEmbeddablesService { getEmbeddableFactories: () => IterableIterator; - getStateTransfer: () => EmbeddableStateTransfer; } diff --git a/x-pack/plugins/canvas/public/services/index.ts b/x-pack/plugins/canvas/public/services/index.ts index ed55f919e4c76..f4292810b8089 100644 --- a/x-pack/plugins/canvas/public/services/index.ts +++ b/x-pack/plugins/canvas/public/services/index.ts @@ -17,7 +17,6 @@ import { CanvasNavLinkService } from './nav_link'; import { CanvasNotifyService } from './notify'; import { CanvasPlatformService } from './platform'; import { CanvasReportingService } from './reporting'; -import { CanvasVisualizationsService } from './visualizations'; import { CanvasWorkpadService } from './workpad'; export interface CanvasPluginServices { @@ -29,7 +28,6 @@ export interface CanvasPluginServices { notify: CanvasNotifyService; platform: CanvasPlatformService; reporting: CanvasReportingService; - visualizations: CanvasVisualizationsService; workpad: CanvasWorkpadService; } @@ -46,6 +44,4 @@ export const useNavLinkService = () => (() => pluginServices.getHooks().navLink. export const useNotifyService = () => (() => pluginServices.getHooks().notify.useService())(); export const usePlatformService = () => (() => pluginServices.getHooks().platform.useService())(); export const useReportingService = () => (() => pluginServices.getHooks().reporting.useService())(); -export const useVisualizationsService = () => - (() => pluginServices.getHooks().visualizations.useService())(); export const useWorkpadService = () => (() => pluginServices.getHooks().workpad.useService())(); diff --git a/x-pack/plugins/canvas/public/services/kibana/embeddables.ts b/x-pack/plugins/canvas/public/services/kibana/embeddables.ts index 8d1a86edab3d8..054b9da7409fb 100644 --- a/x-pack/plugins/canvas/public/services/kibana/embeddables.ts +++ b/x-pack/plugins/canvas/public/services/kibana/embeddables.ts @@ -16,5 +16,4 @@ export type EmbeddablesServiceFactory = KibanaPluginServiceFactory< export const embeddablesServiceFactory: EmbeddablesServiceFactory = ({ startPlugins }) => ({ getEmbeddableFactories: startPlugins.embeddable.getEmbeddableFactories, - getStateTransfer: startPlugins.embeddable.getStateTransfer, }); diff --git a/x-pack/plugins/canvas/public/services/kibana/index.ts b/x-pack/plugins/canvas/public/services/kibana/index.ts index 91767947bc0a6..1eb010e8d6f9d 100644 --- a/x-pack/plugins/canvas/public/services/kibana/index.ts +++ b/x-pack/plugins/canvas/public/services/kibana/index.ts @@ -22,7 +22,6 @@ import { navLinkServiceFactory } from './nav_link'; import { notifyServiceFactory } from './notify'; import { platformServiceFactory } from './platform'; import { reportingServiceFactory } from './reporting'; -import { visualizationsServiceFactory } from './visualizations'; import { workpadServiceFactory } from './workpad'; export { customElementServiceFactory } from './custom_element'; @@ -32,7 +31,6 @@ export { labsServiceFactory } from './labs'; export { notifyServiceFactory } from './notify'; export { platformServiceFactory } from './platform'; export { reportingServiceFactory } from './reporting'; -export { visualizationsServiceFactory } from './visualizations'; export { workpadServiceFactory } from './workpad'; export const pluginServiceProviders: PluginServiceProviders< @@ -47,7 +45,6 @@ export const pluginServiceProviders: PluginServiceProviders< notify: new PluginServiceProvider(notifyServiceFactory), platform: new PluginServiceProvider(platformServiceFactory), reporting: new PluginServiceProvider(reportingServiceFactory), - visualizations: new PluginServiceProvider(visualizationsServiceFactory), workpad: new PluginServiceProvider(workpadServiceFactory), }; diff --git a/x-pack/plugins/canvas/public/services/kibana/visualizations.ts b/x-pack/plugins/canvas/public/services/kibana/visualizations.ts deleted file mode 100644 index e319ec1c1f427..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/visualizations.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { KibanaPluginServiceFactory } from '../../../../../../src/plugins/presentation_util/public'; -import { CanvasStartDeps } from '../../plugin'; -import { CanvasVisualizationsService } from '../visualizations'; - -export type VisualizationsServiceFactory = KibanaPluginServiceFactory< - CanvasVisualizationsService, - CanvasStartDeps ->; - -export const visualizationsServiceFactory: VisualizationsServiceFactory = ({ startPlugins }) => ({ - showNewVisModal: startPlugins.visualizations.showNewVisModal, - getByGroup: startPlugins.visualizations.getByGroup, - getAliases: startPlugins.visualizations.getAliases, -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/embeddables.ts b/x-pack/plugins/canvas/public/services/stubs/embeddables.ts index 9c2cf4d0650ab..173d27563e2b2 100644 --- a/x-pack/plugins/canvas/public/services/stubs/embeddables.ts +++ b/x-pack/plugins/canvas/public/services/stubs/embeddables.ts @@ -14,5 +14,4 @@ const noop = (..._args: any[]): any => {}; export const embeddablesServiceFactory: EmbeddablesServiceFactory = () => ({ getEmbeddableFactories: noop, - getStateTransfer: noop, }); diff --git a/x-pack/plugins/canvas/public/services/stubs/index.ts b/x-pack/plugins/canvas/public/services/stubs/index.ts index 2216013a29c12..06a5ff49e9c04 100644 --- a/x-pack/plugins/canvas/public/services/stubs/index.ts +++ b/x-pack/plugins/canvas/public/services/stubs/index.ts @@ -22,7 +22,6 @@ import { navLinkServiceFactory } from './nav_link'; import { notifyServiceFactory } from './notify'; import { platformServiceFactory } from './platform'; import { reportingServiceFactory } from './reporting'; -import { visualizationsServiceFactory } from './visualizations'; import { workpadServiceFactory } from './workpad'; export { customElementServiceFactory } from './custom_element'; @@ -32,7 +31,6 @@ export { navLinkServiceFactory } from './nav_link'; export { notifyServiceFactory } from './notify'; export { platformServiceFactory } from './platform'; export { reportingServiceFactory } from './reporting'; -export { visualizationsServiceFactory } from './visualizations'; export { workpadServiceFactory } from './workpad'; export const pluginServiceProviders: PluginServiceProviders = { @@ -44,7 +42,6 @@ export const pluginServiceProviders: PluginServiceProviders; - -const noop = (..._args: any[]): any => {}; - -export const visualizationsServiceFactory: VisualizationsServiceFactory = () => ({ - showNewVisModal: noop, - getByGroup: noop, - getAliases: noop, -}); diff --git a/x-pack/plugins/canvas/public/services/visualizations.ts b/x-pack/plugins/canvas/public/services/visualizations.ts deleted file mode 100644 index c602b1dd39f3d..0000000000000 --- a/x-pack/plugins/canvas/public/services/visualizations.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { VisualizationsStart } from '../../../../../src/plugins/visualizations/public'; - -export interface CanvasVisualizationsService { - showNewVisModal: VisualizationsStart['showNewVisModal']; - getByGroup: VisualizationsStart['getByGroup']; - getAliases: VisualizationsStart['getAliases']; -} diff --git a/x-pack/plugins/canvas/public/state/reducers/embeddable.ts b/x-pack/plugins/canvas/public/state/reducers/embeddable.ts index 092d4300d86b7..4cfdc7f21945f 100644 --- a/x-pack/plugins/canvas/public/state/reducers/embeddable.ts +++ b/x-pack/plugins/canvas/public/state/reducers/embeddable.ts @@ -40,7 +40,7 @@ export const embeddableReducer = handleActions< const element = pageWithElement.elements.find((elem) => elem.id === elementId); - if (!element || element.expression === embeddableExpression) { + if (!element) { return workpadState; } diff --git a/x-pack/plugins/canvas/server/plugin.ts b/x-pack/plugins/canvas/server/plugin.ts index ebe43ba76a46a..4071b891e4c3d 100644 --- a/x-pack/plugins/canvas/server/plugin.ts +++ b/x-pack/plugins/canvas/server/plugin.ts @@ -14,7 +14,6 @@ import { ExpressionsServerSetup } from 'src/plugins/expressions/server'; import { BfetchServerSetup } from 'src/plugins/bfetch/server'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { HomeServerPluginSetup } from 'src/plugins/home/server'; -import { EmbeddableSetup } from 'src/plugins/embeddable/server'; import { ESSQL_SEARCH_STRATEGY } from '../common/lib/constants'; import { ReportingSetup } from '../../reporting/server'; import { PluginSetupContract as FeaturesPluginSetup } from '../../features/server'; @@ -31,7 +30,6 @@ import { CanvasRouteHandlerContext, createWorkpadRouteContext } from './workpad_ interface PluginsSetup { expressions: ExpressionsServerSetup; - embeddable: EmbeddableSetup; features: FeaturesPluginSetup; home: HomeServerPluginSetup; bfetch: BfetchServerSetup; @@ -84,12 +82,7 @@ export class CanvasPlugin implements Plugin { const kibanaIndex = coreSetup.savedObjects.getKibanaIndex(); registerCanvasUsageCollector(plugins.usageCollection, kibanaIndex); - setupInterpreter(expressionsFork, { - embeddablePersistableStateService: { - extract: plugins.embeddable.extract, - inject: plugins.embeddable.inject, - }, - }); + setupInterpreter(expressionsFork); coreSetup.getStartServices().then(([_, depsStart]) => { const strategy = essqlSearchStrategyProvider(); diff --git a/x-pack/plugins/canvas/server/setup_interpreter.ts b/x-pack/plugins/canvas/server/setup_interpreter.ts index 849ad79717056..2fe23eb86c086 100644 --- a/x-pack/plugins/canvas/server/setup_interpreter.ts +++ b/x-pack/plugins/canvas/server/setup_interpreter.ts @@ -7,15 +7,9 @@ import { ExpressionsServerSetup } from 'src/plugins/expressions/server'; import { functions } from '../canvas_plugin_src/functions/server'; -import { - initFunctions as initExternalFunctions, - InitializeArguments, -} from '../canvas_plugin_src/functions/external'; +import { functions as externalFunctions } from '../canvas_plugin_src/functions/external'; -export function setupInterpreter( - expressions: ExpressionsServerSetup, - dependencies: InitializeArguments -) { +export function setupInterpreter(expressions: ExpressionsServerSetup) { functions.forEach((f) => expressions.registerFunction(f)); - initExternalFunctions(dependencies).forEach((f) => expressions.registerFunction(f)); + externalFunctions.forEach((f) => expressions.registerFunction(f)); } diff --git a/x-pack/plugins/canvas/types/embeddables.ts b/x-pack/plugins/canvas/types/embeddables.ts deleted file mode 100644 index b78efece59d8f..0000000000000 --- a/x-pack/plugins/canvas/types/embeddables.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { TimeRange } from 'src/plugins/data/public'; -import { Filter } from '@kbn/es-query'; -import { EmbeddableInput as Input } from '../../../../src/plugins/embeddable/common/'; - -export type EmbeddableInput = Input & { - timeRange?: TimeRange; - filters?: Filter[]; - savedObjectId?: string; -}; diff --git a/x-pack/plugins/canvas/types/functions.ts b/x-pack/plugins/canvas/types/functions.ts index c80102915ed95..2569e0b10685b 100644 --- a/x-pack/plugins/canvas/types/functions.ts +++ b/x-pack/plugins/canvas/types/functions.ts @@ -10,8 +10,8 @@ import { UnwrapPromiseOrReturn } from '@kbn/utility-types'; import { functions as commonFunctions } from '../canvas_plugin_src/functions/common'; import { functions as browserFunctions } from '../canvas_plugin_src/functions/browser'; import { functions as serverFunctions } from '../canvas_plugin_src/functions/server'; -import { initFunctions as initExternalFunctions } from '../canvas_plugin_src/functions/external'; -import { initFunctions as initClientFunctions } from '../public/functions'; +import { functions as externalFunctions } from '../canvas_plugin_src/functions/external'; +import { initFunctions } from '../public/functions'; /** * A `ExpressionFunctionFactory` is a powerful type used for any function that produces @@ -90,11 +90,9 @@ export type FunctionFactory = type CommonFunction = FunctionFactory; type BrowserFunction = FunctionFactory; type ServerFunction = FunctionFactory; -type ExternalFunction = FunctionFactory< - ReturnType extends Array ? U : never ->; +type ExternalFunction = FunctionFactory; type ClientFunctions = FunctionFactory< - ReturnType extends Array ? U : never + ReturnType extends Array ? U : never >; /** diff --git a/x-pack/plugins/canvas/types/index.ts b/x-pack/plugins/canvas/types/index.ts index 930f337292088..09ae1510be6da 100644 --- a/x-pack/plugins/canvas/types/index.ts +++ b/x-pack/plugins/canvas/types/index.ts @@ -9,7 +9,6 @@ export * from '../../../../src/plugins/expressions/common'; export * from './assets'; export * from './canvas'; export * from './elements'; -export * from './embeddables'; export * from './filters'; export * from './functions'; export * from './renderers'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_router.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_router.test.tsx index c0278c765e85e..9598212d3e0c9 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_router.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_router.test.tsx @@ -5,9 +5,6 @@ * 2.0. */ -import '../../../__mocks__/shallow_useeffect.mock'; -import '../../../__mocks__/react_router'; -import { setMockActions, setMockValues } from '../../../__mocks__/kea_logic'; import '../../__mocks__/engine_logic.mock'; import React from 'react'; @@ -15,110 +12,13 @@ import { Route, Switch } from 'react-router-dom'; import { shallow } from 'enzyme'; -import { LogRetentionOptions } from '../log_retention'; - import { CurationsRouter } from './'; -const MOCK_VALUES = { - // CurationsSettingsLogic - dataLoading: false, - curationsSettings: { - enabled: true, - mode: 'automatic', - }, - // LogRetentionLogic - logRetention: { - [LogRetentionOptions.Analytics]: { - enabled: true, - }, - }, - // LicensingLogic - hasPlatinumLicense: true, -}; - -const MOCK_ACTIONS = { - // CurationsSettingsLogic - loadCurationsSettings: jest.fn(), - onSkipLoadingCurationsSettings: jest.fn(), - // LogRetentionLogic - fetchLogRetention: jest.fn(), -}; - describe('CurationsRouter', () => { - beforeEach(() => { - jest.clearAllMocks(); - setMockActions(MOCK_ACTIONS); - }); - it('renders', () => { const wrapper = shallow(); expect(wrapper.find(Switch)).toHaveLength(1); expect(wrapper.find(Route)).toHaveLength(4); }); - - it('loads log retention settings', () => { - setMockValues(MOCK_VALUES); - shallow(); - - expect(MOCK_ACTIONS.fetchLogRetention).toHaveBeenCalled(); - }); - - describe('when the user has no platinum license', () => { - beforeEach(() => { - setMockValues({ - ...MOCK_VALUES, - hasPlatinumLicense: false, - }); - }); - - it('it does not fetch log retention', () => { - shallow(); - expect(MOCK_ACTIONS.fetchLogRetention).toHaveBeenCalledTimes(0); - }); - }); - - describe('loading curation settings based on log retention', () => { - it('loads curation settings when log retention is enabled', () => { - setMockValues({ - ...MOCK_VALUES, - logRetention: { - [LogRetentionOptions.Analytics]: { - enabled: true, - }, - }, - }); - - shallow(); - - expect(MOCK_ACTIONS.loadCurationsSettings).toHaveBeenCalledTimes(1); - }); - - it('skips loading curation settings when log retention is disabled', () => { - setMockValues({ - ...MOCK_VALUES, - logRetention: { - [LogRetentionOptions.Analytics]: { - enabled: false, - }, - }, - }); - - shallow(); - - expect(MOCK_ACTIONS.onSkipLoadingCurationsSettings).toHaveBeenCalledTimes(1); - }); - - it('takes no action if log retention has not yet been loaded', () => { - setMockValues({ - ...MOCK_VALUES, - logRetention: null, - }); - - shallow(); - - expect(MOCK_ACTIONS.loadCurationsSettings).toHaveBeenCalledTimes(0); - expect(MOCK_ACTIONS.onSkipLoadingCurationsSettings).toHaveBeenCalledTimes(0); - }); - }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_router.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_router.tsx index a3b000ea5054a..693e5406b714b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_router.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_router.tsx @@ -5,53 +5,20 @@ * 2.0. */ -import React, { useEffect } from 'react'; +import React from 'react'; import { Route, Switch } from 'react-router-dom'; -import { useValues, useActions } from 'kea'; - -import { LicensingLogic } from '../../../shared/licensing'; import { ENGINE_CURATIONS_PATH, ENGINE_CURATIONS_NEW_PATH, ENGINE_CURATION_PATH, ENGINE_CURATION_SUGGESTION_PATH, } from '../../routes'; -import { LogRetentionLogic, LogRetentionOptions } from '../log_retention'; import { Curation } from './curation'; import { Curations, CurationCreation, CurationSuggestion } from './views'; -import { CurationsSettingsLogic } from './views/curations_settings'; export const CurationsRouter: React.FC = () => { - // We need to loadCurationsSettings here so they are available across all views - - const { hasPlatinumLicense } = useValues(LicensingLogic); - - const { loadCurationsSettings, onSkipLoadingCurationsSettings } = - useActions(CurationsSettingsLogic); - - const { logRetention } = useValues(LogRetentionLogic); - const { fetchLogRetention } = useActions(LogRetentionLogic); - - const analyticsDisabled = !logRetention?.[LogRetentionOptions.Analytics].enabled; - - useEffect(() => { - if (hasPlatinumLicense) { - fetchLogRetention(); - } - }, [hasPlatinumLicense]); - - useEffect(() => { - if (logRetention) { - if (!analyticsDisabled) { - loadCurationsSettings(); - } else { - onSkipLoadingCurationsSettings(); - } - } - }, [logRetention]); - return ( diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.tsx index 2207555772b5b..b0f4f03789af2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.tsx @@ -24,17 +24,15 @@ import { getCurationsBreadcrumbs } from '../utils'; import { CurationsHistory } from './curations_history/curations_history'; import { CurationsOverview } from './curations_overview'; -import { CurationsSettings, CurationsSettingsLogic } from './curations_settings'; +import { CurationsSettings } from './curations_settings'; export const Curations: React.FC = () => { - const { dataLoading: curationsDataLoading, meta, selectedPageTab } = useValues(CurationsLogic); + const { dataLoading, meta, selectedPageTab } = useValues(CurationsLogic); const { loadCurations, onSelectPageTab } = useActions(CurationsLogic); const { engine: { search_relevance_suggestions_active: searchRelevanceSuggestionsActive }, } = useValues(EngineLogic); - const { dataLoading: curationsSettingsDataLoading } = useValues(CurationsSettingsLogic); - const suggestionsEnabled = searchRelevanceSuggestionsActive; const OVERVIEW_TAB = { @@ -82,8 +80,6 @@ export const Curations: React.FC = () => { loadCurations(); }, [meta.page.current]); - const isLoading = curationsSettingsDataLoading || curationsDataLoading; - return ( { {CREATE_NEW_CURATION_TITLE} , ], - tabs: isLoading ? undefined : pageTabs, + tabs: dataLoading ? undefined : pageTabs, }} - isLoading={isLoading} + isLoading={dataLoading} > {selectedPageTab === 'overview' && } {selectedPageTab === 'history' && } diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings/curations_settings.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings/curations_settings.test.tsx index 3b01d1e41c271..4b4e11c31d4b8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings/curations_settings.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings/curations_settings.test.tsx @@ -17,6 +17,8 @@ import { shallow, ShallowWrapper } from 'enzyme'; import { EuiButtonEmpty, EuiCallOut, EuiSwitch } from '@elastic/eui'; +import { mountWithIntl } from '@kbn/test/jest'; + import { Loading } from '../../../../../shared/loading'; import { EuiButtonTo } from '../../../../../shared/react_router_helpers'; import { DataPanel } from '../../../data_panel'; @@ -44,6 +46,8 @@ const MOCK_VALUES = { const MOCK_ACTIONS = { // CurationsSettingsLogic + loadCurationsSettings: jest.fn(), + onSkipLoadingCurationsSettings: jest.fn(), toggleCurationsEnabled: jest.fn(), toggleCurationsMode: jest.fn(), // LogRetentionLogic @@ -56,6 +60,14 @@ describe('CurationsSettings', () => { setMockActions(MOCK_ACTIONS); }); + it('loads curations and log retention settings on load', () => { + setMockValues(MOCK_VALUES); + mountWithIntl(); + + expect(MOCK_ACTIONS.loadCurationsSettings).toHaveBeenCalled(); + expect(MOCK_ACTIONS.fetchLogRetention).toHaveBeenCalled(); + }); + it('contains a switch to toggle curations settings', () => { let wrapper: ShallowWrapper; @@ -154,6 +166,50 @@ describe('CurationsSettings', () => { expect(wrapper.is(Loading)).toBe(true); }); + describe('loading curation settings based on log retention', () => { + it('loads curation settings when log retention is enabled', () => { + setMockValues({ + ...MOCK_VALUES, + logRetention: { + [LogRetentionOptions.Analytics]: { + enabled: true, + }, + }, + }); + + shallow(); + + expect(MOCK_ACTIONS.loadCurationsSettings).toHaveBeenCalledTimes(1); + }); + + it('skips loading curation settings when log retention is enabled', () => { + setMockValues({ + ...MOCK_VALUES, + logRetention: { + [LogRetentionOptions.Analytics]: { + enabled: false, + }, + }, + }); + + shallow(); + + expect(MOCK_ACTIONS.onSkipLoadingCurationsSettings).toHaveBeenCalledTimes(1); + }); + + it('takes no action if log retention has not yet been loaded', () => { + setMockValues({ + ...MOCK_VALUES, + logRetention: null, + }); + + shallow(); + + expect(MOCK_ACTIONS.loadCurationsSettings).toHaveBeenCalledTimes(0); + expect(MOCK_ACTIONS.onSkipLoadingCurationsSettings).toHaveBeenCalledTimes(0); + }); + }); + describe('when the user has no platinum license', () => { beforeEach(() => { setMockValues({ @@ -162,6 +218,11 @@ describe('CurationsSettings', () => { }); }); + it('it does not fetch log retention', () => { + shallow(); + expect(MOCK_ACTIONS.fetchLogRetention).toHaveBeenCalledTimes(0); + }); + it('shows a CTA to upgrade your license when the user when the user', () => { const wrapper = shallow(); expect(wrapper.is(DataPanel)).toBe(true); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings/curations_settings.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings/curations_settings.tsx index a5d4a33d8b870..de669298b11d9 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings/curations_settings.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings/curations_settings.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React from 'react'; +import React, { useEffect } from 'react'; import { useActions, useValues } from 'kea'; @@ -43,12 +43,34 @@ export const CurationsSettings: React.FC = () => { curationsSettings: { enabled, mode }, dataLoading, } = useValues(CurationsSettingsLogic); - const { toggleCurationsEnabled, toggleCurationsMode } = useActions(CurationsSettingsLogic); + const { + loadCurationsSettings, + onSkipLoadingCurationsSettings, + toggleCurationsEnabled, + toggleCurationsMode, + } = useActions(CurationsSettingsLogic); const { isLogRetentionUpdating, logRetention } = useValues(LogRetentionLogic); + const { fetchLogRetention } = useActions(LogRetentionLogic); const analyticsDisabled = !logRetention?.[LogRetentionOptions.Analytics].enabled; + useEffect(() => { + if (hasPlatinumLicense) { + fetchLogRetention(); + } + }, [hasPlatinumLicense]); + + useEffect(() => { + if (logRetention) { + if (!analyticsDisabled) { + loadCurationsSettings(); + } else { + onSkipLoadingCurationsSettings(); + } + } + }, [logRetention]); + if (!hasPlatinumLicense) return ( { onClickValue, onSelectRange, syncColors: false, + useLegacyTimeAxis: false, }; }); diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.tsx index a3022e830c861..80e4a8d4dc8f7 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.tsx @@ -31,6 +31,8 @@ import { LabelOverflowConstraint, DisplayValueStyle, RecursivePartial, + AxisStyle, + GridLineStyle, ScaleType, } from '@elastic/charts'; import { I18nProvider } from '@kbn/i18n/react'; @@ -90,6 +92,7 @@ export type XYChartRenderProps = XYChartProps & { paletteService: PaletteRegistry; formatFactory: FormatFactory; timeZone: string; + useLegacyTimeAxis: boolean; minInterval: number | undefined; interactive?: boolean; onClickValue: (data: LensFilterEvent['data']) => void; @@ -130,6 +133,7 @@ export const getXyChartRenderer = (dependencies: { chartsActiveCursorService: ChartsPluginStart['activeCursor']; paletteService: PaletteRegistry; timeZone: string; + useLegacyTimeAxis: boolean; }): ExpressionRenderDefinition => ({ name: 'lens_xy_chart_renderer', displayName: 'XY chart', @@ -160,6 +164,7 @@ export const getXyChartRenderer = (dependencies: { chartsThemeService={dependencies.chartsThemeService} paletteService={dependencies.paletteService} timeZone={dependencies.timeZone} + useLegacyTimeAxis={dependencies.useLegacyTimeAxis} minInterval={calculateMinInterval(config)} interactive={handlers.isInteractive()} onClickValue={onClickValue} @@ -235,6 +240,7 @@ export function XYChart({ onSelectRange, interactive = true, syncColors, + useLegacyTimeAxis, }: XYChartRenderProps) { const { legend, @@ -320,15 +326,15 @@ export function XYChart({ filteredBarLayers.some((layer) => layer.accessors.length > 1) || filteredBarLayers.some((layer) => layer.splitAccessor); - const isTimeViz = data.dateRange && filteredLayers.every((l) => l.xScaleType === 'time'); + const isTimeViz = Boolean(data.dateRange && filteredLayers.every((l) => l.xScaleType === 'time')); const isHistogramViz = filteredLayers.every((l) => l.isHistogram); const { baseDomain: rawXDomain, extendedDomain: xDomain } = getXDomain( filteredLayers, data, minInterval, - Boolean(isTimeViz), - Boolean(isHistogramViz) + isTimeViz, + isHistogramViz ); const yAxesMap = { @@ -555,6 +561,72 @@ export function XYChart({ floatingColumns: legend?.floatingColumns ?? 1, } as LegendPositionConfig; + // todo be moved in the chart plugin + const shouldUseNewTimeAxis = isTimeViz && !useLegacyTimeAxis && !shouldRotate; + + const gridLineStyle: RecursivePartial = shouldUseNewTimeAxis + ? { + visible: gridlinesVisibilitySettings?.x, + strokeWidth: 0.1, + stroke: darkMode ? 'white' : 'black', + } + : { + visible: gridlinesVisibilitySettings?.x, + strokeWidth: 2, + }; + const xAxisStyle: RecursivePartial = shouldUseNewTimeAxis + ? { + tickLabel: { + visible: Boolean(tickLabelsVisibilitySettings?.x), + rotation: 0, // rotation is disabled on new time axis + fontSize: 11, + padding: + referenceLinePaddings.bottom != null ? { inner: referenceLinePaddings.bottom } : 0, + alignment: { + vertical: Position.Bottom, + horizontal: Position.Left, + }, + offset: { + x: 1.5, + y: 0, + }, + }, + axisLine: { + stroke: darkMode ? 'lightgray' : 'darkgray', + strokeWidth: 1, + }, + tickLine: { + size: 12, + strokeWidth: 0.15, + stroke: darkMode ? 'white' : 'black', + padding: -10, + visible: Boolean(tickLabelsVisibilitySettings?.x), + }, + axisTitle: { + visible: axisTitlesVisibilitySettings.x, + padding: + !tickLabelsVisibilitySettings?.x && referenceLinePaddings.bottom != null + ? { inner: referenceLinePaddings.bottom } + : undefined, + }, + } + : { + tickLabel: { + visible: tickLabelsVisibilitySettings?.x, + rotation: labelsOrientation?.x, + padding: + referenceLinePaddings.bottom != null + ? { inner: referenceLinePaddings.bottom } + : undefined, + }, + axisTitle: { + visible: axisTitlesVisibilitySettings.x, + padding: + !tickLabelsVisibilitySettings?.x && referenceLinePaddings.bottom != null + ? { inner: referenceLinePaddings.bottom } + : undefined, + }, + }; return ( safeXAccessorLabelRenderer(d.value), }} - allowBrushingLastHistogramBin={Boolean(isTimeViz)} + allowBrushingLastHistogramBin={isTimeViz} rotation={shouldRotate ? 90 : 0} xDomain={xDomain} onBrushEnd={interactive ? (brushHandler as BrushEndListener) : undefined} @@ -618,29 +690,11 @@ export function XYChart({ id="x" position={shouldRotate ? Position.Left : Position.Bottom} title={xTitle} - gridLine={{ - visible: gridlinesVisibilitySettings?.x, - strokeWidth: 2, - }} + gridLine={gridLineStyle} hide={filteredLayers[0].hide || !filteredLayers[0].xAccessor} tickFormat={(d) => safeXAccessorLabelRenderer(d)} - style={{ - tickLabel: { - visible: tickLabelsVisibilitySettings?.x, - rotation: labelsOrientation?.x, - padding: - referenceLinePaddings.bottom != null - ? { inner: referenceLinePaddings.bottom } - : undefined, - }, - axisTitle: { - visible: axisTitlesVisibilitySettings.x, - padding: - !tickLabelsVisibilitySettings?.x && referenceLinePaddings.bottom != null - ? { inner: referenceLinePaddings.bottom } - : undefined, - }, - }} + style={xAxisStyle} + timeAxisLayerCount={shouldUseNewTimeAxis ? 3 : 0} /> {yAxesConfiguration.map((axis) => { diff --git a/x-pack/plugins/lens/public/xy_visualization/index.ts b/x-pack/plugins/lens/public/xy_visualization/index.ts index f9d48ffaaae37..d3d461e8f8741 100644 --- a/x-pack/plugins/lens/public/xy_visualization/index.ts +++ b/x-pack/plugins/lens/public/xy_visualization/index.ts @@ -12,6 +12,7 @@ import type { ChartsPluginSetup } from '../../../../../src/plugins/charts/public import type { LensPluginStartDependencies } from '../plugin'; import { getTimeZone } from '../utils'; import type { FormatFactory } from '../../common'; +import { LEGACY_TIME_AXIS } from '../../../../../src/plugins/charts/common'; export interface XyVisualizationPluginSetupPlugins { expressions: ExpressionsSetup; @@ -37,6 +38,7 @@ export class XyVisualization { chartsActiveCursorService: charts.activeCursor, paletteService: palettes, timeZone: getTimeZone(core.uiSettings), + useLegacyTimeAxis: core.uiSettings.get(LEGACY_TIME_AXIS), }) ); return getXyVisualization({ paletteService: palettes, fieldFormats }); diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/__mocks__/analytics_list_item.json b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/__mocks__/analytics_list_item.json index 20343755f7f0f..1b7d353d9f303 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/__mocks__/analytics_list_item.json +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/__mocks__/analytics_list_item.json @@ -22,7 +22,7 @@ }, "model_memory_limit": "50mb", "create_time": 1568974998023, - "version": "8.0.0" + "version": "8.1.0" }, "id": "fq_outlier_1222", "checkpointing": {}, diff --git a/x-pack/plugins/painless_lab/kibana.json b/x-pack/plugins/painless_lab/kibana.json index 7c71d4bdb4b76..1f59bf30bb761 100644 --- a/x-pack/plugins/painless_lab/kibana.json +++ b/x-pack/plugins/painless_lab/kibana.json @@ -1,6 +1,6 @@ { "id": "painlessLab", - "version": "8.0.0", + "version": "8.1.0", "kibanaVersion": "kibana", "owner": { "name": "Stack Management", diff --git a/x-pack/plugins/remote_clusters/common/constants.ts b/x-pack/plugins/remote_clusters/common/constants.ts index 5a36924b26433..072d6d437b8b9 100644 --- a/x-pack/plugins/remote_clusters/common/constants.ts +++ b/x-pack/plugins/remote_clusters/common/constants.ts @@ -20,7 +20,7 @@ export const PLUGIN = { }, }; -export const MAJOR_VERSION = '8.0.0'; +export const MAJOR_VERSION = '8.1.0'; export const API_BASE_PATH = '/api/remote_clusters'; diff --git a/x-pack/plugins/stack_alerts/kibana.json b/x-pack/plugins/stack_alerts/kibana.json index 1b4271328c2f9..693bcf2f8dbca 100644 --- a/x-pack/plugins/stack_alerts/kibana.json +++ b/x-pack/plugins/stack_alerts/kibana.json @@ -5,7 +5,7 @@ "githubTeam": "kibana-alerting-services" }, "server": true, - "version": "8.0.0", + "version": "8.1.0", "kibanaVersion": "kibana", "requiredPlugins": [ "alerting", diff --git a/x-pack/plugins/task_manager/kibana.json b/x-pack/plugins/task_manager/kibana.json index d0b847ce58d77..36e68ca00af81 100644 --- a/x-pack/plugins/task_manager/kibana.json +++ b/x-pack/plugins/task_manager/kibana.json @@ -1,7 +1,7 @@ { "id": "taskManager", "server": true, - "version": "8.0.0", + "version": "8.1.0", "owner": { "name": "Kibana Alerting", "githubTeam": "kibana-alerting-services" diff --git a/x-pack/test/api_integration/apis/security_solution/authentications.ts b/x-pack/test/api_integration/apis/security_solution/authentications.ts index 4ea8b8ab82e16..8254ce034d2a5 100644 --- a/x-pack/test/api_integration/apis/security_solution/authentications.ts +++ b/x-pack/test/api_integration/apis/security_solution/authentications.ts @@ -6,7 +6,10 @@ */ import expect from '@kbn/expect'; -import { HostsQueries } from '../../../../plugins/security_solution/common/search_strategy'; +import { + HostAuthenticationsStrategyResponse, + HostsQueries, +} from '../../../../plugins/security_solution/common/search_strategy'; import { FtrProviderContext } from '../../ftr_provider_context'; @@ -22,16 +25,19 @@ const EDGE_LENGTH = 1; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); + const bsearch = getService('bsearch'); describe('authentications', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/auditbeat/hosts')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/hosts')); + before(async () => await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/hosts')); + + after( + async () => await esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/hosts') + ); it('Make sure that we get Authentication data', async () => { - const { body: authentications } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const authentications = await bsearch.send({ + supertest, + options: { factoryQueryType: HostsQueries.authentications, timerange: { interval: '12h', @@ -47,9 +53,9 @@ export default function ({ getService }: FtrProviderContext) { defaultIndex: ['auditbeat-*'], docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(authentications.edges.length).to.be(EDGE_LENGTH); expect(authentications.totalCount).to.be(TOTAL_COUNT); @@ -57,10 +63,9 @@ export default function ({ getService }: FtrProviderContext) { }); it('Make sure that pagination is working in Authentications query', async () => { - const { body: authentications } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const authentications = await bsearch.send({ + supertest, + options: { factoryQueryType: HostsQueries.authentications, timerange: { interval: '12h', @@ -76,16 +81,16 @@ export default function ({ getService }: FtrProviderContext) { defaultIndex: ['auditbeat-*'], docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(authentications.edges.length).to.be(EDGE_LENGTH); expect(authentications.totalCount).to.be(TOTAL_COUNT); - expect(authentications.edges[0]!.node.lastSuccess!.source!.ip).to.eql([ + expect(authentications.edges[0].node.lastSuccess?.source?.ip).to.eql([ LAST_SUCCESS_SOURCE_IP, ]); - expect(authentications.edges[0]!.node.lastSuccess!.host!.name).to.eql([HOST_NAME]); + expect(authentications.edges[0].node.lastSuccess?.host?.name).to.eql([HOST_NAME]); }); }); } diff --git a/x-pack/test/api_integration/apis/security_solution/events.ts b/x-pack/test/api_integration/apis/security_solution/events.ts index f6a668679b11d..fef37e9939fcb 100644 --- a/x-pack/test/api_integration/apis/security_solution/events.ts +++ b/x-pack/test/api_integration/apis/security_solution/events.ts @@ -11,13 +11,13 @@ import { JsonObject } from '@kbn/utility-types'; import { Direction, TimelineEventsQueries, + TimelineEventsAllStrategyResponse, } from '../../../../plugins/security_solution/common/search_strategy'; import { FtrProviderContext } from '../../ftr_provider_context'; import { getDocValueFields, getFieldsToRequest, getFilterValue } from './utils'; const TO = '3000-01-01T00:00:00.000Z'; const FROM = '2000-01-01T00:00:00.000Z'; -const TEST_URL = '/internal/search/timelineSearchStrategy/'; // typical values that have to change after an update from "scripts/es_archiver" const DATA_COUNT = 7; const HOST_NAME = 'suricata-sensor-amsterdam'; @@ -30,6 +30,8 @@ const LIMITED_PAGE_SIZE = 2; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); + const bsearch = getService('bsearch'); + const getPostBody = (): JsonObject => ({ defaultIndex: ['auditbeat-*'], docValueFields: getDocValueFields(), @@ -66,14 +68,14 @@ export default function ({ getService }: FtrProviderContext) { }); it('returns Timeline data', async () => { - const resp = await supertest - .post(TEST_URL) - .set('kbn-xsrf', 'true') - .set('Content-Type', 'application/json') - .send(getPostBody()) - .expect(200); + const timeline = await bsearch.send({ + supertest, + options: { + ...getPostBody(), + }, + strategy: 'timelineSearchStrategy', + }); - const timeline = resp.body; expect(timeline.edges.length).to.be(EDGE_LENGTH); expect(timeline.edges[0].node.data.length).to.be(DATA_COUNT); expect(timeline.totalCount).to.be(TOTAL_COUNT); @@ -82,20 +84,17 @@ export default function ({ getService }: FtrProviderContext) { }); it('returns paginated Timeline query', async () => { - const resp = await supertest - .post(TEST_URL) - .set('kbn-xsrf', 'true') - .set('Content-Type', 'application/json') - .send({ + const timeline = await bsearch.send({ + supertest, + options: { ...getPostBody(), pagination: { activePage: 0, querySize: LIMITED_PAGE_SIZE, }, - }) - .expect(200); - - const timeline = resp.body; + }, + strategy: 'timelineSearchStrategy', + }); expect(timeline.edges.length).to.be(LIMITED_PAGE_SIZE); expect(timeline.edges[0].node.data.length).to.be(DATA_COUNT); expect(timeline.totalCount).to.be(TOTAL_COUNT); diff --git a/x-pack/test/api_integration/apis/security_solution/host_details.ts b/x-pack/test/api_integration/apis/security_solution/host_details.ts index 114f60a21c4e3..d2de0f84a3769 100644 --- a/x-pack/test/api_integration/apis/security_solution/host_details.ts +++ b/x-pack/test/api_integration/apis/security_solution/host_details.ts @@ -7,16 +7,24 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { HostsQueries } from '../../../../plugins/security_solution/common/search_strategy'; +import { + HostDetailsStrategyResponse, + HostsQueries, +} from '../../../../plugins/security_solution/common/search_strategy'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); + const bsearch = getService('bsearch'); describe('Host Details', () => { describe('With filebeat', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/filebeat/default')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/filebeat/default')); + before( + async () => await esArchiver.load('x-pack/test/functional/es_archives/filebeat/default') + ); + after( + async () => await esArchiver.unload('x-pack/test/functional/es_archives/filebeat/default') + ); const FROM = '2000-01-01T00:00:00.000Z'; const TO = '3000-01-01T00:00:00.000Z'; @@ -213,12 +221,9 @@ export default function ({ getService }: FtrProviderContext) { }; it('Make sure that we get HostDetails data', async () => { - const { - body: { hostDetails }, - } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const { hostDetails } = await bsearch.send({ + supertest, + options: { factoryQueryType: HostsQueries.details, timerange: { interval: '12h', @@ -229,9 +234,9 @@ export default function ({ getService }: FtrProviderContext) { docValueFields: [], hostName: 'raspberrypi', inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(hostDetails).to.eql(expectedResult.hostDetails); }); }); diff --git a/x-pack/test/api_integration/apis/security_solution/hosts.ts b/x-pack/test/api_integration/apis/security_solution/hosts.ts index 4df46002e9a13..bb2969f85a98b 100644 --- a/x-pack/test/api_integration/apis/security_solution/hosts.ts +++ b/x-pack/test/api_integration/apis/security_solution/hosts.ts @@ -10,6 +10,9 @@ import { HostsQueries, Direction, HostsFields, + HostsStrategyResponse, + HostDetailsStrategyResponse, + HostFirstLastSeenStrategyResponse, } from '../../../../plugins/security_solution/common/search_strategy'; import { FtrProviderContext } from '../../ftr_provider_context'; @@ -26,17 +29,19 @@ const CURSOR_ID = '2ab45fc1c41e4c84bbd02202a7e5761f'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); + const bsearch = getService('bsearch'); - // Failing: See https://github.com/elastic/kibana/issues/104260 - describe.skip('hosts', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/auditbeat/hosts')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/hosts')); + describe('hosts', () => { + before(async () => await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/hosts')); + + after( + async () => await esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/hosts') + ); it('Make sure that we get Hosts Table data', async () => { - const { body: hosts } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const hosts = await bsearch.send({ + supertest, + options: { factoryQueryType: HostsQueries.hosts, timerange: { interval: '12h', @@ -56,19 +61,18 @@ export default function ({ getService }: FtrProviderContext) { querySize: 1, }, inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(hosts.edges.length).to.be(EDGE_LENGTH); expect(hosts.totalCount).to.be(TOTAL_COUNT); expect(hosts.pageInfo.fakeTotalCount).to.equal(3); }); it('Make sure that pagination is working in Hosts Table query', async () => { - const { body: hosts } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const hosts = await bsearch.send({ + supertest, + options: { factoryQueryType: HostsQueries.hosts, timerange: { interval: '12h', @@ -88,16 +92,32 @@ export default function ({ getService }: FtrProviderContext) { querySize: 2, }, inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(hosts.edges.length).to.be(EDGE_LENGTH); expect(hosts.totalCount).to.be(TOTAL_COUNT); - expect(hosts.edges[0]!.node.host!.os!.name).to.eql([HOST_NAME]); + expect(hosts.edges[0].node.host?.os?.name).to.eql([HOST_NAME]); }); it('Make sure that we get Host details data', async () => { - const expectedHostDetails = { + const { hostDetails } = await bsearch.send({ + supertest, + options: { + factoryQueryType: HostsQueries.details, + hostName: 'zeek-sensor-san-francisco', + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['auditbeat-*'], + docValueFields: [], + inspect: false, + }, + strategy: 'securitySolutionSearchStrategy', + }); + expect(hostDetails).to.eql({ _id: 'zeek-sensor-san-francisco', host: { architecture: ['x86_64'], @@ -122,91 +142,66 @@ export default function ({ getService }: FtrProviderContext) { provider: ['digitalocean'], region: ['sfo2'], }, - }; - const { - body: { hostDetails }, - } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ - factoryQueryType: HostsQueries.details, - hostName: 'zeek-sensor-san-francisco', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - defaultIndex: ['auditbeat-*'], - docValueFields: [], - inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); - - expect(hostDetails).to.eql(expectedHostDetails); + }); }); it('Make sure that we get First Seen for a Host without docValueFields', async () => { - const { body: firstLastSeenHost } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const firstLastSeenHost = await bsearch.send({ + supertest, + options: { factoryQueryType: HostsQueries.firstOrLastSeen, defaultIndex: ['auditbeat-*'], docValueFields: [], hostName: 'zeek-sensor-san-francisco', order: 'asc', - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(firstLastSeenHost.firstSeen).to.eql('2019-02-19T19:36:23.561Z'); }); it('Make sure that we get Last Seen for a Host without docValueFields', async () => { - const { body: firstLastSeenHost } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const firstLastSeenHost = await bsearch.send({ + supertest, + options: { factoryQueryType: HostsQueries.firstOrLastSeen, defaultIndex: ['auditbeat-*'], docValueFields: [], hostName: 'zeek-sensor-san-francisco', order: 'desc', - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(firstLastSeenHost.lastSeen).to.eql('2019-02-19T20:42:33.561Z'); }); it('Make sure that we get First Seen for a Host with docValueFields', async () => { - const { body: firstLastSeenHost } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const firstLastSeenHost = await bsearch.send({ + supertest, + options: { factoryQueryType: HostsQueries.firstOrLastSeen, defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], docValueFields: [{ field: '@timestamp', format: 'epoch_millis' }], hostName: 'zeek-sensor-san-francisco', order: 'asc', - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(firstLastSeenHost.firstSeen).to.eql(new Date('2019-02-19T19:36:23.561Z').valueOf()); }); it('Make sure that we get Last Seen for a Host with docValueFields', async () => { - const { body: firstLastSeenHost } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const firstLastSeenHost = await bsearch.send({ + supertest, + options: { factoryQueryType: HostsQueries.firstOrLastSeen, defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], docValueFields: [{ field: '@timestamp', format: 'epoch_millis' }], hostName: 'zeek-sensor-san-francisco', order: 'desc', - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(firstLastSeenHost.lastSeen).to.eql(new Date('2019-02-19T20:42:33.561Z').valueOf()); }); }); diff --git a/x-pack/test/api_integration/apis/security_solution/kpi_hosts.ts b/x-pack/test/api_integration/apis/security_solution/kpi_hosts.ts index 632f738d85f36..f38cf406a9dbe 100644 --- a/x-pack/test/api_integration/apis/security_solution/kpi_hosts.ts +++ b/x-pack/test/api_integration/apis/security_solution/kpi_hosts.ts @@ -6,18 +6,27 @@ */ import expect from '@kbn/expect'; -import { HostsKpiQueries } from '../../../../plugins/security_solution/common/search_strategy'; +import { + HostsKpiAuthenticationsStrategyResponse, + HostsKpiHostsStrategyResponse, + HostsKpiQueries, + HostsKpiUniqueIpsStrategyResponse, +} from '../../../../plugins/security_solution/common/search_strategy'; import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { - const retry = getService('retry'); const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); + const bsearch = getService('bsearch'); describe('Kpi Hosts', () => { describe('With filebeat', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/filebeat/kpi_hosts')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/filebeat/kpi_hosts')); + before( + async () => await esArchiver.load('x-pack/test/functional/es_archives/filebeat/kpi_hosts') + ); + after( + async () => await esArchiver.unload('x-pack/test/functional/es_archives/filebeat/kpi_hosts') + ); const FROM = '2000-01-01T00:00:00.000Z'; const TO = '3000-01-01T00:00:00.000Z'; @@ -50,88 +59,80 @@ export default function ({ getService }: FtrProviderContext) { }; it('Make sure that we get KpiHosts data', async () => { - await retry.try(async () => { - const { body: kpiHosts } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ - factoryQueryType: HostsKpiQueries.kpiHosts, - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - defaultIndex: ['filebeat-*'], - docValueFields: [], - inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); - - expect(kpiHosts.hostsHistogram!).to.eql(expectedResult.hostsHistogram); - expect(kpiHosts.hosts!).to.eql(expectedResult.hosts); + const kpiHosts = await bsearch.send({ + supertest, + options: { + factoryQueryType: HostsKpiQueries.kpiHosts, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['filebeat-*'], + docValueFields: [], + inspect: false, + }, + strategy: 'securitySolutionSearchStrategy', }); + expect(kpiHosts.hostsHistogram).to.eql(expectedResult.hostsHistogram); + expect(kpiHosts.hosts).to.eql(expectedResult.hosts); }); it('Make sure that we get KpiAuthentications data', async () => { - await retry.try(async () => { - const { body } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ - factoryQueryType: HostsKpiQueries.kpiAuthentications, - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - defaultIndex: ['filebeat-*'], - docValueFields: [], - inspect: false, - /* We need a very long timeout to avoid returning just partial data. - ** https://github.com/elastic/kibana/blob/master/x-pack/test/api_integration/apis/search/search.ts#L18 - */ - wait_for_completion_timeout: '10s', - }) - .expect(200); - expect(body.authenticationsSuccess!).to.eql(expectedResult.authSuccess); - expect(body.authenticationsSuccessHistogram!).to.eql(expectedResult.authSuccessHistogram); - expect(body.authenticationsFailure!).to.eql(expectedResult.authFailure); - expect(body.authenticationsFailureHistogram!).to.eql(expectedResult.authFailureHistogram); + const body = await bsearch.send({ + supertest, + options: { + factoryQueryType: HostsKpiQueries.kpiAuthentications, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['filebeat-*'], + docValueFields: [], + inspect: false, + }, + strategy: 'securitySolutionSearchStrategy', }); + expect(body.authenticationsSuccess).to.eql(expectedResult.authSuccess); + expect(body.authenticationsSuccessHistogram).to.eql(expectedResult.authSuccessHistogram); + expect(body.authenticationsFailure).to.eql(expectedResult.authFailure); + expect(body.authenticationsFailureHistogram).to.eql(expectedResult.authFailureHistogram); }); it('Make sure that we get KpiUniqueIps data', async () => { - await retry.try(async () => { - const { body } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ - factoryQueryType: HostsKpiQueries.kpiUniqueIps, - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - defaultIndex: ['filebeat-*'], - docValueFields: [], - inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); - expect(body.uniqueDestinationIps!).to.eql(expectedResult.uniqueDestinationIps); - expect(body.uniqueDestinationIpsHistogram!).to.eql( - expectedResult.uniqueDestinationIpsHistogram - ); - expect(body.uniqueSourceIps!).to.eql(expectedResult.uniqueSourceIps); - expect(body.uniqueSourceIpsHistogram!).to.eql(expectedResult.uniqueSourceIpsHistogram); + const body = await bsearch.send({ + supertest, + options: { + factoryQueryType: HostsKpiQueries.kpiUniqueIps, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['filebeat-*'], + docValueFields: [], + inspect: false, + }, + strategy: 'securitySolutionSearchStrategy', }); + expect(body.uniqueDestinationIps).to.eql(expectedResult.uniqueDestinationIps); + expect(body.uniqueDestinationIpsHistogram).to.eql( + expectedResult.uniqueDestinationIpsHistogram + ); + expect(body.uniqueSourceIps).to.eql(expectedResult.uniqueSourceIps); + expect(body.uniqueSourceIpsHistogram).to.eql(expectedResult.uniqueSourceIpsHistogram); }); }); describe('With auditbeat', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/auditbeat/kpi_hosts')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/kpi_hosts')); + before( + async () => await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/kpi_hosts') + ); + after( + async () => + await esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/kpi_hosts') + ); const FROM = '2000-01-01T00:00:00.000Z'; const TO = '3000-01-01T00:00:00.000Z'; @@ -188,79 +189,69 @@ export default function ({ getService }: FtrProviderContext) { }; it('Make sure that we get KpiHosts data', async () => { - await retry.try(async () => { - const { body: kpiHosts } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ - factoryQueryType: HostsKpiQueries.kpiHosts, - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - defaultIndex: ['auditbeat-*'], - docValueFields: [], - inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); - - expect(kpiHosts.hostsHistogram!).to.eql(expectedResult.hostsHistogram); - expect(kpiHosts.hosts!).to.eql(expectedResult.hosts); + const kpiHosts = await bsearch.send({ + supertest, + options: { + factoryQueryType: HostsKpiQueries.kpiHosts, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['auditbeat-*'], + docValueFields: [], + inspect: false, + }, + strategy: 'securitySolutionSearchStrategy', }); + expect(kpiHosts.hostsHistogram).to.eql(expectedResult.hostsHistogram); + expect(kpiHosts.hosts).to.eql(expectedResult.hosts); }); it('Make sure that we get KpiAuthentications data', async () => { - await retry.try(async () => { - const { body } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ - factoryQueryType: HostsKpiQueries.kpiAuthentications, - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - defaultIndex: ['auditbeat-*'], - docValueFields: [], - inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); - expect(body.authenticationsSuccess!).to.eql(expectedResult.authSuccess); - expect(body.authenticationsSuccessHistogram!).to.eql(expectedResult.authSuccessHistogram); - expect(body.authenticationsFailure!).to.eql(expectedResult.authFailure); - expect(body.authenticationsFailureHistogram!).to.eql(expectedResult.authFailureHistogram); + const body = await bsearch.send({ + supertest, + options: { + factoryQueryType: HostsKpiQueries.kpiAuthentications, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['auditbeat-*'], + docValueFields: [], + inspect: false, + }, + strategy: 'securitySolutionSearchStrategy', }); + expect(body.authenticationsSuccess).to.eql(expectedResult.authSuccess); + expect(body.authenticationsSuccessHistogram).to.eql(expectedResult.authSuccessHistogram); + expect(body.authenticationsFailure).to.eql(expectedResult.authFailure); + expect(body.authenticationsFailureHistogram).to.eql(expectedResult.authFailureHistogram); }); it('Make sure that we get KpiUniqueIps data', async () => { - await retry.try(async () => { - const { body } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ - factoryQueryType: HostsKpiQueries.kpiUniqueIps, - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - defaultIndex: ['auditbeat-*'], - docValueFields: [], - inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); - expect(body.uniqueDestinationIps!).to.eql(expectedResult.uniqueDestinationIps); - expect(body.uniqueDestinationIpsHistogram!).to.eql( - expectedResult.uniqueDestinationIpsHistogram - ); - expect(body.uniqueSourceIps!).to.eql(expectedResult.uniqueSourceIps); - expect(body.uniqueSourceIpsHistogram!).to.eql(expectedResult.uniqueSourceIpsHistogram); + const body = await bsearch.send({ + supertest, + options: { + factoryQueryType: HostsKpiQueries.kpiUniqueIps, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['auditbeat-*'], + docValueFields: [], + inspect: false, + }, + strategy: 'securitySolutionSearchStrategy', }); + expect(body.uniqueDestinationIps!).to.eql(expectedResult.uniqueDestinationIps); + expect(body.uniqueDestinationIpsHistogram!).to.eql( + expectedResult.uniqueDestinationIpsHistogram + ); + expect(body.uniqueSourceIps!).to.eql(expectedResult.uniqueSourceIps); + expect(body.uniqueSourceIpsHistogram!).to.eql(expectedResult.uniqueSourceIpsHistogram); }); }); }); diff --git a/x-pack/test/api_integration/apis/security_solution/kpi_network.ts b/x-pack/test/api_integration/apis/security_solution/kpi_network.ts index 53b099bbe18d3..637b69ff1daaa 100644 --- a/x-pack/test/api_integration/apis/security_solution/kpi_network.ts +++ b/x-pack/test/api_integration/apis/security_solution/kpi_network.ts @@ -7,16 +7,28 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { NetworkKpiQueries } from '../../../../plugins/security_solution/common/search_strategy'; +import { + NetworkKpiDnsStrategyResponse, + NetworkKpiNetworkEventsStrategyResponse, + NetworkKpiQueries, + NetworkKpiTlsHandshakesStrategyResponse, + NetworkKpiUniqueFlowsStrategyResponse, + NetworkKpiUniquePrivateIpsStrategyResponse, +} from '../../../../plugins/security_solution/common/search_strategy'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); + const bsearch = getService('bsearch'); describe('Kpi Network', () => { describe('With filebeat', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/filebeat/default')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/filebeat/default')); + before( + async () => await esArchiver.load('x-pack/test/functional/es_archives/filebeat/default') + ); + after( + async () => await esArchiver.unload('x-pack/test/functional/es_archives/filebeat/default') + ); const FROM = '2000-01-01T00:00:00.000Z'; const TO = '3000-01-01T00:00:00.000Z'; @@ -66,10 +78,9 @@ export default function ({ getService }: FtrProviderContext) { }; it('Make sure that we get KpiNetwork uniqueFlows data', async () => { - const { body: kpiNetwork } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const kpiNetwork = await bsearch.send({ + supertest, + options: { factoryQueryType: NetworkKpiQueries.uniqueFlows, timerange: { interval: '12h', @@ -79,18 +90,16 @@ export default function ({ getService }: FtrProviderContext) { defaultIndex: ['filebeat-*'], docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); - + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(kpiNetwork.uniqueFlowId).to.eql(expectedResult.uniqueFlowId); }); it('Make sure that we get KpiNetwork networkEvents data', async () => { - const { body: kpiNetwork } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const kpiNetwork = await bsearch.send({ + supertest, + options: { factoryQueryType: NetworkKpiQueries.networkEvents, timerange: { interval: '12h', @@ -100,18 +109,16 @@ export default function ({ getService }: FtrProviderContext) { defaultIndex: ['filebeat-*'], docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); - + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(kpiNetwork.networkEvents).to.eql(expectedResult.networkEvents); }); it('Make sure that we get KpiNetwork DNS data', async () => { - const { body: kpiNetwork } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const kpiNetwork = await bsearch.send({ + supertest, + options: { factoryQueryType: NetworkKpiQueries.dns, timerange: { interval: '12h', @@ -121,18 +128,16 @@ export default function ({ getService }: FtrProviderContext) { defaultIndex: ['filebeat-*'], docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); - + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(kpiNetwork.dnsQueries).to.eql(expectedResult.dnsQueries); }); it('Make sure that we get KpiNetwork networkEvents data', async () => { - const { body: kpiNetwork } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const kpiNetwork = await bsearch.send({ + supertest, + options: { factoryQueryType: NetworkKpiQueries.networkEvents, timerange: { interval: '12h', @@ -142,18 +147,16 @@ export default function ({ getService }: FtrProviderContext) { defaultIndex: ['filebeat-*'], docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); - + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(kpiNetwork.networkEvents).to.eql(expectedResult.networkEvents); }); it('Make sure that we get KpiNetwork tlsHandshakes data', async () => { - const { body: kpiNetwork } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const kpiNetwork = await bsearch.send({ + supertest, + options: { factoryQueryType: NetworkKpiQueries.tlsHandshakes, timerange: { interval: '12h', @@ -163,18 +166,17 @@ export default function ({ getService }: FtrProviderContext) { defaultIndex: ['filebeat-*'], docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(kpiNetwork.tlsHandshakes).to.eql(expectedResult.tlsHandshakes); }); it('Make sure that we get KpiNetwork uniquePrivateIps data', async () => { - const { body: kpiNetwork } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const kpiNetwork = await bsearch.send({ + supertest, + options: { factoryQueryType: NetworkKpiQueries.uniquePrivateIps, timerange: { interval: '12h', @@ -184,9 +186,9 @@ export default function ({ getService }: FtrProviderContext) { defaultIndex: ['filebeat-*'], docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(kpiNetwork.uniqueDestinationPrivateIps).to.eql( expectedResult.uniqueDestinationPrivateIps @@ -202,8 +204,12 @@ export default function ({ getService }: FtrProviderContext) { }); describe('With packetbeat', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/packetbeat/default')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/packetbeat/default')); + before( + async () => await esArchiver.load('x-pack/test/functional/es_archives/packetbeat/default') + ); + after( + async () => await esArchiver.unload('x-pack/test/functional/es_archives/packetbeat/default') + ); const FROM = '2000-01-01T00:00:00.000Z'; const TO = '3000-01-01T00:00:00.000Z'; @@ -219,10 +225,9 @@ export default function ({ getService }: FtrProviderContext) { }; it('Make sure that we get KpiNetwork uniqueFlows data', async () => { - const { body: kpiNetwork } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const kpiNetwork = await bsearch.send({ + supertest, + options: { factoryQueryType: NetworkKpiQueries.uniqueFlows, timerange: { interval: '12h', @@ -232,18 +237,16 @@ export default function ({ getService }: FtrProviderContext) { defaultIndex: ['packetbeat-*'], docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); - + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(kpiNetwork.uniqueFlowId).to.eql(expectedResult.uniqueFlowId); }); it('Make sure that we get KpiNetwork DNS data', async () => { - const { body: kpiNetwork } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const kpiNetwork = await bsearch.send({ + supertest, + options: { factoryQueryType: NetworkKpiQueries.dns, timerange: { interval: '12h', @@ -253,18 +256,16 @@ export default function ({ getService }: FtrProviderContext) { defaultIndex: ['packetbeat-*'], docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); - + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(kpiNetwork.dnsQueries).to.eql(expectedResult.dnsQueries); }); it('Make sure that we get KpiNetwork networkEvents data', async () => { - const { body: kpiNetwork } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const kpiNetwork = await bsearch.send({ + supertest, + options: { factoryQueryType: NetworkKpiQueries.networkEvents, timerange: { interval: '12h', @@ -274,18 +275,17 @@ export default function ({ getService }: FtrProviderContext) { defaultIndex: ['packetbeat-*'], docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(kpiNetwork.networkEvents).to.eql(expectedResult.networkEvents); }); it('Make sure that we get KpiNetwork tlsHandshakes data', async () => { - const { body: kpiNetwork } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const kpiNetwork = await bsearch.send({ + supertest, + options: { factoryQueryType: NetworkKpiQueries.tlsHandshakes, timerange: { interval: '12h', @@ -295,18 +295,16 @@ export default function ({ getService }: FtrProviderContext) { defaultIndex: ['packetbeat-*'], docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); - + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(kpiNetwork.tlsHandshakes).to.eql(expectedResult.tlsHandshakes); }); it('Make sure that we get KpiNetwork uniquePrivateIps data', async () => { - const { body: kpiNetwork } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const kpiNetwork = await bsearch.send({ + supertest, + options: { factoryQueryType: NetworkKpiQueries.uniquePrivateIps, timerange: { interval: '12h', @@ -316,9 +314,9 @@ export default function ({ getService }: FtrProviderContext) { defaultIndex: ['packetbeat-*'], docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(kpiNetwork.uniqueDestinationPrivateIps).to.eql( expectedResult.uniqueDestinationPrivateIps diff --git a/x-pack/test/api_integration/apis/security_solution/matrix_dns_histogram.ts b/x-pack/test/api_integration/apis/security_solution/matrix_dns_histogram.ts index 6040ecd1001d9..c7b6bbb84436f 100644 --- a/x-pack/test/api_integration/apis/security_solution/matrix_dns_histogram.ts +++ b/x-pack/test/api_integration/apis/security_solution/matrix_dns_histogram.ts @@ -6,54 +6,43 @@ */ import expect from '@kbn/expect'; -import request from 'superagent'; import { MatrixHistogramQuery, MatrixHistogramType, + NetworkDnsStrategyResponse, } from '../../../../plugins/security_solution/common/search_strategy'; import { FtrProviderContext } from '../../ftr_provider_context'; -/** - * Function copied from here: - * test/api_integration/apis/search/bsearch.ts - * - * Splits the JSON lines from bsearch - */ -export const parseBfetchResponse = (resp: request.Response): Array> => { - return resp.text - .trim() - .split('\n') - .map((item) => JSON.parse(item)); -}; - export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); - const retry = getService('retry'); + const bsearch = getService('bsearch'); describe('Matrix DNS Histogram', () => { describe('Large data set', () => { - before(() => - esArchiver.load( - 'x-pack/test/functional/es_archives/security_solution/matrix_dns_histogram/large_dns_query' - ) + before( + async () => + await esArchiver.load( + 'x-pack/test/functional/es_archives/security_solution/matrix_dns_histogram/large_dns_query' + ) ); - after(() => - esArchiver.unload( - 'x-pack/test/functional/es_archives/security_solution/matrix_dns_histogram/large_dns_query' - ) + + after( + async () => + await esArchiver.unload( + 'x-pack/test/functional/es_archives/security_solution/matrix_dns_histogram/large_dns_query' + ) ); const FROM = '2000-01-01T00:00:00.000Z'; const TO = '3000-01-01T00:00:00.000Z'; it('Make sure that we get dns data without getting bucket errors when querying large volume of data', async () => { - const { body: networkDns } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const networkDns = await bsearch.send({ + supertest, + options: { defaultIndex: ['large_volume_dns_data'], docValueFields: [], factoryQueryType: MatrixHistogramQuery, @@ -62,56 +51,14 @@ export default function ({ getService }: FtrProviderContext) { '{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[]}}', isPtrIncluded: false, timerange: { - interval: '12h', + interval: '12', to: TO, from: FROM, }, - }) - .expect(200); - - if (networkDns.isRunning === true) { - await retry.waitForWithTimeout('bsearch to give us results', 5000, async () => { - const resp = await supertest - .post('/internal/bsearch') - .set('kbn-xsrf', 'true') - .send({ - batch: [ - { - request: { - id: networkDns.id, - defaultIndex: ['large_volume_dns_data'], - docValueFields: [], - factoryQueryType: MatrixHistogramQuery, - histogramType: MatrixHistogramType.dns, - filterQuery: - '{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[]}}', - isPtrIncluded: false, - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - }, - options: { - strategy: 'securitySolutionSearchStrategy', - }, - }, - ], - }); - const parsedResponse = parseBfetchResponse(resp); - // NOTE: I would like this test to be ".to.equal(6604)" but that is flakey as sometimes the query - // does not give me that exact value. It gives me failures as seen here with notes: https://github.com/elastic/kibana/issues/97365 - // I don't think this is a bug with the query but possibly a consistency view issue with interacting with the archive - // so we instead loosen this test up a bit to avoid flake. - expect(parsedResponse[0].result.rawResponse.aggregations.dns_count.value).to.be.above( - 0 - ); - return true; - }); - } else { - expect(networkDns.isRunning).to.equal(false); - expect(networkDns.rawResponse.aggregations.dns_count.value).to.equal(6604); - } + }, + strategy: 'securitySolutionSearchStrategy', + }); + expect(networkDns.rawResponse.aggregations?.dns_count).to.eql({ value: 6604 }); }); }); }); diff --git a/x-pack/test/api_integration/apis/security_solution/network_details.ts b/x-pack/test/api_integration/apis/security_solution/network_details.ts index 0397e7550c935..07e526c7c4bf5 100644 --- a/x-pack/test/api_integration/apis/security_solution/network_details.ts +++ b/x-pack/test/api_integration/apis/security_solution/network_details.ts @@ -6,59 +6,70 @@ */ import expect from '@kbn/expect'; -import { NetworkQueries } from '../../../../plugins/security_solution/common/search_strategy'; +import { + NetworkDetailsStrategyResponse, + NetworkQueries, +} from '../../../../plugins/security_solution/common/search_strategy'; import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); + const bsearch = getService('bsearch'); + describe('Network details', () => { describe('With filebeat', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/filebeat/default')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/filebeat/default')); + before( + async () => await esArchiver.load('x-pack/test/functional/es_archives/filebeat/default') + ); + after( + async () => await esArchiver.unload('x-pack/test/functional/es_archives/filebeat/default') + ); it('Make sure that we get Network details data', async () => { - const { body } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const body = await bsearch.send({ + supertest, + options: { ip: '151.205.0.17', defaultIndex: ['filebeat-*'], factoryQueryType: NetworkQueries.details, docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); - expect(body.networkDetails!.source!.geo!.continent_name).to.be('North America'); - expect(body.networkDetails!.source!.geo!.location!.lat!).to.be(37.751); - expect(body.networkDetails!.host.os!.platform!).to.eql(['raspbian']); + expect(body.networkDetails.source?.geo.continent_name).to.be('North America'); + expect(body.networkDetails.source?.geo.location?.lat!).to.be(37.751); + expect(body.networkDetails.host?.os?.platform).to.eql(['raspbian']); }); }); describe('With packetbeat', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/packetbeat/default')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/packetbeat/default')); + before( + async () => await esArchiver.load('x-pack/test/functional/es_archives/packetbeat/default') + ); + after( + async () => await esArchiver.unload('x-pack/test/functional/es_archives/packetbeat/default') + ); it('Make sure that we get Network details data', async () => { - const { body } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const body = await bsearch.send({ + supertest, + options: { ip: '185.53.91.88', defaultIndex: ['packetbeat-*'], factoryQueryType: NetworkQueries.details, docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); - expect(body.networkDetails!.host.id!).to.eql(['2ce8b1e7d69e4a1d9c6bcddc473da9d9']); - expect(body.networkDetails!.host.name!).to.eql(['zeek-sensor-amsterdam']); - expect(body.networkDetails!.host.os!.platform!).to.eql(['ubuntu']); + expect(body.networkDetails.host?.id).to.eql(['2ce8b1e7d69e4a1d9c6bcddc473da9d9']); + expect(body.networkDetails.host?.name).to.eql(['zeek-sensor-amsterdam']); + expect(body.networkDetails.host?.os?.platform!).to.eql(['ubuntu']); }); }); }); diff --git a/x-pack/test/api_integration/apis/security_solution/network_dns.ts b/x-pack/test/api_integration/apis/security_solution/network_dns.ts index 80660860a164b..474c6261babf0 100644 --- a/x-pack/test/api_integration/apis/security_solution/network_dns.ts +++ b/x-pack/test/api_integration/apis/security_solution/network_dns.ts @@ -11,6 +11,7 @@ import { NetworkDnsEdges, Direction, NetworkDnsFields, + NetworkDnsStrategyResponse, } from '../../../../plugins/security_solution/common/search_strategy'; import { FtrProviderContext } from '../../ftr_provider_context'; @@ -18,20 +19,24 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); + const bsearch = getService('bsearch'); describe('Network DNS', () => { describe('With packetbeat', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/packetbeat/dns')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/packetbeat/dns')); + before( + async () => await esArchiver.load('x-pack/test/functional/es_archives/packetbeat/dns') + ); + after( + async () => await esArchiver.unload('x-pack/test/functional/es_archives/packetbeat/dns') + ); const FROM = '2000-01-01T00:00:00.000Z'; const TO = '3000-01-01T00:00:00.000Z'; it('Make sure that we get Dns data and sorting by uniqueDomains ascending', async () => { - const { body: networkDns } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const networkDns = await bsearch.send({ + supertest, + options: { defaultIndex: ['packetbeat-*'], docValueFields: [], factoryQueryType: NetworkQueries.dns, @@ -45,9 +50,9 @@ export default function ({ getService }: FtrProviderContext) { to: TO, from: FROM, }, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(networkDns.edges.length).to.be(10); expect(networkDns.totalCount).to.be(44); @@ -58,10 +63,9 @@ export default function ({ getService }: FtrProviderContext) { }); it('Make sure that we get Dns data and sorting by uniqueDomains descending', async () => { - const { body: networkDns } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const networkDns = await bsearch.send({ + supertest, + options: { ip: '151.205.0.17', defaultIndex: ['packetbeat-*'], factoryQueryType: NetworkQueries.dns, @@ -80,9 +84,9 @@ export default function ({ getService }: FtrProviderContext) { to: TO, from: FROM, }, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(networkDns.edges.length).to.be(10); expect(networkDns.totalCount).to.be(44); diff --git a/x-pack/test/api_integration/apis/security_solution/network_top_n_flow.ts b/x-pack/test/api_integration/apis/security_solution/network_top_n_flow.ts index af8e543907492..41b083ab90578 100644 --- a/x-pack/test/api_integration/apis/security_solution/network_top_n_flow.ts +++ b/x-pack/test/api_integration/apis/security_solution/network_top_n_flow.ts @@ -12,6 +12,7 @@ import { Direction, FlowTargetSourceDest, NetworkTopTablesFields, + NetworkTopNFlowStrategyResponse, } from '../../../../plugins/security_solution/common/search_strategy'; import { FtrProviderContext } from '../../ftr_provider_context'; @@ -21,20 +22,24 @@ const EDGE_LENGTH = 10; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); + const bsearch = getService('bsearch'); describe('Network Top N Flow', () => { describe('With filebeat', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/filebeat/default')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/filebeat/default')); + before( + async () => await esArchiver.load('x-pack/test/functional/es_archives/filebeat/default') + ); + after( + async () => await esArchiver.unload('x-pack/test/functional/es_archives/filebeat/default') + ); const FROM = '2019-02-09T01:57:24.870Z'; const TO = '2019-02-12T01:57:24.870Z'; it('Make sure that we get Source NetworkTopNFlow data with bytes_in descending sort', async () => { - const { body: networkTopNFlow } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const networkTopNFlow = await bsearch.send({ + supertest, + options: { defaultIndex: ['filebeat-*'], factoryQueryType: NetworkQueries.topNFlow, flowTarget: FlowTargetSourceDest.source, @@ -52,9 +57,9 @@ export default function ({ getService }: FtrProviderContext) { }, docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(networkTopNFlow.edges.length).to.be(EDGE_LENGTH); expect(networkTopNFlow.totalCount).to.be(121); @@ -70,10 +75,9 @@ export default function ({ getService }: FtrProviderContext) { }); it('Make sure that we get Source NetworkTopNFlow data with bytes_in ascending sort ', async () => { - const { body: networkTopNFlow } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const networkTopNFlow = await bsearch.send({ + supertest, + options: { defaultIndex: ['filebeat-*'], factoryQueryType: 'topNFlow', filterQuery: @@ -93,9 +97,9 @@ export default function ({ getService }: FtrProviderContext) { }, docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(networkTopNFlow.edges.length).to.be(EDGE_LENGTH); expect(networkTopNFlow.totalCount).to.be(121); @@ -111,10 +115,9 @@ export default function ({ getService }: FtrProviderContext) { }); it('Make sure that we get Destination NetworkTopNFlow data', async () => { - const { body: networkTopNFlow } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const networkTopNFlow = await bsearch.send({ + supertest, + options: { defaultIndex: ['filebeat-*'], factoryQueryType: 'topNFlow', filterQuery: @@ -134,9 +137,10 @@ export default function ({ getService }: FtrProviderContext) { }, docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); + expect(networkTopNFlow.edges.length).to.be(EDGE_LENGTH); expect(networkTopNFlow.totalCount).to.be(154); expect(networkTopNFlow.edges[0].node.destination!.flows).to.be(19); @@ -146,10 +150,9 @@ export default function ({ getService }: FtrProviderContext) { }); it('Make sure that pagination is working in NetworkTopNFlow query', async () => { - const { body: networkTopNFlow } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const networkTopNFlow = await bsearch.send({ + supertest, + options: { defaultIndex: ['filebeat-*'], factoryQueryType: 'topNFlow', filterQuery: @@ -169,9 +172,9 @@ export default function ({ getService }: FtrProviderContext) { }, docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(networkTopNFlow.edges.length).to.be(EDGE_LENGTH); expect(networkTopNFlow.totalCount).to.be(121); diff --git a/x-pack/test/api_integration/apis/security_solution/overview_host.ts b/x-pack/test/api_integration/apis/security_solution/overview_host.ts index 09bd09782d2f2..b2a32ac46c3f3 100644 --- a/x-pack/test/api_integration/apis/security_solution/overview_host.ts +++ b/x-pack/test/api_integration/apis/security_solution/overview_host.ts @@ -8,16 +8,24 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { HostsQueries } from '../../../../plugins/security_solution/common/search_strategy'; +import { + HostsQueries, + HostsOverviewStrategyResponse, +} from '../../../../plugins/security_solution/common/search_strategy'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); + const bsearch = getService('bsearch'); describe('Overview Host', () => { describe('With auditbeat', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/auditbeat/overview')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/overview')); + before( + async () => await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/overview') + ); + after( + async () => await esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/overview') + ); const FROM = '2000-01-01T00:00:00.000Z'; const TO = '3000-01-01T00:00:00.000Z'; @@ -41,12 +49,9 @@ export default function ({ getService }: FtrProviderContext) { }; it('Make sure that we get OverviewHost data', async () => { - const { - body: { overviewHost }, - } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const { overviewHost } = await bsearch.send({ + supertest, + options: { defaultIndex: ['auditbeat-*'], factoryQueryType: HostsQueries.overview, timerange: { @@ -56,9 +61,9 @@ export default function ({ getService }: FtrProviderContext) { }, docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(overviewHost).to.eql(expectedResult); }); }); diff --git a/x-pack/test/api_integration/apis/security_solution/overview_network.ts b/x-pack/test/api_integration/apis/security_solution/overview_network.ts index 00adc903d5733..ffee9b851ffc0 100644 --- a/x-pack/test/api_integration/apis/security_solution/overview_network.ts +++ b/x-pack/test/api_integration/apis/security_solution/overview_network.ts @@ -7,16 +7,24 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { NetworkQueries } from '../../../../plugins/security_solution/common/search_strategy'; +import { + NetworkOverviewStrategyResponse, + NetworkQueries, +} from '../../../../plugins/security_solution/common/search_strategy'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); + const bsearch = getService('bsearch'); describe('Overview Network', () => { describe('With filebeat', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/filebeat/default')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/filebeat/default')); + before( + async () => await esArchiver.load('x-pack/test/functional/es_archives/filebeat/default') + ); + after( + async () => await esArchiver.unload('x-pack/test/functional/es_archives/filebeat/default') + ); const FROM = '2000-01-01T00:00:00.000Z'; const TO = '3000-01-01T00:00:00.000Z'; @@ -34,12 +42,9 @@ export default function ({ getService }: FtrProviderContext) { }; it('Make sure that we get OverviewNetwork data', async () => { - const { - body: { overviewNetwork }, - } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const { overviewNetwork } = await bsearch.send({ + supertest, + options: { defaultIndex: ['filebeat-*'], factoryQueryType: NetworkQueries.overview, timerange: { @@ -49,16 +54,21 @@ export default function ({ getService }: FtrProviderContext) { }, docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(overviewNetwork).to.eql(expectedResult); }); }); describe('With packetbeat', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/packetbeat/overview')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/packetbeat/overview')); + before( + async () => await esArchiver.load('x-pack/test/functional/es_archives/packetbeat/overview') + ); + after( + async () => + await esArchiver.unload('x-pack/test/functional/es_archives/packetbeat/overview') + ); const FROM = '2000-01-01T00:00:00.000Z'; const TO = '3000-01-01T00:00:00.000Z'; @@ -75,12 +85,9 @@ export default function ({ getService }: FtrProviderContext) { }; it('Make sure that we get OverviewNetwork data', async () => { - const { - body: { overviewNetwork }, - } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const { overviewNetwork } = await bsearch.send({ + supertest, + options: { defaultIndex: ['packetbeat-*'], factoryQueryType: NetworkQueries.overview, timerange: { @@ -90,17 +97,20 @@ export default function ({ getService }: FtrProviderContext) { }, docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); - + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(overviewNetwork).to.eql(expectedResult); }); }); describe('With auditbeat', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/auditbeat/overview')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/overview')); + before( + async () => await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/overview') + ); + after( + async () => await esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/overview') + ); const FROM = '2000-01-01T00:00:00.000Z'; const TO = '3000-01-01T00:00:00.000Z'; @@ -117,12 +127,9 @@ export default function ({ getService }: FtrProviderContext) { }; it('Make sure that we get OverviewNetwork data', async () => { - const { - body: { overviewNetwork }, - } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const { overviewNetwork } = await bsearch.send({ + supertest, + options: { defaultIndex: ['auditbeat-*'], factoryQueryType: NetworkQueries.overview, timerange: { @@ -132,9 +139,9 @@ export default function ({ getService }: FtrProviderContext) { }, docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(overviewNetwork).to.eql(expectedResult); }); }); diff --git a/x-pack/test/api_integration/apis/security_solution/timeline_details.ts b/x-pack/test/api_integration/apis/security_solution/timeline_details.ts index 3aefd9f8b597a..9f1b5fccd9d1a 100644 --- a/x-pack/test/api_integration/apis/security_solution/timeline_details.ts +++ b/x-pack/test/api_integration/apis/security_solution/timeline_details.ts @@ -7,7 +7,11 @@ import expect from '@kbn/expect'; import { sortBy } from 'lodash'; -import { TimelineEventsQueries } from '../../../../plugins/security_solution/common/search_strategy'; +import { + TimelineEventsQueries, + TimelineEventsDetailsStrategyResponse, + TimelineKpiStrategyResponse, +} from '../../../../plugins/security_solution/common/search_strategy'; import { FtrProviderContext } from '../../ftr_provider_context'; @@ -668,54 +672,49 @@ const EXPECTED_KPI_COUNTS = { }; export default function ({ getService }: FtrProviderContext) { - const retry = getService('retry'); const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); + const bsearch = getService('bsearch'); describe('Timeline Details', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/filebeat/default')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/filebeat/default')); + before( + async () => await esArchiver.load('x-pack/test/functional/es_archives/filebeat/default') + ); + after( + async () => await esArchiver.unload('x-pack/test/functional/es_archives/filebeat/default') + ); it('Make sure that we get Event Details data', async () => { - await retry.try(async () => { - const { - body: { data: detailsData }, - } = await supertest - .post('/internal/search/timelineSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ - factoryQueryType: TimelineEventsQueries.details, - docValueFields: [], - indexName: INDEX_NAME, - inspect: false, - eventId: ID, - wait_for_completion_timeout: '10s', - }) - .expect(200); - expect(sortBy(detailsData, 'field')).to.eql(sortBy(EXPECTED_DATA, 'field')); + const { data: detailsData } = await bsearch.send({ + supertest, + options: { + factoryQueryType: TimelineEventsQueries.details, + docValueFields: [], + indexName: INDEX_NAME, + inspect: false, + eventId: ID, + }, + strategy: 'timelineSearchStrategy', }); + expect(sortBy(detailsData, 'field')).to.eql(sortBy(EXPECTED_DATA, 'field')); }); it('Make sure that we get kpi data', async () => { - await retry.try(async () => { - const { - body: { destinationIpCount, hostCount, processCount, sourceIpCount, userCount }, - } = await supertest - .post('/internal/search/timelineSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const { destinationIpCount, hostCount, processCount, sourceIpCount, userCount } = + await bsearch.send({ + supertest, + options: { factoryQueryType: TimelineEventsQueries.kpi, docValueFields: [], indexName: INDEX_NAME, inspect: false, eventId: ID, - wait_for_completion_timeout: '10s', - }) - .expect(200); - expect({ destinationIpCount, hostCount, processCount, sourceIpCount, userCount }).to.eql( - EXPECTED_KPI_COUNTS - ); - }); + }, + strategy: 'timelineSearchStrategy', + }); + expect({ destinationIpCount, hostCount, processCount, sourceIpCount, userCount }).to.eql( + EXPECTED_KPI_COUNTS + ); }); }); } diff --git a/x-pack/test/api_integration/apis/security_solution/tls.ts b/x-pack/test/api_integration/apis/security_solution/tls.ts index 9fa251ded4e6b..c872844cb3d46 100644 --- a/x-pack/test/api_integration/apis/security_solution/tls.ts +++ b/x-pack/test/api_integration/apis/security_solution/tls.ts @@ -11,6 +11,7 @@ import { Direction, NetworkTlsFields, FlowTarget, + NetworkTlsStrategyResponse, } from '../../../../plugins/security_solution/common/search_strategy'; import { FtrProviderContext } from '../../ftr_provider_context'; @@ -83,17 +84,21 @@ const expectedOverviewSourceResult = { export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); + const bsearch = getService('bsearch'); describe('Tls Test with Packetbeat', () => { describe('Tls Test', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/packetbeat/tls')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/packetbeat/tls')); + before( + async () => await esArchiver.load('x-pack/test/functional/es_archives/packetbeat/tls') + ); + after( + async () => await esArchiver.unload('x-pack/test/functional/es_archives/packetbeat/tls') + ); it('Ensure data is returned for FlowTarget.Source', async () => { - const { body: tls } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const tls = await bsearch.send({ + supertest, + options: { factoryQueryType: NetworkQueries.tls, timerange: { interval: '12h', @@ -112,19 +117,18 @@ export default function ({ getService }: FtrProviderContext) { defaultIndex: ['packetbeat-*'], docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(tls.edges.length).to.be(1); expect(tls.totalCount).to.be(1); expect(tls.edges[0].node).to.eql(expectedResult); }); it('Ensure data is returned for FlowTarget.Destination', async () => { - const { body: tls } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const tls = await bsearch.send({ + supertest, + options: { factoryQueryType: NetworkQueries.tls, timerange: { interval: '12h', @@ -143,9 +147,9 @@ export default function ({ getService }: FtrProviderContext) { defaultIndex: ['packetbeat-*'], docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); expect(tls.edges.length).to.be(1); expect(tls.totalCount).to.be(1); expect(tls.edges[0].node).to.eql(expectedResult); @@ -153,14 +157,17 @@ export default function ({ getService }: FtrProviderContext) { }); describe('Tls Overview Test', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/packetbeat/tls')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/packetbeat/tls')); + before( + async () => await esArchiver.load('x-pack/test/functional/es_archives/packetbeat/tls') + ); + after( + async () => await esArchiver.unload('x-pack/test/functional/es_archives/packetbeat/tls') + ); it('Ensure data is returned for FlowTarget.Source', async () => { - const { body: tls } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const tls = await bsearch.send({ + supertest, + options: { factoryQueryType: NetworkQueries.tls, timerange: { interval: '12h', @@ -179,18 +186,18 @@ export default function ({ getService }: FtrProviderContext) { defaultIndex: ['packetbeat-*'], docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); + expect(tls.pageInfo).to.eql(expectedOverviewSourceResult.pageInfo); expect(tls.edges[0]).to.eql(expectedOverviewSourceResult.edges[0]); }); it('Ensure data is returned for FlowTarget.Destination', async () => { - const { body: tls } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const tls = await bsearch.send({ + supertest, + options: { factoryQueryType: NetworkQueries.tls, timerange: { interval: '12h', @@ -209,9 +216,10 @@ export default function ({ getService }: FtrProviderContext) { defaultIndex: ['packetbeat-*'], docValueFields: [], inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + }, + strategy: 'securitySolutionSearchStrategy', + }); + expect(tls.pageInfo).to.eql(expectedOverviewDestinationResult.pageInfo); expect(tls.edges[0]).to.eql(expectedOverviewDestinationResult.edges[0]); }); diff --git a/x-pack/test/api_integration/apis/security_solution/uncommon_processes.ts b/x-pack/test/api_integration/apis/security_solution/uncommon_processes.ts index d39cc0afb6461..a6749b27030e1 100644 --- a/x-pack/test/api_integration/apis/security_solution/uncommon_processes.ts +++ b/x-pack/test/api_integration/apis/security_solution/uncommon_processes.ts @@ -13,10 +13,6 @@ import { } from '../../../../plugins/security_solution/common/search_strategy'; import { FtrProviderContext } from '../../ftr_provider_context'; -interface UncommonProcessesResponse { - body: HostsUncommonProcessesStrategyResponse; -} - const FROM = '2000-01-01T00:00:00.000Z'; const TO = '3000-01-01T00:00:00.000Z'; @@ -24,24 +20,51 @@ const TO = '3000-01-01T00:00:00.000Z'; const TOTAL_COUNT = 3; export default function ({ getService }: FtrProviderContext) { - const retry = getService('retry'); const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); + const bsearch = getService('bsearch'); describe('uncommon_processes', () => { - before(() => - esArchiver.load('x-pack/test/functional/es_archives/auditbeat/uncommon_processes') + before( + async () => + await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/uncommon_processes') ); - after(() => - esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/uncommon_processes') + after( + async () => + await esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/uncommon_processes') ); it('should return an edge of length 1 when given a pagination of length 1', async () => { - await retry.try(async () => { - const response = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ + const response = await bsearch.send({ + supertest, + options: { + factoryQueryType: HostsQueries.uncommonProcesses, + sourceId: 'default', + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + pagination: { + activePage: 0, + cursorStart: 0, + fakePossibleCount: 3, + querySize: 1, + }, + defaultIndex: ['auditbeat-uncommon-processes'], + docValueFields: [], + inspect: false, + }, + strategy: 'securitySolutionSearchStrategy', + }); + expect(response.edges.length).to.be(1); + }); + + describe('when given a pagination of length 2', () => { + it('should return an edge of length 2 ', async () => { + const response = await bsearch.send({ + supertest, + options: { factoryQueryType: HostsQueries.uncommonProcesses, sourceId: 'default', timerange: { @@ -53,84 +76,51 @@ export default function ({ getService }: FtrProviderContext) { activePage: 0, cursorStart: 0, fakePossibleCount: 3, - querySize: 1, + querySize: 2, }, defaultIndex: ['auditbeat-uncommon-processes'], docValueFields: [], inspect: false, - }) - .expect(200); - expect(response!.body.edges.length).to.be(1); - }); - }); - - describe('when given a pagination of length 2', () => { - it('should return an edge of length 2 ', async () => { - await retry.try(async () => { - const response = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ - factoryQueryType: HostsQueries.uncommonProcesses, - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - pagination: { - activePage: 0, - cursorStart: 0, - fakePossibleCount: 3, - querySize: 2, - }, - defaultIndex: ['auditbeat-uncommon-processes'], - docValueFields: [], - inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); - expect(response!.body.edges.length).to.be(2); + }, + strategy: 'securitySolutionSearchStrategy', }); + expect(response.edges.length).to.be(2); }); }); describe('when given a pagination of length 1', () => { - let response: null | UncommonProcessesResponse = null; + let response: HostsUncommonProcessesStrategyResponse | null = null; before(async () => { - await retry.try(async () => { - response = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ - factoryQueryType: HostsQueries.uncommonProcesses, - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - pagination: { - activePage: 0, - cursorStart: 0, - fakePossibleCount: 3, - querySize: 1, - }, - defaultIndex: ['auditbeat-uncommon-processes'], - docValueFields: [], - inspect: false, - wait_for_completion_timeout: '10s', - }) - .expect(200); + response = await bsearch.send({ + supertest, + options: { + factoryQueryType: HostsQueries.uncommonProcesses, + sourceId: 'default', + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + pagination: { + activePage: 0, + cursorStart: 0, + fakePossibleCount: 3, + querySize: 1, + }, + defaultIndex: ['auditbeat-uncommon-processes'], + docValueFields: [], + inspect: false, + }, + strategy: 'securitySolutionSearchStrategy', }); }); it('should return an edge of length 1 ', () => { - expect(response!.body.edges.length).to.be(1); + expect(response?.edges.length).to.be(1); }); it('should return a total count of elements', () => { - expect(response!.body.totalCount).to.be(TOTAL_COUNT); + expect(response?.totalCount).to.be(TOTAL_COUNT); }); it('should return a single data set with pagination of 1', () => { @@ -152,7 +142,7 @@ export default function ({ getService }: FtrProviderContext) { }, ], }; - expect(response!.body.edges[0].node).to.eql(expected); + expect(response?.edges[0].node).to.eql(expected); }); }); }); diff --git a/x-pack/test/api_integration/apis/security_solution/users.ts b/x-pack/test/api_integration/apis/security_solution/users.ts index 84335cc2695ce..d592c99bf006f 100644 --- a/x-pack/test/api_integration/apis/security_solution/users.ts +++ b/x-pack/test/api_integration/apis/security_solution/users.ts @@ -11,6 +11,7 @@ import { Direction, NetworkUsersFields, FlowTarget, + NetworkUsersStrategyResponse, } from '../../../../plugins/security_solution/common/search_strategy'; import { FtrProviderContext } from '../../ftr_provider_context'; @@ -20,53 +21,52 @@ const TO = '3000-01-01T00:00:00.000Z'; const IP = '0.0.0.0'; export default function ({ getService }: FtrProviderContext) { - const retry = getService('retry'); const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); + const bsearch = getService('bsearch'); + describe('Users', () => { describe('With auditbeat', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/auditbeat/users')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/users')); + before( + async () => await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/users') + ); + after( + async () => await esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/users') + ); it('Ensure data is returned from auditbeat', async () => { - await retry.try(async () => { - const { body: users } = await supertest - .post('/internal/search/securitySolutionSearchStrategy/') - .set('kbn-xsrf', 'true') - .send({ - factoryQueryType: NetworkQueries.users, - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - defaultIndex: ['auditbeat-users'], - docValueFields: [], - ip: IP, - flowTarget: FlowTarget.destination, - sort: { field: NetworkUsersFields.name, direction: Direction.asc }, - pagination: { - activePage: 0, - cursorStart: 0, - fakePossibleCount: 30, - querySize: 10, - }, - inspect: false, - /* We need a very long timeout to avoid returning just partial data. - ** https://github.com/elastic/kibana/blob/master/x-pack/test/api_integration/apis/search/search.ts#L18 - */ - wait_for_completion_timeout: '10s', - }) - .expect(200); - expect(users.edges.length).to.be(1); - expect(users.totalCount).to.be(1); - expect(users.edges[0].node.user!.id).to.eql(['0']); - expect(users.edges[0].node.user!.name).to.be('root'); - expect(users.edges[0].node.user!.groupId).to.eql(['0']); - expect(users.edges[0].node.user!.groupName).to.eql(['root']); - expect(users.edges[0].node.user!.count).to.be(1); + const users = await bsearch.send({ + supertest, + options: { + factoryQueryType: NetworkQueries.users, + sourceId: 'default', + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['auditbeat-users'], + docValueFields: [], + ip: IP, + flowTarget: FlowTarget.destination, + sort: { field: NetworkUsersFields.name, direction: Direction.asc }, + pagination: { + activePage: 0, + cursorStart: 0, + fakePossibleCount: 30, + querySize: 10, + }, + inspect: false, + }, + strategy: 'securitySolutionSearchStrategy', }); + expect(users.edges.length).to.be(1); + expect(users.totalCount).to.be(1); + expect(users.edges[0].node.user?.id).to.eql(['0']); + expect(users.edges[0].node.user?.name).to.be('root'); + expect(users.edges[0].node.user?.groupId).to.eql(['0']); + expect(users.edges[0].node.user?.groupName).to.eql(['root']); + expect(users.edges[0].node.user?.count).to.be(1); }); }); }); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_endpoint_exceptions.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_endpoint_exceptions.ts index d5e623989b460..6c6fcc366782a 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_endpoint_exceptions.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_endpoint_exceptions.ts @@ -70,8 +70,7 @@ export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); - // Flaky - describe.skip('Rule exception operators for endpoints', () => { + describe('Rule exception operators for endpoints', () => { before(async () => { await esArchiver.load( 'x-pack/test/functional/es_archives/rule_exceptions/endpoint_without_host_type' @@ -113,7 +112,7 @@ export default ({ getService }: FtrProviderContext) => { os: { type: 'linux' }, }, { - os: { type: 'windows' }, + os: { type: 'macos' }, }, { os: { type: 'windows' }, @@ -135,7 +134,7 @@ export default ({ getService }: FtrProviderContext) => { os: { name: 'Linux' }, }, { - os: { name: 'Windows' }, + os: { name: 'Macos' }, }, { os: { name: 'Windows' }, @@ -174,7 +173,7 @@ export default ({ getService }: FtrProviderContext) => { os: { name: 'Linux' }, }, { - os: { name: 'Windows' }, + os: { name: 'Macos' }, }, { os: { name: 'Windows' }, @@ -210,7 +209,7 @@ export default ({ getService }: FtrProviderContext) => { os: { name: 'Linux' }, }, { - os: { name: 'Windows' }, + os: { name: 'Macos' }, }, { os: { name: 'Windows' }, @@ -336,7 +335,7 @@ export default ({ getService }: FtrProviderContext) => { os: { type: 'linux' }, }, { - os: { type: 'windows' }, + os: { type: 'macos' }, }, { os: { type: 'windows' }, @@ -372,7 +371,7 @@ export default ({ getService }: FtrProviderContext) => { os: { type: 'linux' }, }, { - os: { type: 'windows' }, + os: { type: 'macos' }, }, { os: { type: 'windows' }, @@ -501,10 +500,10 @@ export default ({ getService }: FtrProviderContext) => { os: { name: 'Linux' }, }, { - os: { name: 'Windows' }, + os: { type: 'macos' }, }, { - os: { type: 'windows' }, + os: { name: 'Macos' }, }, { os: { type: 'windows' }, @@ -546,10 +545,10 @@ export default ({ getService }: FtrProviderContext) => { os: { name: 'Linux' }, }, { - os: { name: 'Windows' }, + os: { type: 'macos' }, }, { - os: { type: 'windows' }, + os: { name: 'Macos' }, }, { os: { type: 'windows' }, @@ -876,7 +875,7 @@ export default ({ getService }: FtrProviderContext) => { os: { type: 'linux' }, }, { - os: { type: 'windows' }, + os: { type: 'macos' }, }, { os: { type: 'windows' }, diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/ip_array.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/ip_array.ts index 89f7693e72358..efff288fddac2 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/ip_array.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/ip_array.ts @@ -508,6 +508,7 @@ export default ({ getService }: FtrProviderContext) => { ], ]); await waitForRuleSuccessOrStatus(supertest, id); + await waitForSignalsToBePresent(supertest, 1, [id]); const signalsOpen = await getSignalsById(supertest, id); const ips = signalsOpen.hits.hits.map((hit) => hit._source?.ip).sort(); expect(ips.flat(Number.MAX_SAFE_INTEGER)).to.eql([]); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/text.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/text.ts index 9fd733789588f..ff2f680654047 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/text.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/text.ts @@ -426,9 +426,7 @@ export default ({ getService }: FtrProviderContext) => { expect(hits).to.eql(['word four']); }); - // This test is unreliable due to a race condition... we don't know if the rule ran and - // generated 0 signals, or if the index hasn't refreshed yet. - it.skip('should filter 4 text if all are set as exceptions', async () => { + it('should filter 4 text if all are set as exceptions', async () => { const rule = getRuleForSignalTesting(['text']); const { id } = await createRuleWithExceptionEntries(supertest, rule, [ [ @@ -448,9 +446,7 @@ export default ({ getService }: FtrProviderContext) => { }); describe('"is not one of" operator', () => { - // This test is unreliable due to a race condition... we don't know if the rule ran and - // generated 0 signals, or if the index hasn't refreshed yet. - it.skip('will return 0 results if it cannot find what it is excluding', async () => { + it('will return 0 results if it cannot find what it is excluding', async () => { const rule = getRuleForSignalTesting(['text']); const { id } = await createRuleWithExceptionEntries(supertest, rule, [ [ @@ -489,9 +485,7 @@ export default ({ getService }: FtrProviderContext) => { }); describe('"exists" operator', () => { - // This test is unreliable due to a race condition... we don't know if the rule ran and - // generated 0 signals, or if the index hasn't refreshed yet. - it.skip('will return 0 results if matching against text', async () => { + it('will return 0 results if matching against text', async () => { const rule = getRuleForSignalTesting(['text']); const { id } = await createRuleWithExceptionEntries(supertest, rule, [ [ @@ -577,7 +571,7 @@ export default ({ getService }: FtrProviderContext) => { expect(hits).to.eql(['four', 'two']); }); - it.skip('will return 0 results if we have a list that includes all text', async () => { + it('will return 0 results if we have a list that includes all text', async () => { await importTextFile( supertest, 'text', diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/text_array.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/text_array.ts index 3bcf8692d58f9..6d25124667132 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/text_array.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/text_array.ts @@ -337,6 +337,7 @@ export default ({ getService }: FtrProviderContext) => { ], ]); await waitForRuleSuccessOrStatus(supertest, id); + await waitForSignalsToBePresent(supertest, 1, [id]); const signalsOpen = await getSignalsById(supertest, id); const hits = signalsOpen.hits.hits.map((hit) => hit._source?.text).sort(); expect(hits.flat(Number.MAX_SAFE_INTEGER)).to.eql([]); @@ -515,6 +516,7 @@ export default ({ getService }: FtrProviderContext) => { ], ]); await waitForRuleSuccessOrStatus(supertest, id); + await waitForSignalsToBePresent(supertest, 1, [id]); const signalsOpen = await getSignalsById(supertest, id); const hits = signalsOpen.hits.hits.map((hit) => hit._source?.text).sort(); expect(hits.flat(Number.MAX_SAFE_INTEGER)).to.eql([]); diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/index.ts b/x-pack/test/reporting_api_integration/reporting_and_security/index.ts index 159115e2054e1..f6654ff5a6b1d 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/index.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/index.ts @@ -30,6 +30,5 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./spaces')); loadTestFile(require.resolve('./usage')); loadTestFile(require.resolve('./ilm_migration_apis')); - loadTestFile(require.resolve('./search_frozen_indices')); }); } diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/search_frozen_indices.ts b/x-pack/test/reporting_api_integration/reporting_and_security/search_frozen_indices.ts deleted file mode 100644 index daa749649e250..0000000000000 --- a/x-pack/test/reporting_api_integration/reporting_and_security/search_frozen_indices.ts +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../ftr_provider_context'; - -// eslint-disable-next-line import/no-default-export -export default function ({ getService }: FtrProviderContext) { - const kibanaServer = getService('kibanaServer'); - const supertestSvc = getService('supertest'); - const esSupertest = getService('esSupertest'); - const indexPatternId = 'cool-test-index-pattern'; - - async function callExportAPI() { - const job = { - browserTimezone: 'UTC', - columns: ['@timestamp', 'ip', 'utilization'], - searchSource: { - fields: [{ field: '*', include_unmapped: 'true' }], - filter: [ - { - meta: { field: '@timestamp', index: indexPatternId, params: {} }, - range: { - '@timestamp': { - format: 'strict_date_optional_time', - gte: '2020-08-24T00:00:00.000Z', - lte: '2022-08-24T21:40:48.346Z', - }, - }, - }, - ], - index: indexPatternId, - parent: { filter: [], index: indexPatternId, query: { language: 'kuery', query: '' } }, - sort: [{ '@timestamp': 'desc' }], - trackTotalHits: true, - }, - title: 'Test search', - }; - - return await supertestSvc - .post(`/api/reporting/v1/generate/immediate/csv_searchsource`) - .set('kbn-xsrf', 'xxx') - .send(job); - } - - describe('Frozen indices search', () => { - const reset = async () => { - await kibanaServer.uiSettings.replace({ 'search:includeFrozen': false }); - try { - await esSupertest.delete('/test1,test2,test3'); - await kibanaServer.savedObjects.delete({ type: 'index-pattern', id: indexPatternId }); - } catch (err) { - // ignore 404 error - } - }; - - before(reset); - after(reset); - - it('Search includes frozen indices based on Advanced Setting', async () => { - await kibanaServer.uiSettings.update({ 'csv:quoteValues': true }); - - // setup: add multiple indices of test data - await Promise.all([ - esSupertest - .post('/test1/_doc') - .send({ '@timestamp': '2021-08-24T21:36:40Z', ip: '43.98.8.183', utilization: 18725 }), - esSupertest - .post('/test2/_doc') - .send({ '@timestamp': '2021-08-21T09:36:40Z', ip: '63.91.103.79', utilization: 8480 }), - esSupertest - .post('/test3/_doc') - .send({ '@timestamp': '2021-08-17T21:36:40Z', ip: '139.108.162.171', utilization: 3078 }), - ]); - await esSupertest.post('/test*/_refresh'); - - // setup: create index pattern - const indexPatternCreateResponse = await kibanaServer.savedObjects.create({ - type: 'index-pattern', - id: indexPatternId, - overwrite: true, - attributes: { title: 'test*', timeFieldName: '@timestamp' }, - }); - expect(indexPatternCreateResponse.id).to.be(indexPatternId); - - // 1. check the initial data with a CSV export - const initialSearch = await callExportAPI(); - expectSnapshot(initialSearch.text).toMatchInline(` - "\\"@timestamp\\",ip,utilization - \\"Aug 24, 2021 @ 21:36:40.000\\",\\"43.98.8.183\\",\\"18,725\\" - \\"Aug 21, 2021 @ 09:36:40.000\\",\\"63.91.103.79\\",\\"8,480\\" - \\"Aug 17, 2021 @ 21:36:40.000\\",\\"139.108.162.171\\",\\"3,078\\" - " - `); - - // 2. freeze an index in the pattern - await esSupertest.post('/test3/_freeze').expect(200); - await esSupertest.post('/test*/_refresh').expect(200); - - // 3. recheck the search results - const afterFreezeSearch = await callExportAPI(); - expectSnapshot(afterFreezeSearch.text).toMatchInline(` - "\\"@timestamp\\",ip,utilization - \\"Aug 24, 2021 @ 21:36:40.000\\",\\"43.98.8.183\\",\\"18,725\\" - \\"Aug 21, 2021 @ 09:36:40.000\\",\\"63.91.103.79\\",\\"8,480\\" - " - `); - - // 4. update setting to allow searching frozen data - await kibanaServer.uiSettings.update({ 'search:includeFrozen': true }); - - // 5. recheck the search results - const afterAllowSearch = await callExportAPI(); - expectSnapshot(afterAllowSearch.text).toMatchInline(` - "\\"@timestamp\\",ip,utilization - \\"Aug 24, 2021 @ 21:36:40.000\\",\\"43.98.8.183\\",\\"18,725\\" - \\"Aug 21, 2021 @ 09:36:40.000\\",\\"63.91.103.79\\",\\"8,480\\" - \\"Aug 17, 2021 @ 21:36:40.000\\",\\"139.108.162.171\\",\\"3,078\\" - " - `); - }); - }); -} diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/index.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/index.ts index 70d60ba5c1b67..d1cfddbca3a9c 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/index.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/index.ts @@ -15,7 +15,8 @@ import { export default function (providerContext: FtrProviderContext) { const { loadTestFile, getService } = providerContext; - describe('endpoint', function () { + // FAILING: https://github.com/elastic/kibana/issues/72874 + describe.skip('endpoint', function () { const ingestManager = getService('ingestManager'); const log = getService('log'); const endpointTestResources = getService('endpointTestResources'); diff --git a/x-pack/test/timeline/security_and_spaces/tests/basic/events.ts b/x-pack/test/timeline/security_and_spaces/tests/basic/events.ts index e44f29c41640f..1e9cfe3eb841b 100644 --- a/x-pack/test/timeline/security_and_spaces/tests/basic/events.ts +++ b/x-pack/test/timeline/security_and_spaces/tests/basic/events.ts @@ -135,6 +135,8 @@ export default ({ getService }: FtrProviderContext) => { it(`${username} should be able to view alerts from "${featureIds.join(',')}" ${ space != null ? `in space ${space}` : 'when no space specified' }`, async () => { + // This will be flake until it uses the bsearch service, but these tests aren't operational. Once you do make this operational + // use const bsearch = getService('bsearch'); const resp = await supertestWithoutAuth .post(`${getSpaceUrlPrefix(space)}${TEST_URL}`) .auth(username, password) @@ -164,6 +166,8 @@ export default ({ getService }: FtrProviderContext) => { it(`${username} should NOT be able to view alerts from "${featureIds.join(',')}" ${ space != null ? `in space ${space}` : 'when no space specified' }`, async () => { + // This will be flake until it uses the bsearch service, but these tests aren't operational. Once you do make this operational + // use const bsearch = getService('bsearch'); const resp = await supertestWithoutAuth .post(`${getSpaceUrlPrefix(space)}${TEST_URL}`) .auth(username, password) @@ -183,6 +187,8 @@ export default ({ getService }: FtrProviderContext) => { it(`${username} should NOT be able to access "${featureIds.join(',')}" ${ space != null ? `in space ${space}` : 'when no space specified' }`, async () => { + // This will be flake until it uses the bsearch service, but these tests aren't operational. Once you do make this operational + // use const bsearch = getService('bsearch'); await supertestWithoutAuth .post(`${getSpaceUrlPrefix(space)}${TEST_URL}`) .auth(username, password) diff --git a/x-pack/test/timeline/security_and_spaces/tests/trial/events.ts b/x-pack/test/timeline/security_and_spaces/tests/trial/events.ts index 0a73009196baf..91ad87737805f 100644 --- a/x-pack/test/timeline/security_and_spaces/tests/trial/events.ts +++ b/x-pack/test/timeline/security_and_spaces/tests/trial/events.ts @@ -117,6 +117,8 @@ export default ({ getService }: FtrProviderContext) => { it(`${username} should be able to view alerts from "${featureIds.join(',')}" ${ space != null ? `in space ${space}` : 'when no space specified' }`, async () => { + // This will be flake until it uses the bsearch service, but these tests aren't operational. Once you do make this operational + // use const bsearch = getService('bsearch'); const resp = await supertestWithoutAuth .post(`${getSpaceUrlPrefix(space)}${TEST_URL}`) .auth(username, password) @@ -145,6 +147,8 @@ export default ({ getService }: FtrProviderContext) => { it(`${username} should NOT be able to access "${featureIds.join(',')}" ${ space != null ? `in space ${space}` : 'when no space specified' }`, async () => { + // This will be flake until it uses the bsearch service, but these tests aren't operational. Once you do make this operational + // use const bsearch = getService('bsearch'); await supertestWithoutAuth .post(`${getSpaceUrlPrefix(space)}${TEST_URL}`) .auth(username, password) diff --git a/yarn.lock b/yarn.lock index 3e4e3ad4ed224..56d5cf17791ea 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2337,10 +2337,10 @@ dependencies: object-hash "^1.3.0" -"@elastic/charts@38.0.1": - version "38.0.1" - resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-38.0.1.tgz#9c1db7e0f1de869e0b2b505e192bbb9d62d60dc8" - integrity sha512-i9mIA3Ji9jSjuFDtuh9gV1xpCl3sbBEDgJiOgLVt04pr/qZH2W+tr3AV5yHvjsR7Te0Pmh/Cm5wLBvFKaI1nIA== +"@elastic/charts@38.1.0": + version "38.1.0" + resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-38.1.0.tgz#52146564c0e399da2267c10ec4536c33e50969e4" + integrity sha512-u2hQ8+daCvqapKQiFqN8QHWTz3OXby5Xf/ta1Dv59KTDTFIinCZD/M8PyD3MapbKx4b67hL7UxbErqr4rZ8jeA== dependencies: "@popperjs/core" "^2.4.0" chroma-js "^2.1.0" @@ -2351,6 +2351,7 @@ d3-interpolate "^1.4.0" d3-scale "^1.0.7" d3-shape "^1.3.4" + luxon "^1.25.0" prop-types "^15.7.2" re-reselect "^3.4.0" react-redux "^7.1.0" @@ -19720,6 +19721,11 @@ lru-queue@0.1: dependencies: es5-ext "~0.10.2" +luxon@^1.25.0: + version "1.28.0" + resolved "https://registry.yarnpkg.com/luxon/-/luxon-1.28.0.tgz#e7f96daad3938c06a62de0fb027115d251251fbf" + integrity sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ== + lz-string@^1.4.4: version "1.4.4" resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26"