[Entity Analytics][Entity Store] Fix error callout placement on engine status page (#216228)

## Summary

The error callouts were getting squished to the side, I have moved them
to be in their respective engine section.

**Before**

<img width="1728" alt="Screenshot 2025-03-27 at 11 05 38"
src="https://github.com/user-attachments/assets/c244acd1-a75e-4b43-a509-8bff9966b31e"
/>


**After**
<img width="1728" alt="Screenshot 2025-03-27 at 19 39 53"
src="https://github.com/user-attachments/assets/2b0dd9ad-568a-4e9c-aad7-6922b2085d69"
/>

Bonus refactor:

I have added type definitions for the error object keys on the engine
status object and moved the error callout to a common component as it's
now used in 3 places.


## Test Steps

the easies way to test this is to try and init the entity store in a
space that is lobger than 45 chars long.

- create a space with a very long name e.g
'this_is_a_very_long_space_name_indeed_hello_world_123456789'
- enable the entity store from the entity analytics dashboard (it should
error)
- navigate to the entity store management page to see the error
callouts.

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Mark Hopkin 2025-04-02 15:29:24 +01:00 committed by GitHub
parent 58508856be
commit 5bfa0564ae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 102 additions and 51 deletions

View file

@ -59006,6 +59006,16 @@ components:
type: integer
error:
type: object
properties:
action:
enum:
- init
type: string
message:
type: string
required:
- message
- action
fieldHistoryLength:
type: integer
filter:

View file

@ -67888,6 +67888,16 @@ components:
type: integer
error:
type: object
properties:
action:
enum:
- init
type: string
message:
type: string
required:
- message
- action
fieldHistoryLength:
type: integer
filter:

View file

@ -39109,7 +39109,6 @@
"xpack.securitySolution.entityAnalytics.entityStore.enablement.description.risk": "Assure une visibilité en temps réel sur l'activité des utilisateurs, vous aidant ainsi à identifier et à atténuer les risques de sécurité potentiels.",
"xpack.securitySolution.entityAnalytics.entityStore.enablement.description.store": "Stockez les données pour les entités observées dans les événements.",
"xpack.securitySolution.entityAnalytics.entityStore.enablement.enableButton": "Activer",
"xpack.securitySolution.entityAnalytics.entityStore.enablement.errors.title": "Une erreur s'est produite lors de l'initialisation des ressources du magasin d'entités",
"xpack.securitySolution.entityAnalytics.entityStore.enablement.initializing.description": "Cela peut prendre jusqu'à 5 minutes.",
"xpack.securitySolution.entityAnalytics.entityStore.enablement.initializing.risk": "Initialisation du moteur de risque",
"xpack.securitySolution.entityAnalytics.entityStore.enablement.initializing.store": "Initialisation du stockage d'entités",
@ -39155,7 +39154,6 @@
"xpack.securitySolution.entityAnalytics.entityStoreManagementPage.engineStatus.tabTitle": "Statut du moteur",
"xpack.securitySolution.entityAnalytics.entityStoreManagementPage.errors.deleteErrorTitle": "Une erreur est survenue lors de la suppression du magasin dentités",
"xpack.securitySolution.entityAnalytics.entityStoreManagementPage.errors.initErrorTitle": "Un problème est survenu lors de l'initialisation du magasin d'entités",
"xpack.securitySolution.entityAnalytics.entityStoreManagementPage.errors.title": "Une erreur s'est produite lors de l'initialisation des ressources du magasin d'entités",
"xpack.securitySolution.entityAnalytics.entityStoreManagementPage.featureFlagDisabled": "Les fonctionnalités du stockage d'entités ne sont pas disponibles",
"xpack.securitySolution.entityAnalytics.entityStoreManagementPage.importEntities.tabTitle": "Importer des entités",
"xpack.securitySolution.entityAnalytics.entityStoreManagementPage.subTitle": "Stockez les données pour les entités observées dans les événements.",

View file

@ -39079,7 +39079,6 @@
"xpack.securitySolution.entityAnalytics.entityStore.enablement.description.risk": "ユーザーのアクティビティをリアルタイムで可視化し、潜在的なセキュリティリスクを特定して軽減するのに役立ちます。",
"xpack.securitySolution.entityAnalytics.entityStore.enablement.description.store": "イベントで観測されたエンティティのデータを保存します。",
"xpack.securitySolution.entityAnalytics.entityStore.enablement.enableButton": "有効にする",
"xpack.securitySolution.entityAnalytics.entityStore.enablement.errors.title": "エンティティリソース初期化中にエラーが発生しました",
"xpack.securitySolution.entityAnalytics.entityStore.enablement.initializing.description": "これには最大で5分間かかる場合があります。",
"xpack.securitySolution.entityAnalytics.entityStore.enablement.initializing.risk": "リスクエンジンを初期化中",
"xpack.securitySolution.entityAnalytics.entityStore.enablement.initializing.store": "エンティティスコアを初期化中",
@ -39125,7 +39124,6 @@
"xpack.securitySolution.entityAnalytics.entityStoreManagementPage.engineStatus.tabTitle": "エンジンステータス",
"xpack.securitySolution.entityAnalytics.entityStoreManagementPage.errors.deleteErrorTitle": "エンティティストアの削除中に問題が発生しました",
"xpack.securitySolution.entityAnalytics.entityStoreManagementPage.errors.initErrorTitle": "エンティティストアの初期化中に問題が発生しました",
"xpack.securitySolution.entityAnalytics.entityStoreManagementPage.errors.title": "エンティティリソース初期化中にエラーが発生しました",
"xpack.securitySolution.entityAnalytics.entityStoreManagementPage.featureFlagDisabled": "エンティティストア機能を利用できません",
"xpack.securitySolution.entityAnalytics.entityStoreManagementPage.importEntities.tabTitle": "エンティティをインポート",
"xpack.securitySolution.entityAnalytics.entityStoreManagementPage.subTitle": "イベントで観測されたエンティティのデータを保存します。",

View file

@ -39144,7 +39144,6 @@
"xpack.securitySolution.entityAnalytics.entityStore.enablement.description.risk": "提供有关用户活动的实时可见性,帮助您识别并缓解潜在的安全风险。",
"xpack.securitySolution.entityAnalytics.entityStore.enablement.description.store": "存储在事件中观察到的实体的数据。",
"xpack.securitySolution.entityAnalytics.entityStore.enablement.enableButton": "启用",
"xpack.securitySolution.entityAnalytics.entityStore.enablement.errors.title": "实体仓库资源初始化期间出错",
"xpack.securitySolution.entityAnalytics.entityStore.enablement.initializing.description": "这最多可能需要 5 分钟。",
"xpack.securitySolution.entityAnalytics.entityStore.enablement.initializing.risk": "正在初始化风险引擎",
"xpack.securitySolution.entityAnalytics.entityStore.enablement.initializing.store": "正在初始化实体仓库",
@ -39190,7 +39189,6 @@
"xpack.securitySolution.entityAnalytics.entityStoreManagementPage.engineStatus.tabTitle": "引擎状态",
"xpack.securitySolution.entityAnalytics.entityStoreManagementPage.errors.deleteErrorTitle": "删除实体仓库时出现问题",
"xpack.securitySolution.entityAnalytics.entityStoreManagementPage.errors.initErrorTitle": "初始化实体仓库时出现问题",
"xpack.securitySolution.entityAnalytics.entityStoreManagementPage.errors.title": "实体仓库资源初始化期间出错",
"xpack.securitySolution.entityAnalytics.entityStoreManagementPage.featureFlagDisabled": "实体仓库功能不可用",
"xpack.securitySolution.entityAnalytics.entityStoreManagementPage.importEntities.tabTitle": "导入实体",
"xpack.securitySolution.entityAnalytics.entityStoreManagementPage.subTitle": "存储在事件中观察到的实体的数据。",

View file

@ -58,7 +58,12 @@ export const EngineDescriptor = z.object({
.optional()
.default('1m'),
docsPerSecond: z.number().int().optional(),
error: z.object({}).optional(),
error: z
.object({
message: z.string(),
action: z.literal('init'),
})
.optional(),
});
export type TransformStatsMetadata = z.infer<typeof TransformStatsMetadata>;

View file

@ -53,6 +53,16 @@ components:
type: integer
error:
type: object
required:
- message
- action
properties:
message:
type: string
action:
type: string
enum:
- init
EngineStatus:
type: string

View file

@ -1094,6 +1094,16 @@ components:
type: integer
error:
type: object
properties:
action:
enum:
- init
type: string
message:
type: string
required:
- message
- action
fieldHistoryLength:
type: integer
filter:

View file

@ -1094,6 +1094,16 @@ components:
type: integer
error:
type: object
properties:
action:
enum:
- init
type: string
message:
type: string
required:
- message
- action
fieldHistoryLength:
type: integer
filter:

View file

@ -11,10 +11,7 @@ import {
EuiFlexItem,
EuiFlexGroup,
EuiPanel,
EuiCallOut,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { useStoreEntityTypes } from '../../../hooks/use_enabled_entity_types';
import { RiskEngineStatusEnum } from '../../../../../common/api/entity_analytics';
import { EntitiesList } from '../entities_list';
@ -23,6 +20,7 @@ import { EntityAnalyticsRiskScores } from '../../entity_analytics_risk_score';
import { useRiskEngineStatus } from '../../../api/hooks/use_risk_engine_status';
import { EnablementPanel } from './dashboard_enablement_panel';
import { EntityStoreErrorCallout } from './entity_store_error_callout';
const EntityStoreDashboardPanelsComponent = () => {
const riskEngineStatus = useRiskEngineStatus();
@ -31,25 +29,7 @@ const EntityStoreDashboardPanelsComponent = () => {
const callouts = (storeStatusQuery.data?.engines ?? [])
.filter((engine) => engine.status === 'error')
.map((engine) => {
const err = engine.error as {
message: string;
};
return (
<EuiCallOut
title={
<FormattedMessage
id="xpack.securitySolution.entityAnalytics.entityStore.enablement.errors.title"
defaultMessage={'An error occurred during entity store resource initialization'}
/>
}
color="danger"
iconType="error"
>
<p>{err?.message}</p>
</EuiCallOut>
);
});
.map((engine) => <EntityStoreErrorCallout engine={engine} />);
if (storeStatusQuery.status === 'loading') {
return (

View file

@ -25,6 +25,7 @@ import { useEntityStoreStatus } from '../../hooks/use_entity_store';
import { isEngineLoading } from './helpers';
import { EngineStatusHeader } from './components/engine_status_header';
import { EngineStatusHeaderAction } from './components/engine_status_header_action';
import { EntityStoreErrorCallout } from '../entity_store_error_callout';
const FILE_NAME = 'engines_status.json';
@ -93,6 +94,7 @@ export const EngineStatus: React.FC = () => {
entityType={type}
actionButton={<EngineStatusHeaderAction engine={engine} type={type} />}
/>
<EntityStoreErrorCallout engine={engine} size="s" />
<EuiSpacer size="s" />
<EuiPanel hasShadow={false} hasBorder={false}>
{engine && !isEngineLoading(engine.status) && engine.components && (

View file

@ -0,0 +1,39 @@
/*
* 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 { EuiCallOut } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import type { EngineDescriptor } from '../../../../../common/api/entity_analytics/entity_store';
export const EntityStoreErrorCallout: React.FC<{ engine?: EngineDescriptor; size?: 's' | 'm' }> = ({
engine,
size = 'm',
}) => {
if (!engine?.error?.message) {
return null;
}
let title;
// Please update the following code when adding a new action type
switch (engine.error.action) {
case 'init':
title = (
<FormattedMessage
id="xpack.securitySolution.entityAnalytics.entityStore.initError.title"
defaultMessage="An error occurred during {engineType} entity store resource initialization"
values={{ engineType: engine.type }}
/>
);
break;
}
return (
<EuiCallOut title={title} color="danger" iconType="alert" size={size}>
<p>{engine.error.message}</p>
</EuiCallOut>
);
};

View file

@ -50,6 +50,7 @@ import { useEntityEnginePrivileges } from '../components/entity_store/hooks/use_
import { MissingPrivilegesCallout } from '../components/entity_store/components/missing_privileges_callout';
import { EngineStatus } from '../components/entity_store/components/engines_status';
import { useStoreEntityTypes } from '../hooks/use_enabled_entity_types';
import { EntityStoreErrorCallout } from '../components/entity_store/components/entity_store_error_callout';
enum TabId {
Import = 'import',
@ -130,26 +131,7 @@ export const EntityStoreManagementPage = () => {
const callouts = (entityStoreStatus.data?.engines || [])
.filter((engine) => engine.status === 'error')
.map((engine) => {
const err = engine.error as {
message: string;
};
return (
<EuiCallOut
title={
<FormattedMessage
id="xpack.securitySolution.entityAnalytics.entityStoreManagementPage.errors.title"
defaultMessage={'An error occurred during entity store resource initialization'}
/>
}
color="danger"
iconType="alert"
>
<p>{err?.message}</p>
</EuiCallOut>
);
});
.map((engine) => <EntityStoreErrorCallout engine={engine} />);
return (
<>
@ -266,7 +248,7 @@ export const EntityStoreManagementPage = () => {
</p>
</EuiCallOut>
)}
{callouts}
{selectedTabId === TabId.Import && callouts}
{selectedTabId === TabId.Import && <WhatIsAssetCriticalityPanel />}
</EuiFlexGroup>
</EuiFlexItem>

View file

@ -498,7 +498,6 @@ export class EntityStoreDataClient {
status: ENGINE_STATUS.ERROR,
error: {
message: err.message,
stack: err.stack,
action: 'init',
},
});