[Cloud Security] refetch status and dashboard data until data is indexed (#163005)

## Summary

This PR enables the Compliance Dashboard page (CSP dashboards) to
self-recover from different "no findings" states so that the user
doesn't need to reload the page to see the changes after they perform
onboarding steps (install integration, deploy agent, index data, etc.)

fixes 
- https://github.com/elastic/kibana/issues/156616 

### Recording

d0201ebb-b8f8-4bce-b72e-3fdd85ab79fb

### Checklist

Delete any items that are not applicable to this PR.

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Maxim Kholod 2023-08-08 09:48:44 +02:00 committed by GitHub
parent 1696b864a3
commit 9b087e080b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 358 additions and 85 deletions

View file

@ -212,3 +212,5 @@ export const cloudPostureIntegrations: CloudPostureIntegrations = {
};
export const FINDINGS_DOCS_URL = 'https://ela.st/findings';
export const MIN_VERSION_GCP_CIS = '1.5.0';
export const NO_FINDINGS_STATUS_REFRESH_INTERVAL_MS = 10000;

View file

@ -31,8 +31,7 @@ import type { IndexDetails, PostureTypes } from '../../common/types';
import { cspIntegrationDocsNavigation } from '../common/navigation/constants';
import noDataIllustration from '../assets/illustrations/no_data_illustration.svg';
import { useCspIntegrationLink } from '../common/navigation/use_csp_integration_link';
const REFETCH_INTERVAL_MS = 20000;
import { NO_FINDINGS_STATUS_REFRESH_INTERVAL_MS } from '../common/constants';
const NotDeployed = () => {
// using an existing hook to get agent id and package policy id
@ -248,7 +247,7 @@ const ConfigurationFindingsInstalledEmptyPrompt = ({
* */
export const NoFindingsStates = ({ posturetype }: { posturetype: PostureTypes }) => {
const getSetupStatus = useCspSetupStatusApi({
refetchInterval: REFETCH_INTERVAL_MS,
refetchInterval: NO_FINDINGS_STATUS_REFRESH_INTERVAL_MS,
});
const statusKspm = getSetupStatus.data?.kspm?.status;
const statusCspm = getSetupStatus.data?.cspm?.status;

View file

@ -10,7 +10,7 @@ import React from 'react';
import { coreMock } from '@kbn/core/public/mocks';
import { render, screen } from '@testing-library/react';
import { TestProvider } from '../../test/test_provider';
import { ComplianceDashboard } from '.';
import { ComplianceDashboard, getDefaultTab } from '.';
import { useCspSetupStatusApi } from '../../common/api/use_setup_status_api';
import { useLicenseManagementLocatorApi } from '../../common/api/use_license_management_locator_api';
import { useSubscriptionStatus } from '../../common/hooks/use_subscription_status';
@ -21,6 +21,7 @@ import {
KUBERNETES_DASHBOARD_CONTAINER,
KUBERNETES_DASHBOARD_TAB,
CLOUD_DASHBOARD_TAB,
CLOUD_POSTURE_DASHBOARD_PAGE_HEADER,
} from './test_subjects';
import { mockDashboardData } from './mock';
import { createReactQueryResponse } from '../../test/fixtures/react_query';
@ -29,7 +30,9 @@ import { expectIdsInDoc } from '../../test/utils';
import {
CSPM_INTEGRATION_NOT_INSTALLED_TEST_SUBJECT,
KSPM_INTEGRATION_NOT_INSTALLED_TEST_SUBJECT,
PACKAGE_NOT_INSTALLED_TEST_SUBJECT,
} from '../../components/cloud_posture_page';
import { BaseCspSetupStatus, ComplianceDashboardData, CspStatusCode } from '../../../common/types';
jest.mock('../../common/api/use_setup_status_api');
jest.mock('../../common/api/use_stats_api');
@ -73,10 +76,10 @@ describe('<ComplianceDashboard />', () => {
);
});
const renderComplianceDashboardPage = () => {
const ComplianceDashboardWithTestProviders = () => {
const mockCore = coreMock.createStart();
render(
return (
<TestProvider
core={{
...mockCore,
@ -95,6 +98,51 @@ describe('<ComplianceDashboard />', () => {
);
};
const renderComplianceDashboardPage = () => {
return render(<ComplianceDashboardWithTestProviders />);
};
it('shows package not installed page instead of tabs', () => {
(useCspSetupStatusApi as jest.Mock).mockImplementation(() =>
createReactQueryResponse({
status: 'success',
data: {
kspm: { status: 'not-installed', healthyAgents: 0, installedPackagePolicies: 0 },
cspm: { status: 'not-installed', healthyAgents: 0, installedPackagePolicies: 0 },
isPluginInitialized: false,
indicesDetails: [
{ index: 'logs-cloud_security_posture.findings_latest-default', status: 'empty' },
{ index: 'logs-cloud_security_posture.findings-default*', status: 'empty' },
],
},
})
);
(useKspmStatsApi as jest.Mock).mockImplementation(() => ({
isSuccess: true,
isLoading: false,
data: { stats: { totalFindings: 0 } },
}));
(useCspmStatsApi as jest.Mock).mockImplementation(() => ({
isSuccess: true,
isLoading: false,
data: { stats: { totalFindings: 0 } },
}));
renderComplianceDashboardPage();
expectIdsInDoc({
be: [PACKAGE_NOT_INSTALLED_TEST_SUBJECT, CLOUD_POSTURE_DASHBOARD_PAGE_HEADER],
notToBe: [
NO_FINDINGS_STATUS_TEST_SUBJ.NO_AGENTS_DEPLOYED,
NO_FINDINGS_STATUS_TEST_SUBJ.INDEXING,
NO_FINDINGS_STATUS_TEST_SUBJ.INDEX_TIMEOUT,
NO_FINDINGS_STATUS_TEST_SUBJ.UNPRIVILEGED,
CLOUD_DASHBOARD_CONTAINER,
KUBERNETES_DASHBOARD_CONTAINER,
],
});
});
it('no findings state: not-deployed - shows NotDeployed instead of dashboard', () => {
(useCspSetupStatusApi as jest.Mock).mockImplementation(() =>
createReactQueryResponse({
@ -124,11 +172,13 @@ describe('<ComplianceDashboard />', () => {
renderComplianceDashboardPage();
expectIdsInDoc({
be: [NO_FINDINGS_STATUS_TEST_SUBJ.NO_AGENTS_DEPLOYED],
be: [NO_FINDINGS_STATUS_TEST_SUBJ.NO_AGENTS_DEPLOYED, CLOUD_DASHBOARD_TAB],
notToBe: [
NO_FINDINGS_STATUS_TEST_SUBJ.INDEXING,
NO_FINDINGS_STATUS_TEST_SUBJ.INDEX_TIMEOUT,
NO_FINDINGS_STATUS_TEST_SUBJ.UNPRIVILEGED,
CLOUD_DASHBOARD_CONTAINER,
KUBERNETES_DASHBOARD_CONTAINER,
],
});
});
@ -162,11 +212,53 @@ describe('<ComplianceDashboard />', () => {
renderComplianceDashboardPage();
expectIdsInDoc({
be: [NO_FINDINGS_STATUS_TEST_SUBJ.INDEXING],
be: [NO_FINDINGS_STATUS_TEST_SUBJ.INDEXING, CLOUD_DASHBOARD_TAB],
notToBe: [
NO_FINDINGS_STATUS_TEST_SUBJ.NO_AGENTS_DEPLOYED,
NO_FINDINGS_STATUS_TEST_SUBJ.INDEX_TIMEOUT,
NO_FINDINGS_STATUS_TEST_SUBJ.UNPRIVILEGED,
CLOUD_DASHBOARD_CONTAINER,
KUBERNETES_DASHBOARD_CONTAINER,
],
});
});
it('no findings state: indexing - shows Indexing instead of dashboard when waiting_for_results', () => {
(useCspSetupStatusApi as jest.Mock).mockImplementation(() =>
createReactQueryResponse({
status: 'success',
data: {
kspm: { status: 'waiting_for_results', healthyAgents: 1, installedPackagePolicies: 1 },
cspm: { status: 'waiting_for_results', healthyAgents: 1, installedPackagePolicies: 1 },
installedPackageVersion: '1.2.13',
indicesDetails: [
{ index: 'logs-cloud_security_posture.findings_latest-default', status: 'empty' },
{ index: 'logs-cloud_security_posture.findings-default*', status: 'empty' },
],
},
})
);
(useKspmStatsApi as jest.Mock).mockImplementation(() => ({
isSuccess: true,
isLoading: false,
data: { stats: { totalFindings: 1 } },
}));
(useCspmStatsApi as jest.Mock).mockImplementation(() => ({
isSuccess: true,
isLoading: false,
data: { stats: { totalFindings: 1 } },
}));
renderComplianceDashboardPage();
expectIdsInDoc({
be: [NO_FINDINGS_STATUS_TEST_SUBJ.INDEXING, CLOUD_DASHBOARD_TAB],
notToBe: [
NO_FINDINGS_STATUS_TEST_SUBJ.NO_AGENTS_DEPLOYED,
NO_FINDINGS_STATUS_TEST_SUBJ.INDEX_TIMEOUT,
NO_FINDINGS_STATUS_TEST_SUBJ.UNPRIVILEGED,
CLOUD_DASHBOARD_CONTAINER,
KUBERNETES_DASHBOARD_CONTAINER,
],
});
});
@ -200,11 +292,13 @@ describe('<ComplianceDashboard />', () => {
renderComplianceDashboardPage();
expectIdsInDoc({
be: [NO_FINDINGS_STATUS_TEST_SUBJ.INDEX_TIMEOUT],
be: [NO_FINDINGS_STATUS_TEST_SUBJ.INDEX_TIMEOUT, CLOUD_DASHBOARD_TAB],
notToBe: [
NO_FINDINGS_STATUS_TEST_SUBJ.NO_AGENTS_DEPLOYED,
NO_FINDINGS_STATUS_TEST_SUBJ.INDEXING,
NO_FINDINGS_STATUS_TEST_SUBJ.UNPRIVILEGED,
CLOUD_DASHBOARD_CONTAINER,
KUBERNETES_DASHBOARD_CONTAINER,
],
});
});
@ -238,11 +332,13 @@ describe('<ComplianceDashboard />', () => {
renderComplianceDashboardPage();
expectIdsInDoc({
be: [NO_FINDINGS_STATUS_TEST_SUBJ.UNPRIVILEGED],
be: [NO_FINDINGS_STATUS_TEST_SUBJ.UNPRIVILEGED, CLOUD_DASHBOARD_TAB],
notToBe: [
NO_FINDINGS_STATUS_TEST_SUBJ.NO_AGENTS_DEPLOYED,
NO_FINDINGS_STATUS_TEST_SUBJ.INDEXING,
NO_FINDINGS_STATUS_TEST_SUBJ.INDEX_TIMEOUT,
CLOUD_DASHBOARD_CONTAINER,
KUBERNETES_DASHBOARD_CONTAINER,
],
});
});
@ -276,7 +372,7 @@ describe('<ComplianceDashboard />', () => {
renderComplianceDashboardPage();
expectIdsInDoc({
be: [DASHBOARD_CONTAINER],
be: [CLOUD_DASHBOARD_TAB, DASHBOARD_CONTAINER, CLOUD_DASHBOARD_CONTAINER],
notToBe: [
NO_FINDINGS_STATUS_TEST_SUBJ.INDEX_TIMEOUT,
NO_FINDINGS_STATUS_TEST_SUBJ.NO_AGENTS_DEPLOYED,
@ -315,7 +411,7 @@ describe('<ComplianceDashboard />', () => {
renderComplianceDashboardPage();
expectIdsInDoc({
be: [KUBERNETES_DASHBOARD_CONTAINER],
be: [KUBERNETES_DASHBOARD_TAB, KUBERNETES_DASHBOARD_CONTAINER],
notToBe: [
CLOUD_DASHBOARD_CONTAINER,
NO_FINDINGS_STATUS_TEST_SUBJ.INDEX_TIMEOUT,
@ -354,7 +450,7 @@ describe('<ComplianceDashboard />', () => {
renderComplianceDashboardPage();
expectIdsInDoc({
be: [CLOUD_DASHBOARD_CONTAINER],
be: [CLOUD_DASHBOARD_TAB, CLOUD_DASHBOARD_CONTAINER],
notToBe: [
KUBERNETES_DASHBOARD_CONTAINER,
NO_FINDINGS_STATUS_TEST_SUBJ.INDEX_TIMEOUT,
@ -550,10 +646,12 @@ describe('<ComplianceDashboard />', () => {
data: { stats: { totalFindings: 0 } },
}));
renderComplianceDashboardPage();
const { rerender } = renderComplianceDashboardPage();
screen.getByTestId(CLOUD_DASHBOARD_TAB).click();
rerender(<ComplianceDashboardWithTestProviders />);
expectIdsInDoc({
be: [CSPM_INTEGRATION_NOT_INSTALLED_TEST_SUBJECT],
notToBe: [
@ -607,4 +705,148 @@ describe('<ComplianceDashboard />', () => {
],
});
});
it('should not select default tab is user has already selected one themselves', () => {
(useCspSetupStatusApi as jest.Mock).mockImplementation(() =>
createReactQueryResponse({
status: 'success',
data: {
kspm: { status: 'not-installed' },
cspm: { status: 'indexed' },
installedPackageVersion: '1.2.13',
indicesDetails: [
{ index: 'logs-cloud_security_posture.findings_latest-default', status: 'not-empty' },
{ index: 'logs-cloud_security_posture.findings-default*', status: 'empty' },
],
},
})
);
(useKspmStatsApi as jest.Mock).mockImplementation(() => ({
isSuccess: true,
isLoading: false,
data: { stats: { totalFindings: 0 } },
}));
(useCspmStatsApi as jest.Mock).mockImplementation(() => ({
isSuccess: true,
isLoading: false,
data: mockDashboardData,
}));
const { rerender } = renderComplianceDashboardPage();
expectIdsInDoc({
be: [CLOUD_DASHBOARD_CONTAINER],
notToBe: [
KUBERNETES_DASHBOARD_CONTAINER,
NO_FINDINGS_STATUS_TEST_SUBJ.INDEX_TIMEOUT,
NO_FINDINGS_STATUS_TEST_SUBJ.NO_AGENTS_DEPLOYED,
NO_FINDINGS_STATUS_TEST_SUBJ.INDEXING,
NO_FINDINGS_STATUS_TEST_SUBJ.UNPRIVILEGED,
],
});
screen.getByTestId(KUBERNETES_DASHBOARD_TAB).click();
rerender(<ComplianceDashboardWithTestProviders />);
expectIdsInDoc({
be: [KSPM_INTEGRATION_NOT_INSTALLED_TEST_SUBJECT],
notToBe: [
CLOUD_DASHBOARD_CONTAINER,
NO_FINDINGS_STATUS_TEST_SUBJ.INDEX_TIMEOUT,
NO_FINDINGS_STATUS_TEST_SUBJ.NO_AGENTS_DEPLOYED,
NO_FINDINGS_STATUS_TEST_SUBJ.INDEXING,
NO_FINDINGS_STATUS_TEST_SUBJ.UNPRIVILEGED,
],
});
});
});
describe('getDefaultTab', () => {
const getPluginStatusMock = (cspmStatus: CspStatusCode, kspmStatus: CspStatusCode) => {
return {
cspm: { status: cspmStatus },
kspm: { status: kspmStatus },
};
};
const getStatsMock = (findings: number) => {
return {
stats: {
totalFindings: findings,
},
};
};
it('returns CSPM tab if only CSPM has findings', () => {
const pluginStatus = getPluginStatusMock('indexed', 'indexed') as BaseCspSetupStatus;
const cspmStats = getStatsMock(1) as ComplianceDashboardData;
const kspmStats = getStatsMock(0) as ComplianceDashboardData;
expect(getDefaultTab(pluginStatus, cspmStats, kspmStats)).toEqual('cspm');
});
it('returns CSPM tab if both CSPM and KSPM has findings', () => {
const pluginStatus = getPluginStatusMock('indexed', 'indexed') as BaseCspSetupStatus;
const cspmStats = getStatsMock(1) as ComplianceDashboardData;
const kspmStats = getStatsMock(1) as ComplianceDashboardData;
expect(getDefaultTab(pluginStatus, cspmStats, kspmStats)).toEqual('cspm');
});
it('returns KSPM tab if only KSPM has findings', () => {
const pluginStatus = getPluginStatusMock('indexed', 'indexed') as BaseCspSetupStatus;
const cspmStats = getStatsMock(0) as ComplianceDashboardData;
const kspmStats = getStatsMock(1) as ComplianceDashboardData;
expect(getDefaultTab(pluginStatus, cspmStats, kspmStats)).toEqual('kspm');
});
it('when no findings preffers CSPM tab unless not-installed or unprivileged', () => {
const cspmStats = getStatsMock(0) as ComplianceDashboardData;
const kspmStats = getStatsMock(0) as ComplianceDashboardData;
const CspStatusCodeArray: CspStatusCode[] = [
'indexed',
'indexing',
'unprivileged',
'index-timeout',
'not-deployed',
'not-installed',
'waiting_for_results',
];
CspStatusCodeArray.forEach((cspmStatus) => {
CspStatusCodeArray.forEach((kspmStatus) => {
let expectedTab = 'cspm';
const pluginStatus = getPluginStatusMock(cspmStatus, kspmStatus) as BaseCspSetupStatus;
if (
(cspmStatus === 'not-installed' || cspmStatus === 'unprivileged') &&
kspmStatus !== 'not-installed' &&
kspmStatus !== 'unprivileged'
) {
expectedTab = 'kspm';
}
expect(getDefaultTab(pluginStatus, cspmStats, kspmStats)).toEqual(expectedTab);
});
});
});
it('returns CSPM tab is plugin status and kspm status is not provided', () => {
const cspmStats = getStatsMock(1) as ComplianceDashboardData;
expect(getDefaultTab(undefined, cspmStats, undefined)).toEqual('cspm');
});
it('returns KSPM tab is plugin status and csp status is not provided', () => {
const kspmStats = getStatsMock(1) as ComplianceDashboardData;
expect(getDefaultTab(undefined, undefined, kspmStats)).toEqual('kspm');
});
it('returns CSPM tab when only plugins status data is provided', () => {
const pluginStatus = getPluginStatusMock('indexed', 'indexed') as BaseCspSetupStatus;
expect(getDefaultTab(pluginStatus, undefined, undefined)).toEqual('cspm');
});
});

View file

@ -6,6 +6,7 @@
*/
import React, { useEffect, useMemo, useState } from 'react';
import { UseQueryResult } from '@tanstack/react-query';
import { EuiEmptyPrompt, EuiIcon, EuiLink, EuiPageHeader, EuiSpacer } from '@elastic/eui';
import { css } from '@emotion/react';
import { i18n } from '@kbn/i18n';
@ -40,6 +41,10 @@ import { SummarySection } from './dashboard_sections/summary_section';
import { BenchmarksSection } from './dashboard_sections/benchmarks_section';
import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE } from '../../../common/constants';
import { cspIntegrationDocsNavigation } from '../../common/navigation/constants';
import { NO_FINDINGS_STATUS_REFRESH_INTERVAL_MS } from '../../common/constants';
const POSTURE_TYPE_CSPM = CSPM_POLICY_TEMPLATE;
const POSTURE_TYPE_KSPM = KSPM_POLICY_TEMPLATE;
const noDataOptions: Record<
PosturePolicyTemplate,
@ -181,7 +186,7 @@ const IntegrationPostureDashboard = ({
);
};
const getDefaultTab = (
export const getDefaultTab = (
pluginStatus?: BaseCspSetupStatus,
cspmStats?: ComplianceDashboardData,
kspmStats?: ComplianceDashboardData
@ -190,42 +195,109 @@ const getDefaultTab = (
const kspmTotalFindings = kspmStats?.stats.totalFindings;
const installedPolicyTemplatesCspm = pluginStatus?.cspm?.status;
const installedPolicyTemplatesKspm = pluginStatus?.kspm?.status;
let preferredDashboard = CSPM_POLICY_TEMPLATE;
let preferredDashboard = POSTURE_TYPE_CSPM;
// cspm has findings
if (!!cspmTotalFindings) {
preferredDashboard = CSPM_POLICY_TEMPLATE;
preferredDashboard = POSTURE_TYPE_CSPM;
}
// kspm has findings
else if (!!kspmTotalFindings) {
preferredDashboard = KSPM_POLICY_TEMPLATE;
preferredDashboard = POSTURE_TYPE_KSPM;
}
// cspm is installed
else if (
installedPolicyTemplatesCspm !== 'unprivileged' &&
installedPolicyTemplatesCspm !== 'not-installed'
) {
preferredDashboard = CSPM_POLICY_TEMPLATE;
preferredDashboard = POSTURE_TYPE_CSPM;
}
// kspm is installed
else if (
installedPolicyTemplatesKspm !== 'unprivileged' &&
installedPolicyTemplatesKspm !== 'not-installed'
) {
preferredDashboard = KSPM_POLICY_TEMPLATE;
preferredDashboard = POSTURE_TYPE_KSPM;
}
return preferredDashboard;
};
export const ComplianceDashboard = () => {
const [selectedTab, setSelectedTab] = useState(CSPM_POLICY_TEMPLATE);
const { data: getSetupStatus } = useCspSetupStatusApi();
const determineDashboardDataRefetchInterval = (data: ComplianceDashboardData | undefined) => {
if (data?.stats.totalFindings === 0) {
return NO_FINDINGS_STATUS_REFRESH_INTERVAL_MS;
}
return false;
};
const TabContent = ({ posturetype }: { posturetype: PosturePolicyTemplate }) => {
const { data: getSetupStatus } = useCspSetupStatusApi({
refetchInterval: (data) => {
if (data?.[posturetype]?.status === 'indexed') {
return false;
}
return NO_FINDINGS_STATUS_REFRESH_INTERVAL_MS;
},
});
const isCloudSecurityPostureInstalled = !!getSetupStatus?.installedPackageVersion;
const getCspmDashboardData = useCspmStatsApi({
enabled: isCloudSecurityPostureInstalled && posturetype === POSTURE_TYPE_CSPM,
refetchInterval: determineDashboardDataRefetchInterval,
});
const getKspmDashboardData = useKspmStatsApi({
enabled: isCloudSecurityPostureInstalled && posturetype === POSTURE_TYPE_KSPM,
refetchInterval: determineDashboardDataRefetchInterval,
});
const setupStatus = getSetupStatus?.[posturetype]?.status;
const isStatusManagedInDashboard = setupStatus === 'indexed' || setupStatus === 'not-installed';
const shouldRenderNoFindings = !isCloudSecurityPostureInstalled || !isStatusManagedInDashboard;
const cspmIntegrationLink = useCspIntegrationLink(CSPM_POLICY_TEMPLATE);
const kspmIntegrationLink = useCspIntegrationLink(KSPM_POLICY_TEMPLATE);
const isCloudSecurityPostureInstalled = !!getSetupStatus?.installedPackageVersion;
let integrationLink;
let dataTestSubj;
let policyTemplate: PosturePolicyTemplate;
let getDashboardData: UseQueryResult<ComplianceDashboardData>;
switch (posturetype) {
case POSTURE_TYPE_CSPM:
integrationLink = cspmIntegrationLink;
dataTestSubj = CLOUD_DASHBOARD_CONTAINER;
policyTemplate = CSPM_POLICY_TEMPLATE;
getDashboardData = getCspmDashboardData;
break;
case POSTURE_TYPE_KSPM:
integrationLink = kspmIntegrationLink;
dataTestSubj = KUBERNETES_DASHBOARD_CONTAINER;
policyTemplate = KSPM_POLICY_TEMPLATE;
getDashboardData = getKspmDashboardData;
break;
}
if (shouldRenderNoFindings) {
return <NoFindingsStates posturetype={posturetype} />;
}
return (
<CloudPosturePage query={getDashboardData}>
<div data-test-subj={dataTestSubj}>
<IntegrationPostureDashboard
dashboardType={policyTemplate}
complianceData={getDashboardData.data}
notInstalledConfig={getNotInstalledConfig(policyTemplate, integrationLink)}
isIntegrationInstalled={setupStatus !== 'not-installed'}
/>
</div>
</CloudPosturePage>
);
};
export const ComplianceDashboard = () => {
const [selectedTab, setSelectedTab] = useState(POSTURE_TYPE_CSPM);
const [hasUserSelectedTab, setHasUserSelectedTab] = useState(false);
const { data: getSetupStatus } = useCspSetupStatusApi();
const isCloudSecurityPostureInstalled = !!getSetupStatus?.installedPackageVersion;
const getCspmDashboardData = useCspmStatsApi({
enabled: isCloudSecurityPostureInstalled,
});
@ -234,6 +306,10 @@ export const ComplianceDashboard = () => {
});
useEffect(() => {
if (hasUserSelectedTab) {
return;
}
const preferredDashboard = getDefaultTab(
getSetupStatus,
getCspmDashboardData.data,
@ -248,6 +324,7 @@ export const ComplianceDashboard = () => {
getSetupStatus,
getSetupStatus?.cspm?.status,
getSetupStatus?.kspm?.status,
hasUserSelectedTab,
]);
const tabs = useMemo(
@ -259,75 +336,28 @@ export const ComplianceDashboard = () => {
defaultMessage: 'Cloud',
}),
'data-test-subj': CLOUD_DASHBOARD_TAB,
isSelected: selectedTab === CSPM_POLICY_TEMPLATE,
onClick: () => setSelectedTab(CSPM_POLICY_TEMPLATE),
content: (
<>
{isCloudSecurityPostureInstalled &&
(getSetupStatus?.cspm?.status === 'indexed' ||
getSetupStatus?.cspm?.status === 'not-installed') ? (
<CloudPosturePage query={getCspmDashboardData}>
<div data-test-subj={CLOUD_DASHBOARD_CONTAINER}>
<IntegrationPostureDashboard
dashboardType={CSPM_POLICY_TEMPLATE}
complianceData={getCspmDashboardData.data}
notInstalledConfig={getNotInstalledConfig(
CSPM_POLICY_TEMPLATE,
cspmIntegrationLink
)}
isIntegrationInstalled={getSetupStatus?.cspm?.status !== 'not-installed'}
/>
</div>
</CloudPosturePage>
) : (
<NoFindingsStates posturetype={'cspm'} />
)}
</>
),
isSelected: selectedTab === POSTURE_TYPE_CSPM,
onClick: () => {
setSelectedTab(POSTURE_TYPE_CSPM);
setHasUserSelectedTab(true);
},
content: <TabContent posturetype={POSTURE_TYPE_CSPM} />,
},
{
label: i18n.translate('xpack.csp.dashboardTabs.kubernetesTab.tabTitle', {
defaultMessage: 'Kubernetes',
}),
'data-test-subj': KUBERNETES_DASHBOARD_TAB,
isSelected: selectedTab === KSPM_POLICY_TEMPLATE,
onClick: () => setSelectedTab(KSPM_POLICY_TEMPLATE),
content: (
<>
{isCloudSecurityPostureInstalled &&
(getSetupStatus?.kspm?.status === 'indexed' ||
getSetupStatus?.kspm?.status === 'not-installed') ? (
<CloudPosturePage query={getKspmDashboardData}>
<div data-test-subj={KUBERNETES_DASHBOARD_CONTAINER}>
<IntegrationPostureDashboard
dashboardType={KSPM_POLICY_TEMPLATE}
complianceData={getKspmDashboardData.data}
notInstalledConfig={getNotInstalledConfig(
KSPM_POLICY_TEMPLATE,
kspmIntegrationLink
)}
isIntegrationInstalled={getSetupStatus?.kspm?.status !== 'not-installed'}
/>
</div>
</CloudPosturePage>
) : (
<NoFindingsStates posturetype={'kspm'} />
)}
</>
),
isSelected: selectedTab === POSTURE_TYPE_KSPM,
onClick: () => {
setSelectedTab(POSTURE_TYPE_KSPM);
setHasUserSelectedTab(true);
},
content: <TabContent posturetype={POSTURE_TYPE_KSPM} />,
},
]
: [],
[
cspmIntegrationLink,
getCspmDashboardData,
getKspmDashboardData,
kspmIntegrationLink,
selectedTab,
isCloudSecurityPostureInstalled,
getSetupStatus?.cspm?.status,
getSetupStatus?.kspm?.status,
]
[selectedTab, isCloudSecurityPostureInstalled]
);
return (
@ -354,7 +384,7 @@ export const ComplianceDashboard = () => {
`}
>
{tabs.find((t) => t.isSelected)?.content}
{!isCloudSecurityPostureInstalled && <NoFindingsStates posturetype={'cspm'} />}
{!isCloudSecurityPostureInstalled && <NoFindingsStates posturetype={POSTURE_TYPE_CSPM} />}
</div>
</CloudPosturePage>
);