Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Security Solution] New Data Quality dashboard Same family category #167480

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ describe('getCommonTableColumns', () => {
);
});

test('it renders the expected type as a warning', () => {
expect(screen.getByTestId('codeWarning')).toHaveTextContent(indexFieldType);
test('it renders the index field with a "success" style', () => {
expect(screen.getByTestId('codeSuccess')).toHaveTextContent(indexFieldType);
});

test('it renders the same family badge', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import React from 'react';

import { SameFamily } from '../../data_quality_panel/same_family';
import { EcsAllowedValues } from '../ecs_allowed_values';
import { getIsInSameFamily } from '../../helpers';
import { IndexInvalidValues } from '../index_invalid_values';
import { CodeDanger, CodeSuccess, CodeWarning } from '../../styles';
import { CodeDanger, CodeSuccess } from '../../styles';
import * as i18n from '../translations';
import type { AllowedValue, EnrichedFieldMetadata, UnallowedValueCount } from '../../types';

Expand Down Expand Up @@ -45,9 +46,9 @@ export const getCommonTableColumns = (): Array<
name: i18n.INDEX_MAPPING_TYPE_ACTUAL,
render: (_, x) =>
x.type != null && x.indexFieldType !== x.type ? (
x.isInSameFamily ? (
getIsInSameFamily({ ecsExpectedType: x.type, type: x.indexFieldType }) ? (
<div>
<CodeWarning data-test-subj="codeWarning">{x.indexFieldType}</CodeWarning>
<CodeSuccess data-test-subj="codeSuccess">{x.indexFieldType}</CodeSuccess>
<SameFamily />
</div>
) : (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ describe('getIncompatibleMappingsTableColumns', () => {
);
});

test('it renders the expected type as a warning', () => {
expect(screen.getByTestId('codeWarning')).toHaveTextContent(indexFieldType);
test('it renders the expected type with a "success" style', () => {
expect(screen.getByTestId('codeSuccess')).toHaveTextContent(indexFieldType);
});

test('it renders the same family badge', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type { EuiTableFieldDataColumnType } from '@elastic/eui';
import React from 'react';

import { SameFamily } from '../../data_quality_panel/same_family';
import { CodeDanger, CodeSuccess, CodeWarning } from '../../styles';
import { CodeDanger, CodeSuccess } from '../../styles';
import * as i18n from '../translations';
import type { EnrichedFieldMetadata } from '../../types';

Expand Down Expand Up @@ -43,7 +43,7 @@ export const getIncompatibleMappingsTableColumns = (): Array<
render: (indexFieldType: string, x) =>
x.isInSameFamily ? (
<div>
<CodeWarning data-test-subj="codeWarning">{indexFieldType}</CodeWarning>
<CodeSuccess data-test-subj="codeSuccess">{indexFieldType}</CodeSuccess>
<SameFamily />
</div>
) : (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const EMPTY_PARTITIONED_FIELD_METADATA: PartitionedFieldMetadata = {
custom: [],
ecsCompliant: [],
incompatible: [],
sameFamily: [],
};

export async function checkIndex({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ describe('helpers', () => {
type: 'date',
},
],
sameFamily: [],
};

test('it returns a `PartitionedFieldMetadata` with an `incompatible` `@timestamp` when `mappingsProperties` is undefined', () => {
Expand Down Expand Up @@ -301,7 +302,7 @@ describe('helpers', () => {
],
hasEcsMetadata: true,
isEcsCompliant: false,
isInSameFamily: true,
isInSameFamily: false,
},
{
dashed_name: 'host-name',
Expand Down Expand Up @@ -620,7 +621,7 @@ describe('helpers', () => {
],
hasEcsMetadata: true,
isEcsCompliant: false,
isInSameFamily: true,
isInSameFamily: false,
},
{
dashed_name: 'host-name',
Expand Down Expand Up @@ -657,6 +658,7 @@ describe('helpers', () => {
isInSameFamily: false,
},
],
sameFamily: [],
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@ export const ALL_TAB_ID = 'allTab';
export const ECS_COMPLIANT_TAB_ID = 'ecsCompliantTab';
export const CUSTOM_TAB_ID = 'customTab';
export const INCOMPATIBLE_TAB_ID = 'incompatibleTab';
export const SAME_FAMILY_TAB_ID = 'sameFamilyTab';
export const SUMMARY_TAB_ID = 'summaryTab';

export const EMPTY_METADATA: PartitionedFieldMetadata = {
all: [],
ecsCompliant: [],
custom: [],
incompatible: [],
sameFamily: [],
};

export const getSortedPartitionedFieldMetadata = ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,11 @@ const IndexPropertiesComponent: React.FC<Props> = ({
? partitionedFieldMetadata.incompatible.length
: undefined;

const indexSameFamily: number | undefined =
error == null && partitionedFieldMetadata != null
? partitionedFieldMetadata.sameFamily.length
: undefined;

if (patternRollup != null) {
const markdownComments =
partitionedFieldMetadata != null
Expand Down Expand Up @@ -255,6 +260,7 @@ const IndexPropertiesComponent: React.FC<Props> = ({
indexName,
markdownComments,
pattern,
sameFamily: indexSameFamily,
},
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ describe('helpers', () => {
describe('getTabCountsMarkdownComment', () => {
test('it returns a comment with the expected counts', () => {
expect(getTabCountsMarkdownComment(mockPartitionedFieldMetadata)).toBe(
'### **Incompatible fields** `3` **Custom fields** `4` **ECS compliant fields** `2` **All fields** `9`\n'
'### **Incompatible fields** `3` **Same family** `0` **Custom fields** `4` **ECS compliant fields** `2` **All fields** `9`\n'
);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ export const getTabCountsMarkdownComment = (
): string =>
`### **${i18n.INCOMPATIBLE_FIELDS}** ${getCodeFormattedValue(
`${partitionedFieldMetadata.incompatible.length}`
)} **${i18n.SAME_FAMILY}** ${getCodeFormattedValue(
`${partitionedFieldMetadata.sameFamily.length}`
)} **${i18n.CUSTOM_FIELDS}** ${getCodeFormattedValue(
`${partitionedFieldMetadata.custom.length}`
)} **${i18n.ECS_COMPLIANT_FIELDS}** ${getCodeFormattedValue(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,22 @@ export const CUSTOM_CALLOUT = ({ fieldCount, version }: { fieldCount: number; ve
'{fieldCount, plural, =1 {This field is not} other {These fields are not}} defined by the Elastic Common Schema (ECS), version {version}.',
});

export const SAME_FAMILY_CALLOUT = ({
fieldCount,
version,
}: {
fieldCount: number;
version: string;
}) =>
i18n.translate(
'securitySolutionPackages.ecsDataQualityDashboard.indexProperties.sameFamilyCallout',
{
values: { fieldCount, version },
defaultMessage:
"{fieldCount, plural, =1 {This field is} other {These fields are}} defined by the Elastic Common Schema (ECS), version {version}, but {fieldCount, plural, =1 {its mapping type doesn't} other {their mapping types don't}} exactly match.",
}
);

export const CUSTOM_CALLOUT_TITLE = (fieldCount: number) =>
i18n.translate(
'securitySolutionPackages.ecsDataQualityDashboard.indexProperties.customCalloutTitle',
Expand All @@ -286,6 +302,16 @@ export const CUSTOM_CALLOUT_TITLE = (fieldCount: number) =>
}
);

export const SAME_FAMILY_CALLOUT_TITLE = (fieldCount: number) =>
i18n.translate(
'securitySolutionPackages.ecsDataQualityDashboard.indexProperties.sameFamilyCalloutTitle',
{
values: { fieldCount },
defaultMessage:
'{fieldCount} Same family {fieldCount, plural, =1 {field mapping} other {field mappings}}',
}
);

export const CUSTOM_EMPTY = i18n.translate(
'securitySolutionPackages.ecsDataQualityDashboard.indexProperties.customEmptyContent',
{
Expand All @@ -307,13 +333,7 @@ export const INCOMPATIBLE_FIELDS = i18n.translate(
}
);

export const INCOMPATIBLE_CALLOUT = ({
fieldCount,
version,
}: {
fieldCount: number;
version: string;
}) =>
export const INCOMPATIBLE_CALLOUT = (version: string) =>
i18n.translate(
'securitySolutionPackages.ecsDataQualityDashboard.indexProperties.incompatibleCallout',
{
Expand All @@ -323,34 +343,27 @@ export const INCOMPATIBLE_CALLOUT = ({
}
);

export const INCOMPATIBLE_FIELDS_WITH = i18n.translate(
'securitySolutionPackages.ecsDataQualityDashboard.indexProperties.incompatibleCallout.incompatibleFieldsWithLabel',
export const FIELDS_WITH_MAPPINGS_SAME_FAMILY = i18n.translate(
'securitySolutionPackages.ecsDataQualityDashboard.indexProperties.incompatibleCallout.fieldsWithMappingsSameFamilyLabel',
{
defaultMessage:
'Incompatible fields with mappings in the same family have exactly the same search behavior but may have different space usage or performance characteristics.',
'Fields with mappings in the same family have exactly the same search behavior as the type specified by ECS, but may have different space usage or performance characteristics.',
}
);

export const WHEN_AN_INCOMPATIBLE_FIELD = i18n.translate(
'securitySolutionPackages.ecsDataQualityDashboard.indexProperties.incompatibleCallout.whenAnIncompatibleFieldLabel',
export const WHEN_A_FIELD_IS_INCOMPATIBLE = i18n.translate(
'securitySolutionPackages.ecsDataQualityDashboard.indexProperties.incompatibleCallout.whenAFieldIsIncompatibleLabel',
{
defaultMessage: 'When an incompatible field is not in the same family:',
defaultMessage: 'When a field is incompatible:',
}
);

export const INCOMPATIBLE_CALLOUT_TITLE = ({
fieldCount,
fieldsInSameFamily,
}: {
fieldCount: number;
fieldsInSameFamily: number;
}) =>
export const INCOMPATIBLE_CALLOUT_TITLE = (fieldCount: number) =>
i18n.translate(
'securitySolutionPackages.ecsDataQualityDashboard.indexProperties.incompatibleCalloutTitle',
{
values: { fieldCount, fieldsInSameFamily },
defaultMessage:
'{fieldCount} incompatible {fieldCount, plural, =1 {field} other {fields}}, {fieldsInSameFamily} {fieldsInSameFamily, plural, =1 {field} other {fields}} with {fieldsInSameFamily, plural, =1 {a mapping} other {mappings}} in the same family',
values: { fieldCount },
defaultMessage: '{fieldCount} incompatible {fieldCount, plural, =1 {field} other {fields}}',
}
);

Expand Down Expand Up @@ -391,6 +404,21 @@ export const OTHER_APP_CAPABILITIES_WORK_PROPERLY = i18n.translate(
}
);

export const SAME_FAMILY_EMPTY = i18n.translate(
'securitySolutionPackages.ecsDataQualityDashboard.indexProperties.sameFamilyEmptyContent',
{
defaultMessage:
'All of the field mappings and document values in this index are compliant with the Elastic Common Schema (ECS).',
}
);

export const SAME_FAMILY_EMPTY_TITLE = i18n.translate(
'securitySolutionPackages.ecsDataQualityDashboard.indexProperties.sameFamilyEmptyTitle',
{
defaultMessage: 'All field mappings and values are ECS compliant',
}
);

export const PAGES_DISPLAY_EVENTS = i18n.translate(
'securitySolutionPackages.ecsDataQualityDashboard.indexProperties.pagesDisplayEventsMessage',
{
Expand Down Expand Up @@ -428,6 +456,13 @@ export const ECS_IS_A_PERMISSIVE_SCHEMA = i18n.translate(
}
);

export const SAME_FAMILY = i18n.translate(
'securitySolutionPackages.ecsDataQualityDashboard.indexProperties.sameFamilyTab',
{
defaultMessage: 'Same family',
}
);

export const SOMETIMES_INDICES_CREATED_BY_OLDER = i18n.translate(
'securitySolutionPackages.ecsDataQualityDashboard.indexProperties.sometimesIndicesCreatedByOlderDescription',
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ describe('helpers', () => {
'\n#### Incompatible field mappings - auditbeat-custom-index-1\n\n\n| Field | ECS mapping type (expected) | Index mapping type (actual) | \n|-------|-----------------------------|-----------------------------|\n| host.name | `keyword` | `text` |\n| source.ip | `ip` | `text` |\n\n#### Incompatible field values - auditbeat-custom-index-1\n\n\n| Field | ECS values (expected) | Document values (actual) | \n|-------|-----------------------|--------------------------|\n| event.category | `authentication`, `configuration`, `database`, `driver`, `email`, `file`, `host`, `iam`, `intrusion_detection`, `malware`, `network`, `package`, `process`, `registry`, `session`, `threat`, `vulnerability`, `web` | `an_invalid_category` (2),\n`theory` (1) |\n\n',
],
pattern: 'auditbeat-*',
sameFamily: 0,
},
};
const isILMAvailable = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,23 @@ export const INDICES = i18n.translate(
}
);

export const SAME_FAMILY = i18n.translate(
'securitySolutionPackages.ecsDataQualityDashboard.statLabels.sameFamilyLabel',
{
defaultMessage: 'Same family',
}
);

export const SAME_FAMILY_PATTERN_TOOL_TIP = (pattern: string) =>
i18n.translate(
'securitySolutionPackages.ecsDataQualityDashboard.statLabels.sameFamilyPatternToolTip',
{
values: { pattern },
defaultMessage:
'The total count of fields in the same family as the type specified by ECS, in indices matching the {pattern} pattern',
}
);

export const SIZE = i18n.translate(
'securitySolutionPackages.ecsDataQualityDashboard.statLabels.sizeLabel',
{
Expand Down Expand Up @@ -166,6 +183,14 @@ export const TOTAL_INDICES_TOOL_TIP = i18n.translate(
}
);

export const TOTAL_SAME_FAMILY_TOOL_TIP = i18n.translate(
'securitySolutionPackages.ecsDataQualityDashboard.statLabels.totalSameFamilyToolTip',
{
defaultMessage:
'The total count of fields in the same family as the ECS type, in all indices that were checked',
}
);

export const TOTAL_SIZE_TOOL_TIP = i18n.translate(
'securitySolutionPackages.ecsDataQualityDashboard.statLabels.totalSizeToolTip',
{
Expand Down
Loading