Skip to content

Commit

Permalink
Adds field mappings to edit detector pages (opensearch-project#490) (o…
Browse files Browse the repository at this point in the history
…pensearch-project#500)

* Edit detector - UX improvements and updates opensearch-project#482

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* Edit detector - UX improvements and updates opensearch-project#482

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* Communicate to users when the detector is initializing opensearch-project#487

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* Edit detector - UX improvements and updates opensearch-project#482

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* Edit detector - UX improvements and updates opensearch-project#482

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* Edit detector - UX improvements and updates opensearch-project#482

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* Edit detector - UX improvements and updates opensearch-project#482

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* Edit detector - UX improvements and updates opensearch-project#482

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* Edit detector - UX improvements and updates opensearch-project#482

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* Edit detector - UX improvements and updates opensearch-project#482

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* Edit detector - UX improvements and updates opensearch-project#482

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* Edit detector - UX improvements and updates opensearch-project#482

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* Edit detector - UX improvements and updates opensearch-project#482

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

---------

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>
(cherry picked from commit bb277ae)

Co-authored-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>
Signed-off-by: AWSHurneyt <hurneyt@amazon.com>
  • Loading branch information
2 people authored and AWSHurneyt committed Oct 12, 2023
1 parent 6c9c8dc commit c7c6230
Show file tree
Hide file tree
Showing 25 changed files with 567 additions and 87 deletions.
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 @@ -289,7 +289,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 @@ -305,7 +305,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 @@ -203,6 +203,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

0 comments on commit c7c6230

Please sign in to comment.