-
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] Reintroduce ML Jobs warning popover on rule upgrade #159868
Conversation
Pinging @elastic/security-detections-response (Team:Detections and Resp) |
Pinging @elastic/security-solution (Team: SecuritySolution) |
@xcrzx Reintroduced the ML Popover with this approach, but not completely satisfied with what I had to do with the Upgrade context, seems kinda hacky to me. Can you take a look on Monday and tell me what you think? |
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've tested it locally, and the functionality is working as expected. Thanks, @jpdjere! 👍 However, I do have a few suggestions about structuring the business logic within the context. If necessary, we can sync up on this over a Zoom call.
const upgradeRule = useCallback( | ||
(ruleId: string) => { | ||
if (legacyJobsInstalled.length > 0) { | ||
showUpgradeModal(); | ||
setModalConfirmationUpgradeMethod('SINGLE_RULE'); | ||
setRuleIdToUpgrade(ruleId); | ||
} else { | ||
upgradeOneRule(ruleId); | ||
} | ||
}, |
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.
Let's encapsulate this business logic within the rules upgrade context. This is the very purpose of the context – to accommodate all rule-upgrade-related logic, while minimizing its presence in the UI as much as possible. So, when we talk about a single rule upgrade, we could expose a single method from the context that is aware of the context state, performs all the necessary checks for the upgrade process, and can manage basic state manipulations, like setting loading rules, displaying intermediary modal windows, and so on. That way we'll have atomic operations exposed from the context that holds all related business logic instead of assembling it from many pieces in the UI.
const upgradeRulesWrapper = ( | ||
upgradeMethod: ModalConfirmationUpgradeMethod, | ||
upgradeRuleMethod: () => Promise<void> | ||
) => { | ||
if (legacyJobsInstalled.length > 0) { | ||
showUpgradeModal(); | ||
setModalConfirmationUpgradeMethod(upgradeMethod); | ||
} else { | ||
upgradeRuleMethod(); | ||
} | ||
}; | ||
|
||
const mlJobUpgradeModalConfirm = useCallback(() => { | ||
if (modalConfirmationUpdateMethod === 'ALL_RULES') { | ||
upgradeAllRules(); | ||
} else if (modalConfirmationUpdateMethod === 'SPECIFIC_RULES') { | ||
upgradeSelectedRules(); | ||
} else if (modalConfirmationUpdateMethod === 'SINGLE_RULE') { | ||
upgradeOneRule(ruleIdToUpgrade); | ||
} | ||
hideUpgradeModal(); | ||
}, [ | ||
hideUpgradeModal, | ||
modalConfirmationUpdateMethod, | ||
ruleIdToUpgrade, | ||
upgradeAllRules, | ||
upgradeOneRule, | ||
upgradeSelectedRules, | ||
]); |
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.
Same here, we should move this business logic to the context as much as possible.
setModalConfirmationUpgradeMethod: Dispatch<SetStateAction<ModalConfirmationUpgradeMethod>>; | ||
setRuleIdToUpgrade: Dispatch<SetStateAction<string>>; | ||
showUpgradeModal: () => void; | ||
hideUpgradeModal: () => void; |
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.
Those are very low-level methods. Let's try to hide them inside the context and implement rule upgrade logic without exposing them.
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'm approving the PR now so we can merge it before the feature freeze. It's perfectly fine to address the comments in a follow-up.
Added popover Delete mock Refactor code to live in context
@xcrzx Thanks for the review and the approval. I refactored the code following the feedback, centralizing all code in the context. I think it's much cleaner now. Take a look if you wish, I'll leave the CI running during the night and merge it as soon as it's green tomorrow. |
upgradeSingleRuleFromRowCTA, | ||
upgradeSelectedRulesCTAClick, | ||
upgradeAllRulesCTAClick, |
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 ideal to keep the method names neutral and avoid referencing specific use cases. For example, we should remove terms like Row
, Click
, or CTA
from the method names.
/** | ||
* Rule ID of single rule to upgrade when the ML jobs modal is confirmed | ||
* */ | ||
ruleIdToUpgrade: string; |
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.
Is this state still used?
/** | ||
* Legacy ML Jobs that cause modal to pop up before performing rule ugprades | ||
*/ | ||
legacyJobsInstalled: MlSummaryJob[]; | ||
/** | ||
* Upgrade method to execute when the user confirms the modal | ||
*/ | ||
modalConfirmationUpdateMethod: ModalConfirmationUpgradeMethod | null; | ||
/** | ||
* Is true when the modal is visible | ||
* */ | ||
isUpgradeModalVisible: boolean; |
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 propose we take this a step further and make those state props internal. The rules upgrade context should handle modal confirmation internally without revealing anything to the external environment. I might not have been clear enough about handling that state internally, so let's please sync up on this topic separately.
// Wrapper around upgrade rules methods to display ML Jobs warning modal when necessary | ||
const upgradeRulesWrapper = useCallback( | ||
(upgradeMethod: ModalConfirmationUpgradeMethod, upgradeRuleMethod: () => Promise<void>) => | ||
() => { | ||
if (legacyJobsInstalled.length > 0) { | ||
showUpgradeModal(); | ||
setModalConfirmationUpgradeMethod(upgradeMethod); | ||
} else { | ||
upgradeRuleMethod(); | ||
} | ||
}, | ||
[legacyJobsInstalled.length, showUpgradeModal] | ||
); |
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.
Utilizing the wrapper does add a bit of extra complexity to the upgrade logic. For this specific use case, we have a hook named useAsyncConfirmation
. By using it, we can significantly improve the readability of the business logic. Consequently, a single rule upgrade method might look like the following:
const [confirmUpgrade, onConfirm, onCancel] = useAsyncConfirmation({
onInit: showUpgradeModal,
onFinish: hideUpgradeModal,
});
const upgradeOneRule = useCallback(
async (ruleId: RuleSignatureId) => {
try {
// 1. Set loading state
setLoadingRules((prev) => [...prev, ruleId]);
// 2. Confirm upgrade
if (await confirmUpgrade()) {
// 3. Perform upgrade
await upgradeSpecificRulesRequest({});
}
} finally {
// 4. Remove loading state
setLoadingRules((prev) => prev.filter((id) => id !== ruleId));
}
},
[confirmUpgrade, upgradeSpecificRulesRequest]
);
As you can see, all required upgrade steps are located in the method body and are easily readable, no need to split the process into several functions.
Thanks @xcrzx, this is so much easier and tidier.
|
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, @jpdjere, for implementing the suggestions 👍 Verified locally, the modal window works as expected 🎉
💚 Build Succeeded
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 @jpdjere |
Summary
Reintroduces ML Jobs warning popover that was removed during new install/upgrade initial implementation.
ML Jobs warning popover that appears when user has legacy ML jobs installed, and the user attempts to update their prebuilt rules.
Modified behaviour so that the popover now appears in any of the three cases: upgrading all rules, upgrading specific rules and upgrading a single rule.
Testing
In the
state
returned byUpgradePrebuiltRulesTableContextProvider
, replace the value oflegacyJobsInstalled
for a mock value. See below:Checklist
Delete any items that are not applicable to this PR.
For maintainers