mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Security Solution] Fix Add Rules Page not refetching rules after package installed in background (#160389)
Fixes https://github.com/elastic/kibana/issues/160396 ## Summary - Invalidates cache after `security_detection_engine` package is installed in the background so rules available for installation and for upgrade are refetched, and their respective tables correctly populated with them. - Disable Install and Upgrade buttons in both tables while the package is being installed in the background to prevent the user from attempting to install/update outdated version. - Add a Loading Skeleton in the Add Elastic Rules when the user navigates to that page while the `security_detection_engine` is being installed for the first time, to prevent the user from seeing a flash of the "No available rules" component, before rules are loaded. ### Checklist Delete any items that are not applicable to this PR. - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))
This commit is contained in:
parent
c30251c46a
commit
2f03a25362
13 changed files with 120 additions and 37 deletions
|
@ -20,6 +20,9 @@ export interface PrebuiltRulesStatusStats {
|
|||
/** Number of installed prebuilt rules available for upgrade (stock + customized) */
|
||||
num_prebuilt_rules_to_upgrade: number;
|
||||
|
||||
/** Total number of prebuilt rules available in package (including already installed) */
|
||||
num_prebuilt_rules_total_in_package: number;
|
||||
|
||||
// In the future we could add more stats such as:
|
||||
// - number of installed prebuilt rules which were deprecated
|
||||
// - number of installed prebuilt rules which are not compatible with the current version of Kibana
|
||||
|
|
|
@ -11,7 +11,9 @@ import { useMutation } from '@tanstack/react-query';
|
|||
import { PREBUILT_RULES_PACKAGE_NAME } from '../../../../../common/detection_engine/constants';
|
||||
import type { BulkInstallFleetPackagesProps } from '../api';
|
||||
import { bulkInstallFleetPackages } from '../api';
|
||||
import { useInvalidateFetchPrebuiltRulesInstallReviewQuery } from './prebuilt_rules/use_fetch_prebuilt_rules_install_review_query';
|
||||
import { useInvalidateFetchPrebuiltRulesStatusQuery } from './prebuilt_rules/use_fetch_prebuilt_rules_status_query';
|
||||
import { useInvalidateFetchPrebuiltRulesUpgradeReviewQuery } from './prebuilt_rules/use_fetch_prebuilt_rules_upgrade_review_query';
|
||||
|
||||
export const BULK_INSTALL_FLEET_PACKAGES_MUTATION_KEY = [
|
||||
'POST',
|
||||
|
@ -22,6 +24,8 @@ export const useBulkInstallFleetPackagesMutation = (
|
|||
options?: UseMutationOptions<BulkInstallPackagesResponse, Error, BulkInstallFleetPackagesProps>
|
||||
) => {
|
||||
const invalidatePrePackagedRulesStatus = useInvalidateFetchPrebuiltRulesStatusQuery();
|
||||
const invalidatePrebuiltRulesInstallReview = useInvalidateFetchPrebuiltRulesInstallReviewQuery();
|
||||
const invalidatePrebuiltRulesUpdateReview = useInvalidateFetchPrebuiltRulesUpgradeReviewQuery();
|
||||
|
||||
return useMutation((props: BulkInstallFleetPackagesProps) => bulkInstallFleetPackages(props), {
|
||||
...options,
|
||||
|
@ -34,6 +38,8 @@ export const useBulkInstallFleetPackagesMutation = (
|
|||
if (rulesPackage && 'result' in rulesPackage && rulesPackage.result.status === 'installed') {
|
||||
// The rules package was installed/updated, so invalidate the pre-packaged rules status query
|
||||
invalidatePrePackagedRulesStatus();
|
||||
invalidatePrebuiltRulesInstallReview();
|
||||
invalidatePrebuiltRulesUpdateReview();
|
||||
}
|
||||
|
||||
if (options?.onSettled) {
|
||||
|
|
|
@ -11,7 +11,9 @@ import { useMutation } from '@tanstack/react-query';
|
|||
import { PREBUILT_RULES_PACKAGE_NAME } from '../../../../../common/detection_engine/constants';
|
||||
import type { InstallFleetPackageProps } from '../api';
|
||||
import { installFleetPackage } from '../api';
|
||||
import { useInvalidateFetchPrebuiltRulesInstallReviewQuery } from './prebuilt_rules/use_fetch_prebuilt_rules_install_review_query';
|
||||
import { useInvalidateFetchPrebuiltRulesStatusQuery } from './prebuilt_rules/use_fetch_prebuilt_rules_status_query';
|
||||
import { useInvalidateFetchPrebuiltRulesUpgradeReviewQuery } from './prebuilt_rules/use_fetch_prebuilt_rules_upgrade_review_query';
|
||||
|
||||
export const INSTALL_FLEET_PACKAGE_MUTATION_KEY = [
|
||||
'POST',
|
||||
|
@ -22,6 +24,8 @@ export const useInstallFleetPackageMutation = (
|
|||
options?: UseMutationOptions<InstallPackageResponse, Error, InstallFleetPackageProps>
|
||||
) => {
|
||||
const invalidatePrePackagedRulesStatus = useInvalidateFetchPrebuiltRulesStatusQuery();
|
||||
const invalidatePrebuiltRulesInstallReview = useInvalidateFetchPrebuiltRulesInstallReviewQuery();
|
||||
const invalidatePrebuiltRulesUpdateReview = useInvalidateFetchPrebuiltRulesUpgradeReviewQuery();
|
||||
|
||||
return useMutation((props: InstallFleetPackageProps) => installFleetPackage(props), {
|
||||
...options,
|
||||
|
@ -31,6 +35,8 @@ export const useInstallFleetPackageMutation = (
|
|||
if (packageName === PREBUILT_RULES_PACKAGE_NAME) {
|
||||
// Invalidate the pre-packaged rules status query as there might be new rules to install
|
||||
invalidatePrePackagedRulesStatus();
|
||||
invalidatePrebuiltRulesInstallReview();
|
||||
invalidatePrebuiltRulesUpdateReview();
|
||||
}
|
||||
|
||||
if (options?.onSettled) {
|
||||
|
|
|
@ -12,7 +12,7 @@ import * as i18n from './translations';
|
|||
|
||||
export const AddPrebuiltRulesHeaderButtons = () => {
|
||||
const {
|
||||
state: { rules, selectedRules, loadingRules },
|
||||
state: { rules, selectedRules, loadingRules, isRefetching, isUpgradingSecurityPackages },
|
||||
actions: { installAllRules, installSelectedRules },
|
||||
} = useAddPrebuiltRulesTableContext();
|
||||
|
||||
|
@ -21,12 +21,13 @@ export const AddPrebuiltRulesHeaderButtons = () => {
|
|||
const shouldDisplayInstallSelectedRulesButton = numberOfSelectedRules > 0;
|
||||
|
||||
const isRuleInstalling = loadingRules.length > 0;
|
||||
const isRequestInProgress = isRuleInstalling || isRefetching || isUpgradingSecurityPackages;
|
||||
|
||||
return (
|
||||
<EuiFlexGroup alignItems="center" gutterSize="s" responsive={false} wrap={true}>
|
||||
{shouldDisplayInstallSelectedRulesButton ? (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton onClick={installSelectedRules} disabled={isRuleInstalling}>
|
||||
<EuiButton onClick={installSelectedRules} disabled={isRequestInProgress}>
|
||||
{i18n.INSTALL_SELECTED_RULES(numberOfSelectedRules)}
|
||||
{isRuleInstalling ? <EuiLoadingSpinner size="s" /> : undefined}
|
||||
</EuiButton>
|
||||
|
@ -38,7 +39,7 @@ export const AddPrebuiltRulesHeaderButtons = () => {
|
|||
iconType="plusInCircle"
|
||||
data-test-subj="installAllRulesButton"
|
||||
onClick={installAllRules}
|
||||
disabled={!isRulesAvailableForInstall || isRuleInstalling}
|
||||
disabled={!isRulesAvailableForInstall || isRequestInProgress}
|
||||
>
|
||||
{i18n.INSTALL_ALL}
|
||||
{isRuleInstalling ? <EuiLoadingSpinner size="s" /> : undefined}
|
||||
|
|
|
@ -14,7 +14,6 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import React from 'react';
|
||||
|
||||
import { useIsUpgradingSecurityPackages } from '../../../../rule_management/logic/use_upgrade_security_packages';
|
||||
import { RULES_TABLE_INITIAL_PAGE_SIZE, RULES_TABLE_PAGE_SIZE_OPTIONS } from '../constants';
|
||||
import { AddPrebuiltRulesTableNoItemsMessage } from './add_prebuilt_rules_no_items_message';
|
||||
import { useAddPrebuiltRulesTableContext } from './add_prebuilt_rules_table_context';
|
||||
|
@ -25,24 +24,29 @@ import { useAddPrebuiltRulesTableColumns } from './use_add_prebuilt_rules_table_
|
|||
* Table Component for displaying new rules that are available to be installed
|
||||
*/
|
||||
export const AddPrebuiltRulesTable = React.memo(() => {
|
||||
const isUpgradingSecurityPackages = useIsUpgradingSecurityPackages();
|
||||
|
||||
const addRulesTableContext = useAddPrebuiltRulesTableContext();
|
||||
|
||||
const {
|
||||
state: { rules, filteredRules, isFetched, isLoading, isRefetching, selectedRules },
|
||||
state: {
|
||||
rules,
|
||||
filteredRules,
|
||||
isFetched,
|
||||
isLoading,
|
||||
isRefetching,
|
||||
selectedRules,
|
||||
isUpgradingSecurityPackages,
|
||||
},
|
||||
actions: { selectRules },
|
||||
} = addRulesTableContext;
|
||||
const rulesColumns = useAddPrebuiltRulesTableColumns();
|
||||
|
||||
const isTableEmpty = isFetched && rules.length === 0;
|
||||
|
||||
const shouldShowLinearProgress = (isFetched && isRefetching) || isUpgradingSecurityPackages;
|
||||
const shouldShowLoadingOverlay = !isFetched && isRefetching;
|
||||
const shouldShowProgress = isUpgradingSecurityPackages || isRefetching;
|
||||
|
||||
return (
|
||||
<>
|
||||
{shouldShowLinearProgress && (
|
||||
{shouldShowProgress && (
|
||||
<EuiProgress
|
||||
data-test-subj="loadingRulesInfoProgress"
|
||||
size="xs"
|
||||
|
@ -51,7 +55,7 @@ export const AddPrebuiltRulesTable = React.memo(() => {
|
|||
/>
|
||||
)}
|
||||
<EuiSkeletonLoading
|
||||
isLoading={isLoading || shouldShowLoadingOverlay}
|
||||
isLoading={isLoading}
|
||||
loadingContent={
|
||||
<>
|
||||
<EuiSkeletonTitle />
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
import type { Dispatch, SetStateAction } from 'react';
|
||||
import React, { createContext, useCallback, useContext, useMemo, useState } from 'react';
|
||||
import { useFetchPrebuiltRulesStatusQuery } from '../../../../rule_management/api/hooks/prebuilt_rules/use_fetch_prebuilt_rules_status_query';
|
||||
import { useIsUpgradingSecurityPackages } from '../../../../rule_management/logic/use_upgrade_security_packages';
|
||||
import type { RuleInstallationInfoForReview } from '../../../../../../common/detection_engine/prebuilt_rules/api/review_rule_installation/response_schema';
|
||||
import type { RuleSignatureId } from '../../../../../../common/detection_engine/rule_schema';
|
||||
import { invariant } from '../../../../../../common/utils/invariant';
|
||||
|
@ -47,6 +49,11 @@ export interface AddPrebuiltRulesTableState {
|
|||
* Is true whenever a background refetch is in-flight, which does not include initial loading
|
||||
*/
|
||||
isRefetching: boolean;
|
||||
/**
|
||||
* Is true when installing security_detection_rules
|
||||
* package in background
|
||||
*/
|
||||
isUpgradingSecurityPackages: boolean;
|
||||
/**
|
||||
* List of rule IDs that are currently being upgraded
|
||||
*/
|
||||
|
@ -92,6 +99,10 @@ export const AddPrebuiltRulesTableContextProvider = ({
|
|||
tags: [],
|
||||
});
|
||||
|
||||
const { data: prebuiltRulesStatus } = useFetchPrebuiltRulesStatusQuery();
|
||||
|
||||
const isUpgradingSecurityPackages = useIsUpgradingSecurityPackages();
|
||||
|
||||
const {
|
||||
data: { rules, stats: { tags } } = {
|
||||
rules: [],
|
||||
|
@ -105,6 +116,12 @@ export const AddPrebuiltRulesTableContextProvider = ({
|
|||
} = usePrebuiltRulesInstallReview({
|
||||
refetchInterval: 60000, // Refetch available rules for installation every minute
|
||||
keepPreviousData: true, // Use this option so that the state doesn't jump between "success" and "loading" on page change
|
||||
// Fetch rules to install only after background installation of security_detection_rules package is complete
|
||||
enabled: Boolean(
|
||||
!isUpgradingSecurityPackages &&
|
||||
prebuiltRulesStatus &&
|
||||
prebuiltRulesStatus.num_prebuilt_rules_total_in_package > 0
|
||||
),
|
||||
});
|
||||
|
||||
const { mutateAsync: installAllRulesRequest } = usePerformInstallAllRules();
|
||||
|
@ -175,6 +192,7 @@ export const AddPrebuiltRulesTableContextProvider = ({
|
|||
isLoading,
|
||||
loadingRules,
|
||||
isRefetching,
|
||||
isUpgradingSecurityPackages,
|
||||
selectedRules,
|
||||
lastUpdated: dataUpdatedAt,
|
||||
},
|
||||
|
@ -189,6 +207,7 @@ export const AddPrebuiltRulesTableContextProvider = ({
|
|||
isLoading,
|
||||
loadingRules,
|
||||
isRefetching,
|
||||
isUpgradingSecurityPackages,
|
||||
selectedRules,
|
||||
dataUpdatedAt,
|
||||
actions,
|
||||
|
|
|
@ -85,14 +85,20 @@ const INTEGRATIONS_COLUMN: TableColumn = {
|
|||
|
||||
const createInstallButtonColumn = (
|
||||
installOneRule: AddPrebuiltRulesTableActions['installOneRule'],
|
||||
loadingRules: RuleSignatureId[]
|
||||
loadingRules: RuleSignatureId[],
|
||||
isDisabled: boolean
|
||||
): TableColumn => ({
|
||||
field: 'rule_id',
|
||||
name: '',
|
||||
render: (ruleId: RuleSignatureId) => {
|
||||
const isRuleInstalling = loadingRules.includes(ruleId);
|
||||
const isInstallButtonDisabled = isRuleInstalling || isDisabled;
|
||||
return (
|
||||
<EuiButtonEmpty size="s" disabled={isRuleInstalling} onClick={() => installOneRule(ruleId)}>
|
||||
<EuiButtonEmpty
|
||||
size="s"
|
||||
disabled={isInstallButtonDisabled}
|
||||
onClick={() => installOneRule(ruleId)}
|
||||
>
|
||||
{isRuleInstalling ? <EuiLoadingSpinner size="s" /> : i18n.INSTALL_RULE_BUTTON}
|
||||
</EuiButtonEmpty>
|
||||
);
|
||||
|
@ -106,10 +112,12 @@ export const useAddPrebuiltRulesTableColumns = (): TableColumn[] => {
|
|||
const hasCRUDPermissions = hasUserCRUDPermission(canUserCRUD);
|
||||
const [showRelatedIntegrations] = useUiSetting$<boolean>(SHOW_RELATED_INTEGRATIONS_SETTING);
|
||||
const {
|
||||
state: { loadingRules },
|
||||
state: { loadingRules, isRefetching, isUpgradingSecurityPackages },
|
||||
actions: { installOneRule },
|
||||
} = useAddPrebuiltRulesTableContext();
|
||||
|
||||
const isDisabled = isRefetching || isUpgradingSecurityPackages;
|
||||
|
||||
return useMemo(
|
||||
() => [
|
||||
RULE_NAME_COLUMN,
|
||||
|
@ -135,8 +143,10 @@ export const useAddPrebuiltRulesTableColumns = (): TableColumn[] => {
|
|||
truncateText: true,
|
||||
width: '12%',
|
||||
},
|
||||
...(hasCRUDPermissions ? [createInstallButtonColumn(installOneRule, loadingRules)] : []),
|
||||
...(hasCRUDPermissions
|
||||
? [createInstallButtonColumn(installOneRule, loadingRules, isDisabled)]
|
||||
: []),
|
||||
],
|
||||
[hasCRUDPermissions, installOneRule, loadingRules, showRelatedIntegrations]
|
||||
[hasCRUDPermissions, installOneRule, loadingRules, isDisabled, showRelatedIntegrations]
|
||||
);
|
||||
};
|
||||
|
|
|
@ -17,7 +17,6 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import * as i18n from '../../../../../detections/pages/detection_engine/rules/translations';
|
||||
import { useIsUpgradingSecurityPackages } from '../../../../rule_management/logic/use_upgrade_security_packages';
|
||||
import { RULES_TABLE_INITIAL_PAGE_SIZE, RULES_TABLE_PAGE_SIZE_OPTIONS } from '../constants';
|
||||
import { UpgradePrebuiltRulesTableButtons } from './upgrade_prebuilt_rules_table_buttons';
|
||||
import { useUpgradePrebuiltRulesTableContext } from './upgrade_prebuilt_rules_table_context';
|
||||
|
@ -36,24 +35,29 @@ const NO_ITEMS_MESSAGE = (
|
|||
* Table Component for displaying rules that have available updates
|
||||
*/
|
||||
export const UpgradePrebuiltRulesTable = React.memo(() => {
|
||||
const isUpgradingSecurityPackages = useIsUpgradingSecurityPackages();
|
||||
|
||||
const upgradeRulesTableContext = useUpgradePrebuiltRulesTableContext();
|
||||
|
||||
const {
|
||||
state: { rules, filteredRules, isFetched, isLoading, isRefetching, selectedRules },
|
||||
state: {
|
||||
rules,
|
||||
filteredRules,
|
||||
isFetched,
|
||||
isLoading,
|
||||
selectedRules,
|
||||
isRefetching,
|
||||
isUpgradingSecurityPackages,
|
||||
},
|
||||
actions: { selectRules },
|
||||
} = upgradeRulesTableContext;
|
||||
const rulesColumns = useUpgradePrebuiltRulesTableColumns();
|
||||
|
||||
const isTableEmpty = isFetched && rules.length === 0;
|
||||
|
||||
const shouldShowLinearProgress = (isFetched && isRefetching) || isUpgradingSecurityPackages;
|
||||
const shouldShowLoadingOverlay = !isFetched && isRefetching;
|
||||
const shouldShowProgress = isUpgradingSecurityPackages || isRefetching;
|
||||
|
||||
return (
|
||||
<>
|
||||
{shouldShowLinearProgress && (
|
||||
{shouldShowProgress && (
|
||||
<EuiProgress
|
||||
data-test-subj="loadingRulesInfoProgress"
|
||||
size="xs"
|
||||
|
@ -62,7 +66,7 @@ export const UpgradePrebuiltRulesTable = React.memo(() => {
|
|||
/>
|
||||
)}
|
||||
<EuiSkeletonLoading
|
||||
isLoading={isLoading || shouldShowLoadingOverlay}
|
||||
isLoading={isLoading}
|
||||
loadingContent={
|
||||
<>
|
||||
<EuiSkeletonTitle />
|
||||
|
|
|
@ -12,7 +12,7 @@ import { useUpgradePrebuiltRulesTableContext } from './upgrade_prebuilt_rules_ta
|
|||
|
||||
export const UpgradePrebuiltRulesTableButtons = () => {
|
||||
const {
|
||||
state: { rules, selectedRules, loadingRules },
|
||||
state: { rules, selectedRules, loadingRules, isRefetching, isUpgradingSecurityPackages },
|
||||
actions: { upgradeAllRules, upgradeSelectedRules },
|
||||
} = useUpgradePrebuiltRulesTableContext();
|
||||
|
||||
|
@ -21,12 +21,13 @@ export const UpgradePrebuiltRulesTableButtons = () => {
|
|||
const shouldDisplayUpgradeSelectedRulesButton = numberOfSelectedRules > 0;
|
||||
|
||||
const isRuleUpgrading = loadingRules.length > 0;
|
||||
const isRequestInProgress = isRuleUpgrading || isRefetching || isUpgradingSecurityPackages;
|
||||
|
||||
return (
|
||||
<EuiFlexGroup alignItems="center" gutterSize="s" responsive={false} wrap={true}>
|
||||
{shouldDisplayUpgradeSelectedRulesButton ? (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton onClick={upgradeSelectedRules} disabled={isRuleUpgrading}>
|
||||
<EuiButton onClick={upgradeSelectedRules} disabled={isRequestInProgress}>
|
||||
<>
|
||||
{i18n.UPDATE_SELECTED_RULES(numberOfSelectedRules)}
|
||||
{isRuleUpgrading ? <EuiLoadingSpinner size="s" /> : undefined}
|
||||
|
@ -39,7 +40,7 @@ export const UpgradePrebuiltRulesTableButtons = () => {
|
|||
fill
|
||||
iconType="plusInCircle"
|
||||
onClick={upgradeAllRules}
|
||||
disabled={!isRulesAvailableForUpgrade || isRuleUpgrading}
|
||||
disabled={!isRulesAvailableForUpgrade || isRequestInProgress}
|
||||
>
|
||||
{i18n.UPDATE_ALL}
|
||||
{isRuleUpgrading ? <EuiLoadingSpinner size="s" /> : undefined}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import type { Dispatch, SetStateAction } from 'react';
|
||||
import React, { createContext, useCallback, useContext, useMemo, useState } from 'react';
|
||||
import { useIsUpgradingSecurityPackages } from '../../../../rule_management/logic/use_upgrade_security_packages';
|
||||
import { useInstalledSecurityJobs } from '../../../../../common/components/ml/hooks/use_installed_security_jobs';
|
||||
import { useBoolState } from '../../../../../common/hooks/use_bool_state';
|
||||
import { affectedJobIds } from '../../../../../detections/components/callouts/ml_job_compatibility_callout/affected_job_ids';
|
||||
|
@ -53,6 +54,11 @@ export interface UpgradePrebuiltRulesTableState {
|
|||
* Is true whenever a background refetch is in-flight, which does not include initial loading
|
||||
*/
|
||||
isRefetching: boolean;
|
||||
/**
|
||||
* Is true when installing security_detection_rules
|
||||
* package in background
|
||||
*/
|
||||
isUpgradingSecurityPackages: boolean;
|
||||
/**
|
||||
* List of rule IDs that are currently being upgraded
|
||||
*/
|
||||
|
@ -100,6 +106,8 @@ export const UpgradePrebuiltRulesTableContextProvider = ({
|
|||
tags: [],
|
||||
});
|
||||
|
||||
const isUpgradingSecurityPackages = useIsUpgradingSecurityPackages();
|
||||
|
||||
const {
|
||||
data: { rules, stats: { tags } } = {
|
||||
rules: [],
|
||||
|
@ -211,11 +219,10 @@ export const UpgradePrebuiltRulesTableContextProvider = ({
|
|||
isFetched,
|
||||
isLoading: isLoading && loadingJobs,
|
||||
isRefetching,
|
||||
isUpgradingSecurityPackages,
|
||||
selectedRules,
|
||||
loadingRules,
|
||||
lastUpdated: dataUpdatedAt,
|
||||
legacyJobsInstalled,
|
||||
isUpgradeModalVisible,
|
||||
},
|
||||
actions,
|
||||
};
|
||||
|
@ -228,11 +235,10 @@ export const UpgradePrebuiltRulesTableContextProvider = ({
|
|||
isLoading,
|
||||
loadingJobs,
|
||||
isRefetching,
|
||||
isUpgradingSecurityPackages,
|
||||
selectedRules,
|
||||
loadingRules,
|
||||
dataUpdatedAt,
|
||||
legacyJobsInstalled,
|
||||
isUpgradeModalVisible,
|
||||
actions,
|
||||
]);
|
||||
|
||||
|
|
|
@ -85,14 +85,20 @@ const INTEGRATIONS_COLUMN: TableColumn = {
|
|||
|
||||
const createUpgradeButtonColumn = (
|
||||
upgradeOneRule: UpgradePrebuiltRulesTableActions['upgradeOneRule'],
|
||||
loadingRules: RuleSignatureId[]
|
||||
loadingRules: RuleSignatureId[],
|
||||
isDisabled: boolean
|
||||
): TableColumn => ({
|
||||
field: 'rule_id',
|
||||
name: '',
|
||||
render: (ruleId: RuleUpgradeInfoForReview['rule_id']) => {
|
||||
const isRuleUpgrading = loadingRules.includes(ruleId);
|
||||
const isUpgradeButtonDisabled = isRuleUpgrading || isDisabled;
|
||||
return (
|
||||
<EuiButtonEmpty size="s" disabled={isRuleUpgrading} onClick={() => upgradeOneRule(ruleId)}>
|
||||
<EuiButtonEmpty
|
||||
size="s"
|
||||
disabled={isUpgradeButtonDisabled}
|
||||
onClick={() => upgradeOneRule(ruleId)}
|
||||
>
|
||||
{isRuleUpgrading ? <EuiLoadingSpinner size="s" /> : i18n.UPDATE_RULE_BUTTON}
|
||||
</EuiButtonEmpty>
|
||||
);
|
||||
|
@ -106,10 +112,12 @@ export const useUpgradePrebuiltRulesTableColumns = (): TableColumn[] => {
|
|||
const hasCRUDPermissions = hasUserCRUDPermission(canUserCRUD);
|
||||
const [showRelatedIntegrations] = useUiSetting$<boolean>(SHOW_RELATED_INTEGRATIONS_SETTING);
|
||||
const {
|
||||
state: { loadingRules },
|
||||
state: { loadingRules, isRefetching, isUpgradingSecurityPackages },
|
||||
actions: { upgradeOneRule },
|
||||
} = useUpgradePrebuiltRulesTableContext();
|
||||
|
||||
const isDisabled = isRefetching || isUpgradingSecurityPackages;
|
||||
|
||||
return useMemo(
|
||||
() => [
|
||||
RULE_NAME_COLUMN,
|
||||
|
@ -136,8 +144,10 @@ export const useUpgradePrebuiltRulesTableColumns = (): TableColumn[] => {
|
|||
truncateText: true,
|
||||
width: '12%',
|
||||
},
|
||||
...(hasCRUDPermissions ? [createUpgradeButtonColumn(upgradeOneRule, loadingRules)] : []),
|
||||
...(hasCRUDPermissions
|
||||
? [createUpgradeButtonColumn(upgradeOneRule, loadingRules, isDisabled)]
|
||||
: []),
|
||||
],
|
||||
[hasCRUDPermissions, loadingRules, showRelatedIntegrations, upgradeOneRule]
|
||||
[hasCRUDPermissions, loadingRules, isDisabled, showRelatedIntegrations, upgradeOneRule]
|
||||
);
|
||||
};
|
||||
|
|
|
@ -38,7 +38,7 @@ export const getPrebuiltRulesStatusRoute = (router: SecuritySolutionPluginRouter
|
|||
ruleAssetsClient,
|
||||
ruleObjectsClient,
|
||||
});
|
||||
const { currentRules, installableRules, upgradeableRules } =
|
||||
const { currentRules, installableRules, upgradeableRules, totalAvailableRules } =
|
||||
getVersionBuckets(ruleVersionsMap);
|
||||
|
||||
const body: GetPrebuiltRulesStatusResponseBody = {
|
||||
|
@ -46,6 +46,7 @@ export const getPrebuiltRulesStatusRoute = (router: SecuritySolutionPluginRouter
|
|||
num_prebuilt_rules_installed: currentRules.length,
|
||||
num_prebuilt_rules_to_install: installableRules.length,
|
||||
num_prebuilt_rules_to_upgrade: upgradeableRules.length,
|
||||
num_prebuilt_rules_total_in_package: totalAvailableRules.length,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -31,14 +31,25 @@ export interface VersionBuckets {
|
|||
*/
|
||||
target: PrebuiltRuleAsset;
|
||||
}>;
|
||||
/**
|
||||
* All available rules
|
||||
* (installed and not installed)
|
||||
*/
|
||||
totalAvailableRules: PrebuiltRuleAsset[];
|
||||
}
|
||||
|
||||
export const getVersionBuckets = (ruleVersionsMap: Map<string, RuleVersions>): VersionBuckets => {
|
||||
const currentRules: RuleResponse[] = [];
|
||||
const installableRules: PrebuiltRuleAsset[] = [];
|
||||
const totalAvailableRules: PrebuiltRuleAsset[] = [];
|
||||
const upgradeableRules: VersionBuckets['upgradeableRules'] = [];
|
||||
|
||||
ruleVersionsMap.forEach(({ current, target }) => {
|
||||
if (target != null) {
|
||||
// If this rule is available in the package
|
||||
totalAvailableRules.push(target);
|
||||
}
|
||||
|
||||
if (current != null) {
|
||||
// If this rule is installed
|
||||
currentRules.push(current);
|
||||
|
@ -62,5 +73,6 @@ export const getVersionBuckets = (ruleVersionsMap: Map<string, RuleVersions>): V
|
|||
currentRules,
|
||||
installableRules,
|
||||
upgradeableRules,
|
||||
totalAvailableRules,
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue