Skip to content

Commit

Permalink
Rule flyout opening from Findings and Alerts page (#219)
Browse files Browse the repository at this point in the history
* rule flyout opening from findings and alerts page

Signed-off-by: Aleksandar Djindjic <[email protected]>

* update cypress test for findings page

Signed-off-by: Aleksandar Djindjic <[email protected]>

* make code shorter

Signed-off-by: Aleksandar Djindjic <[email protected]>

* toast error notifications for rule deletion

Signed-off-by: Aleksandar Djindjic <[email protected]>

* cleanup component state

Signed-off-by: Aleksandar Djindjic <[email protected]>

* avoid as any in favor of RuleItemInfoBase

Signed-off-by: Aleksandar Djindjic <[email protected]>

* fix cypress test for rules

Signed-off-by: Aleksandar Djindjic <[email protected]>

Signed-off-by: Aleksandar Djindjic <[email protected]>
  • Loading branch information
djindjic authored Dec 16, 2022
1 parent abfa8b8 commit 11e47b3
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 28 deletions.
2 changes: 1 addition & 1 deletion cypress/integration/2_rules.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ describe('Rules', () => {
);

// Close the flyout
cy.get('[data-test-subj="euiFlyoutCloseButton"]', TWENTY_SECONDS_TIMEOUT).click({
cy.get('[data-test-subj="close-rule-details-flyout"]', TWENTY_SECONDS_TIMEOUT).click({
force: true,
});
});
Expand Down
21 changes: 14 additions & 7 deletions cypress/integration/4_findings.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { PLUGIN_NAME } from '../support/constants';
import { PLUGIN_NAME, TWENTY_SECONDS_TIMEOUT } from '../support/constants';
import sample_document from '../fixtures/sample_document.json';
import sample_index_settings from '../fixtures/sample_index_settings.json';
import sample_field_mappings from '../fixtures/sample_field_mappings.json';
Expand Down Expand Up @@ -106,14 +106,21 @@ describe('Findings', () => {
// TODO - upon reaching rules page, trigger appropriate rules detail flyout
// see github issue #124 at https://github.com/opensearch-project/security-analytics-dashboards-plugin/issues/124

it('takes user to rules page when rule name inside accordion drop down is clicked', () => {
it('opens rule details flyout when rule name inside accordion drop down is clicked', () => {
// Click rule link
cy.get(`[data-test-subj="finding-details-flyout-USB Device Plugged-details"]`)
.invoke('removeAttr', 'target')
.click({ force: true });
cy.get(`[data-test-subj="finding-details-flyout-USB Device Plugged-details"]`).click({
force: true,
});

// Confirm destination reached
cy.url().should('include', 'opensearch_security_analytics_dashboards#/rules');
// Validate flyout appearance
cy.get('[data-test-subj="rule_flyout_USB Device Plugged"]', TWENTY_SECONDS_TIMEOUT).within(
() => {
cy.get('[data-test-subj="rule_flyout_rule_name"]', TWENTY_SECONDS_TIMEOUT).contains(
'USB Device Plugged',
TWENTY_SECONDS_TIMEOUT
);
}
);
});

after(() => {
Expand Down
40 changes: 37 additions & 3 deletions public/pages/Findings/components/FindingDetailsFlyout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,21 @@ import {
import { capitalizeFirstLetter, renderTime } from '../../../utils/helpers';
import { DEFAULT_EMPTY_DATA, ROUTES } from '../../../utils/constants';
import { Finding, Query } from '../models/interfaces';
import { RuleViewerFlyout } from '../../Rules/components/RuleViewerFlyout/RuleViewerFlyout';
import { RuleTableItem } from '../../Rules/utils/helpers';
import { RuleSource } from '../../../../server/models/interfaces';
import { RuleItemInfoBase } from '../../Rules/models/types';

interface FindingDetailsFlyoutProps {
finding: Finding;
closeFlyout: () => void;
backButton?: React.ReactNode;
allRules: object;
allRules: { [id: string]: RuleSource };
}

interface FindingDetailsFlyoutState {
loading: boolean;
ruleViewerFlyoutData: RuleTableItem | null;
}

export default class FindingDetailsFlyout extends Component<
Expand All @@ -45,6 +50,7 @@ export default class FindingDetailsFlyout extends Component<
super(props);
this.state = {
loading: false,
ruleViewerFlyoutData: null,
};
}

Expand All @@ -62,6 +68,27 @@ export default class FindingDetailsFlyout extends Component<
);
};

showRuleDetails = (fullRule, ruleId: string) => {
this.setState({
...this.state,
ruleViewerFlyoutData: {
ruleId: ruleId,
title: fullRule.title,
level: fullRule.level,
category: fullRule.category,
description: fullRule.description,
source: fullRule.source,
ruleInfo: {
_source: fullRule,
} as RuleItemInfoBase,
},
});
};

hideRuleDetails = () => {
this.setState({ ...this.state, ruleViewerFlyoutData: null });
};

renderRuleDetails = (rules: Query[] = []) => {
const {
allRules,
Expand Down Expand Up @@ -94,8 +121,7 @@ export default class FindingDetailsFlyout extends Component<
{/*//TODO: Refactor EuiLink to filter rules table to the specific rule.*/}
<EuiFormRow label={'Rule name'}>
<EuiLink
href={`#${ROUTES.RULES}`}
target={'_blank'}
onClick={() => this.showRuleDetails(fullRule, rule.id)}
data-test-subj={`finding-details-flyout-${fullRule.title}-details`}
>
{fullRule.title || DEFAULT_EMPTY_DATA}
Expand Down Expand Up @@ -208,6 +234,13 @@ export default class FindingDetailsFlyout extends Component<
hideCloseButton
data-test-subj={'finding-details-flyout'}
>
{this.state.ruleViewerFlyoutData && (
<RuleViewerFlyout
hideFlyout={this.hideRuleDetails}
ruleTableItem={this.state.ruleViewerFlyoutData}
/>
)}

<EuiFlyoutHeader hasBorder={true}>
<EuiFlexGroup justifyContent="flexStart" alignItems="center">
<EuiFlexItem>
Expand All @@ -222,6 +255,7 @@ export default class FindingDetailsFlyout extends Component<
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonIcon
aria-label="close"
iconType="cross"
display="empty"
iconSize="m"
Expand Down
55 changes: 40 additions & 15 deletions public/pages/Rules/components/RuleViewerFlyout/RuleViewerFlyout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,23 @@ import {
EuiFlyoutBody,
EuiFlyoutHeader,
EuiTitle,
EuiButtonIcon,
} from '@elastic/eui';
import { errorNotificationToast } from '../../../../utils/helpers';
import { ROUTES } from '../../../../utils/constants';
import React, { useMemo, useState } from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { RuleTableItem } from '../../utils/helpers';
import { DeleteRuleModal } from '../DeleteModal/DeleteModal';
import { RuleContentViewer } from '../RuleContentViewer/RuleContentViewer';
import { RuleViewerFlyoutHeaderActions } from './RuleViewFlyoutHeaderActions';
import { RuleService } from '../../../../services';
import { RuleService, NotificationsStart } from '../../../../services';

export interface RuleViewerFlyoutProps {
history: RouteComponentProps['history'];
history?: RouteComponentProps['history'];
ruleTableItem: RuleTableItem;
ruleService: RuleService;
ruleService?: RuleService;
notifications?: NotificationsStart;
hideFlyout: (refreshRules?: boolean) => void;
}

Expand All @@ -32,6 +35,7 @@ export const RuleViewerFlyout: React.FC<RuleViewerFlyoutProps> = ({
hideFlyout,
ruleTableItem,
ruleService,
notifications,
}) => {
const [actionsPopoverOpen, setActionsPopoverOpen] = useState(false);
const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false);
Expand All @@ -42,14 +46,14 @@ export const RuleViewerFlyout: React.FC<RuleViewerFlyoutProps> = ({
setActionsPopoverOpen(false);
};
const duplicateRule = () => {
history.push({
history?.push({
pathname: ROUTES.RULES_DUPLICATE,
state: { ruleItem: ruleTableItem.ruleInfo },
});
};

const editRule = () => {
history.push({
history?.push({
pathname: ROUTES.RULES_EDIT,
state: { ruleItem: ruleTableItem.ruleInfo },
});
Expand All @@ -74,14 +78,17 @@ export const RuleViewerFlyout: React.FC<RuleViewerFlyoutProps> = ({
};

const onDeleteRuleConfirmed = async () => {
if (!ruleService) {
return;
}
const deleteRuleRes = await ruleService.deleteRule(ruleTableItem.ruleId);

if (!deleteRuleRes.ok) {
// TODO: show error
if (deleteRuleRes.ok) {
closeDeleteModal();
hideFlyout(true);
} else {
errorNotificationToast(notifications, 'delete', 'rule', deleteRuleRes.error);
}

closeDeleteModal();
hideFlyout(true);
};

const deleteModal = useMemo(
Expand All @@ -97,17 +104,35 @@ export const RuleViewerFlyout: React.FC<RuleViewerFlyoutProps> = ({
);

return (
<EuiFlyout onClose={hideFlyout} data-test-subj={`rule_flyout_${ruleTableItem.title}`}>
<EuiFlyout
onClose={hideFlyout}
hideCloseButton
ownFocus={true}
size={'m'}
data-test-subj={`rule_flyout_${ruleTableItem.title}`}
>
{isDeleteModalVisible && deleteModal ? deleteModal : null}
<EuiFlyoutHeader hasBorder>
<EuiFlexGroup>
<EuiFlyoutHeader hasBorder={true}>
<EuiFlexGroup alignItems="center">
<EuiFlexItem>
<EuiTitle size="m">
<h3>{ruleTableItem.title}</h3>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false} style={{ marginRight: '50px' }}>
{headerActions}
{ruleService && history && (
<EuiFlexItem grow={false} style={{ marginRight: '50px' }}>
{headerActions}
</EuiFlexItem>
)}
<EuiFlexItem grow={false}>
<EuiButtonIcon
aria-label="close"
iconType="cross"
display="empty"
iconSize="m"
onClick={() => hideFlyout()}
data-test-subj={`close-rule-details-flyout`}
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlyoutHeader>
Expand Down
1 change: 1 addition & 0 deletions public/pages/Rules/containers/Rules/Rules.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export const Rules: React.FC<RulesProps> = (props) => {
history={props.history}
ruleTableItem={flyoutData}
ruleService={services.ruleService}
notifications={props.notifications}
/>
) : null}
<EuiFlexGroup direction="column">
Expand Down
4 changes: 2 additions & 2 deletions public/utils/helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ export function createTextDetailsGroup(
) : (
<>
<EuiFlexGroup>
{data.map(({ label, content, url }) => {
{data.map(({ label, content, url }, index) => {
return (
<EuiFlexItem
key={label}
key={index}
grow={false}
style={{ minWidth: `${100 / (columnNum || data.length)}%` }}
>
Expand Down

0 comments on commit 11e47b3

Please sign in to comment.