Skip to content

Commit

Permalink
Dashboard review changes (elastic#87)
Browse files Browse the repository at this point in the history
  • Loading branch information
JordanSh authored Jan 6, 2022
1 parent c303a4a commit f876d4e
Show file tree
Hide file tree
Showing 19 changed files with 184 additions and 180 deletions.
13 changes: 8 additions & 5 deletions x-pack/plugins/cloud_security_posture/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,24 @@ export type Evaluation = 'passed' | 'failed' | 'NA';
/** number between 1-100 */
export type Score = number;

export interface BenchmarkStats {
name: string;
export interface Stats {
postureScore?: Score;
totalFindings?: number;
totalPassed?: number;
totalFailed?: number;
}

export interface EvaluationStats {
export interface BenchmarkStats extends Stats {
name: string;
}

export interface EvaluationResult {
resource: string;
value: number;
evaluation: Evaluation;
}

export interface CloudPostureStats extends BenchmarkStats {
export interface CloudPostureStats extends Stats {
benchmarksStats: BenchmarkStats[];
resourcesEvaluations: EvaluationStats[];
resourcesEvaluations: EvaluationResult[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import { useKibana } from '../../../../../../src/plugins/kibana_react/public';
import { CloudPostureStats } from '../../../common/types';
import { STATS_ROUTE_PATH } from '../../../common/constants';

const getStatsKey = 'csp_dashboard_stats';

export const useCloudPostureStatsApi = () => {
const { http } = useKibana().services;
return useQuery(['csp_dashboard_stats'], () => http!.get<CloudPostureStats>(STATS_ROUTE_PATH));
return useQuery([getStatsKey], () => http!.get<CloudPostureStats>(STATS_ROUTE_PATH));
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import { useHistory } from 'react-router-dom';
import { CSP_FINDINGS_PATH } from './constants';

export const useNavigateToCSPFindings = () => {
export const useNavigateToCspFindings = () => {
const history = useHistory();

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,47 +6,42 @@
*/

import React from 'react';
import { render } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import { ChartPanel } from './chart_panel';
import { CHART_PANEL_TEST_SUBJECTS } from './constants';
import Chance from 'chance';

const testData = 'test';
const chance = new Chance();
const testData = chance.word();

const TestingChart = ({ data }: { data: string }) => {
return <div data-test-subj="testing-chart">{data}</div>;
const TestingChart = ({ data }: { data: string | undefined }) => {
return <div data-test-subj={CHART_PANEL_TEST_SUBJECTS.TEST_CHART}>{data}</div>;
};

describe('Testing chart panel display state', () => {
describe('<ChartPanel />', () => {
it('renders loading state', () => {
const component = render(
<ChartPanel isLoading={true} isError={false} data={testData} chart={TestingChart} />
);
expect(component.getByTestId('loading')).toBeInTheDocument();
expect(component.queryByTestId('testing-chart')).not.toBeInTheDocument();
render(<ChartPanel isLoading={true} isError={false} data={testData} chart={TestingChart} />);
expect(screen.getByTestId(CHART_PANEL_TEST_SUBJECTS.LOADING)).toBeInTheDocument();
expect(screen.queryByTestId(CHART_PANEL_TEST_SUBJECTS.TEST_CHART)).not.toBeInTheDocument();
});

it('renders error state', () => {
const component = render(
<ChartPanel isLoading={false} isError={true} data={testData} chart={TestingChart} />
);
expect(component.getByTestId('error')).toBeInTheDocument();
expect(component.queryByTestId('testing-chart')).not.toBeInTheDocument();
render(<ChartPanel isLoading={false} isError={true} data={testData} chart={TestingChart} />);
expect(screen.getByTestId(CHART_PANEL_TEST_SUBJECTS.ERROR)).toBeInTheDocument();
expect(screen.queryByTestId(CHART_PANEL_TEST_SUBJECTS.TEST_CHART)).not.toBeInTheDocument();
});

it('renders empty state', () => {
const component = render(
<ChartPanel isLoading={false} isError={false} data={undefined} chart={TestingChart} />
);
expect(component.getByTestId('empty')).toBeInTheDocument();
expect(component.queryByTestId('testing-chart')).not.toBeInTheDocument();
render(<ChartPanel isLoading={false} isError={false} data={undefined} chart={TestingChart} />);
expect(screen.getByTestId(CHART_PANEL_TEST_SUBJECTS.EMPTY)).toBeInTheDocument();
expect(screen.queryByTestId(CHART_PANEL_TEST_SUBJECTS.TEST_CHART)).not.toBeInTheDocument();
});

it('renders chart component', () => {
const component = render(
<ChartPanel isLoading={false} isError={false} data={testData} chart={TestingChart} />
);
expect(component.queryByTestId('loading')).not.toBeInTheDocument();
expect(component.queryByTestId('error')).not.toBeInTheDocument();
expect(component.queryByTestId('empty')).not.toBeInTheDocument();
expect(component.getByTestId('testing-chart')).toBeInTheDocument();
render(<ChartPanel isLoading={false} isError={false} data={testData} chart={TestingChart} />);
expect(screen.queryByTestId(CHART_PANEL_TEST_SUBJECTS.LOADING)).not.toBeInTheDocument();
expect(screen.queryByTestId(CHART_PANEL_TEST_SUBJECTS.ERROR)).not.toBeInTheDocument();
expect(screen.queryByTestId(CHART_PANEL_TEST_SUBJECTS.EMPTY)).not.toBeInTheDocument();
expect(screen.getByTestId(CHART_PANEL_TEST_SUBJECTS.TEST_CHART)).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,50 +6,63 @@
*/

import React, { useCallback } from 'react';
import styled from 'styled-components';
import { css } from '@emotion/react';
import { EuiPanel, EuiText, EuiTitle, EuiLoadingChart, EuiFlexGroup } from '@elastic/eui';
import { CHART_PANEL_TEST_SUBJECTS } from './constants';

interface ChartPanelProps {
interface ChartPanelProps<TData = unknown> {
title?: string;
description?: string;
hasBorder?: boolean;
isLoading: boolean;
isError: boolean;
data: any;
chart: React.FC<{ data: any }>;
data: TData;
chart: React.FC<{ data: TData }>;
}

const Loading = () => (
<EuiFlexGroup justifyContent="center" alignItems="center" data-test-subj="loading">
<EuiFlexGroup
justifyContent="center"
alignItems="center"
data-test-subj={CHART_PANEL_TEST_SUBJECTS.LOADING}
>
<EuiLoadingChart size="m" />
</EuiFlexGroup>
);

const Error = () => (
<EuiFlexGroup justifyContent="center" alignItems="center" data-test-subj="error">
<EuiFlexGroup
justifyContent="center"
alignItems="center"
data-test-subj={CHART_PANEL_TEST_SUBJECTS.ERROR}
>
<EuiText size="xs" color="subdued">
{'Error'}
</EuiText>
</EuiFlexGroup>
);

const Empty = () => (
<EuiFlexGroup justifyContent="center" alignItems="center" data-test-subj="empty">
<EuiFlexGroup
justifyContent="center"
alignItems="center"
data-test-subj={CHART_PANEL_TEST_SUBJECTS.EMPTY}
>
<EuiText size="xs" color="subdued">
{'No data to display'}
</EuiText>
</EuiFlexGroup>
);

export const ChartPanel = ({
export const ChartPanel = <TData extends unknown>({
title,
description,
hasBorder = true,
chart: Chart,
isLoading,
isError,
data,
}: ChartPanelProps) => {
}: ChartPanelProps<TData>) => {
const renderChart = useCallback(() => {
if (isLoading) return <Loading />;
if (isError) return <Error />;
Expand All @@ -61,9 +74,9 @@ export const ChartPanel = ({
<EuiPanel hasBorder={hasBorder} hasShadow={false} data-test-subj="chart-panel">
<EuiFlexGroup direction="column" gutterSize="xs">
{title && (
<StyledEuiTitle size="s">
<EuiTitle size="s" css={euiTitleStyle}>
<h3>{title}</h3>
</StyledEuiTitle>
</EuiTitle>
)}
{description && (
<EuiText size="xs" color="subdued">
Expand All @@ -76,6 +89,6 @@ export const ChartPanel = ({
);
};

const StyledEuiTitle = styled(EuiTitle)`
const euiTitleStyle = css`
font-weight: 400;
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

export const CHART_PANEL_TEST_SUBJECTS = {
LOADING: 'chart_is_loading',
EMPTY: 'chart_is_empty',
ERROR: 'chart_is_error',
TEST_CHART: 'testing_chart',
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@
*/

import React from 'react';
import { EuiBadge } from '@elastic/eui';
import { EuiBadge, EuiBadgeProps } from '@elastic/eui';

interface Props {
type: 'passed' | 'failed';
}

export const CSPEvaluationBadge = ({ type }: Props) => (
<EuiBadge color={type === 'passed' ? 'success' : type === 'failed' ? 'danger' : 'default'}>
{type.toUpperCase()}
</EuiBadge>
const getColor = (type: Props['type']): EuiBadgeProps['color'] => {
if (type === 'passed') return 'success';
if (type === 'failed') return 'danger';
return 'default';
};

export const CspEvaluationBadge = ({ type }: Props) => (
<EuiBadge color={getColor(type)}>{type.toUpperCase()}</EuiBadge>
);
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface Props {
value: Score;
}

export const CSPHealthBadge = ({ value }: Props) => {
export const CspHealthBadge = ({ value }: Props) => {
if (value <= 65) return <EuiBadge color="danger">{'Critical'}</EuiBadge>;
if (value <= 86) return <EuiBadge color="warning">{'Warning'}</EuiBadge>;
if (value <= 100) return <EuiBadge color="success">{'Healthy'}</EuiBadge>;
Expand Down
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@
*/

import React from 'react';
import { Chart, Datum, Partition, PartitionLayout, Settings } from '@elastic/charts';
import {
Chart,
Datum,
ElementClickListener,
Partition,
PartitionLayout,
Settings,
} from '@elastic/charts';
import { EuiText } from '@elastic/eui';
import { useNavigateToCSPFindings } from '../../../common/navigation/use_navigate_to_csp_findings';
import type { BenchmarkStats } from '../../../../common/types';
import type { PartitionElementEvent } from '@elastic/charts';
import { statusColors } from '../../../common/constants';
import type { BenchmarkStats } from '../../../../common/types';
import { useNavigateToCspFindings } from '../../../common/navigation/use_navigate_to_csp_findings';

interface CloudPostureScoreChartProps {
data: BenchmarkStats;
Expand All @@ -19,17 +27,16 @@ interface CloudPostureScoreChartProps {
export const CloudPostureScoreChart = ({
data: { totalPassed, totalFailed, name: benchmarkName },
}: CloudPostureScoreChartProps) => {
const { navigate } = useNavigateToCSPFindings();
const { navigate } = useNavigateToCspFindings();
if (totalPassed === undefined || totalFailed === undefined || name === undefined) return null;

// TODO: add type
// @ts-ignore
const handleElementClick = (e) => {
const [data] = e;
const [groupsData] = data;
const handleElementClick: ElementClickListener = (elements) => {
const [element] = elements as PartitionElementEvent[];
const [layerValue] = element;
const rollupValue = layerValue[0].groupByRollup as string;

navigate(
`(language:kuery,query:'rule.benchmark : "${benchmarkName}" and result.evaluation : ${groupsData[0].groupByRollup.toLowerCase()}')`
`(language:kuery,query:'rule.benchmark : "${benchmarkName}" and result.evaluation : ${rollupValue.toLowerCase()}')`
);
};

Expand Down
Loading

0 comments on commit f876d4e

Please sign in to comment.