-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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] Add rule snooze settings on the rule details page #155407
[Security Solution] Add rule snooze settings on the rule details page #155407
Conversation
Pinging @elastic/security-detections-response (Team:Detections and Resp) |
Pinging @elastic/security-solution (Team: SecuritySolution) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, @maximpn, for working on this feature! I have tested the PR locally, and it works as expected. Overall, the implementation looks good. I have left a few comments for further improvements; please let me know if you want to discuss them over Zoom.
jest.mock('./components/rule_details_snooze_settings', () => ({ | ||
RuleDetailsSnoozeSettings: () => <></>, | ||
})); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, it's the 14th mock added to this test file 😅.
Honestly, it might be better just to delete this messy test altogether.
Relying heavily on mocks in a single test isn't great for several reasons:
- Bad readability: Too many mocks make reading and understanding the test difficult. In this case, there are ~170 LoC mock definitions, roughly half of the test file.
- Fragility: Mocks can cause tests to break easily when the code changes. This is because mocks assume certain things about how the system works, and if those things change, the test will fail even if everything else is still working fine.
- Violation of encapsulation: Mocks usually rely on implementation detail. This makes introducing code changes without breaking tests hard, slowing development.
- Fake test scenarios: When using too many mocks, you basically test mocks instead of actual code. This can cause tests to pass or fail regardless of the existing system behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I totally agree with the comment though I'd like to abstain from any other changes in the test file in this PR. It more or less outside of scope here so I'd rather address test file refactoring in a subsequent PR if you don't mind.
/** | ||
* Rule SO's id (not ruleId) to snooze settings map, | ||
*/ | ||
data: Record<string, RuleSnoozeSettings>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure how "Rule SO's id" is related to this structure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment is fixed, it should reflect the data field's essence better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately this problem takes more time to be fixed. I've created a task to address this bug after feature freeze.
const { | ||
state: { rulesSnoozeSettings }, | ||
} = useRulesTableContext(); | ||
|
||
return useMemo( | ||
() => ({ | ||
field: 'snooze', | ||
name: i18n.COLUMN_SNOOZE, | ||
render: (_, rule: Rule) => <RuleSnoozeBadge id={rule.id} />, | ||
render: (_, rule: Rule) => { | ||
const snoozeSettings = rulesSnoozeSettings.data[rule.id]; | ||
const { isFetching, isError } = rulesSnoozeSettings; | ||
|
||
return ( | ||
<RuleSnoozeBadge | ||
snoozeSettings={snoozeSettings} | ||
error={ | ||
isError || (!snoozeSettings && !isFetching) | ||
? rulesTableI18n.UNABLE_TO_FETCH_RULES_SNOOZE_SETTINGS | ||
: undefined | ||
} | ||
/> | ||
); | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to abstract the settings and error retrieval logic into a reusable hook. Something like:
const { snoozingSettings, error } = useRuleSnoozingSettings(rule.id)
Moreover, this logic is duplicated in the RuleDetailsSnoozeSettings
component. It would be better to encapsulate it inside the RuleSnoozeBadge
component instead of handling the data access part outside. The component might try to get the rule settings from the table context if it's available and fall back to data fetching in other cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I'm gonna address this in the next PR for adding support of rule snooze on the rule editing page.
@@ -40,8 +40,18 @@ import { RuleSource } from './rules_table_saved_state'; | |||
import { useRulesTableSavedState } from './use_rules_table_saved_state'; | |||
|
|||
interface RulesSnoozeSettings { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not related to this PR directly.
I was thinking about the snooze state inside the table context, and it seems a bit alien there. If I understood correctly, its purpose is to batch outgoing HTTP requests, i.e., send a single rule snooze request instead of 1 x N table rows. So I think it would be better to create an abstraction just for that. It could be a data hook that doesn't trigger a request immediately but waits some time and accumulates request params if other similar hooks are present on the page. Something similar to the GraphQL dataloader batching functionality but adapted for usage with react query.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, I also had some similar ideas already. My main concern is to make it simple, maintainable and reusable as creating such functionality only for one feature is time consuming. I think we can take the thoughts into account and analyze the possibilities when the snoozing epic is done.
💛 Build succeeded, but was flaky
Failed CI StepsTest Failures
Metrics [docs]Module Count
Async chunks
Unknown metric groupsESLint disabled line counts
Total ESLint disabled count
History
To update your PR or re-run it, just comment with: cc @maximpn |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
Addresses: #155406
Summary
This PR adds rule snoozing support on the Rule Details page.
Screen.Recording.2023-04-20.at.15.49.31.mov
Checklist