Skip to content

Commit

Permalink
addresses comments
Browse files Browse the repository at this point in the history
  • Loading branch information
dplumlee committed Sep 13, 2024
1 parent b427aab commit 97947ba
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const PERFORM_SPECIFIC_RULES_INSTALLATION_KEY = [

export interface UsePerformSpecificRulesInstallParams {
rules: InstallSpecificRulesRequest['rules'];
enableOnInstall?: boolean;
enable?: boolean;
}

export const usePerformSpecificRulesInstallMutation = (
Expand All @@ -54,9 +54,8 @@ export const usePerformSpecificRulesInstallMutation = (
Error,
UsePerformSpecificRulesInstallParams
>(
(rulesToInstall: UsePerformSpecificRulesInstallParams) => {
return performInstallSpecificRules(rulesToInstall.rules);
},
(rulesToInstall: UsePerformSpecificRulesInstallParams) =>
performInstallSpecificRules(rulesToInstall.rules),
{
...options,
mutationKey: PERFORM_SPECIFIC_RULES_INSTALLATION_KEY,
Expand All @@ -70,11 +69,11 @@ export const usePerformSpecificRulesInstallMutation = (
invalidateRuleStatus();
invalidateFetchCoverageOverviewQuery();

const [response, , { enableOnInstall }] = args;
const [response, , { enable }] = args;

if (response && enableOnInstall) {
const idMap = response.results.created.map((rule) => rule.id);
const bulkAction: BulkAction = { type: 'enable', ids: idMap };
if (response && enable) {
const ruleIdsToEnable = response.results.created.map((rule) => rule.id);
const bulkAction: BulkAction = { type: 'enable', ids: ruleIdsToEnable };
mutateAsync({ bulkAction });
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import {
EuiLoadingSpinner,
EuiPopover,
} from '@elastic/eui';
import React, { useState } from 'react';
import React, { useCallback, useMemo } from 'react';
import { useBoolean } from 'react-use';
import { useUserData } from '../../../../../detections/components/user_info';
import { useAddPrebuiltRulesTableContext } from './add_prebuilt_rules_table_context';
import * as i18n from './translations';
Expand All @@ -40,39 +41,46 @@ export const AddPrebuiltRulesHeaderButtons = () => {
const isRuleInstalling = loadingRules.length > 0;
const isRequestInProgress = isRuleInstalling || isRefetching || isUpgradingSecurityPackages;

const [isOverflowPopoverOpen, setOverflowPopover] = useState(false);
const [isOverflowPopoverOpen, setOverflowPopover] = useBoolean(false);

const onButtonClick = () => {
const onOverflowButtonClick = () => {
setOverflowPopover(!isOverflowPopoverOpen);
};

const closeOverflowPopover = () => {
const closeOverflowPopover = useCallback(() => {
setOverflowPopover(false);
};
}, [setOverflowPopover]);

const enableOnClick = () => {
const enableOnClick = useCallback(() => {
installSelectedRules(true);
closeOverflowPopover();
};
}, [closeOverflowPopover, installSelectedRules]);

const overflowItems = [
<EuiContextMenuItem key="copy" icon={'play'} onClick={enableOnClick}>
{i18n.INSTALL_AND_ENABLE_BUTTON_LABEL}
</EuiContextMenuItem>,
];
const installOnClick = useCallback(() => {
installSelectedRules();
}, [installSelectedRules]);

const overflowItems = useMemo(
() => [
<EuiContextMenuItem key="copy" icon={'play'} onClick={enableOnClick}>
{i18n.INSTALL_AND_ENABLE_BUTTON_LABEL}
</EuiContextMenuItem>,
],
[enableOnClick]
);

return (
<EuiFlexGroup alignItems="center" gutterSize="s" responsive={false} wrap={true}>
{shouldDisplayInstallSelectedRulesButton ? (
<>
<EuiFlexItem grow={false}>
<EuiButton
onClick={() => installSelectedRules()}
onClick={installOnClick}
disabled={!canUserEditRules || isRequestInProgress}
data-test-subj="installSelectedRulesButton"
>
{i18n.INSTALL_SELECTED_RULES(numberOfSelectedRules)}
{isRuleInstalling ? <EuiLoadingSpinner size="s" /> : undefined}
{isRuleInstalling && <EuiLoadingSpinner size="s" />}
</EuiButton>
</EuiFlexItem>
<EuiFlexItem grow={false}>
Expand All @@ -83,7 +91,7 @@ export const AddPrebuiltRulesHeaderButtons = () => {
size="m"
iconType="boxesVertical"
aria-label={i18n.INSTALL_RULES_OVERFLOW_BUTTON_ARIA_LABEL}
onClick={onButtonClick}
onClick={onOverflowButtonClick}
disabled={!canUserEditRules || isRequestInProgress}
/>
}
Expand All @@ -107,7 +115,7 @@ export const AddPrebuiltRulesHeaderButtons = () => {
aria-label={i18n.INSTALL_ALL_ARIA_LABEL}
>
{i18n.INSTALL_ALL}
{isRuleInstalling ? <EuiLoadingSpinner size="s" /> : undefined}
{isRuleInstalling && <EuiLoadingSpinner size="s" />}
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,90 +15,104 @@ import {
EuiLoadingSpinner,
EuiPopover,
} from '@elastic/eui';
import React, { useState } from 'react';
import React, { useCallback, useMemo } from 'react';
import { useBoolean } from 'react-use';
import type { Rule } from '../../../../rule_management/logic';
import type { RuleSignatureId } from '../../../../../../common/api/detection_engine';
import type { AddPrebuiltRulesTableActions } from './add_prebuilt_rules_table_context';
import * as i18n from './translations';

export interface PrebuiltRulesInstallButtonProps {
ruleId: RuleSignatureId;
record: Rule;
installOneRule: AddPrebuiltRulesTableActions['installOneRule'];
loadingRules: RuleSignatureId[];
isDisabled: boolean;
}

export const PrebuiltRulesInstallButton = ({
ruleId,
record,
installOneRule,
loadingRules,
isDisabled,
}: {
ruleId: RuleSignatureId;
record: Rule;
installOneRule: AddPrebuiltRulesTableActions['installOneRule'];
loadingRules: RuleSignatureId[];
isDisabled: boolean;
}) => {
}: PrebuiltRulesInstallButtonProps) => {
const isRuleInstalling = loadingRules.includes(ruleId);
const isInstallButtonDisabled = isRuleInstalling || isDisabled;
const [isPopoverOpen, setPopover] = useState(false);
const [isPopoverOpen, setPopover] = useBoolean(false);

const onOverflowButtonClick = () => {
const onOverflowButtonClick = useCallback(() => {
setPopover(!isPopoverOpen);
};
}, [isPopoverOpen, setPopover]);

const closeOverflowPopover = () => {
const closeOverflowPopover = useCallback(() => {
setPopover(false);
};
}, [setPopover]);

const enableOnClick = () => {
const enableOnClick = useCallback(() => {
installOneRule(ruleId, true);
closeOverflowPopover();
};
}, [closeOverflowPopover, installOneRule, ruleId]);

const installOnClick = useCallback(() => {
installOneRule(ruleId);
}, [installOneRule, ruleId]);

const overflowItems = [
<EuiContextMenuItem key="copy" icon={'play'} onClick={enableOnClick}>
{i18n.INSTALL_AND_ENABLE_BUTTON_LABEL}
</EuiContextMenuItem>,
];
const overflowItems = useMemo(
() => [
<EuiContextMenuItem key="copy" icon={'play'} onClick={enableOnClick}>
{i18n.INSTALL_AND_ENABLE_BUTTON_LABEL}
</EuiContextMenuItem>,
],
[enableOnClick]
);

const popoverButton = useMemo(
() => (
<EuiButtonIcon
display="empty"
size="s"
iconType="boxesVertical"
aria-label={i18n.INSTALL_RULES_OVERFLOW_BUTTON_ARIA_LABEL}
onClick={onOverflowButtonClick}
disabled={isInstallButtonDisabled}
/>
),
[isInstallButtonDisabled, onOverflowButtonClick]
);

if (isRuleInstalling) {
return (
<EuiLoadingSpinner
size="s"
data-test-subj={`installSinglePrebuiltRuleButton-loadingSpinner-${ruleId}`}
/>
);
}
return (
<>
{isRuleInstalling ? (
<EuiLoadingSpinner
<EuiFlexGroup responsive={false} gutterSize="xs" alignItems="center">
<EuiFlexItem grow={false}>
<EuiButtonEmpty
size="s"
data-test-subj={`installSinglePrebuiltRuleButton-loadingSpinner-${ruleId}`}
/>
) : (
<EuiFlexGroup responsive={false} gutterSize="xs" alignItems="center">
<EuiFlexItem grow={false}>
<EuiButtonEmpty
size="s"
disabled={isInstallButtonDisabled}
onClick={() => installOneRule(ruleId)}
data-test-subj={`installSinglePrebuiltRuleButton-${ruleId}`}
aria-label={i18n.INSTALL_RULE_BUTTON_ARIA_LABEL(record.name)}
>
{i18n.INSTALL_BUTTON_LABEL}
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiPopover
button={
<EuiButtonIcon
display="empty"
size="s"
iconType="boxesVertical"
aria-label={i18n.INSTALL_RULES_OVERFLOW_BUTTON_ARIA_LABEL}
onClick={onOverflowButtonClick}
disabled={isInstallButtonDisabled}
/>
}
isOpen={isPopoverOpen}
closePopover={closeOverflowPopover}
panelPaddingSize="s"
anchorPosition="downRight"
>
<EuiContextMenuPanel size="s" items={overflowItems} />
</EuiPopover>
</EuiFlexItem>
</EuiFlexGroup>
)}
</>
disabled={isInstallButtonDisabled}
onClick={installOnClick}
data-test-subj={`installSinglePrebuiltRuleButton-${ruleId}`}
aria-label={i18n.INSTALL_RULE_BUTTON_ARIA_LABEL(record.name)}
>
{i18n.INSTALL_BUTTON_LABEL}
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiPopover
button={popoverButton}
isOpen={isPopoverOpen}
closePopover={closeOverflowPopover}
panelPaddingSize="s"
anchorPosition="downRight"
>
<EuiContextMenuPanel size="s" items={overflowItems} />
</EuiPopover>
</EuiFlexItem>
</EuiFlexGroup>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ export interface AddPrebuiltRulesTableState {

export interface AddPrebuiltRulesTableActions {
reFetchRules: () => void;
installOneRule: (ruleId: RuleSignatureId, enableOnInstall?: boolean) => void;
installOneRule: (ruleId: RuleSignatureId, enable?: boolean) => void;
installAllRules: () => void;
installSelectedRules: (enableOnInstall?: boolean) => void;
installSelectedRules: (enable?: boolean) => void;
setFilterOptions: Dispatch<SetStateAction<AddPrebuiltRulesTableFilterOptions>>;
selectRules: (rules: RuleResponse[]) => void;
openRulePreview: (ruleId: RuleSignatureId) => void;
Expand Down Expand Up @@ -140,15 +140,15 @@ export const AddPrebuiltRulesTableContextProvider = ({
const filteredRules = useFilterPrebuiltRulesToInstall({ filterOptions, rules });

const installOneRule = useCallback(
async (ruleId: RuleSignatureId, enableOnInstall?: boolean) => {
async (ruleId: RuleSignatureId, enable?: boolean) => {
const rule = rules.find((r) => r.rule_id === ruleId);
invariant(rule, `Rule with id ${ruleId} not found`);

setLoadingRules((prev) => [...prev, ruleId]);
try {
await installSpecificRulesRequest({
rules: [{ rule_id: ruleId, version: rule.version }],
enableOnInstall,
enable,
});
} finally {
setLoadingRules((prev) => prev.filter((id) => id !== ruleId));
Expand All @@ -158,14 +158,14 @@ export const AddPrebuiltRulesTableContextProvider = ({
);

const installSelectedRules = useCallback(
async (enableOnInstall?: boolean) => {
async (enable?: boolean) => {
const rulesToUpgrade = selectedRules.map((rule) => ({
rule_id: rule.rule_id,
version: rule.version,
}));
setLoadingRules((prev) => [...prev, ...rulesToUpgrade.map((r) => r.rule_id)]);
try {
await installSpecificRulesRequest({ rules: rulesToUpgrade, enableOnInstall });
await installSpecificRulesRequest({ rules: rulesToUpgrade, enable });
} finally {
setLoadingRules((prev) =>
prev.filter((id) => !rulesToUpgrade.some((r) => r.rule_id === id))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ export const INSTALL_BUTTON_LABEL = i18n.translate(
);

export const INSTALL_WITHOUT_ENABLING_BUTTON_LABEL = i18n.translate(
'xpack.securitySolution.detectionEngine.ruleDetails.installButtonLabel',
'xpack.securitySolution.detectionEngine.ruleDetails.installWithoutEnablingButtonLabel',
{
defaultMessage: 'Install without enabling',
}
);

export const INSTALL_AND_ENABLE_BUTTON_LABEL = i18n.translate(
'xpack.securitySolution.detectionEngine.ruleDetails.installButtonLabel',
'xpack.securitySolution.detectionEngine.ruleDetails.installAndEnableButtonLabel',
{
defaultMessage: 'Install and enable',
}
Expand Down

0 comments on commit 97947ba

Please sign in to comment.