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

Adds field mappings to edit detector pages #490

Merged
merged 15 commits into from
Apr 4, 2023
Merged
Show file tree
Hide file tree
Changes from 14 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
121 changes: 121 additions & 0 deletions cypress/integration/1_detectors.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,127 @@ describe('Detectors', () => {
cy.contains('Active rules (1)');
});

it('...should update field mappings if data source is changed', () => {
// Click on detector name
cy.contains(detectorName).click({ force: true });
cy.waitForPageLoad('detector-details', {
contains: detectorName,
});

// Click "Edit" button in detector details
cy.get(`[data-test-subj="edit-detector-basic-details"]`).click({ force: true });

// Confirm arrival at "Edit detector details" page
cy.waitForPageLoad('edit-detector-details', {
contains: 'Edit detector details',
});

cy.get('.reviewFieldMappings').should('not.exist');

// Change input source
cy.get(`[data-test-subj="define-detector-select-data-source"]`)
.find('input')
.ospClear()
.focus()
.realType(cypressIndexWindows)
.realPress('Enter');

cy.get('.reviewFieldMappings').should('be.visible');
cy.get('.reviewFieldMappings').within(($el) => {
cy.get($el).contains('Automatically mapped fields (0)');
});

// Change input source
cy.get(`[data-test-subj="define-detector-select-data-source"]`)
.find('input')
.ospClear()
.focus()
.realType(cypressIndexDns)
.realPress('Enter');

cy.get('.reviewFieldMappings').should('be.visible');
cy.get('.reviewFieldMappings').within(($el) => {
cy.get($el).contains('Automatically mapped fields (1)');
});

// Save changes to detector details
cy.get(`[data-test-subj="save-basic-details-edits"]`).click({ force: true });
});

it('...should update field mappings if rule selection is changed', () => {
// Click on detector name
cy.contains(detectorName).click({ force: true });
cy.waitForPageLoad('detector-details', {
contains: detectorName,
});

// Click "Edit" button in detector details
cy.get(`[data-test-subj="edit-detector-rules"]`).click({ force: true });

// Confirm arrival at "Edit detector details" page
cy.waitForPageLoad('edit-detector-rules', {
contains: 'Edit detector rules',
});

cy.get('.reviewFieldMappings').should('not.exist');

// Search for specific rule
cy.get(`input[placeholder="Search..."]`).ospSearch(cypressDNSRule);

cy.intercept('mappings/view').as('getMappingsView');

// Toggle single search result to unchecked
cy.contains('table tr', cypressDNSRule).within(() => {
// Of note, timeout can sometimes work instead of wait here, but is very unreliable from case to case.
cy.wait(1000);
cy.get('button').eq(1).click();
});

cy.wait('@getMappingsView');
cy.get('.reviewFieldMappings').should('be.visible');
cy.get('.reviewFieldMappings').within(($el) => {
cy.get($el).contains('Automatically mapped fields (0)');
});

//Suspicious DNS Query with B64 Encoded String
cy.get(`input[placeholder="Search..."]`).ospSearch(cypressDNSRule);
cy.contains('table tr', cypressDNSRule).within(() => {
// Of note, timeout can sometimes work instead of wait here, but is very unreliable from case to case.
cy.wait(1000);
cy.get('button').eq(1).click();
});

cy.wait('@getMappingsView');
cy.get(`input[placeholder="Search..."]`).ospSearch(
'Suspicious DNS Query with B64 Encoded String'
);
cy.contains('table tr', 'Suspicious DNS Query with B64 Encoded String').within(() => {
// Of note, timeout can sometimes work instead of wait here, but is very unreliable from case to case.
cy.wait(1000);
cy.get('button').eq(1).click();
});

cy.wait('@getMappingsView');
cy.get('.reviewFieldMappings').should('be.visible');
cy.get('.reviewFieldMappings').within(($el) => {
cy.get($el).contains('Automatically mapped fields (1)');
});

cy.get(`input[placeholder="Search..."]`).ospSearch('High TXT Records Requests Rate');
cy.contains('table tr', 'High TXT Records Requests Rate').within(() => {
// Of note, timeout can sometimes work instead of wait here, but is very unreliable from case to case.
cy.wait(1000);
cy.get('button').eq(1).click();
});

cy.wait('@getMappingsView');
cy.get('.reviewFieldMappings').should('be.visible');
cy.get('.reviewFieldMappings').within(($el) => {
cy.get($el).contains('Automatically mapped fields (1)');
cy.get($el).contains('1 rule fields may need manual mapping');
});
});

