diff --git a/packages/kbn-test/index.ts b/packages/kbn-test/index.ts index b5506cc804ad3..cc97a4afa7906 100644 --- a/packages/kbn-test/index.ts +++ b/packages/kbn-test/index.ts @@ -69,8 +69,6 @@ export { getUrl } from './src/jest/get_url'; export { runCheckJestConfigsCli } from './src/jest/run_check_jest_configs_cli'; -export { runCheckFtrCodeOwnersCli } from './src/functional_test_runner/run_check_ftr_code_owners'; - export { runJest } from './src/jest/run'; export * from './src/kbn_archiver_cli'; diff --git a/packages/kbn-test/src/functional_test_runner/cli/code_owners.ts b/packages/kbn-test/src/functional_test_runner/cli/code_owners.ts new file mode 100644 index 0000000000000..62948bbfcde55 --- /dev/null +++ b/packages/kbn-test/src/functional_test_runner/cli/code_owners.ts @@ -0,0 +1,48 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { run } from '@kbn/dev-cli-runner'; +import { createFailError } from '@kbn/dev-cli-errors'; +import { getRepoFiles } from '@kbn/get-repo-files'; +import { getCodeOwnersEntries } from '@kbn/code-owners'; +import ignore from 'ignore'; + +const TEST_DIRECTORIES = ['test', 'x-pack/test', 'x-pack/test_serverless']; + +export async function checkFTRCodeOwnersCLI() { + await run( + async ({ log }) => { + const matcher = ignore().add( + getCodeOwnersEntries() + .filter((entry) => entry.teams.length > 0) + .map((entry) => entry.pattern) + ); + const hasOwner = (path: string): boolean => matcher.test(path).ignored; + + const testFiles = await getRepoFiles(TEST_DIRECTORIES); + const filesWithoutOwner = testFiles + .filter((repoPath) => !hasOwner(repoPath.repoRel)) + .map((repoPath) => repoPath.repoRel); + + log.info(`Checked ${testFiles.length} test files in ${process.uptime().toFixed(2)}s`); + + if (filesWithoutOwner.length === 0) { + log.success(`All test files have a code owner 🥳`); + return; + } + + log.write('Test files without a code owner:'); + log.write(filesWithoutOwner.map((i) => ` - ${i}`).join('\n')); + throw createFailError(`Found ${filesWithoutOwner.length} test files without code owner`); + }, + { + description: 'Check that all test files are covered by GitHub CODEOWNERS', + } + ); +} diff --git a/packages/kbn-test/src/functional_test_runner/cli.ts b/packages/kbn-test/src/functional_test_runner/cli/ftr.ts similarity index 98% rename from packages/kbn-test/src/functional_test_runner/cli.ts rename to packages/kbn-test/src/functional_test_runner/cli/ftr.ts index fe153e17b8d69..d9694973e9252 100644 --- a/packages/kbn-test/src/functional_test_runner/cli.ts +++ b/packages/kbn-test/src/functional_test_runner/cli/ftr.ts @@ -16,8 +16,8 @@ import { ToolingLog } from '@kbn/tooling-log'; import { getTimeReporter } from '@kbn/ci-stats-reporter'; import exitHook from 'exit-hook'; -import { readConfigFile, EsVersion } from './lib'; -import { FunctionalTestRunner } from './functional_test_runner'; +import { readConfigFile, EsVersion } from '../lib'; +import { FunctionalTestRunner } from '../functional_test_runner'; export function runFtrCli() { const runStartTime = Date.now(); diff --git a/src/platform/plugins/shared/embeddable/public/lib/embeddables/index.ts b/packages/kbn-test/src/functional_test_runner/cli/index.ts similarity index 59% rename from src/platform/plugins/shared/embeddable/public/lib/embeddables/index.ts rename to packages/kbn-test/src/functional_test_runner/cli/index.ts index 029a653a9f1c6..6e29c1bdc231f 100644 --- a/src/platform/plugins/shared/embeddable/public/lib/embeddables/index.ts +++ b/packages/kbn-test/src/functional_test_runner/cli/index.ts @@ -7,8 +7,5 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -export * from '../../../common/lib/saved_object_embeddable'; -export { Embeddable } from './embeddable'; -export { EmbeddableErrorHandler } from './embeddable_error_handler'; -export { ErrorEmbeddable } from './error_embeddable'; -export type { EmbeddableInput, EmbeddableOutput, IEmbeddable } from './i_embeddable'; +export { runFtrCli } from './ftr'; +export { checkFTRCodeOwnersCLI } from './code_owners'; diff --git a/packages/kbn-test/src/functional_test_runner/index.ts b/packages/kbn-test/src/functional_test_runner/index.ts index 6c5641cbe8aab..42bdde23b0439 100644 --- a/packages/kbn-test/src/functional_test_runner/index.ts +++ b/packages/kbn-test/src/functional_test_runner/index.ts @@ -18,6 +18,6 @@ export { runCheckFtrConfigsCli, DedicatedTaskRunner, } from './lib'; -export { runFtrCli } from './cli'; +export * from './cli'; export * from './lib/docker_servers'; export * from './public_types'; diff --git a/packages/kbn-test/src/functional_test_runner/run_check_ftr_code_owners.ts b/packages/kbn-test/src/functional_test_runner/run_check_ftr_code_owners.ts deleted file mode 100644 index 8a1ec50bd1a3e..0000000000000 --- a/packages/kbn-test/src/functional_test_runner/run_check_ftr_code_owners.ts +++ /dev/null @@ -1,67 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { run } from '@kbn/dev-cli-runner'; -import { createFailError } from '@kbn/dev-cli-errors'; -import { getRepoFiles } from '@kbn/get-repo-files'; -import { getOwningTeamsForPath, getCodeOwnersEntries } from '@kbn/code-owners'; - -const TEST_DIRECTORIES = ['test', 'x-pack/test', 'x-pack/test_serverless']; - -const fmtMs = (ms: number) => { - if (ms < 1000) { - return `${Math.round(ms)} ms`; - } - - return `${(Math.round(ms) / 1000).toFixed(2)} s`; -}; - -const fmtList = (list: Iterable) => [...list].map((i) => ` - ${i}`).join('\n'); - -export async function runCheckFtrCodeOwnersCli() { - run( - async ({ log }) => { - const start = performance.now(); - - const missingOwners = new Set(); - - // cache codeowners for quicker lookup - log.info('Reading CODEOWNERS file'); - const codeOwnersEntries = getCodeOwnersEntries(); - - const testFiles = await getRepoFiles(TEST_DIRECTORIES); - log.info(`Checking ownership for ${testFiles.length} test files (this will take a while)`); - - for (const { repoRel } of testFiles) { - const owners = getOwningTeamsForPath(repoRel, codeOwnersEntries); - - if (owners.length === 0) { - missingOwners.add(repoRel); - } - } - - const timeSpent = fmtMs(performance.now() - start); - log.info(`Ownership check complete (took ${timeSpent})`); - - if (missingOwners.size) { - log.error( - `The following test files do not have a GitHub code owner:\n${fmtList(missingOwners)}` - ); - throw createFailError( - `Found ${missingOwners.size} test files without code owner (checked ${testFiles.length} test files in ${timeSpent})` - ); - } - - log.success(`All test files have a code owner. 🥳`); - }, - { - description: 'Check that all test files are covered by GitHub CODEOWNERS', - } - ); -} diff --git a/scripts/check_ftr_code_owners.js b/scripts/check_ftr_code_owners.js index 875f835d1d7b4..b35590500b313 100644 --- a/scripts/check_ftr_code_owners.js +++ b/scripts/check_ftr_code_owners.js @@ -8,4 +8,4 @@ */ require('../src/setup_node_env'); -require('@kbn/test').runCheckFtrCodeOwnersCli(); +void require('@kbn/test').checkFTRCodeOwnersCLI(); diff --git a/src/platform/packages/shared/presentation/presentation_publishing/embeddable_api_context.ts b/src/platform/packages/shared/presentation/presentation_publishing/embeddable_api_context.ts new file mode 100644 index 0000000000000..3af7b7f428596 --- /dev/null +++ b/src/platform/packages/shared/presentation/presentation_publishing/embeddable_api_context.ts @@ -0,0 +1,22 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +export interface EmbeddableApiContext { + /** + * TODO: once all actions are entirely decoupled from the embeddable system, this key should be renamed to "api" + * to reflect the fact that this context could contain any api. + */ + embeddable: unknown; +} + +export const isEmbeddableApiContext = (context: unknown): context is EmbeddableApiContext => + !!context && + typeof context === 'object' && + !!(context as EmbeddableApiContext).embeddable && + typeof (context as EmbeddableApiContext).embeddable === 'object'; diff --git a/src/platform/packages/shared/presentation/presentation_publishing/index.ts b/src/platform/packages/shared/presentation/presentation_publishing/index.ts index 09e6453586665..62e68521a5b09 100644 --- a/src/platform/packages/shared/presentation/presentation_publishing/index.ts +++ b/src/platform/packages/shared/presentation/presentation_publishing/index.ts @@ -7,13 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -export interface EmbeddableApiContext { - /** - * TODO: once all actions are entirely decoupled from the embeddable system, this key should be renamed to "api" - * to reflect the fact that this context could contain any api. - */ - embeddable: unknown; -} +export { isEmbeddableApiContext, type EmbeddableApiContext } from './embeddable_api_context'; export { getInitialValuesFromComparators, diff --git a/src/platform/plugins/shared/dashboard/public/dashboard_api/types.ts b/src/platform/plugins/shared/dashboard/public/dashboard_api/types.ts index 73e7e9422641f..238bd5976bfa1 100644 --- a/src/platform/plugins/shared/dashboard/public/dashboard_api/types.ts +++ b/src/platform/plugins/shared/dashboard/public/dashboard_api/types.ts @@ -41,12 +41,7 @@ import { ControlGroupSerializedState, } from '@kbn/controls-plugin/public'; import { Filter, Query, TimeRange } from '@kbn/es-query'; -import { - DefaultEmbeddableApi, - EmbeddablePackageState, - ErrorEmbeddable, - IEmbeddable, -} from '@kbn/embeddable-plugin/public'; +import type { DefaultEmbeddableApi, EmbeddablePackageState } from '@kbn/embeddable-plugin/public'; import { Observable, Subject } from 'rxjs'; import { RefreshInterval, SearchSessionInfoProvider } from '@kbn/data-plugin/public'; import { IKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public'; @@ -175,9 +170,7 @@ export type DashboardApi = CanExpandPanels & setTags: (tags: string[]) => void; setTimeRange: (timeRange?: TimeRange | undefined) => void; unifiedSearchFilters$: PublishesUnifiedSearch['filters$']; - - // TODO remove types below this line - from legacy embeddable system - untilEmbeddableLoaded: (id: string) => Promise; + untilEmbeddableLoaded: (id: string) => Promise; }; export interface DashboardInternalApi { diff --git a/src/platform/plugins/shared/dashboard/public/dashboard_container/index.ts b/src/platform/plugins/shared/dashboard/public/dashboard_container/index.ts index c3f1989d66cd6..02b84b619aaf9 100644 --- a/src/platform/plugins/shared/dashboard/public/dashboard_container/index.ts +++ b/src/platform/plugins/shared/dashboard/public/dashboard_container/index.ts @@ -16,4 +16,3 @@ export const LATEST_DASHBOARD_CONTAINER_VERSION = convertNumberToDashboardVersio export { LazyDashboardRenderer } from './external_api/lazy_dashboard_renderer'; export type { DashboardLocatorParams } from './types'; -export type { IProvidesLegacyPanelPlacementSettings } from './panel_placement'; diff --git a/src/platform/plugins/shared/dashboard/public/dashboard_container/panel_placement/index.ts b/src/platform/plugins/shared/dashboard/public/dashboard_container/panel_placement/index.ts index d903886695745..3706aefca3512 100644 --- a/src/platform/plugins/shared/dashboard/public/dashboard_container/panel_placement/index.ts +++ b/src/platform/plugins/shared/dashboard/public/dashboard_container/panel_placement/index.ts @@ -11,4 +11,4 @@ export { placeClonePanel } from './place_clone_panel_strategy'; export { registerDashboardPanelPlacementSetting } from './panel_placement_registry'; -export type { GetPanelPlacementSettings, IProvidesLegacyPanelPlacementSettings } from './types'; +export type { GetPanelPlacementSettings } from './types'; diff --git a/src/platform/plugins/shared/dashboard/public/dashboard_container/panel_placement/types.ts b/src/platform/plugins/shared/dashboard/public/dashboard_container/panel_placement/types.ts index 2dd826f9a5821..93f9d2d7fc78e 100644 --- a/src/platform/plugins/shared/dashboard/public/dashboard_container/panel_placement/types.ts +++ b/src/platform/plugins/shared/dashboard/public/dashboard_container/panel_placement/types.ts @@ -7,7 +7,6 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { EmbeddableInput } from '@kbn/embeddable-plugin/public'; import { MaybePromise } from '@kbn/utility-types'; import { DashboardPanelState } from '../../../common'; import type { GridData } from '../../../server/content_management'; @@ -30,16 +29,6 @@ export interface PanelPlacementProps { currentPanels: { [key: string]: DashboardPanelState }; } -export interface IProvidesLegacyPanelPlacementSettings< - InputType extends EmbeddableInput = EmbeddableInput, - AttributesType = unknown -> { - getLegacyPanelPlacementSettings: ( - input: InputType, - attributes?: AttributesType - ) => Partial; -} - export type GetPanelPlacementSettings = ( serializedState?: SerializedState ) => MaybePromise; diff --git a/src/platform/plugins/shared/dashboard/public/index.ts b/src/platform/plugins/shared/dashboard/public/index.ts index 109be5bc0eaf0..458d1cc35ddde 100644 --- a/src/platform/plugins/shared/dashboard/public/index.ts +++ b/src/platform/plugins/shared/dashboard/public/index.ts @@ -22,7 +22,6 @@ export { LazyDashboardRenderer as DashboardRenderer, DASHBOARD_CONTAINER_TYPE, type DashboardLocatorParams, - type IProvidesLegacyPanelPlacementSettings, } from './dashboard_container'; export type { DashboardSetup, DashboardStart, DashboardFeatureFlagConfig } from './plugin'; diff --git a/src/platform/plugins/shared/embeddable/public/index.ts b/src/platform/plugins/shared/embeddable/public/index.ts index 4ec1c43df2dbb..b388427f402bc 100644 --- a/src/platform/plugins/shared/embeddable/public/index.ts +++ b/src/platform/plugins/shared/embeddable/public/index.ts @@ -17,10 +17,7 @@ export { CELL_VALUE_TRIGGER, contextMenuTrigger, CONTEXT_MENU_TRIGGER, - Embeddable, EmbeddableStateTransfer, - ErrorEmbeddable, - isContextMenuTriggerContext, isMultiValueClickTriggerContext, isRangeSelectTriggerContext, isRowClickTriggerContext, @@ -41,12 +38,8 @@ export { export type { CellValueContext, ChartActionContext, - EmbeddableContext, EmbeddableEditorState, - EmbeddableInput, - EmbeddableOutput, EmbeddablePackageState, - IEmbeddable, MultiValueClickContext, PropertySpec, RangeSelectContext, diff --git a/src/platform/plugins/shared/embeddable/public/lib/embeddables/embeddable_error_handler.tsx b/src/platform/plugins/shared/embeddable/public/lib/embeddables/embeddable_error_handler.tsx deleted file mode 100644 index 33402bfb85e0d..0000000000000 --- a/src/platform/plugins/shared/embeddable/public/lib/embeddables/embeddable_error_handler.tsx +++ /dev/null @@ -1,58 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { isFunction } from 'lodash'; -import React, { ReactNode, useEffect, useRef, useState } from 'react'; -import { isPromise } from '@kbn/std'; -import type { MaybePromise } from '@kbn/utility-types'; -import type { ErrorLike } from '@kbn/expressions-plugin/common'; -import type { EmbeddableInput, EmbeddableOutput, IEmbeddable } from './i_embeddable'; - -type IReactEmbeddable = IEmbeddable>; - -interface EmbeddableErrorHandlerProps { - children: IReactEmbeddable['catchError']; - embeddable?: IReactEmbeddable; - error: ErrorLike | string; -} - -export function EmbeddableErrorHandler({ - children, - embeddable, - error, -}: EmbeddableErrorHandlerProps) { - const [node, setNode] = useState(); - const ref = useRef(null); - - useEffect(() => { - if (!ref.current) { - return; - } - - const handler = embeddable?.catchError?.bind(embeddable) ?? children; - if (!handler) { - return; - } - - const renderedNode = handler( - typeof error === 'string' ? { message: error, name: '' } : error, - ref.current - ); - if (isFunction(renderedNode)) { - return renderedNode; - } - if (isPromise(renderedNode)) { - renderedNode.then(setNode); - } else { - setNode(renderedNode); - } - }, [children, embeddable, error]); - - return
{node}
; -} diff --git a/src/platform/plugins/shared/embeddable/public/lib/index.ts b/src/platform/plugins/shared/embeddable/public/lib/index.ts index 60f8a3638816d..3c816f15095b3 100644 --- a/src/platform/plugins/shared/embeddable/public/lib/index.ts +++ b/src/platform/plugins/shared/embeddable/public/lib/index.ts @@ -8,7 +8,6 @@ */ export * from './errors'; -export * from './embeddables'; export * from './types'; export * from './triggers'; export * from './state_transfer'; diff --git a/src/platform/plugins/shared/embeddable/public/lib/triggers/triggers.ts b/src/platform/plugins/shared/embeddable/public/lib/triggers/triggers.ts index 818c80283bf1c..cdebc6129afb6 100644 --- a/src/platform/plugins/shared/embeddable/public/lib/triggers/triggers.ts +++ b/src/platform/plugins/shared/embeddable/public/lib/triggers/triggers.ts @@ -12,14 +12,6 @@ import type { EmbeddableApiContext } from '@kbn/presentation-publishing'; import { Datatable, DatatableColumnMeta } from '@kbn/expressions-plugin/common'; import { Trigger, RowClickContext } from '@kbn/ui-actions-plugin/public'; import { BooleanRelation } from '@kbn/es-query'; -import { IEmbeddable } from '..'; - -/** - * @deprecated use `EmbeddableApiContext` from `@kbn/presentation-publishing` - */ -export interface EmbeddableContext { - embeddable: T; -} export type ValueClickContext = Partial & { data: { @@ -192,9 +184,3 @@ export const isRowClickTriggerContext = (context: ChartActionContext): context i !!context.data && typeof context.data === 'object' && typeof (context as RowClickContext).data.rowIndex === 'number'; - -export const isContextMenuTriggerContext = (context: unknown): context is EmbeddableContext => - !!context && - typeof context === 'object' && - !!(context as EmbeddableContext).embeddable && - typeof (context as EmbeddableContext).embeddable === 'object'; diff --git a/src/platform/plugins/shared/embeddable/tsconfig.json b/src/platform/plugins/shared/embeddable/tsconfig.json index aeb64ab3f2c32..54498ade512b6 100644 --- a/src/platform/plugins/shared/embeddable/tsconfig.json +++ b/src/platform/plugins/shared/embeddable/tsconfig.json @@ -12,7 +12,6 @@ "@kbn/utility-types", "@kbn/es-query", "@kbn/i18n", - "@kbn/std", "@kbn/expressions-plugin", "@kbn/saved-objects-management-plugin", "@kbn/saved-objects-tagging-oss-plugin", diff --git a/src/platform/plugins/shared/presentation_util/public/components/floating_actions/floating_actions.tsx b/src/platform/plugins/shared/presentation_util/public/components/floating_actions/floating_actions.tsx index ade106ae11098..4fcc0ef869c96 100644 --- a/src/platform/plugins/shared/presentation_util/public/components/floating_actions/floating_actions.tsx +++ b/src/platform/plugins/shared/presentation_util/public/components/floating_actions/floating_actions.tsx @@ -15,7 +15,6 @@ import { Subscription } from 'rxjs'; import { PANEL_HOVER_TRIGGER, panelHoverTrigger, - type EmbeddableInput, type ViewMode, } from '@kbn/embeddable-plugin/public'; import { apiHasUniqueId } from '@kbn/presentation-publishing'; @@ -31,7 +30,7 @@ export interface FloatingActionsProps { isEnabled?: boolean; api?: unknown; viewMode?: ViewMode; - disabledActions?: EmbeddableInput['disabledActions']; + disabledActions?: string[]; } export type FloatingActionItem = AnyApiAction & { diff --git a/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts index dd327dd4706d5..81e564da36292 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts @@ -141,6 +141,7 @@ export const applicationUsageSchema = { enterpriseSearchAnalytics: commonSchema, enterpriseSearchApplications: commonSchema, enterpriseSearchAISearch: commonSchema, + enterpriseSearchRedirect: commonSchema, enterpriseSearchSemanticSearch: commonSchema, enterpriseSearchVectorSearch: commonSchema, enterpriseSearchElasticsearch: commonSchema, diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json index 0e324ad0b4343..5b0712ac1e5a4 100644 --- a/src/plugins/telemetry/schema/oss_plugins.json +++ b/src/plugins/telemetry/schema/oss_plugins.json @@ -2753,6 +2753,137 @@ } } }, + "enterpriseSearchRedirect": { + "properties": { + "appId": { + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } + }, + "viewId": { + "type": "keyword", + "_meta": { + "description": "Always `main`" + } + }, + "clicks_total": { + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } + }, + "clicks_7_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } + }, + "clicks_30_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } + }, + "clicks_90_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } + }, + "minutes_on_screen_total": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } + }, + "minutes_on_screen_7_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } + }, + "minutes_on_screen_30_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } + }, + "minutes_on_screen_90_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } + }, + "views": { + "type": "array", + "items": { + "properties": { + "appId": { + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } + }, + "viewId": { + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } + }, + "clicks_total": { + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } + }, + "clicks_7_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } + }, + "clicks_30_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } + }, + "clicks_90_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } + }, + "minutes_on_screen_total": { + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } + }, + "minutes_on_screen_7_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } + }, + "minutes_on_screen_30_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } + }, + "minutes_on_screen_90_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } + } + } + } + } + } + }, "enterpriseSearchSemanticSearch": { "properties": { "appId": { diff --git a/src/plugins/ui_actions_enhanced/public/dynamic_actions/dynamic_action_grouping.ts b/src/plugins/ui_actions_enhanced/public/dynamic_actions/dynamic_action_grouping.ts index 640a3bbb70391..8493c00d522b5 100644 --- a/src/plugins/ui_actions_enhanced/public/dynamic_actions/dynamic_action_grouping.ts +++ b/src/plugins/ui_actions_enhanced/public/dynamic_actions/dynamic_action_grouping.ts @@ -8,12 +8,10 @@ */ import { i18n } from '@kbn/i18n'; -import { IEmbeddable } from '@kbn/embeddable-plugin/public'; +import type { EmbeddableApiContext } from '@kbn/presentation-publishing'; import { UiActionsPresentableGrouping as PresentableGrouping } from '@kbn/ui-actions-plugin/public'; -export const dynamicActionGrouping: PresentableGrouping<{ - embeddable?: IEmbeddable; -}> = [ +export const dynamicActionGrouping: PresentableGrouping = [ { id: 'dynamicActions', getDisplayName: () => diff --git a/src/plugins/visualizations/kibana.jsonc b/src/plugins/visualizations/kibana.jsonc index 8e8b492e99a0b..33817bed4357f 100644 --- a/src/plugins/visualizations/kibana.jsonc +++ b/src/plugins/visualizations/kibana.jsonc @@ -45,7 +45,8 @@ "kibanaUtils", "kibanaReact", "charts", - "savedObjects" + "savedObjects", + "presentationPanel" ], "extraPublicDirs": [ "common/constants", diff --git a/src/plugins/visualizations/public/legacy/embeddable/create_vis_embeddable_from_object.ts b/src/plugins/visualizations/public/legacy/embeddable/create_vis_embeddable_from_object.ts index 76acb5da63c53..843aa51731abc 100644 --- a/src/plugins/visualizations/public/legacy/embeddable/create_vis_embeddable_from_object.ts +++ b/src/plugins/visualizations/public/legacy/embeddable/create_vis_embeddable_from_object.ts @@ -7,7 +7,6 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { ErrorEmbeddable } from '@kbn/embeddable-plugin/public'; import type { DataView } from '@kbn/data-views-plugin/public'; import { Vis } from '../../types'; import type { @@ -22,6 +21,7 @@ import { getHttp, getTimeFilter, getCapabilities } from '../../services'; import { urlFor } from '../../utils/saved_visualize_utils'; import { createVisualizeEmbeddableAsync } from './visualize_embeddable_async'; import { AttributeService } from './attribute_service'; +import { ErrorEmbeddable } from './error_embeddable'; /** @deprecated * VisualizeEmbeddable is no longer registered with the legacy embeddable system and is only diff --git a/src/platform/plugins/shared/embeddable/public/lib/embeddables/diff_embeddable_input.test.ts b/src/plugins/visualizations/public/legacy/embeddable/diff_embeddable_input.test.ts similarity index 98% rename from src/platform/plugins/shared/embeddable/public/lib/embeddables/diff_embeddable_input.test.ts rename to src/plugins/visualizations/public/legacy/embeddable/diff_embeddable_input.test.ts index b4b8a2a1da920..80724cca7cd9f 100644 --- a/src/platform/plugins/shared/embeddable/public/lib/embeddables/diff_embeddable_input.test.ts +++ b/src/plugins/visualizations/public/legacy/embeddable/diff_embeddable_input.test.ts @@ -7,9 +7,8 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { ViewMode } from '..'; import { KibanaExecutionContext } from '@kbn/core/types'; -import { EmbeddableInput } from '.'; +import { EmbeddableInput, ViewMode } from '@kbn/embeddable-plugin/common'; import { omitGenericEmbeddableInput, genericEmbeddableInputIsEqual } from './diff_embeddable_input'; const getGenericEmbeddableState = (state?: Partial): EmbeddableInput => { diff --git a/src/platform/plugins/shared/embeddable/public/lib/embeddables/diff_embeddable_input.ts b/src/plugins/visualizations/public/legacy/embeddable/diff_embeddable_input.ts similarity index 97% rename from src/platform/plugins/shared/embeddable/public/lib/embeddables/diff_embeddable_input.ts rename to src/plugins/visualizations/public/legacy/embeddable/diff_embeddable_input.ts index ba55f098bba45..baf145152f72b 100644 --- a/src/platform/plugins/shared/embeddable/public/lib/embeddables/diff_embeddable_input.ts +++ b/src/plugins/visualizations/public/legacy/embeddable/diff_embeddable_input.ts @@ -9,7 +9,7 @@ import fastIsEqual from 'fast-deep-equal'; import { pick, omit } from 'lodash'; -import { EmbeddableInput } from '.'; +import type { EmbeddableInput } from '@kbn/embeddable-plugin/common'; // list out the keys from the EmbeddableInput type to allow lodash to pick them later const allGenericInputKeys: Readonly> = [ diff --git a/src/platform/plugins/shared/embeddable/public/lib/embeddables/embeddable.tsx b/src/plugins/visualizations/public/legacy/embeddable/embeddable.tsx similarity index 99% rename from src/platform/plugins/shared/embeddable/public/lib/embeddables/embeddable.tsx rename to src/plugins/visualizations/public/legacy/embeddable/embeddable.tsx index 3af13b3d998a3..738df6d3280ea 100644 --- a/src/platform/plugins/shared/embeddable/public/lib/embeddables/embeddable.tsx +++ b/src/plugins/visualizations/public/legacy/embeddable/embeddable.tsx @@ -14,8 +14,8 @@ import { merge } from 'rxjs'; import { debounceTime, distinctUntilChanged, map, skip } from 'rxjs'; import { RenderCompleteDispatcher } from '@kbn/kibana-utils-plugin/public'; import { Adapters } from '@kbn/inspector-plugin/public'; +import { EmbeddableInput, ViewMode } from '@kbn/embeddable-plugin/common'; import { EmbeddableError, EmbeddableOutput, IEmbeddable } from './i_embeddable'; -import { EmbeddableInput, ViewMode } from '../../../common/types'; import { genericEmbeddableInputIsEqual, omitGenericEmbeddableInput } from './diff_embeddable_input'; function getPanelTitle(input: EmbeddableInput, output: EmbeddableOutput) { diff --git a/src/platform/plugins/shared/embeddable/public/lib/embeddables/error_embeddable.scss b/src/plugins/visualizations/public/legacy/embeddable/error_embeddable.scss similarity index 100% rename from src/platform/plugins/shared/embeddable/public/lib/embeddables/error_embeddable.scss rename to src/plugins/visualizations/public/legacy/embeddable/error_embeddable.scss diff --git a/src/platform/plugins/shared/embeddable/public/lib/embeddables/error_embeddable.tsx b/src/plugins/visualizations/public/legacy/embeddable/error_embeddable.tsx similarity index 100% rename from src/platform/plugins/shared/embeddable/public/lib/embeddables/error_embeddable.tsx rename to src/plugins/visualizations/public/legacy/embeddable/error_embeddable.tsx diff --git a/src/platform/plugins/shared/embeddable/public/lib/embeddables/i_embeddable.ts b/src/plugins/visualizations/public/legacy/embeddable/i_embeddable.ts similarity index 98% rename from src/platform/plugins/shared/embeddable/public/lib/embeddables/i_embeddable.ts rename to src/plugins/visualizations/public/legacy/embeddable/i_embeddable.ts index 51a24527dd4aa..29bb089ceeef2 100644 --- a/src/platform/plugins/shared/embeddable/public/lib/embeddables/i_embeddable.ts +++ b/src/plugins/visualizations/public/legacy/embeddable/i_embeddable.ts @@ -10,7 +10,7 @@ import { ErrorLike } from '@kbn/expressions-plugin/common'; import { Adapters } from '@kbn/inspector-plugin/public'; import { Observable } from 'rxjs'; -import { EmbeddableInput } from '../../../common/types'; +import type { EmbeddableInput } from '@kbn/embeddable-plugin/common'; export type EmbeddableError = ErrorLike; export type { EmbeddableInput }; diff --git a/src/plugins/visualizations/public/legacy/embeddable/visualize_embeddable.tsx b/src/plugins/visualizations/public/legacy/embeddable/visualize_embeddable.tsx index 1f631f30f8eb5..3f77ce9ecb661 100644 --- a/src/plugins/visualizations/public/legacy/embeddable/visualize_embeddable.tsx +++ b/src/plugins/visualizations/public/legacy/embeddable/visualize_embeddable.tsx @@ -22,7 +22,7 @@ import type { DataView } from '@kbn/data-views-plugin/public'; import { Warnings } from '@kbn/charts-plugin/public'; import { hasUnsupportedDownsampledAggregationFailure } from '@kbn/search-response-warnings'; import { Adapters } from '@kbn/inspector-plugin/public'; -import { Embeddable, EmbeddableInput, EmbeddableOutput } from '@kbn/embeddable-plugin/public'; +import { EmbeddableInput } from '@kbn/embeddable-plugin/common'; import { SavedObjectEmbeddableInput } from '@kbn/embeddable-plugin/common'; import { ExpressionAstExpression, @@ -47,6 +47,8 @@ import { VisSavedObject } from '../../types'; import { toExpressionAst } from '../../embeddable/to_ast'; import { AttributeService } from './attribute_service'; import { VisualizationsStartDeps } from '../../plugin'; +import { Embeddable } from './embeddable'; +import { EmbeddableOutput } from './i_embeddable'; export interface VisualizeEmbeddableDeps { start: StartServicesGetter< diff --git a/src/plugins/visualizations/tsconfig.json b/src/plugins/visualizations/tsconfig.json index 51deaf4139aa2..32811524e65f7 100644 --- a/src/plugins/visualizations/tsconfig.json +++ b/src/plugins/visualizations/tsconfig.json @@ -73,7 +73,8 @@ "@kbn/search-response-warnings", "@kbn/embeddable-enhanced-plugin", "@kbn/content-management-utils", - "@kbn/react-hooks" + "@kbn/react-hooks", + "@kbn/presentation-panel-plugin" ], "exclude": ["target/**/*"] } diff --git a/x-pack/platform/packages/shared/ai-assistant/icon/__stories__/beacon.stories.tsx b/x-pack/platform/packages/shared/ai-assistant/icon/__stories__/beacon.stories.tsx index b0a77f6cab3cb..4027b431110ac 100644 --- a/x-pack/platform/packages/shared/ai-assistant/icon/__stories__/beacon.stories.tsx +++ b/x-pack/platform/packages/shared/ai-assistant/icon/__stories__/beacon.stories.tsx @@ -19,6 +19,11 @@ export default { options: ['original', 's', 'm', 'l', 'xl', 'xxl'], defaultValue: 'xxl', }, + backgroundColor: { + control: 'select', + options: ['body', 'emptyShade', 'lightShade', 'darkShade'], + defaultValue: 'body', + }, }, } as ComponentMeta; diff --git a/x-pack/platform/packages/shared/ai-assistant/icon/avatar.styles.ts b/x-pack/platform/packages/shared/ai-assistant/icon/avatar.styles.ts deleted file mode 100644 index 3b9d0b40ef274..0000000000000 --- a/x-pack/platform/packages/shared/ai-assistant/icon/avatar.styles.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useEuiTheme } from '@elastic/eui'; -import { css } from '@emotion/react'; - -export const useStyles = () => { - const { - euiTheme: { border, size }, - } = useEuiTheme(); - - const root = css` - border: ${border.thin}; - padding: ${size.xs}; - `; - - return { root }; -}; diff --git a/x-pack/platform/packages/shared/ai-assistant/icon/avatar.tsx b/x-pack/platform/packages/shared/ai-assistant/icon/avatar.tsx index 40142b8b30fa8..ce539979f202c 100644 --- a/x-pack/platform/packages/shared/ai-assistant/icon/avatar.tsx +++ b/x-pack/platform/packages/shared/ai-assistant/icon/avatar.tsx @@ -9,7 +9,6 @@ import React from 'react'; import { EuiAvatar, EuiAvatarProps } from '@elastic/eui'; import { AssistantIcon } from './icon'; -import { useStyles } from './avatar.styles'; /** * Avatar component for the AI Assistant. @@ -23,11 +22,9 @@ export type AssistantAvatarProps = Omit< * A `EuiAvatar` component customized for the AI Assistant. */ export const AssistantAvatar = ({ - css, color = 'plain', size = 'm', ...props }: AssistantAvatarProps) => { - const { root } = useStyles(); - return ; + return ; }; diff --git a/x-pack/platform/packages/shared/kbn-ai-assistant/src/chat/welcome_message.tsx b/x-pack/platform/packages/shared/kbn-ai-assistant/src/chat/welcome_message.tsx index 6133df55c57e0..555461de16d77 100644 --- a/x-pack/platform/packages/shared/kbn-ai-assistant/src/chat/welcome_message.tsx +++ b/x-pack/platform/packages/shared/kbn-ai-assistant/src/chat/welcome_message.tsx @@ -80,7 +80,7 @@ export function WelcomeMessage({ className={fullHeightClassName} > - + diff --git a/x-pack/platform/packages/shared/kbn-elastic-assistant/impl/assistant/assistant_body/empty_convo.tsx b/x-pack/platform/packages/shared/kbn-elastic-assistant/impl/assistant/assistant_body/empty_convo.tsx index 3aa0e2271beff..86bd31318349c 100644 --- a/x-pack/platform/packages/shared/kbn-elastic-assistant/impl/assistant/assistant_body/empty_convo.tsx +++ b/x-pack/platform/packages/shared/kbn-elastic-assistant/impl/assistant/assistant_body/empty_convo.tsx @@ -9,7 +9,7 @@ import React, { Dispatch, SetStateAction } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiText } from '@elastic/eui'; import { css } from '@emotion/react'; import { PromptResponse } from '@kbn/elastic-assistant-common'; -import { AssistantAnimatedIcon } from '../assistant_animated_icon'; +import { AssistantBeacon } from '@kbn/ai-assistant-icon'; import { SystemPrompt } from '../prompt_editor/system_prompt'; import { SetupKnowledgeBaseButton } from '../../knowledge_base/setup_knowledge_base_button'; import * as i18n from '../translations'; @@ -41,7 +41,7 @@ export const EmptyConvo: React.FC = ({ > - + diff --git a/x-pack/platform/packages/shared/kbn-elastic-assistant/impl/assistant/assistant_body/index.tsx b/x-pack/platform/packages/shared/kbn-elastic-assistant/impl/assistant/assistant_body/index.tsx index 757f385db058c..6fc10341864f3 100644 --- a/x-pack/platform/packages/shared/kbn-elastic-assistant/impl/assistant/assistant_body/index.tsx +++ b/x-pack/platform/packages/shared/kbn-elastic-assistant/impl/assistant/assistant_body/index.tsx @@ -18,7 +18,7 @@ import { HttpSetup } from '@kbn/core-http-browser'; import { euiThemeVars } from '@kbn/ui-theme'; import { css } from '@emotion/react'; import { PromptResponse } from '@kbn/elastic-assistant-common'; -import { AssistantAnimatedIcon } from '../assistant_animated_icon'; +import { AssistantBeacon } from '@kbn/ai-assistant-icon'; import { EmptyConvo } from './empty_convo'; import { WelcomeSetup } from './welcome_setup'; import { Conversation } from '../../..'; @@ -102,7 +102,10 @@ export const AssistantBody: FunctionComponent = ({ {isLoading ? ( - } /> + } + /> ) : isWelcomeSetup ? ( = ({ data-test-subj="welcome-setup" > - + diff --git a/x-pack/platform/packages/shared/kbn-elastic-assistant/impl/assistant/assistant_title/index.tsx b/x-pack/platform/packages/shared/kbn-elastic-assistant/impl/assistant/assistant_title/index.tsx index 03016f143b6b0..5c78ab2552ab4 100644 --- a/x-pack/platform/packages/shared/kbn-elastic-assistant/impl/assistant/assistant_title/index.tsx +++ b/x-pack/platform/packages/shared/kbn-elastic-assistant/impl/assistant/assistant_title/index.tsx @@ -8,9 +8,9 @@ import React, { useCallback, useEffect, useState } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiInlineEditTitle } from '@elastic/eui'; import { css } from '@emotion/react'; +import { AssistantIcon } from '@kbn/ai-assistant-icon'; import { DataStreamApis } from '../use_data_stream_apis'; import type { Conversation } from '../../..'; -import { AssistantAvatar } from '../assistant_avatar/assistant_avatar'; import { useConversation } from '../use_conversation'; import { NEW_CHAT } from '../conversations/conversation_sidepanel/translations'; @@ -51,7 +51,7 @@ export const AssistantTitle: React.FC<{ return ( - + { test('returns correct hex code for low for 0 <= score < 3', () => { - expect(getSeverityColor(0)).toBe('#d2e9f7'); - expect(getSeverityColor(0.001)).toBe('#d2e9f7'); - expect(getSeverityColor(2.99)).toBe('#d2e9f7'); + expect(getSeverityColor(0)).toBe(ML_SEVERITY_COLORS.LOW); + expect(getSeverityColor(0.001)).toBe(ML_SEVERITY_COLORS.LOW); + expect(getSeverityColor(2.99)).toBe(ML_SEVERITY_COLORS.LOW); }); test('returns correct hex code for warning for 3 <= score < 25', () => { - expect(getSeverityColor(3)).toBe('#8bc8fb'); - expect(getSeverityColor(24.99)).toBe('#8bc8fb'); + expect(getSeverityColor(3)).toBe(ML_SEVERITY_COLORS.WARNING); + expect(getSeverityColor(24.99)).toBe(ML_SEVERITY_COLORS.WARNING); }); test('returns correct hex code for minor for 25 <= score < 50', () => { - expect(getSeverityColor(25)).toBe('#fdec25'); - expect(getSeverityColor(49.99)).toBe('#fdec25'); + expect(getSeverityColor(25)).toBe(ML_SEVERITY_COLORS.MINOR); + expect(getSeverityColor(49.99)).toBe(ML_SEVERITY_COLORS.MINOR); }); test('returns correct hex code for major for 50 <= score < 75', () => { - expect(getSeverityColor(50)).toBe('#fba740'); - expect(getSeverityColor(74.99)).toBe('#fba740'); + expect(getSeverityColor(50)).toBe(ML_SEVERITY_COLORS.MAJOR); + expect(getSeverityColor(74.99)).toBe(ML_SEVERITY_COLORS.MAJOR); }); test('returns correct hex code for critical for score >= 75', () => { - expect(getSeverityColor(75)).toBe('#fe5050'); - expect(getSeverityColor(100)).toBe('#fe5050'); - expect(getSeverityColor(1000)).toBe('#fe5050'); + expect(getSeverityColor(75)).toBe(ML_SEVERITY_COLORS.CRITICAL); + expect(getSeverityColor(100)).toBe(ML_SEVERITY_COLORS.CRITICAL); + expect(getSeverityColor(1000)).toBe(ML_SEVERITY_COLORS.CRITICAL); }); test('returns correct hex code for unknown for scores less than 0', () => { - expect(getSeverityColor(-10)).toBe('#ffffff'); + expect(getSeverityColor(-10)).toBe(ML_SEVERITY_COLORS.UNKNOWN); }); }); diff --git a/x-pack/platform/packages/shared/ml/anomaly_utils/get_severity_color.ts b/x-pack/platform/packages/shared/ml/anomaly_utils/get_severity_color.ts index f17609ecef5e7..dcc5ac3544e1b 100644 --- a/x-pack/platform/packages/shared/ml/anomaly_utils/get_severity_color.ts +++ b/x-pack/platform/packages/shared/ml/anomaly_utils/get_severity_color.ts @@ -9,7 +9,7 @@ import { ML_ANOMALY_THRESHOLD } from './anomaly_threshold'; import { ML_SEVERITY_COLORS } from './severity_colors'; /** - * Returns a severity RGB color (one of critical, major, minor, warning, low or blank) + * Returns a severity RGB color (one of critical, major, minor, warning, low or unknown) * for the supplied normalized anomaly score (a value between 0 and 100). * @param normalizedScore - A normalized score between 0-100, which is based on the probability of the anomalousness of this record */ @@ -25,6 +25,6 @@ export function getSeverityColor(normalizedScore: number): string { } else if (normalizedScore >= ML_ANOMALY_THRESHOLD.LOW) { return ML_SEVERITY_COLORS.LOW; } else { - return ML_SEVERITY_COLORS.BLANK; + return ML_SEVERITY_COLORS.UNKNOWN; } } diff --git a/x-pack/platform/packages/shared/ml/anomaly_utils/severity_colors.ts b/x-pack/platform/packages/shared/ml/anomaly_utils/severity_colors.ts index e871528463399..67cc59fe46a2b 100644 --- a/x-pack/platform/packages/shared/ml/anomaly_utils/severity_colors.ts +++ b/x-pack/platform/packages/shared/ml/anomaly_utils/severity_colors.ts @@ -38,5 +38,5 @@ export const ML_SEVERITY_COLORS = { /** * Color used in the UI to indicate an anomaly for which the score is unknown. */ - BLANK: '#ffffff', + UNKNOWN: '#ffffff', }; diff --git a/x-pack/platform/plugins/shared/integration_assistant/public/components/create_integration/create_integration_assistant/header/header.tsx b/x-pack/platform/plugins/shared/integration_assistant/public/components/create_integration/create_integration_assistant/header/header.tsx index 7b417aee5576f..609226c48c8dd 100644 --- a/x-pack/platform/plugins/shared/integration_assistant/public/components/create_integration/create_integration_assistant/header/header.tsx +++ b/x-pack/platform/plugins/shared/integration_assistant/public/components/create_integration/create_integration_assistant/header/header.tsx @@ -5,16 +5,9 @@ * 2.0. */ -import { - EuiAvatar, - EuiFlexGroup, - EuiFlexItem, - EuiSpacer, - EuiText, - useEuiTheme, -} from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText, useEuiTheme } from '@elastic/eui'; import { css } from '@emotion/react'; -import { AssistantAvatar } from '@kbn/elastic-assistant'; +import { AssistantAvatar } from '@kbn/ai-assistant-icon'; import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; import React from 'react'; import { useActions } from '../state'; @@ -40,8 +33,8 @@ interface HeaderProps { } export const Header = React.memo(({ currentStep, isGenerating }) => { const { setStep } = useActions(); - const { euiTheme } = useEuiTheme(); const avatarCss = useAvatarCss(); + return ( @@ -56,13 +49,7 @@ export const Header = React.memo(({ currentStep, isGenerating }) => justifyContent="center" > - + diff --git a/x-pack/platform/plugins/shared/integration_assistant/public/components/create_integration/create_integration_landing/integration_assistant_card.tsx b/x-pack/platform/plugins/shared/integration_assistant/public/components/create_integration/create_integration_landing/integration_assistant_card.tsx index 3dec795111425..dbae30ad664de 100644 --- a/x-pack/platform/plugins/shared/integration_assistant/public/components/create_integration/create_integration_landing/integration_assistant_card.tsx +++ b/x-pack/platform/plugins/shared/integration_assistant/public/components/create_integration/create_integration_landing/integration_assistant_card.tsx @@ -15,7 +15,7 @@ import { EuiTitle, EuiBetaBadge, } from '@elastic/eui'; -import { AssistantAvatar } from '@kbn/elastic-assistant'; +import { AssistantIcon } from '@kbn/ai-assistant-icon'; import { useAuthorization } from '../../../common/hooks/use_authorization'; import { MissingPrivilegesTooltip } from '../../../common/components/authorization'; import { useNavigate, Page } from '../../../common/hooks/use_navigate'; @@ -28,7 +28,7 @@ export const IntegrationAssistantCard = React.memo(() => { - + { @@ -19,31 +24,31 @@ describe('getAlertFormatters', () => { test('format anomaly score correctly', () => { expect(alertFormatter(ALERT_ANOMALY_SCORE, 50.3)).toEqual( - + 50 ); expect(alertFormatter(ALERT_ANOMALY_SCORE, '50.3,89.6')).toEqual( - + 89 ); expect(alertFormatter(ALERT_ANOMALY_SCORE, '0.7')).toEqual( - + < 1 ); expect(alertFormatter(ALERT_ANOMALY_SCORE, '0')).toEqual( - + < 1 ); expect(alertFormatter(ALERT_ANOMALY_SCORE, '')).toEqual( - + < 1 ); diff --git a/x-pack/platform/plugins/shared/ml/public/application/_index.scss b/x-pack/platform/plugins/shared/ml/public/application/_index.scss index 91201434b20b1..66b04a8ff0e78 100644 --- a/x-pack/platform/plugins/shared/ml/public/application/_index.scss +++ b/x-pack/platform/plugins/shared/ml/public/application/_index.scss @@ -1,6 +1,3 @@ -// ML has it's own variables for coloring -@import 'variables'; - // Protect the rest of Kibana from ML generic namespacing // SASSTODO: Prefix ml selectors instead .ml-app { @@ -14,4 +11,4 @@ @import 'components/job_selector/index'; @import 'components/rule_editor/index'; // SASSTODO: This file overwrites EUI directly -} \ No newline at end of file +} diff --git a/x-pack/platform/plugins/shared/ml/public/application/_variables.scss b/x-pack/platform/plugins/shared/ml/public/application/_variables.scss deleted file mode 100644 index f81a97cf8c156..0000000000000 --- a/x-pack/platform/plugins/shared/ml/public/application/_variables.scss +++ /dev/null @@ -1,12 +0,0 @@ -$mlColorCritical: #FE5050; -$mlColorMajor: #FBA740; -$mlColorMinor: #FDEC25; -$mlColorWarning: #8BC8FB; -$mlColorLowWarning: #D2E9F7; -$mlColorUnknown: #C0C0C0; - -$mlColorCriticalText: makeHighContrastColor($mlColorCritical, $euiColorEmptyShade); -$mlColorMajorText: makeHighContrastColor($mlColorMajor, $euiColorEmptyShade); -$mlColorMinorText: makeHighContrastColor($mlColorMinor, $euiColorEmptyShade); -$mlColorWarningText: makeHighContrastColor($mlColorWarning, $euiColorEmptyShade); -$mlColorUnknownText: $euiColorDarkShade; diff --git a/x-pack/platform/plugins/shared/ml/public/application/components/anomalies_table/severity_cell/severity_cell.test.tsx b/x-pack/platform/plugins/shared/ml/public/application/components/anomalies_table/severity_cell/severity_cell.test.tsx index e9166c0c6c28c..25071f30400cb 100644 --- a/x-pack/platform/plugins/shared/ml/public/application/components/anomalies_table/severity_cell/severity_cell.test.tsx +++ b/x-pack/platform/plugins/shared/ml/public/application/components/anomalies_table/severity_cell/severity_cell.test.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { render } from '@testing-library/react'; +import { ML_SEVERITY_COLORS } from '@kbn/ml-anomaly-utils/severity_colors'; import { SeverityCell } from './severity_cell'; describe('SeverityCell', () => { @@ -18,7 +19,7 @@ describe('SeverityCell', () => { const { container } = render(); expect(container.textContent).toBe('75'); const svgEl = container.querySelectorAll('[data-euiicon-type]')[0]; - expect(svgEl && svgEl.getAttribute('color')).toBe('#fe5050'); + expect(svgEl && svgEl.getAttribute('color')).toBe(ML_SEVERITY_COLORS.CRITICAL); }); test('should render a multi-bucket marker with low severity score', () => { @@ -29,6 +30,6 @@ describe('SeverityCell', () => { const { container } = render(); expect(container.textContent).toBe('< 1'); const svgEl = container.getElementsByTagName('svg').item(0); - expect(svgEl && svgEl.getAttribute('fill')).toBe('#d2e9f7'); + expect(svgEl && svgEl.getAttribute('fill')).toBe(ML_SEVERITY_COLORS.LOW); }); }); diff --git a/x-pack/platform/plugins/shared/ml/public/application/components/influencers_list/influencers_list_styles.ts b/x-pack/platform/plugins/shared/ml/public/application/components/influencers_list/influencers_list_styles.ts index d54eb495a0a33..e6cfd5b3f66fa 100644 --- a/x-pack/platform/plugins/shared/ml/public/application/components/influencers_list/influencers_list_styles.ts +++ b/x-pack/platform/plugins/shared/ml/public/application/components/influencers_list/influencers_list_styles.ts @@ -9,7 +9,7 @@ import { css } from '@emotion/react'; import { useEuiFontSize, useEuiTheme } from '@elastic/eui'; -import { mlColors } from '../../styles'; +import { ML_SEVERITY_COLORS } from '@kbn/ml-anomaly-utils'; export const useInfluencersListStyles = () => { const { euiTheme } = useEuiTheme(); @@ -50,12 +50,12 @@ export const useInfluencersListStyles = () => { width: `${barScore}%`, backgroundColor: severity === 'critical' - ? mlColors.critical + ? ML_SEVERITY_COLORS.CRITICAL : severity === 'major' - ? mlColors.major + ? ML_SEVERITY_COLORS.MAJOR : severity === 'minor' - ? mlColors.minor - : mlColors.warning, + ? ML_SEVERITY_COLORS.MINOR + : ML_SEVERITY_COLORS.WARNING, }), scoreLabel: (severity: string) => css({ @@ -67,12 +67,12 @@ export const useInfluencersListStyles = () => { display: 'inline', borderColor: severity === 'critical' - ? mlColors.critical + ? ML_SEVERITY_COLORS.CRITICAL : severity === 'major' - ? mlColors.major + ? ML_SEVERITY_COLORS.MAJOR : severity === 'minor' - ? mlColors.minor - : mlColors.warning, + ? ML_SEVERITY_COLORS.MINOR + : ML_SEVERITY_COLORS.WARNING, }), totalScoreLabel: css({ width: euiTheme.size.xl, diff --git a/x-pack/platform/plugins/shared/ml/public/application/components/severity_control/severity_control.tsx b/x-pack/platform/plugins/shared/ml/public/application/components/severity_control/severity_control.tsx index 1392c38d84507..096b7d263b183 100644 --- a/x-pack/platform/plugins/shared/ml/public/application/components/severity_control/severity_control.tsx +++ b/x-pack/platform/plugins/shared/ml/public/application/components/severity_control/severity_control.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import type { EuiRangeProps } from '@elastic/eui'; import { EuiFieldNumber, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiRange } from '@elastic/eui'; -import { ML_ANOMALY_THRESHOLD } from '@kbn/ml-anomaly-utils'; +import { ML_ANOMALY_THRESHOLD, ML_SEVERITY_COLORS } from '@kbn/ml-anomaly-utils'; export interface SeveritySelectorProps { value: number | undefined; @@ -24,22 +24,22 @@ export const SeverityControl: FC = React.memo(({ value, o { min: ML_ANOMALY_THRESHOLD.LOW, max: ML_ANOMALY_THRESHOLD.MINOR, - color: '#8BC8FB', + color: ML_SEVERITY_COLORS.WARNING, }, { min: ML_ANOMALY_THRESHOLD.MINOR, max: ML_ANOMALY_THRESHOLD.MAJOR, - color: '#FDEC25', + color: ML_SEVERITY_COLORS.MINOR, }, { min: ML_ANOMALY_THRESHOLD.MAJOR, max: ML_ANOMALY_THRESHOLD.CRITICAL, - color: '#FBA740', + color: ML_SEVERITY_COLORS.MAJOR, }, { min: ML_ANOMALY_THRESHOLD.CRITICAL, max: MAX_ANOMALY_SCORE, - color: '#FE5050', + color: ML_SEVERITY_COLORS.CRITICAL, }, ]; diff --git a/x-pack/platform/plugins/shared/ml/public/application/explorer/explorer_charts/_explorer_chart.scss b/x-pack/platform/plugins/shared/ml/public/application/explorer/explorer_charts/_explorer_chart.scss deleted file mode 100644 index 29967e8db9b3f..0000000000000 --- a/x-pack/platform/plugins/shared/ml/public/application/explorer/explorer_charts/_explorer_chart.scss +++ /dev/null @@ -1,120 +0,0 @@ -// stylelint-disable selector-no-qualifying-type -.ml-explorer-chart-container { - overflow: hidden; - - .ml-explorer-chart-svg { - font-size: $euiFontSizeXS; - font-family: $euiFontFamily; - - .line-chart { - rect { - fill: $euiColorEmptyShade; - opacity: 1; - } - - rect.selected-interval { - fill: rgba(200, 200, 200, .1); - stroke: $euiColorDarkShade; - stroke-width: calc($euiSizeXS / 2); - stroke-opacity: .8; - } - - rect.scheduled-event-marker { - stroke-width: 1px; - stroke: $euiColorDarkShade; - fill: $euiColorLightShade; - pointer-events: none; - } - } - } - - .axis path, .axis line { - fill: none; - stroke: $euiBorderColor; - shape-rendering: crispEdges; - } - - .axis .tick line.ml-tick-emphasis { - stroke: rgba(0, 0, 0, .2); - } - - .axis text { - fill: $euiColorDarkShade; - } - - .axis .tick line { - stroke: $euiColorLightShade; - stroke-width: 1px; - } - - .values-line { - fill: none; - stroke: $euiColorPrimary; - stroke-width: 2; - } - - .values-dots circle, - .values-dots-circle { - fill: $euiColorPrimary; - stroke-width: 0; - } - - .values-dots circle.values-dots-circle-blur { - fill: $euiColorMediumShade; - } - - .metric-value { - opacity: 1; - fill: transparent; - stroke: $euiColorPrimary; - stroke-width: 0; - } - - .anomaly-marker { - stroke-width: 1px; - stroke: $euiColorMediumShade; - } - - .anomaly-marker:hover { - stroke-width: 6px; - stroke: $euiColorPrimary; - } - - .anomaly-marker.critical { - fill: $mlColorCritical; - } - - .anomaly-marker.major { - fill: $mlColorMajor; - } - - .anomaly-marker.minor { - fill: $mlColorMinor; - } - - .anomaly-marker.warning { - fill: $mlColorWarning; - } - - .anomaly-marker.low { - fill: $mlColorLowWarning; - } - - .metric-value:hover, - .anomaly-marker:hover { - stroke-width: 6px; - stroke-opacity: .65; - } -} - -.ml-explorer-chart { - overflow: hidden; -} - -.ml-explorer-chart-content-wrapper { - height: 215px; -} - -.ml-explorer-chart-axis-emphasis { - font-weight: bold; -} diff --git a/x-pack/platform/plugins/shared/ml/public/application/explorer/explorer_charts/_index.scss b/x-pack/platform/plugins/shared/ml/public/application/explorer/explorer_charts/_index.scss index d32d1ce81cd78..62ef4c05e1f7a 100644 --- a/x-pack/platform/plugins/shared/ml/public/application/explorer/explorer_charts/_index.scss +++ b/x-pack/platform/plugins/shared/ml/public/application/explorer/explorer_charts/_index.scss @@ -1,3 +1 @@ -@import '../../../application/variables'; @import 'components/explorer_chart_label/index'; -@import 'explorer_chart'; diff --git a/x-pack/platform/plugins/shared/ml/public/application/explorer/explorer_charts/explorer_chart_distribution.js b/x-pack/platform/plugins/shared/ml/public/application/explorer/explorer_charts/explorer_chart_distribution.js index c7fcddbe4c515..0210663103ac5 100644 --- a/x-pack/platform/plugins/shared/ml/public/application/explorer/explorer_charts/explorer_chart_distribution.js +++ b/x-pack/platform/plugins/shared/ml/public/application/explorer/explorer_charts/explorer_chart_distribution.js @@ -47,6 +47,7 @@ import { CHART_HEIGHT, TRANSPARENT_BACKGROUND } from './constants'; import { filter } from 'rxjs'; import { drawCursor } from './utils/draw_anomaly_explorer_charts_cursor'; import { SCHEDULE_EVENT_MARKER_ENTITY } from '../../../../common/constants/charts'; +import { cssMlExplorerChart } from './explorer_chart_styles'; const popoverMenuOffset = 0; const CONTENT_WRAPPER_HEIGHT = 215; @@ -776,7 +777,7 @@ export class ExplorerChartDistribution extends React.Component { )} -
+
{isLoading && } {!isLoading &&
}
diff --git a/x-pack/platform/plugins/shared/ml/public/application/explorer/explorer_charts/explorer_chart_single_metric.js b/x-pack/platform/plugins/shared/ml/public/application/explorer/explorer_charts/explorer_chart_single_metric.js index 1b746647ef38d..9935af37feec6 100644 --- a/x-pack/platform/plugins/shared/ml/public/application/explorer/explorer_charts/explorer_chart_single_metric.js +++ b/x-pack/platform/plugins/shared/ml/public/application/explorer/explorer_charts/explorer_chart_single_metric.js @@ -12,6 +12,7 @@ import PropTypes from 'prop-types'; import React from 'react'; +import { css } from '@emotion/react'; import d3 from 'd3'; import moment from 'moment'; @@ -48,10 +49,15 @@ import { LoadingIndicator } from '../../components/loading_indicator/loading_ind import { CHART_HEIGHT, TRANSPARENT_BACKGROUND } from './constants'; import { filter } from 'rxjs'; import { drawCursor } from './utils/draw_anomaly_explorer_charts_cursor'; +import { cssMlExplorerChart } from './explorer_chart_styles'; const popoverMenuOffset = 0; const CONTENT_WRAPPER_HEIGHT = 215; +// Not used for CSS, but with d3 to select elements. const CONTENT_WRAPPER_CLASS = 'ml-explorer-chart-content-wrapper'; +const mlExplorerChartContentWrapper = css({ + height: `${CONTENT_WRAPPER_HEIGHT}px`, +}); export class ExplorerChartSingleMetric extends React.Component { static contextType = context; @@ -721,9 +727,11 @@ export class ExplorerChartSingleMetric extends React.Component {
)} -
+
{isLoading && } - {!isLoading &&
} + {!isLoading && ( +
+ )}
); diff --git a/x-pack/platform/plugins/shared/ml/public/application/explorer/explorer_charts/explorer_chart_styles.ts b/x-pack/platform/plugins/shared/ml/public/application/explorer/explorer_charts/explorer_chart_styles.ts new file mode 100644 index 0000000000000..e89877fc03392 --- /dev/null +++ b/x-pack/platform/plugins/shared/ml/public/application/explorer/explorer_charts/explorer_chart_styles.ts @@ -0,0 +1,131 @@ +/* + * 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 { css } from '@emotion/react'; + +import { useEuiFontSize, useEuiTheme, mathWithUnits, transparentize } from '@elastic/eui'; + +import { ML_SEVERITY_COLORS } from '@kbn/ml-anomaly-utils'; + +export const useCssMlExplorerChartContainer = () => { + const { euiTheme } = useEuiTheme(); + const euiFontSizeXS = useEuiFontSize('xs').fontSize; + + return css({ + overflow: 'hidden', + + '.ml-explorer-chart-svg': { + fontSize: euiFontSizeXS, + fontFamily: euiTheme.font.family, + + '.line-chart': { + rect: { + fill: euiTheme.colors.emptyShade, + opacity: 1, + }, + + 'rect.selected-interval': { + fill: transparentize('#c8c8c8', 0.1), + stroke: euiTheme.colors.darkShade, + strokeWidth: mathWithUnits(euiTheme.size.xs, (x) => x / 2), + strokeOpacity: 0.8, + }, + + 'rect.scheduled-event-marker': { + strokeWidth: '1px', + stroke: euiTheme.colors.darkShade, + fill: euiTheme.colors.lightShade, + pointerEvents: 'none', + }, + }, + }, + + '.axis path, .axis line': { + fill: 'none', + stroke: euiTheme.border.color, + shapeRendering: 'crispEdges', + }, + + '.axis .tick line.ml-tick-emphasis': { + stroke: transparentize('#000', 0.2), + }, + + '.axis text': { + fill: euiTheme.colors.lightShade, + }, + + '.axis .tick line': { + stroke: euiTheme.colors.lightShade, + strokeWidth: '1px', + }, + + '.values-line': { + fill: 'none', + stroke: euiTheme.colors.primary, + strokeWidth: '2px', + }, + + '.values-dots circle, .values-dots-circle': { + fill: euiTheme.colors.primary, + strokeWidth: 0, + }, + + '.values-dots circle.values-dots-circle-blur': { + fill: euiTheme.colors.mediumShade, + }, + + '.metric-value': { + opacity: 1, + fill: 'transparent', + stroke: euiTheme.colors.primary, + strokeWidth: 0, + }, + + '.anomaly-marker': { + strokeWidth: '1px', + stroke: euiTheme.colors.mediumShade, + }, + + '.anomaly-marker:hover': { + strokeWidth: '6px', + stroke: euiTheme.colors.primary, + }, + + '.anomaly-marker.critical': { + fill: ML_SEVERITY_COLORS.CRITICAL, + }, + + '.anomaly-marker.major': { + fill: ML_SEVERITY_COLORS.MAJOR, + }, + + '.anomaly-marker.minor': { + fill: ML_SEVERITY_COLORS.MINOR, + }, + + '.anomaly-marker.warning': { + fill: ML_SEVERITY_COLORS.WARNING, + }, + + '.anomaly-marker.low': { + fill: ML_SEVERITY_COLORS.LOW, + }, + + '.metric-value:hover, .anomaly-marker:hover': { + strokeWidth: '6px', + strokeOpacity: 0.65, + }, + + 'ml-explorer-chart-axis-emphasis': { + fontWeight: 'bold', + }, + }); +}; + +export const cssMlExplorerChart = css({ + overflow: 'hidden', +}); diff --git a/x-pack/platform/plugins/shared/ml/public/application/explorer/explorer_charts/explorer_charts_container.js b/x-pack/platform/plugins/shared/ml/public/application/explorer/explorer_charts/explorer_charts_container.js index 9bc1317a9aa50..1f3a2d20eea28 100644 --- a/x-pack/platform/plugins/shared/ml/public/application/explorer/explorer_charts/explorer_charts_container.js +++ b/x-pack/platform/plugins/shared/ml/public/application/explorer/explorer_charts/explorer_charts_container.js @@ -45,6 +45,7 @@ import { EmbeddedMapComponentWrapper } from './explorer_chart_embedded_map'; import { useActiveCursor } from '@kbn/charts-plugin/public'; import { BarSeries, Chart, Settings, LEGACY_LIGHT_THEME } from '@elastic/charts'; import { escapeKueryForFieldValuePair } from '../../util/string_utils'; +import { useCssMlExplorerChartContainer } from './explorer_chart_styles'; const textTooManyBuckets = i18n.translate('xpack.ml.explorer.charts.tooManyBucketsDescription', { defaultMessage: @@ -398,6 +399,7 @@ export const ExplorerChartsContainerUI = ({ chartsService, showFilterIcons = true, }) => { + const cssMlExplorerChartContainer = useCssMlExplorerChartContainer(); const { services: { embeddable: embeddablePlugin, maps: mapsPlugin }, } = kibana; @@ -443,7 +445,8 @@ export const ExplorerChartsContainerUI = ({ return ( { // We test child components with snapshots separately // so we just do a high level check here. - expect(wrapper.find('div.ml-explorer-chart-container').children()).toHaveLength(1); + expect( + wrapper.find('div[data-test-subj="mlExplorerChartContainerItem"]').children() + ).toHaveLength(1); // Check if the additional y-axis information for rare charts is not part of the chart expect(wrapper.html().search(rareChartUniqueString)).toBe(-1); @@ -148,7 +150,9 @@ describe('ExplorerChartsContainer', () => { // We test child components with snapshots separately // so we just do a high level check here. - expect(wrapper.find('div.ml-explorer-chart-container').children()).toHaveLength(1); + expect( + wrapper.find('div[data-test-subj="mlExplorerChartContainerItem"]').children() + ).toHaveLength(1); // Check if the additional y-axis information for rare charts is part of the chart expect(wrapper.html().search(rareChartUniqueString)).toBeGreaterThan(0); diff --git a/x-pack/platform/plugins/shared/ml/public/application/timeseriesexplorer/components/timeseries_chart/timeseries_chart.js b/x-pack/platform/plugins/shared/ml/public/application/timeseriesexplorer/components/timeseries_chart/timeseries_chart.js index f39bab106c643..d43603684b043 100644 --- a/x-pack/platform/plugins/shared/ml/public/application/timeseriesexplorer/components/timeseries_chart/timeseries_chart.js +++ b/x-pack/platform/plugins/shared/ml/public/application/timeseriesexplorer/components/timeseries_chart/timeseries_chart.js @@ -20,7 +20,11 @@ import moment from 'moment'; import { EuiPopover } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { getFormattedSeverityScore, getSeverityWithLow } from '@kbn/ml-anomaly-utils'; +import { + getFormattedSeverityScore, + getSeverityWithLow, + ML_SEVERITY_COLORS, +} from '@kbn/ml-anomaly-utils'; import { formatHumanReadableDateTimeSeconds } from '@kbn/ml-date-utils'; import { context } from '@kbn/kibana-react-plugin/public'; @@ -87,7 +91,13 @@ const ZOOM_INTERVAL_OPTIONS = [ const anomalyColorScale = d3.scale .threshold() .domain([3, 25, 50, 75, 100]) - .range(['#d2e9f7', '#8bc8fb', '#ffdd00', '#ff7e00', '#fe5050']); + .range([ + ML_SEVERITY_COLORS.LOW, + ML_SEVERITY_COLORS.WARNING, + ML_SEVERITY_COLORS.MINOR, + ML_SEVERITY_COLORS.MAJOR, + ML_SEVERITY_COLORS.CRITICAL, + ]); // Create a gray-toned version of the color scale to use under the context chart mask. const anomalyGrayScale = d3.scale diff --git a/x-pack/platform/plugins/shared/ml/public/application/timeseriesexplorer/styles.ts b/x-pack/platform/plugins/shared/ml/public/application/timeseriesexplorer/styles.ts index 7c4315e01688b..0c9ba5619908d 100644 --- a/x-pack/platform/plugins/shared/ml/public/application/timeseriesexplorer/styles.ts +++ b/x-pack/platform/plugins/shared/ml/public/application/timeseriesexplorer/styles.ts @@ -10,7 +10,7 @@ import { css } from '@emotion/react'; import { useEuiFontSize, useEuiTheme, transparentize } from '@elastic/eui'; -import { mlColors } from '../styles'; +import { ML_SEVERITY_COLORS } from '@kbn/ml-anomaly-utils'; // Annotations constants const mlAnnotationBorderWidth = '2px'; @@ -119,23 +119,23 @@ export const useTimeseriesExplorerStyles = () => { stroke: euiTheme.colors.mediumShade, '&.critical': { - fill: mlColors.critical, + fill: ML_SEVERITY_COLORS.CRITICAL, }, '&.major': { - fill: mlColors.major, + fill: ML_SEVERITY_COLORS.MAJOR, }, '&.minor': { - fill: mlColors.minor, + fill: ML_SEVERITY_COLORS.MINOR, }, '&.warning': { - fill: mlColors.warning, + fill: ML_SEVERITY_COLORS.WARNING, }, '&.low': { - fill: mlColors.lowWarning, + fill: ML_SEVERITY_COLORS.LOW, }, }, diff --git a/x-pack/platform/plugins/shared/ml/public/embeddables/types.ts b/x-pack/platform/plugins/shared/ml/public/embeddables/types.ts index 1bcb0f9ae3579..56749e7ab40cb 100644 --- a/x-pack/platform/plugins/shared/ml/public/embeddables/types.ts +++ b/x-pack/platform/plugins/shared/ml/public/embeddables/types.ts @@ -7,7 +7,8 @@ import type { CoreStart } from '@kbn/core/public'; import type { RefreshInterval } from '@kbn/data-plugin/common'; -import type { DefaultEmbeddableApi, EmbeddableInput } from '@kbn/embeddable-plugin/public'; +import type { DefaultEmbeddableApi } from '@kbn/embeddable-plugin/public'; +import type { EmbeddableInput } from '@kbn/embeddable-plugin/common'; import type { Filter, Query, TimeRange } from '@kbn/es-query'; import type { MlEntityField } from '@kbn/ml-anomaly-utils'; import type { diff --git a/x-pack/platform/plugins/shared/rule_registry/server/search_strategy/search_strategy.ts b/x-pack/platform/plugins/shared/rule_registry/server/search_strategy/search_strategy.ts index 246b38aaf733d..bfecc958ce3d1 100644 --- a/x-pack/platform/plugins/shared/rule_registry/server/search_strategy/search_strategy.ts +++ b/x-pack/platform/plugins/shared/rule_registry/server/search_strategy/search_strategy.ts @@ -64,7 +64,7 @@ export const ruleRegistrySearchStrategyProvider = ( const registeredRuleTypes = alerting.listTypes(); - const [validRuleTypeIds, invalidRuleTypeIds] = partition(request.ruleTypeIds, (ruleTypeId) => + const [validRuleTypeIds, _] = partition(request.ruleTypeIds, (ruleTypeId) => registeredRuleTypes.has(ruleTypeId) ); @@ -75,12 +75,6 @@ export const ruleRegistrySearchStrategyProvider = ( ); } - invalidRuleTypeIds.forEach((ruleTypeId) => { - logger.warn( - `Found invalid rule type '${ruleTypeId}' while using ${RULE_SEARCH_STRATEGY_NAME} search strategy. No alert data from this rule type will be searched.` - ); - }); - const securityAuditLogger = security?.audit.asScoped(deps.request); const getActiveSpace = async () => spaces?.spacesService.getActiveSpace(deps.request); diff --git a/x-pack/platform/plugins/shared/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_modal.tsx b/x-pack/platform/plugins/shared/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_modal.tsx index e90c7db5de0b4..6e590b0ed38d4 100644 --- a/x-pack/platform/plugins/shared/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_modal.tsx +++ b/x-pack/platform/plugins/shared/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_modal.tsx @@ -21,6 +21,7 @@ import { EuiBetaBadge, EuiButtonGroup, EuiSpacer, + useGeneratedHtmlId, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import './connector_add_modal.scss'; @@ -214,12 +215,15 @@ const ConnectorAddModal = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + const modalTitleId = useGeneratedHtmlId(); + return ( @@ -231,7 +235,7 @@ const ConnectorAddModal = ({ - + { id: expect.any(String), index: '.kibana-reporting', op_type: 'create', - refresh: 'wait_for', body: { '@timestamp': '1970-01-01T00:00:00.000Z', parent_id: 'something', @@ -317,7 +316,6 @@ describe('ContentStream', () => { id: expect.any(String), index: '.kibana-reporting', op_type: 'create', - refresh: 'wait_for', body: { '@timestamp': '1970-01-01T00:00:00.000Z', parent_id: 'something', @@ -348,7 +346,6 @@ describe('ContentStream', () => { id: expect.any(String), index: '.kibana-reporting', op_type: 'create', - refresh: 'wait_for', body: { parent_id: 'something', '@timestamp': '1970-01-01T00:00:00.000Z', @@ -365,7 +362,6 @@ describe('ContentStream', () => { id: expect.any(String), index: '.kibana-reporting', op_type: 'create', - refresh: 'wait_for', body: { parent_id: 'something', '@timestamp': '1970-01-01T00:00:00.000Z', diff --git a/x-pack/plugins/reporting/server/lib/content_stream.ts b/x-pack/plugins/reporting/server/lib/content_stream.ts index b3c113dd43c3b..e5006a4a45268 100644 --- a/x-pack/plugins/reporting/server/lib/content_stream.ts +++ b/x-pack/plugins/reporting/server/lib/content_stream.ts @@ -192,7 +192,6 @@ export class ContentStream extends Duplex { const body = await this.client.update({ ...this.document, - refresh: 'wait_for', body: { doc: { output: { content }, @@ -212,7 +211,6 @@ export class ContentStream extends Duplex { await this.client.index({ id, index: REPORTING_DATA_STREAM_ALIAS, - refresh: 'wait_for', op_type: 'create', body: { parent_id: parentId, diff --git a/x-pack/solutions/observability/plugins/apm/public/embeddable/types.ts b/x-pack/solutions/observability/plugins/apm/public/embeddable/types.ts index 14b8d18fe2101..1e61aedcd0e2d 100644 --- a/x-pack/solutions/observability/plugins/apm/public/embeddable/types.ts +++ b/x-pack/solutions/observability/plugins/apm/public/embeddable/types.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { EmbeddableInput } from '@kbn/embeddable-plugin/public'; +import type { EmbeddableInput } from '@kbn/embeddable-plugin/common'; import type { CoreStart, CoreSetup } from '@kbn/core/public'; import type { ObservabilityRuleTypeRegistry } from '@kbn/observability-plugin/public'; import type { ApmPluginStartDeps, ApmPluginSetupDeps } from '../plugin'; diff --git a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/group_view/group_view.tsx b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/group_view/group_view.tsx index 76221ecabe496..db2e2a213a20a 100644 --- a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/group_view/group_view.tsx +++ b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/group_view/group_view.tsx @@ -9,16 +9,14 @@ import { Filter } from '@kbn/es-query'; import React, { useEffect, useState } from 'react'; import { Subject } from 'rxjs'; import { GroupView } from '../../../../pages/slos/components/grouped_slos/group_view'; -import { GroupByField } from '../../../../pages/slos/components/slo_list_group_by'; -import { SLOView } from '../../../../pages/slos/components/toggle_slo_view'; -import { SortField } from '../../../../pages/slos/hooks/use_url_search_state'; +import type { ViewType, GroupByField, SortField } from '../../../../pages/slos/types'; import { buildCombinedKqlQuery } from './helpers/build_kql_query'; interface Props { groupBy: GroupByField; groups?: string[]; kqlQuery?: string; - view: SLOView; + view: ViewType; sort?: SortField; filters?: Filter[]; reloadSubject: Subject; diff --git a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/group_view/helpers/build_kql_query.test.ts b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/group_view/helpers/build_kql_query.test.ts index fff968f7459f3..8d007e99c831d 100644 --- a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/group_view/helpers/build_kql_query.test.ts +++ b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/group_view/helpers/build_kql_query.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { GroupByField } from '../../../../../pages/slos/components/slo_list_group_by'; +import type { GroupByField } from '../../../../../pages/slos/types'; import { buildCombinedKqlQuery } from './build_kql_query'; describe('buildCombinedKqlQuery', () => { diff --git a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/group_view/helpers/build_kql_query.ts b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/group_view/helpers/build_kql_query.ts index 019536a2156a5..1319bbdb39009 100644 --- a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/group_view/helpers/build_kql_query.ts +++ b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/group_view/helpers/build_kql_query.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { GroupByField } from '../../../../../pages/slos/components/slo_list_group_by'; +import type { GroupByField } from '../../../../../pages/slos/types'; interface Props { kqlQuery: string; diff --git a/x-pack/solutions/observability/plugins/slo/public/hooks/use_fetch_slo_groups.ts b/x-pack/solutions/observability/plugins/slo/public/hooks/use_fetch_slo_groups.ts index 4b409a2c56562..da9b93e0eb209 100644 --- a/x-pack/solutions/observability/plugins/slo/public/hooks/use_fetch_slo_groups.ts +++ b/x-pack/solutions/observability/plugins/slo/public/hooks/use_fetch_slo_groups.ts @@ -18,7 +18,7 @@ import { DEFAULT_SLO_GROUPS_PAGE_SIZE, SLO_SUMMARY_DESTINATION_INDEX_PATTERN, } from '../../common/constants'; -import { GroupByField } from '../pages/slos/components/slo_list_group_by'; +import type { GroupByField } from '../pages/slos/types'; import { SearchState } from '../pages/slos/hooks/use_url_search_state'; import { useKibana } from './use_kibana'; import { sloKeys } from './query_key_factory'; diff --git a/x-pack/solutions/observability/plugins/slo/public/hooks/use_fetch_slo_list.ts b/x-pack/solutions/observability/plugins/slo/public/hooks/use_fetch_slo_list.ts index aba2fe66dcb03..2ed986fd1ffc8 100644 --- a/x-pack/solutions/observability/plugins/slo/public/hooks/use_fetch_slo_list.ts +++ b/x-pack/solutions/observability/plugins/slo/public/hooks/use_fetch_slo_list.ts @@ -14,11 +14,12 @@ import { DEFAULT_SLO_PAGE_SIZE, SLO_SUMMARY_DESTINATION_INDEX_PATTERN, } from '../../common/constants'; -import { SearchState, SortDirection, SortField } from '../pages/slos/hooks/use_url_search_state'; +import { SearchState } from '../pages/slos/hooks/use_url_search_state'; import { useKibana } from './use_kibana'; import { sloKeys } from './query_key_factory'; import { useCreateDataView } from './use_create_data_view'; import { usePluginContext } from './use_plugin_context'; +import type { SortDirection, SortField } from '../pages/slos/types'; export interface SLOListParams { kqlQuery?: string; diff --git a/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/common/sort_by_select.tsx b/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/common/sort_by_select.tsx index 189dbee8b4f8c..d7114800f5bec 100644 --- a/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/common/sort_by_select.tsx +++ b/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/common/sort_by_select.tsx @@ -9,9 +9,10 @@ import { EuiPanel, EuiSelectableOption, EuiText } from '@elastic/eui'; import { EuiSelectableOptionCheckedType } from '@elastic/eui/src/components/selectable/selectable_option'; import { i18n } from '@kbn/i18n'; import React, { useState } from 'react'; -import type { SortField, SearchState } from '../../hooks/use_url_search_state'; +import type { SearchState } from '../../hooks/use_url_search_state'; import type { Option } from '../slo_context_menu'; import { ContextMenuItem, SLOContextMenu } from '../slo_context_menu'; +import type { SortField } from '../../types'; export interface Props { onStateChange: (newState: Partial) => void; diff --git a/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/grouped_slos/group_list_view.tsx b/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/grouped_slos/group_list_view.tsx index a433b57073e3b..98e4d64283486 100644 --- a/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/grouped_slos/group_list_view.tsx +++ b/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/grouped_slos/group_list_view.tsx @@ -28,16 +28,14 @@ import { paths } from '../../../../../common/locators/paths'; import { useFetchSloList } from '../../../../hooks/use_fetch_slo_list'; import { useKibana } from '../../../../hooks/use_kibana'; import { useSloFormattedSLIValue } from '../../hooks/use_slo_summary'; -import type { SortDirection, SortField } from '../../hooks/use_url_search_state'; import { SlosView } from '../slos_view'; -import { GroupByField } from '../slo_list_group_by'; -import { SLOView } from '../toggle_slo_view'; +import type { ViewType, GroupByField, SortDirection, SortField } from '../../types'; import { useGroupName } from './hooks/use_group_name'; interface Props { group: string; kqlQuery?: string; - view: SLOView; + view: ViewType; sort?: SortField; direction?: SortDirection; groupBy: GroupByField; diff --git a/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/grouped_slos/group_view.tsx b/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/grouped_slos/group_view.tsx index 3cec6fef539e6..bbccbfb40b532 100644 --- a/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/grouped_slos/group_view.tsx +++ b/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/grouped_slos/group_view.tsx @@ -8,10 +8,8 @@ import { EuiEmptyPrompt, EuiFlexItem, EuiLoadingSpinner, EuiTablePagination } fr import { Filter } from '@kbn/es-query'; import React, { useEffect } from 'react'; import { useFetchSloGroups } from '../../../../hooks/use_fetch_slo_groups'; -import type { SortDirection } from '../../hooks/use_url_search_state'; -import { SortField, useUrlSearchState } from '../../hooks/use_url_search_state'; -import { GroupByField } from '../slo_list_group_by'; -import { SLOView } from '../toggle_slo_view'; +import { useUrlSearchState } from '../../hooks/use_url_search_state'; +import type { ViewType, GroupByField, SortDirection, SortField } from '../../types'; import { SloGroupListEmpty } from './group_list_empty'; import { SloGroupListError } from './group_list_error'; import { GroupListView } from './group_list_view'; @@ -19,7 +17,7 @@ import { GroupListView } from './group_list_view'; interface Props { groupBy: GroupByField; kqlQuery?: string; - view: SLOView; + view: ViewType; sort?: SortField; direction?: SortDirection; filters?: Filter[]; diff --git a/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/grouped_slos/hooks/use_group_name.ts b/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/grouped_slos/hooks/use_group_name.ts index ba19459d4dded..689c0ec1819d8 100644 --- a/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/grouped_slos/hooks/use_group_name.ts +++ b/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/grouped_slos/hooks/use_group_name.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import { ALL_VALUE, GroupSummary } from '@kbn/slo-schema'; import { assertNever } from '@kbn/std'; import { SLI_OPTIONS } from '../../../../slo_edit/constants'; -import { GroupByField } from '../../slo_list_group_by'; +import type { GroupByField } from '../../../types'; export function useGroupName(groupBy: GroupByField, group: string, summary?: GroupSummary) { const groupName = group.toLowerCase(); diff --git a/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/slo_list_group_by.tsx b/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/slo_list_group_by.tsx index 7223f91d49519..a7f0de71e1054 100644 --- a/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/slo_list_group_by.tsx +++ b/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/slo_list_group_by.tsx @@ -12,14 +12,8 @@ import { useGetSettings } from '../../slo_settings/hooks/use_get_settings'; import type { SearchState } from '../hooks/use_url_search_state'; import type { Option } from './slo_context_menu'; import { ContextMenuItem, SLOContextMenu } from './slo_context_menu'; +import type { GroupByField } from '../types'; -export type GroupByField = - | 'ungrouped' - | 'slo.tags' - | 'status' - | 'slo.indicator.type' - | 'slo.instanceId' - | '_index'; export interface Props { onStateChange: (newState: Partial) => void; state: SearchState; diff --git a/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/slos_view.tsx b/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/slos_view.tsx index eca4282508404..02b624577ab9b 100644 --- a/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/slos_view.tsx +++ b/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/slos_view.tsx @@ -14,13 +14,13 @@ import { HealthCallout } from './health_callout/health_callout'; import { SloListEmpty } from './slo_list_empty'; import { SloListError } from './slo_list_error'; import { SloListView } from './slo_list_view/slo_list_view'; -import { SLOView } from './toggle_slo_view'; +import type { ViewType } from '../types'; export interface Props { sloList: SLOWithSummaryResponse[]; loading: boolean; error: boolean; - view: SLOView; + view: ViewType; } export function SlosView({ sloList, loading, error, view }: Props) { diff --git a/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/toggle_slo_view.tsx b/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/toggle_slo_view.tsx index a6a35912269a1..03470fd0dde5f 100644 --- a/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/toggle_slo_view.tsx +++ b/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/toggle_slo_view.tsx @@ -13,12 +13,12 @@ import React from 'react'; import type { SearchState } from '../hooks/use_url_search_state'; import { SLOSortBy } from './common/sort_by_select'; import { SloGroupBy } from './slo_list_group_by'; -export type SLOView = 'cardView' | 'listView' | 'compactView'; +import type { ViewType } from '../types'; interface Props { - onChangeView: (view: SLOView) => void; + onChangeView: (view: ViewType) => void; onStateChange: (newState: Partial) => void; - view: SLOView; + view: ViewType; state: SearchState; sloList?: FindSLOResponse; loading: boolean; @@ -96,7 +96,7 @@ export function ToggleSLOView({ })} options={toggleButtonsIcons} idSelected={view} - onChange={(id) => onChangeView(id as SLOView)} + onChange={(id) => onChangeView(id as ViewType)} isIconOnly isDisabled={loading} /> diff --git a/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/ungrouped_slos/ungrouped_view.tsx b/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/ungrouped_slos/ungrouped_view.tsx index 0374204b7e651..a96d3ba963634 100644 --- a/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/ungrouped_slos/ungrouped_view.tsx +++ b/x-pack/solutions/observability/plugins/slo/public/pages/slos/components/ungrouped_slos/ungrouped_view.tsx @@ -10,13 +10,13 @@ import { FindSLOResponse } from '@kbn/slo-schema'; import React from 'react'; import { useUrlSearchState } from '../../hooks/use_url_search_state'; import { SlosView } from '../slos_view'; -import { SLOView } from '../toggle_slo_view'; +import type { ViewType } from '../../types'; export interface Props { sloList: FindSLOResponse | undefined; loading: boolean; error: boolean; - view: SLOView; + view: ViewType; } export function UngroupedView({ sloList, loading, error, view }: Props) { diff --git a/x-pack/solutions/observability/plugins/slo/public/pages/slos/hooks/use_url_search_state.ts b/x-pack/solutions/observability/plugins/slo/public/pages/slos/hooks/use_url_search_state.ts index 5da3b4596ed71..e3d81c3d1144b 100644 --- a/x-pack/solutions/observability/plugins/slo/public/pages/slos/hooks/use_url_search_state.ts +++ b/x-pack/solutions/observability/plugins/slo/public/pages/slos/hooks/use_url_search_state.ts @@ -6,25 +6,19 @@ */ import type { Filter } from '@kbn/es-query'; -import { createKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public'; +import { + createKbnUrlStateStorage, + createSessionStorageStateStorage, +} from '@kbn/kibana-utils-plugin/public'; import deepmerge from 'deepmerge'; +import { pick } from 'lodash'; import { useCallback, useEffect, useRef, useState } from 'react'; import { useHistory } from 'react-router-dom'; import { DEFAULT_SLO_PAGE_SIZE } from '../../../../common/constants'; -import type { GroupByField } from '../components/slo_list_group_by'; -import type { SLOView } from '../components/toggle_slo_view'; +import type { GroupByField, SortDirection, SortField, ViewType } from '../types'; export const SLO_LIST_SEARCH_URL_STORAGE_KEY = 'search'; -export type SortField = - | 'sli_value' - | 'error_budget_consumed' - | 'error_budget_remaining' - | 'status' - | 'burn_rate_5m' - | 'burn_rate_1h' - | 'burn_rate_1d'; - -export type SortDirection = 'asc' | 'desc'; +export const SLO_LIST_SEARCH_SESSION_STORAGE_KEY = 'slo.list_page_search_state'; export interface SearchState { kqlQuery: string; @@ -34,7 +28,7 @@ export interface SearchState { by: SortField; direction: SortDirection; }; - view: SLOView; + view: ViewType; groupBy: GroupByField; filters: Filter[]; lastRefresh?: number; @@ -42,13 +36,13 @@ export interface SearchState { statusFilter?: Filter; } -export const DEFAULT_STATE = { +export const DEFAULT_STATE: SearchState = { kqlQuery: '', page: 0, perPage: DEFAULT_SLO_PAGE_SIZE, - sort: { by: 'status' as const, direction: 'desc' as const }, - view: 'cardView' as const, - groupBy: 'ungrouped' as const, + sort: { by: 'status', direction: 'desc' }, + view: 'cardView', + groupBy: 'ungrouped', filters: [], lastRefresh: 0, }; @@ -67,6 +61,8 @@ export function useUrlSearchState(): { }) ); + const sessionStorage = useRef(createSessionStorageStateStorage(window.localStorage)); + useEffect(() => { const sub = urlStateStorage.current ?.change$(SLO_LIST_SEARCH_URL_STORAGE_KEY) @@ -77,21 +73,30 @@ export function useUrlSearchState(): { }); setState( - urlStateStorage.current?.get(SLO_LIST_SEARCH_URL_STORAGE_KEY) ?? DEFAULT_STATE + urlStateStorage.current?.get(SLO_LIST_SEARCH_URL_STORAGE_KEY) ?? + sessionStorage.current?.get(SLO_LIST_SEARCH_SESSION_STORAGE_KEY) ?? + DEFAULT_STATE ); return () => { sub?.unsubscribe(); }; - }, [urlStateStorage]); + }, [urlStateStorage, sessionStorage]); const onStateChange = useCallback( (newState: Partial) => { const updatedState = { ...state, page: 0, ...newState }; - setState((stateN) => updatedState); + setState(() => updatedState); + urlStateStorage.current?.set(SLO_LIST_SEARCH_URL_STORAGE_KEY, updatedState, { replace: true, }); + + // Discard search itself from session storage. Keep only view preferences + sessionStorage.current?.set( + SLO_LIST_SEARCH_SESSION_STORAGE_KEY, + pick(updatedState, 'sort', 'view', 'groupBy') + ); }, [state] ); diff --git a/x-pack/solutions/observability/plugins/slo/public/pages/slos/types.ts b/x-pack/solutions/observability/plugins/slo/public/pages/slos/types.ts new file mode 100644 index 0000000000000..aae9533a8a542 --- /dev/null +++ b/x-pack/solutions/observability/plugins/slo/public/pages/slos/types.ts @@ -0,0 +1,24 @@ +/* + * 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 type ViewType = 'cardView' | 'listView' | 'compactView'; +export type GroupByField = + | 'ungrouped' + | 'slo.tags' + | 'status' + | 'slo.indicator.type' + | 'slo.instanceId' + | '_index'; +export type SortDirection = 'asc' | 'desc'; +export type SortField = + | 'sli_value' + | 'error_budget_consumed' + | 'error_budget_remaining' + | 'status' + | 'burn_rate_5m' + | 'burn_rate_1h' + | 'burn_rate_1d'; diff --git a/x-pack/solutions/observability/plugins/slo/server/plugin.ts b/x-pack/solutions/observability/plugins/slo/server/plugin.ts index e7b25fe06ef32..c7a5a1dda3280 100644 --- a/x-pack/solutions/observability/plugins/slo/server/plugin.ts +++ b/x-pack/solutions/observability/plugins/slo/server/plugin.ts @@ -160,8 +160,8 @@ export class SLOPlugin const sloInstaller = new DefaultSLOInstaller(sloResourceInstaller, this.logger); await sloInstaller.install(); }) - .catch((error) => { - this.logger.error(`Failed to install the default SLOs: ${error}`); + .catch(() => { + // noop - error already logged from the installer }); this.sloOrphanCleanupTask = new SloOrphanSummaryCleanupTask( diff --git a/x-pack/solutions/observability/plugins/slo/server/services/create_slo.ts b/x-pack/solutions/observability/plugins/slo/server/services/create_slo.ts index a8e01fb4681f4..c74f49c1ccac8 100644 --- a/x-pack/solutions/observability/plugins/slo/server/services/create_slo.ts +++ b/x-pack/solutions/observability/plugins/slo/server/services/create_slo.ts @@ -100,14 +100,14 @@ export class CreateSLO { ]); } catch (err) { this.logger.error( - `Cannot install the SLO [id: ${slo.id}, revision: ${slo.revision}]. Rolling back.` + `Cannot create the SLO [id: ${slo.id}, revision: ${slo.revision}]. Rolling back. ${err}` ); await asyncForEach(rollbackOperations.reverse(), async (operation) => { try { await operation(); } catch (rollbackErr) { - this.logger.error('Rollback operation failed', rollbackErr); + this.logger.error(`Rollback operation failed. ${rollbackErr}`); } }); diff --git a/x-pack/solutions/observability/plugins/slo/server/services/reset_slo.ts b/x-pack/solutions/observability/plugins/slo/server/services/reset_slo.ts index c9da382c2d6ce..e91e720b4fd8d 100644 --- a/x-pack/solutions/observability/plugins/slo/server/services/reset_slo.ts +++ b/x-pack/solutions/observability/plugins/slo/server/services/reset_slo.ts @@ -87,7 +87,7 @@ export class ResetSLO { ); } catch (err) { this.logger.error( - `Cannot reset the SLO [id: ${slo.id}, revision: ${slo.revision}]. Rolling back.` + `Cannot reset the SLO [id: ${slo.id}, revision: ${slo.revision}]. Rolling back. ${err}` ); await this.summaryTransformManager.stop(summaryTransformId); diff --git a/x-pack/solutions/observability/plugins/slo/server/services/resource_installer.ts b/x-pack/solutions/observability/plugins/slo/server/services/resource_installer.ts index b81fbe183c4ff..d6544d352f90f 100644 --- a/x-pack/solutions/observability/plugins/slo/server/services/resource_installer.ts +++ b/x-pack/solutions/observability/plugins/slo/server/services/resource_installer.ts @@ -79,7 +79,7 @@ export class DefaultResourceInstaller implements ResourceInstaller { await this.createIndex(SLO_SUMMARY_DESTINATION_INDEX_NAME); await this.createIndex(SLO_SUMMARY_TEMP_INDEX_NAME); } catch (err) { - this.logger.error(`Error installing resources shared for SLO: ${err.message}`); + this.logger.error(`Error while installing SLO shared resources: ${err}`); throw err; } } diff --git a/x-pack/solutions/observability/plugins/slo/server/services/slo_installer.ts b/x-pack/solutions/observability/plugins/slo/server/services/slo_installer.ts index 9484ecd907d9f..eab4c266aae8e 100644 --- a/x-pack/solutions/observability/plugins/slo/server/services/slo_installer.ts +++ b/x-pack/solutions/observability/plugins/slo/server/services/slo_installer.ts @@ -29,7 +29,7 @@ export class DefaultSLOInstaller implements SLOInstaller { await this.sloResourceInstaller.ensureCommonResourcesInstalled(); } catch (error) { - this.logger.error('Failed to install SLO common resources'); + this.logger.error(`Failed to install SLO common resources: ${error}`); } finally { this.isInstalling = false; clearTimeout(installTimeout); diff --git a/x-pack/solutions/observability/plugins/slo/server/services/summary_search_client.ts b/x-pack/solutions/observability/plugins/slo/server/services/summary_search_client.ts index 6493e613bbedc..0d12ee7255dc8 100644 --- a/x-pack/solutions/observability/plugins/slo/server/services/summary_search_client.ts +++ b/x-pack/solutions/observability/plugins/slo/server/services/summary_search_client.ts @@ -177,7 +177,7 @@ export class DefaultSummarySearchClient implements SummarySearchClient { }), }; } catch (err) { - this.logger.error(new Error(`Summary search query error, ${err.message}`, { cause: err })); + this.logger.error(`Error while searching SLO summary documents. ${err}`); return { total: 0, perPage: pagination.perPage, page: pagination.page, results: [] }; } } diff --git a/x-pack/solutions/observability/plugins/slo/server/services/summay_transform_manager.ts b/x-pack/solutions/observability/plugins/slo/server/services/summay_transform_manager.ts index 27d24e7fb5039..9389210505b4c 100644 --- a/x-pack/solutions/observability/plugins/slo/server/services/summay_transform_manager.ts +++ b/x-pack/solutions/observability/plugins/slo/server/services/summay_transform_manager.ts @@ -32,7 +32,7 @@ export class DefaultSummaryTransformManager implements TransformManager { } ); } catch (err) { - this.logger.error(`Cannot create summary transform for SLO [${slo.id}]`); + this.logger.error(`Cannot create summary transform for SLO [${slo.id}]. ${err}`); if (err.meta?.body?.error?.type === 'security_exception') { throw new SecurityException(err.meta.body.error.reason); } @@ -57,7 +57,7 @@ export class DefaultSummaryTransformManager implements TransformManager { { logger: this.logger } ); } catch (err) { - this.logger.error(`Cannot preview SLO summary transform [${transformId}]`); + this.logger.error(`Cannot preview SLO summary transform [${transformId}]. ${err}`); throw err; } } @@ -75,7 +75,7 @@ export class DefaultSummaryTransformManager implements TransformManager { } ); } catch (err) { - this.logger.error(`Cannot start SLO summary transform [${transformId}]`); + this.logger.error(`Cannot start SLO summary transform [${transformId}]. ${err}`); throw err; } } @@ -91,7 +91,7 @@ export class DefaultSummaryTransformManager implements TransformManager { { logger: this.logger } ); } catch (err) { - this.logger.error(`Cannot stop SLO summary transform [${transformId}]`); + this.logger.error(`Cannot stop SLO summary transform [${transformId}]. ${err}`); throw err; } } @@ -107,7 +107,7 @@ export class DefaultSummaryTransformManager implements TransformManager { { logger: this.logger } ); } catch (err) { - this.logger.error(`Cannot delete SLO summary transform [${transformId}]`); + this.logger.error(`Cannot delete SLO summary transform [${transformId}]. ${err}`); throw err; } } diff --git a/x-pack/solutions/observability/plugins/slo/server/services/tasks/orphan_summary_cleanup_task.ts b/x-pack/solutions/observability/plugins/slo/server/services/tasks/orphan_summary_cleanup_task.ts index c3d56854f4946..6d0aa1ee9c587 100644 --- a/x-pack/solutions/observability/plugins/slo/server/services/tasks/orphan_summary_cleanup_task.ts +++ b/x-pack/solutions/observability/plugins/slo/server/services/tasks/orphan_summary_cleanup_task.ts @@ -67,7 +67,7 @@ export class SloOrphanSummaryCleanupTask { }, cancel: async () => { - this.abortController.abort('[SLO] Definitions clean up Task timed out'); + this.abortController.abort('orphan-slo-summary-cleanup task timed out'); }, }; }, @@ -101,7 +101,7 @@ export class SloOrphanSummaryCleanupTask { if (sloSummaryIdsToDelete.length > 0) { this.logger.info( - `[SLO] Deleting ${sloSummaryIdsToDelete.length} SLO Summaries from the summary index` + `[SLO] Deleting ${sloSummaryIdsToDelete.length} SLO Summary documents from the summary index` ); await this.esClient.deleteByQuery({ @@ -124,7 +124,7 @@ export class SloOrphanSummaryCleanupTask { searchAfter?: AggregationsCompositeAggregateKey; sloSummaryIds: Array<{ id: string; revision: number }>; }> => { - this.logger.debug(`[SLO] Fetching SLO Summaries ids after ${searchAfter}`); + this.logger.debug(`[TASK] Fetching SLO Summary ids after ${searchAfter}`); if (!this.esClient) { return { searchAfter: undefined, @@ -227,7 +227,9 @@ export class SloOrphanSummaryCleanupTask { this.esClient = esClient; if (!taskManager) { - this.logger.info('[SLO] Missing required service during startup, skipping task.'); + this.logger.info( + 'Missing required service during startup, skipping orphan-slo-summary-cleanup task.' + ); return; } diff --git a/x-pack/solutions/observability/plugins/slo/server/services/transform_generators/common.ts b/x-pack/solutions/observability/plugins/slo/server/services/transform_generators/common.ts index 35a6e180650fa..4958a65a17a15 100644 --- a/x-pack/solutions/observability/plugins/slo/server/services/transform_generators/common.ts +++ b/x-pack/solutions/observability/plugins/slo/server/services/transform_generators/common.ts @@ -39,7 +39,7 @@ export function parseStringFilters(filters: string, logger: Logger) { try { return JSON.parse(filters); } catch (e) { - logger.error(`Failed to parse filters: ${e.message}`); + logger.info(`Failed to parse filters: ${e}`); } return {}; diff --git a/x-pack/solutions/observability/plugins/slo/server/services/transform_manager.ts b/x-pack/solutions/observability/plugins/slo/server/services/transform_manager.ts index 464d1f1aeaa59..c07c8d78a5ca4 100644 --- a/x-pack/solutions/observability/plugins/slo/server/services/transform_manager.ts +++ b/x-pack/solutions/observability/plugins/slo/server/services/transform_manager.ts @@ -46,7 +46,9 @@ export class DefaultTransformManager implements TransformManager { } ); } catch (err) { - this.logger.error(`Cannot create SLO transform for indicator type [${slo.indicator.type}]`); + this.logger.error( + `Cannot create SLO transform for indicator type [${slo.indicator.type}]. ${err}` + ); if (err.meta?.body?.error?.type === 'security_exception') { throw new SecurityException(err.meta.body.error.reason); } @@ -77,7 +79,7 @@ export class DefaultTransformManager implements TransformManager { { logger: this.logger } ); } catch (err) { - this.logger.error(`Cannot preview SLO transform [${transformId}]`); + this.logger.error(`Cannot preview SLO transform [${transformId}]. ${err}`); throw err; } } @@ -94,7 +96,7 @@ export class DefaultTransformManager implements TransformManager { ); await this.scheduleNowTransform(transformId); } catch (err) { - this.logger.error(`Cannot start SLO transform [${transformId}]`); + this.logger.error(`Cannot start SLO transform [${transformId}]. ${err}`); throw err; } } @@ -110,7 +112,7 @@ export class DefaultTransformManager implements TransformManager { { logger: this.logger } ); } catch (err) { - this.logger.error(`Cannot stop SLO transform [${transformId}]`); + this.logger.error(`Cannot stop SLO transform [${transformId}]. ${err}`); throw err; } } @@ -126,7 +128,7 @@ export class DefaultTransformManager implements TransformManager { { logger: this.logger } ); } catch (err) { - this.logger.error(`Cannot delete SLO transform [${transformId}]`); + this.logger.error(`Cannot delete SLO transform [${transformId}]. ${err}`); throw err; } } @@ -138,8 +140,7 @@ export class DefaultTransformManager implements TransformManager { this.logger.debug(`SLO transform [${transformId}] scheduled now successfully`); }) .catch((e) => { - this.logger.error(`Cannot schedule now SLO transform [${transformId}]`); - this.logger.error(e); + this.logger.error(`Cannot schedule now SLO transform [${transformId}]. ${e}`); }); } } diff --git a/x-pack/solutions/observability/plugins/slo/server/services/update_slo.ts b/x-pack/solutions/observability/plugins/slo/server/services/update_slo.ts index 402ca82acecd4..30d62140f80d9 100644 --- a/x-pack/solutions/observability/plugins/slo/server/services/update_slo.ts +++ b/x-pack/solutions/observability/plugins/slo/server/services/update_slo.ts @@ -103,14 +103,14 @@ export class UpdateSLO { ); } catch (err) { this.logger.error( - `Cannot update the SLO summary pipeline [id: ${updatedSlo.id}, revision: ${updatedSlo.revision}].` + `Cannot update the SLO summary pipeline [id: ${updatedSlo.id}, revision: ${updatedSlo.revision}]. ${err}` ); await asyncForEach(rollbackOperations.reverse(), async (operation) => { try { await operation(); } catch (rollbackErr) { - this.logger.error('Rollback operation failed', rollbackErr); + this.logger.error(`Rollback operation failed. ${rollbackErr}`); } }); @@ -182,14 +182,14 @@ export class UpdateSLO { ); } catch (err) { this.logger.error( - `Cannot update the SLO [id: ${updatedSlo.id}, revision: ${updatedSlo.revision}]. Rolling back.` + `Cannot update the SLO [id: ${updatedSlo.id}, revision: ${updatedSlo.revision}]. Rolling back. ${err}` ); await asyncForEach(rollbackOperations.reverse(), async (operation) => { try { await operation(); } catch (rollbackErr) { - this.logger.error('Rollback operation failed', rollbackErr); + this.logger.error(`Rollback operation failed. ${rollbackErr}`); } }); diff --git a/x-pack/solutions/search/plugins/enterprise_search/public/applications/enterprise_search_redirect/index.test.tsx b/x-pack/solutions/search/plugins/enterprise_search/public/applications/enterprise_search_redirect/index.test.tsx new file mode 100644 index 0000000000000..94c19ba7ce869 --- /dev/null +++ b/x-pack/solutions/search/plugins/enterprise_search/public/applications/enterprise_search_redirect/index.test.tsx @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { MemoryRouter } from 'react-router-dom'; + +import { render, waitFor } from '@testing-library/react'; + +import { useKibana } from '@kbn/kibana-react-plugin/public'; + +import { ApplicationRedirect } from '.'; + +jest.mock('@kbn/kibana-react-plugin/public', () => ({ + useKibana: jest.fn(), +})); + +describe('RedirectWithReplace', () => { + const navigateToUrlMock = jest.fn(); + const coreMock = { + application: { + navigateToUrl: navigateToUrlMock, + }, + }; + + beforeEach(() => { + (useKibana as jest.Mock).mockReturnValue({ services: coreMock }); + + // Mock window.location.pathname + Object.defineProperty(window, 'location', { + writable: true, + value: { pathname: '/enterprise_search/content/search_indices' }, + }); + }); + + it('should redirect to the new path', async () => { + render( + + + + ); + + await waitFor(() => { + expect(navigateToUrlMock).toHaveBeenCalledWith('/elasticsearch/content/search_indices'); + }); + }); +}); diff --git a/x-pack/solutions/search/plugins/enterprise_search/public/applications/enterprise_search_redirect/index.tsx b/x-pack/solutions/search/plugins/enterprise_search/public/applications/enterprise_search_redirect/index.tsx new file mode 100644 index 0000000000000..d861f9e65c580 --- /dev/null +++ b/x-pack/solutions/search/plugins/enterprise_search/public/applications/enterprise_search_redirect/index.tsx @@ -0,0 +1,35 @@ +/* + * 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, { useEffect } from 'react'; + +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { Routes, Route } from '@kbn/shared-ux-router'; + +const RedirectWithReplace = () => { + const { application } = useKibana().services; + + useEffect(() => { + const fullPath = location.pathname; + + // Construct the new path by replacing 'enterprise_search' with 'elasticsearch' + const newPath = fullPath.replace('/enterprise_search', '/elasticsearch'); + + // Perform the client-side navigation using core + application?.navigateToUrl(newPath); + }, []); + + return null; +}; + +export const ApplicationRedirect = () => { + return ( + + + + ); +}; diff --git a/x-pack/solutions/search/plugins/enterprise_search/public/applications/enterprise_search_redirect/jest.config.js b/x-pack/solutions/search/plugins/enterprise_search/public/applications/enterprise_search_redirect/jest.config.js new file mode 100644 index 0000000000000..776cca733229a --- /dev/null +++ b/x-pack/solutions/search/plugins/enterprise_search/public/applications/enterprise_search_redirect/jest.config.js @@ -0,0 +1,28 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../../../../..', + roots: [ + '/x-pack/solutions/search/plugins/enterprise_search/public/applications/enterprise_search_redirect', + ], + collectCoverage: true, + coverageReporters: ['text', 'html'], + collectCoverageFrom: [ + '/x-pack/solutions/search/plugins/enterprise_search/public/applications/**/*.{ts,tsx}', + '!/x-pack/solutions/search/plugins/enterprise_search/public/*.ts', + '!/x-pack/solutions/search/plugins/enterprise_search/server/*.ts', + '!/x-pack/solutions/search/plugins/enterprise_search/public/applications/test_helpers/**/*.{ts,tsx}', + ], + coverageDirectory: + '/target/kibana-coverage/jest/x-pack/solutions/search/plugins/enterprise_search/public/applications/enterprise_search_redirect', + modulePathIgnorePatterns: [ + '/x-pack/solutions/search/plugins/enterprise_search/public/applications/app_search/cypress', + '/x-pack/solutions/search/plugins/enterprise_search/public/applications/workplace_search/cypress', + ], +}; diff --git a/x-pack/solutions/search/plugins/enterprise_search/public/plugin.ts b/x-pack/solutions/search/plugins/enterprise_search/public/plugin.ts index 0a472cd2aa564..6c33d08913c54 100644 --- a/x-pack/solutions/search/plugins/enterprise_search/public/plugin.ts +++ b/x-pack/solutions/search/plugins/enterprise_search/public/plugin.ts @@ -489,6 +489,23 @@ export class EnterpriseSearchPlugin implements Plugin { visibleIn: [], }); + core.application.register({ + appRoute: '/app/enterprise_search', + category: DEFAULT_APP_CATEGORIES.enterpriseSearch, + id: 'enterpriseSearchRedirect', + mount: async (params: AppMountParameters) => { + const kibanaDeps = await this.getKibanaDeps(core, params, cloud); + const pluginData = this.getPluginData(); + + const { renderApp } = await import('./applications'); + const { ApplicationRedirect } = await import('./applications/enterprise_search_redirect'); + + return renderApp(ApplicationRedirect, kibanaDeps, pluginData); + }, + title: 'EnterpriseSearchRedirect', + visibleIn: [], + }); + if (plugins.home) { plugins.home.featureCatalogue.registerSolution({ description: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.DESCRIPTION, diff --git a/x-pack/solutions/security/packages/ecs_data_quality_dashboard/impl/data_quality_panel/actions/chat/index.tsx b/x-pack/solutions/security/packages/ecs_data_quality_dashboard/impl/data_quality_panel/actions/chat/index.tsx index fb990fc295bbf..51c4b26f6255c 100644 --- a/x-pack/solutions/security/packages/ecs_data_quality_dashboard/impl/data_quality_panel/actions/chat/index.tsx +++ b/x-pack/solutions/security/packages/ecs_data_quality_dashboard/impl/data_quality_panel/actions/chat/index.tsx @@ -6,9 +6,10 @@ */ import React, { FC, useCallback } from 'react'; -import { AssistantAvatar, NewChat } from '@kbn/elastic-assistant'; +import { NewChat } from '@kbn/elastic-assistant'; import styled from 'styled-components'; +import { AssistantIcon } from '@kbn/ai-assistant-icon'; import { DATA_QUALITY_DASHBOARD_CONVERSATION_ID, DATA_QUALITY_PROMPT_CONTEXT_PILL, @@ -44,7 +45,7 @@ const ChatActionComponent: FC = ({ indexName, markdownComment }) => { iconType={null} > - + {ASK_ASSISTANT} diff --git a/x-pack/solutions/security/packages/ecs_data_quality_dashboard/tsconfig.json b/x-pack/solutions/security/packages/ecs_data_quality_dashboard/tsconfig.json index 2d76e9b8b0b4b..95cb9be72b6ce 100644 --- a/x-pack/solutions/security/packages/ecs_data_quality_dashboard/tsconfig.json +++ b/x-pack/solutions/security/packages/ecs_data_quality_dashboard/tsconfig.json @@ -26,5 +26,6 @@ "@kbn/core", "@kbn/core-notifications-browser", "@kbn/core-notifications-browser-mocks", + "@kbn/ai-assistant-icon", ] } diff --git a/x-pack/solutions/security/packages/upselling/sections/attack_discovery/index.tsx b/x-pack/solutions/security/packages/upselling/sections/attack_discovery/index.tsx index 0c6a12c88d7fd..db9bc7c24ea69 100644 --- a/x-pack/solutions/security/packages/upselling/sections/attack_discovery/index.tsx +++ b/x-pack/solutions/security/packages/upselling/sections/attack_discovery/index.tsx @@ -5,10 +5,10 @@ * 2.0. */ -import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText } from '@elastic/eui'; import React, { useMemo } from 'react'; +import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText } from '@elastic/eui'; +import { AssistantBeacon } from '@kbn/ai-assistant-icon'; -import { AssistantAvatar } from './assistant_avatar/assistant_avatar'; import * as i18n from './translations'; interface Props { @@ -30,7 +30,7 @@ const AttackDiscoveryUpsellingSectionComponent: React.FC = ({ () => ( - + diff --git a/x-pack/solutions/security/packages/upselling/tsconfig.json b/x-pack/solutions/security/packages/upselling/tsconfig.json index 653738495ed81..93486d9365016 100644 --- a/x-pack/solutions/security/packages/upselling/tsconfig.json +++ b/x-pack/solutions/security/packages/upselling/tsconfig.json @@ -20,6 +20,7 @@ "@kbn/i18n", "@kbn/security-solution-navigation", "@kbn/shared-ux-page-kibana-template", + "@kbn/ai-assistant-icon", ], "exclude": [ "target/**/*" diff --git a/x-pack/solutions/security/plugins/security_solution/public/app/actions/add_to_timeline/lens/add_to_timeline.test.ts b/x-pack/solutions/security/plugins/security_solution/public/app/actions/add_to_timeline/lens/add_to_timeline.test.ts index ef920458f51dd..362fb5f9ee885 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/app/actions/add_to_timeline/lens/add_to_timeline.test.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/app/actions/add_to_timeline/lens/add_to_timeline.test.ts @@ -5,8 +5,7 @@ * 2.0. */ import { BehaviorSubject, Subject } from 'rxjs'; -import type { CellValueContext, EmbeddableInput, IEmbeddable } from '@kbn/embeddable-plugin/public'; -import { ErrorEmbeddable } from '@kbn/embeddable-plugin/public'; +import type { CellValueContext } from '@kbn/embeddable-plugin/public'; import type { SecurityAppStore } from '../../../../common/store/types'; import { createAddToTimelineLensAction, getInvestigatedValue } from './add_to_timeline'; import { KibanaServices } from '../../../../common/lib/kibana'; @@ -15,7 +14,7 @@ import type { DataProvider } from '../../../../../common/types'; import { TimelineId, EXISTS_OPERATOR } from '../../../../../common/types'; import { addProvider } from '../../../../timelines/store/actions'; import type { ActionExecutionContext } from '@kbn/ui-actions-plugin/public'; -import type { Query, Filter, AggregateQuery, TimeRange } from '@kbn/es-query'; +import type { TimeRange } from '@kbn/es-query'; import type { LensApi } from '@kbn/lens-plugin/public'; import { getLensApiMock } from '@kbn/lens-plugin/public/react_embeddable/mocks'; @@ -46,16 +45,6 @@ const getMockLensApi = ( saveToLibrary: jest.fn(async () => 'saved-id'), }); -const getMockEmbeddable = (type: string): IEmbeddable => - ({ - type, - filters$: new BehaviorSubject([]), - query$: new BehaviorSubject({ - query: 'test', - language: 'kuery', - }), - } as unknown as IEmbeddable); - const lensEmbeddable = getMockLensApi(); const columnMeta = { @@ -90,11 +79,14 @@ describe('createAddToTimelineLensAction', () => { }); describe('isCompatible', () => { - it('should return false if error embeddable', async () => { + it('should return false if lens embeddable has blocking error', async () => { expect( await addToTimelineAction.isCompatible({ ...context, - embeddable: new ErrorEmbeddable('some error', {} as EmbeddableInput), + embeddable: { + ...getMockLensApi(), + blockingError: new BehaviorSubject(new Error('some error')), + }, }) ).toEqual(false); }); @@ -103,7 +95,9 @@ describe('createAddToTimelineLensAction', () => { expect( await addToTimelineAction.isCompatible({ ...context, - embeddable: getMockEmbeddable('not_lens') as unknown as IEmbeddable, + embeddable: { + type: 'not_lens', + }, }) ).toEqual(false); }); diff --git a/x-pack/solutions/security/plugins/security_solution/public/app/actions/copy_to_clipboard/lens/copy_to_clipboard.test.ts b/x-pack/solutions/security/plugins/security_solution/public/app/actions/copy_to_clipboard/lens/copy_to_clipboard.test.ts index 0ec4e00848348..98a8b07fd127d 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/app/actions/copy_to_clipboard/lens/copy_to_clipboard.test.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/app/actions/copy_to_clipboard/lens/copy_to_clipboard.test.ts @@ -5,8 +5,7 @@ * 2.0. */ -import type { CellValueContext, EmbeddableInput, IEmbeddable } from '@kbn/embeddable-plugin/public'; -import { ErrorEmbeddable } from '@kbn/embeddable-plugin/public'; +import type { CellValueContext } from '@kbn/embeddable-plugin/public'; import type { LensApi } from '@kbn/lens-plugin/public'; import { createCopyToClipboardLensAction } from './copy_to_clipboard'; import { KibanaServices } from '../../../../common/lib/kibana'; @@ -40,13 +39,6 @@ const getMockLensApi = ( saveToLibrary: jest.fn(async () => 'saved-id'), }); -const getMockEmbeddable = (type: string): IEmbeddable => - ({ - type, - getFilters: jest.fn(), - getQuery: jest.fn(), - } as unknown as IEmbeddable); - const lensEmbeddable = getMockLensApi(); const columnMeta = { @@ -83,7 +75,10 @@ describe('createCopyToClipboardLensAction', () => { expect( await copyToClipboardAction.isCompatible({ ...context, - embeddable: new ErrorEmbeddable('some error', {} as EmbeddableInput), + embeddable: { + ...getMockLensApi(), + blockingError: new BehaviorSubject(new Error('some error')), + }, }) ).toEqual(false); }); @@ -92,7 +87,9 @@ describe('createCopyToClipboardLensAction', () => { expect( await copyToClipboardAction.isCompatible({ ...context, - embeddable: getMockEmbeddable('not_lens') as unknown as IEmbeddable, + embeddable: { + type: 'not_lens', + }, }) ).toEqual(false); }); diff --git a/x-pack/solutions/security/plugins/security_solution/public/assistant/get_comments/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/assistant/get_comments/index.tsx index b3be6370e905d..8b9dc2f2c80f4 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/assistant/get_comments/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/assistant/get_comments/index.tsx @@ -9,7 +9,7 @@ import type { ClientMessage, GetAssistantMessages } from '@kbn/elastic-assistant import { EuiAvatar, EuiLoadingSpinner } from '@elastic/eui'; import React from 'react'; -import { AssistantAvatar } from '@kbn/elastic-assistant'; +import { AssistantAvatar } from '@kbn/ai-assistant-icon'; import type { Replacements } from '@kbn/elastic-assistant-common'; import { replaceAnonymizedValuesWithOriginalValues } from '@kbn/elastic-assistant-common'; import styled from '@emotion/styled'; @@ -117,9 +117,7 @@ export const getComments: GetAssistantMessages = ({ ? [ { username: i18n.SYSTEM, - timelineAvatar: ( - - ), + timelineAvatar: , timestamp: currentConversation.messages[0].timestamp.length === 0 ? new Date().toLocaleString() @@ -148,7 +146,7 @@ export const getComments: GetAssistantMessages = ({ timelineAvatar: isUser ? ( ) : ( - + ), timestamp: i18n.AT( message.timestamp.length === 0 diff --git a/x-pack/solutions/security/plugins/security_solution/public/assistant/header_link.tsx b/x-pack/solutions/security/plugins/security_solution/public/assistant/header_link.tsx index 342a95454cdb4..afbe0abd9fb01 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/assistant/header_link.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/assistant/header_link.tsx @@ -10,7 +10,7 @@ import React, { useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import { useAssistantContext } from '@kbn/elastic-assistant/impl/assistant_context'; -import { AssistantAvatar } from '@kbn/elastic-assistant'; +import { AssistantIcon } from '@kbn/ai-assistant-icon'; const isMac = navigator.platform.toLowerCase().indexOf('mac') >= 0; @@ -45,7 +45,7 @@ export const AssistantHeaderLink = () => { - + {LINK_LABEL} diff --git a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/attack_discovery_panel/title/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/attack_discovery_panel/title/index.tsx index 13326a07adc70..40e258f5c5116 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/attack_discovery_panel/title/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/attack_discovery_panel/title/index.tsx @@ -6,7 +6,6 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiSkeletonTitle, EuiTitle, useEuiTheme } from '@elastic/eui'; -import { AssistantAvatar } from '@kbn/elastic-assistant'; import { replaceAnonymizedValuesWithOriginalValues, type Replacements, @@ -14,6 +13,7 @@ import { import { css } from '@emotion/react'; import React, { useMemo } from 'react'; +import { AssistantIcon } from '@kbn/ai-assistant-icon'; const AVATAR_SIZE = 24; // px @@ -55,11 +55,11 @@ const TitleComponent: React.FC = ({ data-test-subj="assistantAvatar" grow={false} > - diff --git a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/attack_discovery_panel/view_in_ai_assistant/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/attack_discovery_panel/view_in_ai_assistant/index.tsx index e254ce5d334b8..3a10a9be9c8c6 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/attack_discovery_panel/view_in_ai_assistant/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/attack_discovery_panel/view_in_ai_assistant/index.tsx @@ -5,11 +5,11 @@ * 2.0. */ -import { AssistantAvatar } from '@kbn/elastic-assistant'; import type { AttackDiscovery, Replacements } from '@kbn/elastic-assistant-common'; import { EuiButton, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React from 'react'; +import { AssistantIcon } from '@kbn/ai-assistant-icon'; import * as i18n from './translations'; import { useViewInAiAssistant } from './use_view_in_ai_assistant'; @@ -48,7 +48,7 @@ const ViewInAiAssistantComponent: React.FC = ({ > - + {i18n.VIEW_IN_AI_ASSISTANT} diff --git a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/empty_states/empty_prompt/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/empty_states/empty_prompt/index.tsx index 3d89f5be87030..ecaf1753a3263 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/empty_states/empty_prompt/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/empty_states/empty_prompt/index.tsx @@ -5,7 +5,6 @@ * 2.0. */ -import { AssistantAvatar } from '@kbn/elastic-assistant'; import { EuiEmptyPrompt, EuiFlexGroup, @@ -19,6 +18,7 @@ import { import { css } from '@emotion/react'; import React, { useMemo } from 'react'; +import { AssistantBeacon } from '@kbn/ai-assistant-icon'; import { AnimatedCounter } from './animated_counter'; import { Generate } from '../generate'; import * as i18n from './translations'; @@ -50,7 +50,7 @@ const EmptyPromptComponent: React.FC = ({ gutterSize="none" > - + diff --git a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/empty_states/no_alerts/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/empty_states/no_alerts/index.tsx index ace75f568bf3d..216b7355fe486 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/empty_states/no_alerts/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/empty_states/no_alerts/index.tsx @@ -5,7 +5,6 @@ * 2.0. */ -import { AssistantAvatar } from '@kbn/elastic-assistant'; import { EuiEmptyPrompt, EuiFlexGroup, @@ -16,6 +15,7 @@ import { } from '@elastic/eui'; import React, { useMemo } from 'react'; +import { AssistantIcon } from '@kbn/ai-assistant-icon'; import * as i18n from './translations'; import { Generate } from '../generate'; @@ -35,7 +35,7 @@ const NoAlertsComponent: React.FC = ({ isDisabled, isLoading, onGenerate gutterSize="none" > - + diff --git a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/empty_states/welcome/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/empty_states/welcome/index.tsx index 7ab90b524bb93..f03727fc87dbe 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/empty_states/welcome/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/empty_states/welcome/index.tsx @@ -5,11 +5,11 @@ * 2.0. */ -import { AssistantAvatar } from '@kbn/elastic-assistant'; import { ConnectorSetup } from '@kbn/elastic-assistant/impl/connectorland/connector_setup'; import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText } from '@elastic/eui'; import React, { useMemo } from 'react'; +import { AssistantIcon } from '@kbn/ai-assistant-icon'; import * as i18n from './translations'; const WelcomeComponent: React.FC = () => { @@ -22,7 +22,7 @@ const WelcomeComponent: React.FC = () => { gutterSize="none" > - + diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/ml/score/create_description_list.tsx b/x-pack/solutions/security/plugins/security_solution/public/common/components/ml/score/create_description_list.tsx index 7ca8bf81ed06e..b197daff4d301 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/components/ml/score/create_description_list.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/common/components/ml/score/create_description_list.tsx @@ -11,7 +11,7 @@ import styled from 'styled-components'; import type { DescriptionList } from '../../../../../common/utility_types'; import type { Anomaly, NarrowDateRange } from '../types'; -import { getScoreString } from './score_health'; +import { getScoreString } from './get_score_string'; import { PreferenceFormattedDate } from '../../formatted_date'; import { createInfluencers } from '../influencers/create_influencers'; import * as i18n from './translations'; diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/ml/score/get_score_string.test.ts b/x-pack/solutions/security/plugins/security_solution/public/common/components/ml/score/get_score_string.test.ts index 1eeaa3521f030..87b2d092ada78 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/components/ml/score/get_score_string.test.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/common/components/ml/score/get_score_string.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { getScoreString } from './score_health'; +import { getScoreString } from './get_score_string'; describe('create_influencers', () => { test('it rounds up to 1 from 0.3', () => { diff --git a/x-pack/platform/plugins/shared/ml/public/application/styles.ts b/x-pack/solutions/security/plugins/security_solution/public/common/components/ml/score/get_score_string.ts similarity index 52% rename from x-pack/platform/plugins/shared/ml/public/application/styles.ts rename to x-pack/solutions/security/plugins/security_solution/public/common/components/ml/score/get_score_string.ts index 86f4dbe3bbcd4..d0edd52c68f1e 100644 --- a/x-pack/platform/plugins/shared/ml/public/application/styles.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/common/components/ml/score/get_score_string.ts @@ -5,13 +5,4 @@ * 2.0. */ -// Replacement for ./_variables.scss as we aim to remove the scss files - -export const mlColors = { - critical: '#FE5050', - major: '#FBA740', - minor: '#FDEC25', - warning: '#8BC8FB', - lowWarning: '#D2E9F7', - unknown: '#C0C0C0', -}; +export const getScoreString = (score: number) => String(Math.ceil(score)); diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/ml/score/score.tsx b/x-pack/solutions/security/plugins/security_solution/public/common/components/ml/score/score.tsx index 3c5030706da05..b4baad7b392c8 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/components/ml/score/score.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/common/components/ml/score/score.tsx @@ -13,7 +13,7 @@ import { } from '../../cell_actions'; import type { Anomaly } from '../types'; import { Spacer } from '../../page'; -import { getScoreString } from './score_health'; +import { getScoreString } from './get_score_string'; export const ScoreComponent = ({ index = 0, diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/ml/score/score_health.tsx b/x-pack/solutions/security/plugins/security_solution/public/common/components/ml/score/score_health.tsx deleted file mode 100644 index ac179b2ac8337..0000000000000 --- a/x-pack/solutions/security/plugins/security_solution/public/common/components/ml/score/score_health.tsx +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { EuiHealth } from '@elastic/eui'; - -interface Props { - score: number; -} - -export const getScoreString = (score: number) => String(Math.ceil(score)); - -export const ScoreHealth = React.memo(({ score }) => { - const scoreCeiling = getScoreString(score); - const color = getSeverityColor(score); - return {scoreCeiling}; -}); - -ScoreHealth.displayName = 'ScoreHealth'; - -// ಠ_ಠ A hard-fork of the @kbn/ml-anomaly-utils;#getSeverityColor ಠ_ಠ -// -// Returns a severity label (one of critical, major, minor, warning, low or unknown) -// for the supplied normalized anomaly score (a value between 0 and 100), where scores -// less than 3 are assigned a severity of 'low'. -export const getSeverityColor = (normalizedScore: number): string => { - if (normalizedScore >= 75) { - return '#fe5050'; - } else if (normalizedScore >= 50) { - return '#fba740'; - } else if (normalizedScore >= 25) { - return '#fdec25'; - } else if (normalizedScore >= 3) { - return '#8bc8fb'; - } else if (normalizedScore >= 0) { - return '#d2e9f7'; - } else { - return '#ffffff'; - } -}; diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/ai_assistant/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/ai_assistant/index.tsx index b0142b0e32f7e..8900e69254753 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/ai_assistant/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/ai_assistant/index.tsx @@ -9,8 +9,10 @@ import React, { useCallback } from 'react'; import { EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { NewChat, AssistantAvatar } from '@kbn/elastic-assistant'; +import { NewChat } from '@kbn/elastic-assistant'; +import { AssistantIcon } from '@kbn/ai-assistant-icon'; +import { css } from '@emotion/react'; import { METRIC_TYPE, TELEMETRY_EVENT, track } from '../../../../common/lib/telemetry'; import { useAssistantAvailability } from '../../../../assistant/use_assistant_availability'; import * as i18nAssistant from '../../../../detections/pages/detection_engine/translations'; @@ -116,7 +118,13 @@ Proposed solution should be valid and must not contain new line symbols (\\n)`; isAssistantEnabled={isAssistantEnabled} onExportCodeBlock={handleOnExportCodeBlock} > - {i18n.ASK_ASSISTANT_ERROR_BUTTON} + {' '} + {i18n.ASK_ASSISTANT_ERROR_BUTTON} ), }} diff --git a/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/helpers.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/helpers.test.tsx index 2599b10b93a48..c590bd12bddb1 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/helpers.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/helpers.test.tsx @@ -5,10 +5,8 @@ * 2.0. */ import type { Action, ActionExecutionContext } from '@kbn/ui-actions-plugin/public'; -import type { Embeddable } from '@kbn/embeddable-plugin/public'; import { createResetGroupByFieldAction, showInitialLoadingSpinner } from './helpers'; -import type { LensDataTableEmbeddable } from '../../../../common/components/visualization_actions/types'; describe('helpers', () => { describe('showInitialLoadingSpinner', () => { @@ -69,13 +67,13 @@ describe('createResetGroupByFieldAction', () => { }, }, }, - } as unknown as Embeddable), + }), updateInput: jest.fn(), }; const context = { embeddable, - } as unknown as ActionExecutionContext>; + } as unknown as ActionExecutionContext; const mockCallback = jest.fn(); beforeAll(async () => { action = createResetGroupByFieldAction({ callback: mockCallback }); diff --git a/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/helpers.tsx b/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/helpers.tsx index 8757316038b4a..0b928864053ad 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/helpers.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/helpers.tsx @@ -6,10 +6,14 @@ */ import type { Action, ActionExecutionContext } from '@kbn/ui-actions-plugin/public'; -import type { Embeddable } from '@kbn/embeddable-plugin/public'; import { RESET_GROUP_BY_FIELDS } from '../../../../common/components/chart_settings_popover/configurations/default/translations'; import type { LensDataTableEmbeddable } from '../../../../common/components/visualization_actions/types'; +interface LegacyLensEmbeddable { + getInput: () => LensDataTableEmbeddable; + updateInput: (input: LensDataTableEmbeddable) => void; +} + /** * Returns `true` when the alerts histogram initial loading spinner should be shown * @@ -48,7 +52,7 @@ export const createResetGroupByFieldAction: CreateResetGroupByFieldAction = ({ async execute({ embeddable, }: ActionExecutionContext<{ - embeddable: Embeddable; + embeddable: LegacyLensEmbeddable; }>): Promise { callback?.(); diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/insights/workflow_insights_scan.tsx b/x-pack/solutions/security/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/insights/workflow_insights_scan.tsx index 74b1147531a01..2bb37cb74b67c 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/insights/workflow_insights_scan.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/insights/workflow_insights_scan.tsx @@ -8,7 +8,6 @@ import React, { useCallback, useMemo } from 'react'; import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiPanel, EuiText } from '@elastic/eui'; import { - AssistantAvatar, DEFEND_INSIGHTS_STORAGE_KEY, ConnectorSelectorInline, DEFAULT_ASSISTANT_NAMESPACE, @@ -17,6 +16,7 @@ import { import { noop } from 'lodash/fp'; import useLocalStorage from 'react-use/lib/useLocalStorage'; import { some } from 'lodash'; +import { AssistantBeacon } from '@kbn/ai-assistant-icon'; import { useSpaceId } from '../../../../../../../common/hooks/use_space_id'; import { WORKFLOW_INSIGHTS } from '../../../translations'; import { useKibana } from '../../../../../../../common/lib/kibana'; @@ -106,7 +106,7 @@ export const WorkflowInsightsScanSection = ({ - + diff --git a/x-pack/solutions/security/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/index.ts b/x-pack/solutions/security/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/index.ts index 4850b1ee2d865..e1a8640249b39 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/index.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/index.ts @@ -6,7 +6,7 @@ */ import React from 'react'; -import { AssistantAvatar } from '@kbn/elastic-assistant'; +import { AssistantIcon } from '@kbn/ai-assistant-icon'; import type { OnboardingCardConfig } from '../../../../types'; import { OnboardingCardId } from '../../../../constants'; import { ASSISTANT_CARD_TITLE } from './translations'; @@ -16,7 +16,7 @@ import type { AssistantCardMetadata } from './types'; export const assistantCardConfig: OnboardingCardConfig = { id: OnboardingCardId.assistant, title: ASSISTANT_CARD_TITLE, - icon: AssistantAvatar, + icon: AssistantIcon, Component: React.lazy( () => import( diff --git a/x-pack/solutions/security/plugins/security_solution/public/onboarding/components/onboarding_body/cards/siem_migrations/ai_connector/index.ts b/x-pack/solutions/security/plugins/security_solution/public/onboarding/components/onboarding_body/cards/siem_migrations/ai_connector/index.ts index d0b32eb1bd638..9e8426df92ddc 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/onboarding/components/onboarding_body/cards/siem_migrations/ai_connector/index.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/onboarding/components/onboarding_body/cards/siem_migrations/ai_connector/index.ts @@ -6,7 +6,7 @@ */ import React from 'react'; -import { AssistantAvatar } from '@kbn/elastic-assistant/impl/assistant/assistant_avatar/assistant_avatar'; +import { AssistantIcon } from '@kbn/ai-assistant-icon'; import type { OnboardingCardConfig } from '../../../../../types'; import { OnboardingCardId } from '../../../../../constants'; import { AI_CONNECTOR_CARD_TITLE } from './translations'; @@ -16,7 +16,7 @@ import type { AIConnectorCardMetadata } from './types'; export const aiConnectorCardConfig: OnboardingCardConfig = { id: OnboardingCardId.siemMigrationsAiConnectors, title: AI_CONNECTOR_CARD_TITLE, - icon: AssistantAvatar, + icon: AssistantIcon, Component: React.lazy( () => import( diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rule_details_flyout/tabs/summary/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rule_details_flyout/tabs/summary/index.tsx index 8561eff458a26..ab5d9deb3852d 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rule_details_flyout/tabs/summary/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rule_details_flyout/tabs/summary/index.tsx @@ -7,9 +7,9 @@ import React, { useMemo } from 'react'; import type { EuiCommentProps } from '@elastic/eui'; -import { EuiAvatar, EuiCommentList, EuiMarkdownFormat, EuiSpacer } from '@elastic/eui'; +import { EuiCommentList, EuiMarkdownFormat, EuiSpacer } from '@elastic/eui'; import moment from 'moment'; -import { AssistantAvatar } from '@kbn/elastic-assistant'; +import { AssistantAvatar } from '@kbn/ai-assistant-icon'; import { RuleMigrationStatusEnum, type RuleMigration, @@ -31,9 +31,7 @@ export const SummaryTab: React.FC = React.memo(({ ruleMigration return { username: i18n.ASSISTANT_USERNAME, timelineAvatarAriaLabel: i18n.ASSISTANT_USERNAME, - timelineAvatar: ( - - ), + timelineAvatar: , event: ruleMigration.status === RuleMigrationStatusEnum.failed ? i18n.COMMENT_EVENT_FAILED diff --git a/x-pack/test/api_integration/apis/streams/helpers/requests.ts b/x-pack/test/api_integration/apis/streams/helpers/requests.ts index ae3a325b5f9b4..f26c53aaaf0aa 100644 --- a/x-pack/test/api_integration/apis/streams/helpers/requests.ts +++ b/x-pack/test/api_integration/apis/streams/helpers/requests.ts @@ -60,3 +60,15 @@ export async function deleteStream(supertest: Agent, id: string) { const response = await req.send().expect(200); return response.body; } + +export async function getUnmappedFieldsForStream(supertest: Agent, id: string) { + const req = supertest.get(`/api/streams/${id}/schema/unmapped_fields`).set('kbn-xsrf', 'xxx'); + const response = await req.send().expect(200); + return response.body; +} + +export async function simulateFieldsForStream(supertest: Agent, id: string, body: JsonObject) { + const req = supertest.post(`/api/streams/${id}/schema/fields_simulation`).set('kbn-xsrf', 'xxx'); + const response = await req.send(body).expect(200); + return response.body; +} diff --git a/x-pack/test/api_integration/apis/streams/index.ts b/x-pack/test/api_integration/apis/streams/index.ts index 14decb2400196..6c4cf358b8ac3 100644 --- a/x-pack/test/api_integration/apis/streams/index.ts +++ b/x-pack/test/api_integration/apis/streams/index.ts @@ -13,5 +13,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./enrichment')); loadTestFile(require.resolve('./classic')); loadTestFile(require.resolve('./flush_config')); + loadTestFile(require.resolve('./schema')); }); } diff --git a/x-pack/test/api_integration/apis/streams/schema.ts b/x-pack/test/api_integration/apis/streams/schema.ts new file mode 100644 index 0000000000000..c8b90e90939c1 --- /dev/null +++ b/x-pack/test/api_integration/apis/streams/schema.ts @@ -0,0 +1,98 @@ +/* + * 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 { + deleteStream, + enableStreams, + forkStream, + getUnmappedFieldsForStream, + indexDocument, + simulateFieldsForStream, +} from './helpers/requests'; +import { FtrProviderContext } from '../../ftr_provider_context'; +import { cleanUpRootStream } from './helpers/cleanup'; +import { waitForDocumentInIndex } from '../../../alerting_api_integration/observability/helpers/alerting_wait_for_helpers'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const esClient = getService('es'); + const retryService = getService('retry'); + const logger = getService('log'); + + describe('Streams Schema', () => { + after(async () => { + await deleteStream(supertest, 'logs.nginx'); + await cleanUpRootStream(esClient); + }); + + before(async () => { + await enableStreams(supertest); + + const doc = { + '@timestamp': '2024-01-01T00:00:10.000Z', + message: '2023-01-01T00:00:10.000Z error test', + ['some.field']: 'some value', + ['another.field']: 'another value', + lastField: 'last value', + ['log.level']: 'warning', + }; + + await indexDocument(esClient, 'logs', doc); + await waitForDocumentInIndex({ esClient, indexName: 'logs', retryService, logger }); + }); + + describe('Unmapped fields API', () => { + it('Returns unmapped fields', async () => { + const response = await getUnmappedFieldsForStream(supertest, 'logs'); + expect(response.unmappedFields).to.eql(['another.field', 'lastField', 'some.field']); + }); + }); + + describe('Fields simulation API', () => { + it('Returns failure status when simulation would fail', async () => { + const response = await simulateFieldsForStream(supertest, 'logs', { + field_definitions: [{ name: 'message', type: 'boolean' }], + }); + + expect(response.status).to.be('failure'); + expect(response.simulationError).to.be.a('string'); + expect(response.documentsWithRuntimeFieldsApplied).to.be(null); + }); + it('Returns success status when simulation would succeed', async () => { + const response = await simulateFieldsForStream(supertest, 'logs', { + field_definitions: [{ name: 'message', type: 'keyword' }], + }); + + expect(response.status).to.be('success'); + expect(response.simulationError).to.be(null); + expect(response.documentsWithRuntimeFieldsApplied).length(1); + }); + it('Returns unknown status when documents are missing and status cannot be determined', async () => { + const forkBody = { + stream: { + name: 'logs.nginx', + }, + condition: { + field: 'log.logger', + operator: 'eq', + value: 'nginx', + }, + }; + + await forkStream(supertest, 'logs', forkBody); + const response = await simulateFieldsForStream(supertest, 'logs.nginx', { + field_definitions: [{ name: 'message', type: 'keyword' }], + }); + + expect(response.status).to.be('unknown'); + expect(response.simulationError).to.be(null); + expect(response.documentsWithRuntimeFieldsApplied).to.be(null); + }); + }); + }); +} diff --git a/x-pack/test/functional/services/ml/anomaly_charts.ts b/x-pack/test/functional/services/ml/anomaly_charts.ts index 50c639094408e..8f63c8cf3710a 100644 --- a/x-pack/test/functional/services/ml/anomaly_charts.ts +++ b/x-pack/test/functional/services/ml/anomaly_charts.ts @@ -31,7 +31,7 @@ export function AnomalyChartsProvider({ getService }: FtrProviderContext) { ? await testSubjects.find(chartsContainerSubj) : await testSubjects.find('mlExplorerChartsContainer'); const actualChartsCount = ( - await chartsContainer?.findAllByClassName('ml-explorer-chart-container', 3000) + await chartsContainer?.findAllByTestSubject('mlExplorerChartContainerItem', 3000) ).length; expect(actualChartsCount).to.eql( expectedChartsCount,