Skip to content

Commit 14c32cb

Browse files
[Security Solution] Eliminates a redundant external link icon (#94194)
## [Security Solution] Eliminates a redundant external link icon - Fixes an issue where [a redundant external link icon](#89084) was rendered next to port numbers Per the [EuiLink documentation](https://elastic.github.io/eui/#/navigation/link), it's no longer necessary to render our own icon, because `EuiLink` will automatically display one when `target="_blank"` is passed as a prop to the link. - Updates the existing link icon unit test such that it asserts a specific icon count to catch any regressions ### Before <img width="1673" alt="before" src="https://user-images.githubusercontent.com/4459398/110530119-4cd0ac00-80d7-11eb-9d54-5d6656491e69.png"> ### After <img width="1677" alt="after" src="https://user-images.githubusercontent.com/4459398/110530165-5c4ff500-80d7-11eb-99a3-68741fab9218.png"> ### Desk testing Desk tested in: - Chrome `89.0.4389.82` - Firefox `86.0` - Safari `14.0.3`
1 parent 9aeb9f4 commit 14c32cb

File tree

11 files changed

+34
-158
lines changed

11 files changed

+34
-158
lines changed

x-pack/plugins/security_solution/public/common/components/external_link_icon/index.test.tsx

Lines changed: 0 additions & 76 deletions
This file was deleted.

x-pack/plugins/security_solution/public/common/components/external_link_icon/index.tsx

Lines changed: 0 additions & 48 deletions
This file was deleted.

x-pack/plugins/security_solution/public/common/components/links/index.test.tsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* 2.0.
66
*/
77

8-
import { mount, shallow, ShallowWrapper } from 'enzyme';
8+
import { mount, shallow, ReactWrapper, ShallowWrapper } from 'enzyme';
99
import React from 'react';
1010
import { removeExternalLinkText } from '../../../../common/test_utils';
1111
import { mountWithIntl } from '@kbn/test/jest';
@@ -121,11 +121,11 @@ describe('Custom Links', () => {
121121
describe('External Link', () => {
122122
const mockLink = 'https://www.virustotal.com/gui/search/';
123123
const mockLinkName = 'Link';
124-
let wrapper: ShallowWrapper;
124+
let wrapper: ReactWrapper | ShallowWrapper;
125125

126126
describe('render', () => {
127127
beforeAll(() => {
128-
wrapper = shallow(
128+
wrapper = mount(
129129
<ExternalLink url={mockLink} idx={0} allItemsLimit={5} overflowIndexStart={5}>
130130
{mockLinkName}
131131
</ExternalLink>
@@ -137,11 +137,13 @@ describe('Custom Links', () => {
137137
});
138138

139139
test('it renders ExternalLinkIcon', () => {
140-
expect(wrapper.find('[data-test-subj="externalLinkIcon"]').exists()).toBeTruthy();
140+
expect(wrapper.find('span [data-euiicon-type="popout"]').length).toBe(1);
141141
});
142142

143143
test('it renders correct url', () => {
144-
expect(wrapper.find('[data-test-subj="externalLink"]').prop('href')).toEqual(mockLink);
144+
expect(wrapper.find('[data-test-subj="externalLink"]').first().prop('href')).toEqual(
145+
mockLink
146+
);
145147
});
146148

147149
test('it renders comma if id is given', () => {
@@ -435,14 +437,14 @@ describe('Custom Links', () => {
435437

436438
test('it renders correct number of external icons by default', () => {
437439
const wrapper = mountWithIntl(<ReputationLink domain={'192.0.2.0'} />);
438-
expect(wrapper.find('[data-test-subj="externalLinkIcon"]')).toHaveLength(5);
440+
expect(wrapper.find('span [data-euiicon-type="popout"]')).toHaveLength(5);
439441
});
440442

441443
test('it renders correct number of external icons', () => {
442444
const wrapper = mountWithIntl(
443445
<ReputationLink domain={'192.0.2.0'} overflowIndexStart={1} />
444446
);
445-
expect(wrapper.find('[data-test-subj="externalLinkIcon"]')).toHaveLength(1);
447+
expect(wrapper.find('span [data-euiicon-type="popout"]')).toHaveLength(1);
446448
});
447449
});
448450
});

x-pack/plugins/security_solution/public/common/components/links/index.tsx

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ import {
3939
} from '../../../../common/search_strategy/security_solution/network';
4040
import { useUiSetting$, useKibana } from '../../lib/kibana';
4141
import { isUrlInvalid } from '../../utils/validators';
42-
import { ExternalLinkIcon } from '../external_link_icon';
4342

4443
import * as i18n from './translations';
4544
import { SecurityPageName } from '../../../app/types';
@@ -54,6 +53,13 @@ export const LinkAnchor: React.FC<EuiLinkProps> = ({ children, ...props }) => (
5453
<EuiLink {...props}>{children}</EuiLink>
5554
);
5655

56+
export const PortContainer = styled.div`
57+
& svg {
58+
position: relative;
59+
top: -1px;
60+
}
61+
`;
62+
5763
// Internal Links
5864
const HostDetailsLinkComponent: React.FC<{
5965
children?: React.ReactNode;
@@ -112,11 +118,12 @@ export const ExternalLink = React.memo<{
112118
const inAllowlist = allowedUrlSchemes.some((scheme) => url.indexOf(scheme) === 0);
113119
return url && inAllowlist && !isUrlInvalid(url) && children ? (
114120
<EuiToolTip content={url} position="top" data-test-subj="externalLinkTooltip">
115-
<EuiLink href={url} target="_blank" rel="noopener" data-test-subj="externalLink">
116-
{children}
117-
<ExternalLinkIcon data-test-subj="externalLinkIcon" />
121+
<>
122+
<EuiLink href={url} target="_blank" rel="noopener" data-test-subj="externalLink">
123+
{children}
124+
</EuiLink>
118125
{!isNil(idx) && idx < lastIndexToShow && <Comma data-test-subj="externalLinkComma" />}
119-
</EuiLink>
126+
</>
120127
</EuiToolTip>
121128
) : null;
122129
}
@@ -229,15 +236,17 @@ export const PortOrServiceNameLink = React.memo<{
229236
children?: React.ReactNode;
230237
portOrServiceName: number | string;
231238
}>(({ children, portOrServiceName }) => (
232-
<EuiLink
233-
data-test-subj="port-or-service-name-link"
234-
href={`https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=${encodeURIComponent(
235-
String(portOrServiceName)
236-
)}`}
237-
target="_blank"
238-
>
239-
{children ? children : portOrServiceName}
240-
</EuiLink>
239+
<PortContainer>
240+
<EuiLink
241+
data-test-subj="port-or-service-name-link"
242+
href={`https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=${encodeURIComponent(
243+
String(portOrServiceName)
244+
)}`}
245+
target="_blank"
246+
>
247+
{children ? children : portOrServiceName}
248+
</EuiLink>
249+
</PortContainer>
241250
));
242251

243252
PortOrServiceNameLink.displayName = 'PortOrServiceNameLink';

x-pack/plugins/security_solution/public/network/components/port/__snapshots__/index.test.tsx.snap

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x-pack/plugins/security_solution/public/network/components/port/index.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,13 @@ describe('Port', () => {
6060
);
6161
});
6262

63-
test('it renders an external link', () => {
63+
test('it renders only one external link icon', () => {
6464
const wrapper = mount(
6565
<TestProviders>
6666
<Port contextId="test" eventId="abcd" fieldName="destination.port" value="443" />
6767
</TestProviders>
6868
);
6969

70-
expect(wrapper.find('[data-test-subj="external-link-icon"]').first().exists()).toBe(true);
70+
expect(wrapper.find('span [data-euiicon-type="popout"]').length).toBe(1);
7171
});
7272
});

x-pack/plugins/security_solution/public/network/components/port/index.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import React from 'react';
99

1010
import { DefaultDraggable } from '../../../common/components/draggables';
1111
import { getEmptyValue } from '../../../common/components/empty_value';
12-
import { ExternalLinkIcon } from '../../../common/components/external_link_icon';
1312
import { PortOrServiceNameLink } from '../../../common/components/links';
1413

1514
export const CLIENT_PORT_FIELD_NAME = 'client.port';
@@ -40,7 +39,6 @@ export const Port = React.memo<{
4039
value={value}
4140
>
4241
<PortOrServiceNameLink portOrServiceName={value || getEmptyValue()} />
43-
<ExternalLinkIcon />
4442
</DefaultDraggable>
4543
));
4644

x-pack/plugins/security_solution/public/timelines/components/certificate_fingerprint/index.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import React from 'react';
1010
import styled from 'styled-components';
1111

1212
import { DraggableBadge } from '../../../common/components/draggables';
13-
import { ExternalLinkIcon } from '../../../common/components/external_link_icon';
1413
import { CertificateFingerprintLink } from '../../../common/components/links';
1514

1615
import * as i18n from './translations';
@@ -61,7 +60,6 @@ export const CertificateFingerprint = React.memo<{
6160
{certificateType === 'client' ? i18n.CLIENT_CERT : i18n.SERVER_CERT}
6261
</FingerprintLabel>
6362
<CertificateFingerprintLink certificateFingerprint={value || ''} />
64-
<ExternalLinkIcon />
6563
</DraggableBadge>
6664
);
6765
});

x-pack/plugins/security_solution/public/timelines/components/ja3_fingerprint/index.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import React from 'react';
99
import styled from 'styled-components';
1010

1111
import { DraggableBadge } from '../../../common/components/draggables';
12-
import { ExternalLinkIcon } from '../../../common/components/external_link_icon';
1312
import { Ja3FingerprintLink } from '../../../common/components/links';
1413

1514
import * as i18n from './translations';
@@ -45,7 +44,6 @@ export const Ja3Fingerprint = React.memo<{
4544
{i18n.JA3_FINGERPRINT_LABEL}
4645
</Ja3FingerprintLabel>
4746
<Ja3FingerprintLink data-test-subj="ja3-hash-link" ja3Fingerprint={value || ''} />
48-
<ExternalLinkIcon />
4947
</DraggableBadge>
5048
));
5149

x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/catalog/index.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
import { EuiLink } from '@elastic/eui';
99
import React from 'react';
10-
import { ExternalLinkIcon } from '../../../../common/components/external_link_icon';
1110

1211
import { RowRendererId } from '../../../../../common/types/timeline';
1312
import {
@@ -37,7 +36,6 @@ const Link = ({ children, url }: { children: React.ReactNode; url: string }) =>
3736
data-test-subj="externalLink"
3837
>
3938
{children}
40-
<ExternalLinkIcon data-test-subj="externalLinkIcon" />
4139
</EuiLink>
4240
);
4341

0 commit comments

Comments
 (0)