it('...can be deleted', () => {
// Click on detector to be removed
cy.contains('test detector edited').click({ force: true });
Expand Down
3 changes: 2 additions & 1 deletion public/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ $euiTextColor: $euiColorDarkestShade !default;

@import "./components/Charts/ChartContainer.scss";
@import "./pages/Overview/components/Widgets/WidgetContainer.scss";
@import "./pages/Detectors/components/ReviewFieldMappings/ReviewFieldMappings.scss";

.selected-radio-panel {
background-color: tintOrShade($euiColorPrimary, 90%, 70%);
Expand Down Expand Up @@ -119,4 +120,4 @@ $euiTextColor: $euiColorDarkestShade !default;

.sa-overview-widget-empty tbody > .euiTableRow > .euiTableRowCell {
border-bottom: none;
}
}
7 changes: 6 additions & 1 deletion public/components/ContentPanel/ContentPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ interface ContentPanelProps {
horizontalRuleClassName?: string;
actions?: React.ReactNode | React.ReactNode[];
children: React.ReactNode | React.ReactNode[];
className?: string;
}

const renderSubTitleText = (subTitleText: string | JSX.Element): JSX.Element | null => {
Expand All @@ -45,8 +46,12 @@ const ContentPanel: React.SFC<ContentPanelProps> = ({
horizontalRuleClassName = '',
actions,
children,
className = '',
}) => (
<EuiPanel style={{ paddingLeft: '0px', paddingRight: '0px', ...panelStyles }}>
<EuiPanel
style={{ paddingLeft: '0px', paddingRight: '0px', ...panelStyles }}
className={className}
>
<EuiFlexGroup style={{ padding: '0px 10px' }} justifyContent="spaceBetween" alignItems="center">
<EuiFlexItem>
{typeof title === 'string' ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,7 @@ exports[`<Alerts /> spec renders the component 1`] = `
title="Alerts"
>
<EuiPanel
className=""
style={
Object {
"paddingLeft": "0px",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@ export default class FieldNameSelector extends Component<SIEMFieldNameProps, SIE
};
}

public componentDidUpdate(
prevProps: Readonly<SIEMFieldNameProps>,
prevState: Readonly<SIEMFieldNameState>,
snapshot?: any
): void {
if (this.props.selectedField !== prevProps.selectedField) {
// if the props.selectedField is changed, update the state
this.setState({
selectedOptions: [{ label: this.props.selectedField }],
});
}
}

onMappingChange = (selectedOptions: EuiComboBoxOptionOption<string>[]) => {
this.setState({ selectedOptions });
this.props.onChange(selectedOptions[0]?.label);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export interface ruleFieldToIndexFieldMap {
interface ConfigureFieldMappingProps extends RouteComponentProps {
isEdit: boolean;
detector: Detector;
filedMappingService: FieldMappingService;
fieldMappingService: FieldMappingService;
fieldMappings: FieldMapping[];
loading: boolean;
enabledRules: CreateDetectorRulesState['allRules'];
Expand Down Expand Up @@ -82,7 +82,7 @@ export default class ConfigureFieldMapping extends Component<

getAllMappings = async () => {
this.setState({ loading: true });
const mappingsView = await this.props.filedMappingService.getMappingsView(
const mappingsView = await this.props.fieldMappingService.getMappingsView(
this.props.detector.inputs[0].detector_input.indices[0],
this.props.detector.detector_type.toLowerCase()
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { RuleItemInfoBase } from '../../../../../../Rules/models/types';
import { RuleInfo } from './../../../../../../../../server/models/interfaces/Rules';
import { RuleInfo } from '../../../../../../../../server/models/interfaces';
import { RuleItemInfoBase } from '../../../../../../../../types';

export interface RuleItem {
name: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { FieldMappingService } from '../../../../../../services';
interface DetectorDataSourceProps {
detectorIndices: string[];
indexService: IndexService;
filedMappingService: FieldMappingService;
fieldMappingService: FieldMappingService;
isEdit: boolean;
onDetectorInputIndicesChange: (selectedOptions: EuiComboBoxOptionOption<string>[]) => void;
notifications: NotificationsStart;
Expand Down Expand Up @@ -109,7 +109,7 @@ export default class DetectorDataSource extends Component<
for (const indexName of allIndices) {
if (!this.indicesMappings[indexName]) {
const detectorType = this.props.detector_type.toLowerCase();
const result = await this.props.filedMappingService.getMappingsView(
const result = await this.props.fieldMappingService.getMappingsView(
indexName,
detectorType
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ interface DefineDetectorProps extends RouteComponentProps {
detector: Detector;
isEdit: boolean;
indexService: IndexService;
filedMappingService: FieldMappingService;
fieldMappingService: FieldMappingService;
rulesState: CreateDetectorRulesState;
notifications: NotificationsStart;
loadingRules?: boolean;
Expand Down Expand Up @@ -165,7 +165,7 @@ export default class DefineDetector extends Component<DefineDetectorProps, Defin
onRuleToggle,
onPageChange,
onAllRulesToggle,
filedMappingService,
fieldMappingService,
} = this.props;
const { name, inputs, detector_type } = this.props.detector;
const { description, indices } = inputs[0].detector_input;
Expand Down Expand Up @@ -197,7 +197,7 @@ export default class DefineDetector extends Component<DefineDetectorProps, Defin
{...this.props}
detector_type={detector_type}
detectorIndices={indices}
filedMappingService={filedMappingService}
fieldMappingService={fieldMappingService}
onDetectorInputIndicesChange={this.onDetectorInputIndicesChange}
/>

Expand Down
4 changes: 2 additions & 2 deletions public/pages/CreateDetector/containers/CreateDetector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ export default class CreateDetector extends Component<CreateDetectorProps, Creat
{...this.props}
detector={this.state.detector}
indexService={services.indexService}
filedMappingService={services.fieldMappingService}
fieldMappingService={services.fieldMappingService}
rulesState={this.state.rulesState}
loadingRules={this.state.loadingRules}
onRuleToggle={this.onRuleToggle}
Expand All @@ -344,7 +344,7 @@ export default class CreateDetector extends Component<CreateDetectorProps, Creat
{...this.props}
detector={this.state.detector}
loading={false}
filedMappingService={services.fieldMappingService}
fieldMappingService={services.fieldMappingService}
fieldMappings={this.state.fieldMappings}
enabledRules={this.state.rulesState.allRules.filter((rule) => rule.enabled)}
replaceFieldMappings={this.replaceFieldMappings}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ exports[`<DetectorRulesView /> spec renders the component 1`] = `
title="Active rules (2)"
>
<EuiPanel
className=""
style={
Object {
"paddingLeft": "0px",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.reviewFieldMappings {
.editFieldMappings {
.euiPanel {
&.euiPanel--hasShadow {
border: none !important;
box-shadow: none !important;
}

&.euiPanel--paddingMedium, .euiAccordion__button {
padding-left: 0 !important;
}
}
.euiHorizontalRule {
background-color: transparent !important;
}
}
}
Loading