Skip to content

Commit

Permalink
[8.x] [Security Solution] Display readonly placeholders when field va…
Browse files Browse the repository at this point in the history
…lue is empty (#203826) (#204279)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[Security Solution] Display readonly placeholders when field value is
empty (#203826)](#203826)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Nikita
Indik","email":"nikita.indik@elastic.co"},"sourceCommit":{"committedDate":"2024-12-13T20:06:40Z","message":"[Security
Solution] Display readonly placeholders when field value is empty
(#203826)\n\n**Partially addresses:
https://github.com/elastic/kibana/issues/171520**\r\n\r\n##
Summary\r\nThis PR updates readonly components of the Rule Upgrade
flyout to\r\ndisplay placeholders in cases when a field value is
empty.\r\n\r\n## Changes\r\n - Added placeholders to readonly components
in the Rule Upgrade flyout\r\n- Simplified Storybook stories to make
them more readable and less\r\ndependent on flyout context\r\n- Added
stories that showcase empty states. You can run Storybook with\r\n`yarn
storybook security_solution`.\r\n\r\n## Screenshots\r\n**Before /
After**\r\n<img width=\"2560\" alt=\"Scherm­afbeelding 2024-12-12 om 00
05
56\"\r\nsrc=\"https://github.com/user-attachments/assets/e85a4514-4861-4be7-b0d2-534f7ad2d8cf\"\r\n/>\r\n\r\nWork
started on
11-Dec-2024","sha":"27fe7e49e53807597ab47aca7ecfe40ac8d6e5fd","branchLabelMapping":{"^v9.0.0$":"main","^v8.18.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:Detections
and Resp","Team: SecuritySolution","Team:Detection Rule
Management","Feature:Prebuilt Detection
Rules","backport:version","v8.18.0"],"title":"[Security Solution]
Display readonly placeholders when field value is
empty","number":203826,"url":"https://github.com/elastic/kibana/pull/203826","mergeCommit":{"message":"[Security
Solution] Display readonly placeholders when field value is empty
(#203826)\n\n**Partially addresses:
https://github.com/elastic/kibana/issues/171520**\r\n\r\n##
Summary\r\nThis PR updates readonly components of the Rule Upgrade
flyout to\r\ndisplay placeholders in cases when a field value is
empty.\r\n\r\n## Changes\r\n - Added placeholders to readonly components
in the Rule Upgrade flyout\r\n- Simplified Storybook stories to make
them more readable and less\r\ndependent on flyout context\r\n- Added
stories that showcase empty states. You can run Storybook with\r\n`yarn
storybook security_solution`.\r\n\r\n## Screenshots\r\n**Before /
After**\r\n<img width=\"2560\" alt=\"Scherm­afbeelding 2024-12-12 om 00
05
56\"\r\nsrc=\"https://github.com/user-attachments/assets/e85a4514-4861-4be7-b0d2-534f7ad2d8cf\"\r\n/>\r\n\r\nWork
started on
11-Dec-2024","sha":"27fe7e49e53807597ab47aca7ecfe40ac8d6e5fd"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/203826","number":203826,"mergeCommit":{"message":"[Security
Solution] Display readonly placeholders when field value is empty
(#203826)\n\n**Partially addresses:
https://github.com/elastic/kibana/issues/171520**\r\n\r\n##
Summary\r\nThis PR updates readonly components of the Rule Upgrade
flyout to\r\ndisplay placeholders in cases when a field value is
empty.\r\n\r\n## Changes\r\n - Added placeholders to readonly components
in the Rule Upgrade flyout\r\n- Simplified Storybook stories to make
them more readable and less\r\ndependent on flyout context\r\n- Added
stories that showcase empty states. You can run Storybook with\r\n`yarn
storybook security_solution`.\r\n\r\n## Screenshots\r\n**Before /
After**\r\n<img width=\"2560\" alt=\"Scherm­afbeelding 2024-12-12 om 00
05
56\"\r\nsrc=\"https://github.com/user-attachments/assets/e85a4514-4861-4be7-b0d2-534f7ad2d8cf\"\r\n/>\r\n\r\nWork
started on
11-Dec-2024","sha":"27fe7e49e53807597ab47aca7ecfe40ac8d6e5fd"}},{"branch":"8.x","label":"v8.18.0","branchLabelMappingKey":"^v8.18.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Nikita Indik <nikita.indik@elastic.co>
  • Loading branch information
kibanamachine and nikitaindik authored Dec 13, 2024
1 parent 12ecdde commit 4ffca46
Show file tree
Hide file tree
Showing 65 changed files with 568 additions and 1,236 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39211,7 +39211,6 @@
"xpack.securitySolution.detectionEngine.rules.updatePrebuiltRulesCalloutTitle": "Mises à jour disponibles pour les règles installées. Examinez et mettez à jour dans {link}.",
"xpack.securitySolution.detectionEngine.rules.updatePrePackagedRulesAndTimelinesButton": "Mettez à jour {updateRules} {updateRules, plural, =1 {règle prédéfinie} other {règles prédéfinies}} d'Elastic et {updateTimelines} {updateTimelines, plural, =1 {chronologie prédéfinie} other {chronologies prédéfinies}} d'Elastic",
"xpack.securitySolution.detectionEngine.rules.updatePrePackagedTimelinesButton": "Mettez à jour {updateTimelines} {updateTimelines, plural, =1 {chronologie prédéfinie} other {chronologies prédéfinies}} d'Elastic",
"xpack.securitySolution.detectionEngine.rules.upgradeRuleFields.dataSourceLabel": "Source de données",
"xpack.securitySolution.detectionEngine.rules.upgradeRuleFields.eqlQueryLabel": "Requête EQL",
"xpack.securitySolution.detectionEngine.rules.upgradeRuleFields.esqlQueryLabel": "Requête ESQL",
"xpack.securitySolution.detectionEngine.rules.upgradeRuleFields.kqlQueryLabel": "Requête KQL",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39067,7 +39067,6 @@
"xpack.securitySolution.detectionEngine.rules.updatePrebuiltRulesCalloutTitle": "インストールされたルールの更新が利用可能です。{link}で確認して更新してください。",
"xpack.securitySolution.detectionEngine.rules.updatePrePackagedRulesAndTimelinesButton": "{updateRules} Elasticの事前構築済みの{updateRules, plural, other {個のルール}}と{updateTimelines} Elasticの事前構築済みの{updateTimelines, plural, other {個のタイムライン}}を更新",
"xpack.securitySolution.detectionEngine.rules.updatePrePackagedTimelinesButton": "{updateTimelines} Elastic事前構築済み{updateTimelines, plural, other {タイムライン}}を更新",
"xpack.securitySolution.detectionEngine.rules.upgradeRuleFields.dataSourceLabel": "データソース",
"xpack.securitySolution.detectionEngine.rules.upgradeRuleFields.eqlQueryLabel": "EQL クエリ",
"xpack.securitySolution.detectionEngine.rules.upgradeRuleFields.esqlQueryLabel": "EQLクエリ",
"xpack.securitySolution.detectionEngine.rules.upgradeRuleFields.kqlQueryLabel": "KQLクエリ",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39158,7 +39158,6 @@
"xpack.securitySolution.detectionEngine.rules.updatePrebuiltRulesCalloutTitle": "已安装规则有可用更新。在 {link} 中复查并更新。",
"xpack.securitySolution.detectionEngine.rules.updatePrePackagedRulesAndTimelinesButton": "更新 {updateRules} 个 Elastic 预构建{updateRules, plural, other {规则}}及 {updateTimelines} 个 Elastic 预构建{updateTimelines, plural, other {时间线}}",
"xpack.securitySolution.detectionEngine.rules.updatePrePackagedTimelinesButton": "更新 {updateTimelines} 个 Elastic 预构建{updateTimelines, plural, other {时间线}}",
"xpack.securitySolution.detectionEngine.rules.upgradeRuleFields.dataSourceLabel": "数据源",
"xpack.securitySolution.detectionEngine.rules.upgradeRuleFields.eqlQueryLabel": "EQL 查询",
"xpack.securitySolution.detectionEngine.rules.upgradeRuleFields.esqlQueryLabel": "ESQL 查询",
"xpack.securitySolution.detectionEngine.rules.upgradeRuleFields.kqlQueryLabel": "KQL 查询",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,17 @@ import {
THREAT_INDEX_FIELD_LABEL,
THREAT_MAPPING_FIELD_LABEL,
HISTORY_WINDOW_SIZE_FIELD_LABEL,
DATA_SOURCE_FIELD_LABEL,
ALERT_SUPPRESSION_FIELD_LABEL,
INVESTIGATION_FIELDS_FIELD_LABEL,
} from '../translations';

/**
* Used when fields have different display names or formats than their corresponding rule object fields
*/
export const fieldToDisplayNameMap: Record<string, string> = {
data_source: i18n.translate(
'xpack.securitySolution.detectionEngine.rules.upgradeRuleFields.dataSourceLabel',
{
defaultMessage: 'Data source',
}
),
alert_suppression: ALERT_SUPPRESSION_FIELD_LABEL,
data_source: DATA_SOURCE_FIELD_LABEL,
note: i18n.translate('xpack.securitySolution.detectionEngine.rules.upgradeRuleFields.noteLabel', {
defaultMessage: 'Investigation guide',
}),
Expand All @@ -39,6 +38,7 @@ export const fieldToDisplayNameMap: Record<string, string> = {
references: REFERENCES_FIELD_LABEL,
threat_indicator_path: THREAT_INDICATOR_PATH_LABEL,
index_patterns: INDEX_FIELD_LABEL,
investigation_fields: INVESTIGATION_FIELDS_FIELD_LABEL,
data_view_id: DATA_VIEW_ID_FIELD_LABEL,
threat: THREAT_FIELD_LABEL,
eql_query: i18n.translate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ import type {
} from '@kbn/securitysolution-io-ts-alerting-types';
import { ALERT_RISK_SCORE } from '@kbn/rule-data-utils';
import { requiredOptional } from '@kbn/zod-helpers';
import type { RuleResponse } from '../../../../../common/api/detection_engine/model/rule_schema';
import type {
BuildingBlockType,
RuleResponse,
} from '../../../../../common/api/detection_engine/model/rule_schema';
import { SeverityBadge } from '../../../../common/components/severity_badge';
import { defaultToEmptyTag } from '../../../../common/components/empty_value';
import { filterEmptyThreats } from '../../../rule_creation_ui/pages/rule_creation/helpers';
Expand Down Expand Up @@ -76,9 +79,15 @@ export const Author = ({ author }: AuthorProps) => (
<BadgeList badges={author} data-test-subj="authorPropertyValue" />
);

export const BuildingBlock = () => (
interface BuildingBlockProps {
type: BuildingBlockType | undefined;
}

export const BuildingBlock = ({ type }: BuildingBlockProps) => (
<EuiText size="s" data-test-subj="buildingBlockPropertyValue">
{i18n.BUILDING_BLOCK_FIELD_DESCRIPTION}
{type
? i18n.BUILDING_BLOCK_ENABLED_FIELD_DESCRIPTION
: i18n.BUILDING_BLOCK_DISABLED_FIELD_DESCRIPTION}
</EuiText>
);

Expand Down Expand Up @@ -294,7 +303,7 @@ const prepareAboutSectionListItems = (
title: (
<span data-test-subj="buildingBlockPropertyTitle">{i18n.BUILDING_BLOCK_FIELD_LABEL}</span>
),
description: <BuildingBlock />,
description: <BuildingBlock type="default" />,
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import { EuiText } from '@elastic/eui';
import * as i18n from './translations';

export function EmptyFieldValuePlaceholder() {
return (
<EuiText size="s" color="subdued">
{`<${i18n.EMPTY_FIELD_VALUE_PLACEHOLDER}>`}
</EuiText>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* 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 { EmptyFieldValuePlaceholder } from './empty_field_value_placeholder';
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { i18n } from '@kbn/i18n';

export const EMPTY_FIELD_VALUE_PLACEHOLDER = i18n.translate(
'xpack.securitySolution.detectionEngine.rules.upgradeRules.emptyFieldValuePlaceholder',
{
defaultMessage: 'Field value is empty',
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@
*/

import React from 'react';
import type { Story } from '@storybook/react';
import { AlertSuppressionReadOnly } from './alert_suppression';
import { FieldFinalReadOnly } from '../../field_final_readonly';
import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine';
import { mockCustomQueryRule } from '../../storybook/mocks';
import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers';

export default {
Expand All @@ -19,29 +15,28 @@ export default {
'Rule Management/Prebuilt Rules/Upgrade Flyout/ThreeWayDiff/FieldReadOnly/alert_suppression',
};

interface TemplateProps {
finalDiffableRule: DiffableRule;
}
export const OtherRuleTypes = () => (
<ThreeWayDiffStorybookProviders>
<AlertSuppressionReadOnly
ruleType="query"
alertSuppression={{
group_by: ['host.name'],
duration: { value: 5, unit: 'm' },
missing_fields_strategy: 'suppress',
}}
/>
</ThreeWayDiffStorybookProviders>
);

const Template: Story<TemplateProps> = (args) => {
return (
<ThreeWayDiffStorybookProviders
finalDiffableRule={args.finalDiffableRule}
fieldName="alert_suppression"
>
<FieldFinalReadOnly />
</ThreeWayDiffStorybookProviders>
);
};

export const Default = Template.bind({});
export const Threshold = () => (
<ThreeWayDiffStorybookProviders>
<AlertSuppressionReadOnly
ruleType="threshold"
alertSuppression={{
duration: { value: 5, unit: 'm' },
}}
/>
</ThreeWayDiffStorybookProviders>
);

Default.args = {
finalDiffableRule: mockCustomQueryRule({
alert_suppression: {
group_by: ['host.name'],
duration: { value: 5, unit: 'm' },
missing_fields_strategy: 'suppress',
},
}),
};
export const EmptyValue = () => <AlertSuppressionReadOnly ruleType="query" />;
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
SuppressAlertsByField,
SuppressAlertsDuration,
} from '../../../../rule_definition_section';
import { EmptyFieldValuePlaceholder } from '../../empty_field_value_placeholder';

interface AlertSuppressionReadOnlyProps {
alertSuppression?: AlertSuppression | ThresholdAlertSuppression;
Expand All @@ -30,7 +31,16 @@ export function AlertSuppressionReadOnly({
ruleType,
}: AlertSuppressionReadOnlyProps) {
if (!alertSuppression) {
return null;
return (
<EuiDescriptionList
listItems={[
{
title: ruleDetailsI18n.ALERT_SUPPRESSION_FIELD_LABEL,
description: <EmptyFieldValuePlaceholder />,
},
]}
/>
);
}

const listItems = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,12 @@
*/

import React from 'react';
import type { Story } from '@storybook/react';
import { AnomalyThresholdReadOnly } from './anomaly_threshold';
import { FieldFinalReadOnly } from '../../field_final_readonly';
import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine';
import { mockMachineLearningRule } from '../../storybook/mocks';
import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers';

export default {
component: AnomalyThresholdReadOnly,
title:
'Rule Management/Prebuilt Rules/Upgrade Flyout/ThreeWayDiff/FieldReadOnly/anomaly_threshold',
};

interface TemplateProps {
finalDiffableRule: DiffableRule;
}

const Template: Story<TemplateProps> = (args) => {
return (
<ThreeWayDiffStorybookProviders
finalDiffableRule={args.finalDiffableRule}
fieldName="anomaly_threshold"
>
<FieldFinalReadOnly />
</ThreeWayDiffStorybookProviders>
);
};

export const Default = Template.bind({});

Default.args = {
finalDiffableRule: mockMachineLearningRule({
anomaly_threshold: 50,
}),
};
export const Default = () => <AnomalyThresholdReadOnly anomalyThreshold={50} />;
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,13 @@
*/

import React from 'react';
import type { Story } from '@storybook/react';
import { BuildingBlockReadOnly } from './building_block';
import { FieldFinalReadOnly } from '../../field_final_readonly';
import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine';
import { mockCustomQueryRule } from '../../storybook/mocks';
import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers';

export default {
component: BuildingBlockReadOnly,
title: 'Rule Management/Prebuilt Rules/Upgrade Flyout/ThreeWayDiff/FieldReadOnly/building_block',
};

interface TemplateProps {
finalDiffableRule: DiffableRule;
}
export const Default = () => <BuildingBlockReadOnly buildingBlock={{ type: 'default' }} />;

const Template: Story<TemplateProps> = (args) => {
return (
<ThreeWayDiffStorybookProviders
finalDiffableRule={args.finalDiffableRule}
fieldName="building_block"
>
<FieldFinalReadOnly />
</ThreeWayDiffStorybookProviders>
);
};

export const Default = Template.bind({});

Default.args = {
finalDiffableRule: mockCustomQueryRule({
building_block: {
type: 'default',
},
}),
};
export const NoValue = () => <BuildingBlockReadOnly />;
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,12 @@ interface BuildingBlockReadOnlyProps {
}

export function BuildingBlockReadOnly({ buildingBlock }: BuildingBlockReadOnlyProps) {
if (!buildingBlock || !buildingBlock.type) {
return null;
}

return (
<EuiDescriptionList
listItems={[
{
title: ruleDetailsI18n.BUILDING_BLOCK_FIELD_LABEL,
description: <BuildingBlock />,
description: <BuildingBlock type={buildingBlock?.type} />,
},
]}
/>
Expand Down
Loading

0 comments on commit 4ffca46

Please sign in to comment.