Skip to content

Commit

Permalink
[Security Solution][Exceptions Lists] Adds overflow container for exc…
Browse files Browse the repository at this point in the history
…eptions list table (#103377)
  • Loading branch information
dplumlee committed Jun 30, 2021
1 parent 1ff2407 commit fee7348
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@ import React from 'react';
import { EuiButtonIcon, EuiBasicTableColumn, EuiToolTip } from '@elastic/eui';

import type { NamespaceType } from '@kbn/securitysolution-io-ts-list-types';
import { Spacer } from '../../../../../../common/components/page';
import { FormatUrl } from '../../../../../../common/components/link_to';
import { LinkAnchor } from '../../../../../../common/components/links';
import * as i18n from './translations';
import { ExceptionListInfo } from './use_all_exception_lists';
import { getRuleDetailsUrl } from '../../../../../../common/components/link_to/redirect_to_detection_engine';
import { ExceptionOverflowDisplay } from './exceptions_overflow_display';

export type AllExceptionListsColumns = EuiBasicTableColumn<ExceptionListInfo>;

Expand Down Expand Up @@ -72,24 +70,11 @@ export const getAllExceptionListsColumns = (
width: '20%',
render: (value: ExceptionListInfo['rules']) => {
return (
<>
{value.map(({ id, name }, index) => (
<Spacer key={id}>
<LinkAnchor
key={id}
data-test-subj="ruleName"
onClick={(ev: { preventDefault: () => void }) => {
ev.preventDefault();
navigateToUrl(formatUrl(getRuleDetailsUrl(id)));
}}
href={formatUrl(getRuleDetailsUrl(id))}
>
{name}
</LinkAnchor>
{index !== value.length - 1 ? ', ' : ''}
</Spacer>
))}
</>
<ExceptionOverflowDisplay
rules={value}
navigateToUrl={navigateToUrl}
formatUrl={formatUrl}
/>
);
},
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* 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.
*/

import React, { useState } from 'react';
import { EuiPopover, EuiBadgeGroup, EuiButton } from '@elastic/eui';
import styled from 'styled-components';
import * as i18n from '../../translations';
import { Spacer } from '../../../../../../common/components/page';
import { LinkAnchor } from '../../../../../../common/components/links';
import { getRuleDetailsUrl } from '../../../../../../common/components/link_to/redirect_to_detection_engine';
import { Rule } from '../../../../../containers/detection_engine/rules';
import { FormatUrl } from '../../../../../../common/components/link_to';

interface ExceptionOverflowDisplayProps {
rules: Rule[];
navigateToUrl: (url: string) => Promise<void>;
formatUrl: FormatUrl;
}

interface OverflowListComponentProps {
rule: Rule;
index: number;
}

const ExceptionOverflowWrapper = styled(EuiBadgeGroup)`
width: 100%;
`;

const ExceptionOverflowPopoverWrapper = styled(EuiBadgeGroup)`
max-height: 200px;
max-width: 600px;
overflow: auto;
`;

const ExceptionOverflowPopoverButton = styled(EuiButton)`
font-size: ${({ theme }) => theme.eui.euiFontSizeXS}
font-weight: 500;
height: 20px;
`;

/**
* @param rules to display for filtering
*/
const ExceptionOverflowDisplayComponent = ({
rules,
navigateToUrl,
formatUrl,
}: ExceptionOverflowDisplayProps) => {
const [isExceptionOverflowPopoverOpen, setIsExceptionOverflowPopoverOpen] = useState(false);

const OverflowListComponent = ({ rule: { id, name }, index }: OverflowListComponentProps) => {
return (
<Spacer key={id}>
<LinkAnchor
key={id}
data-test-subj="ruleName"
onClick={(ev: { preventDefault: () => void }) => {
ev.preventDefault();
navigateToUrl(formatUrl(getRuleDetailsUrl(id)));
}}
href={formatUrl(getRuleDetailsUrl(id))}
>
{name}
</LinkAnchor>
{index !== rules.length - 1 ? ', ' : ''}
</Spacer>
);
};

return (
<>
{rules.length <= 2 ? (
<ExceptionOverflowWrapper data-test-subj="rules">
{rules.map((rule, index: number) => (
<OverflowListComponent rule={rule} index={index} />
))}
</ExceptionOverflowWrapper>
) : (
<ExceptionOverflowWrapper data-test-subj="rules">
{rules.slice(0, 2).map((rule, index: number) => (
<OverflowListComponent rule={rule} index={index} />
))}

<EuiPopover
ownFocus
display="block"
data-test-subj="rules-display-popover"
button={
<ExceptionOverflowPopoverButton
size="s"
data-test-subj={'rules-display-popover-button'}
onClick={() => setIsExceptionOverflowPopoverOpen(!isExceptionOverflowPopoverOpen)}
>
{i18n.COLUMN_SEE_ALL_POPOVER}
</ExceptionOverflowPopoverButton>
}
isOpen={isExceptionOverflowPopoverOpen}
closePopover={() => setIsExceptionOverflowPopoverOpen(!isExceptionOverflowPopoverOpen)}
repositionOnScroll
>
<ExceptionOverflowPopoverWrapper>
{rules.map((rule, index: number) => (
<OverflowListComponent rule={rule} index={index} />
))}
</ExceptionOverflowPopoverWrapper>
</EuiPopover>
</ExceptionOverflowWrapper>
)}
</>
);
};

export const ExceptionOverflowDisplay = React.memo(ExceptionOverflowDisplayComponent);

ExceptionOverflowDisplay.displayName = 'ExceptionOverflowDisplay';

0 comments on commit fee7348

Please sign in to comment.