Skip to content

Commit 6fd9966

Browse files
authored
Add hover tooltip for truncated text and restore streams description column. (#26826)
* Display tooltip on hover for truncated text. * Improve styling of tooltip component. * Show description cell again by default in streams overview. * Adding changelog. * Fix failing test.
1 parent 0205d9d commit 6fd9966

7 files changed

Lines changed: 46 additions & 17 deletions

File tree

changelog/unreleased/pr-26826.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
type = "c"
2+
message = "Stream titles in the streams overview no longer include the description text underneath; descriptions are shown in their own column again."
3+
4+
pulls = ["26826"]

graylog2-web-interface/src/components/common/TextOverflowEllipsis.tsx

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,12 @@
1515
* <http://www.mongodb.com/licensing/server-side-public-license>.
1616
*/
1717
import * as React from 'react';
18+
import { useRef, useState, useLayoutEffect } from 'react';
1819
import styled from 'styled-components';
1920

21+
import Tooltip from 'components/common/Tooltip';
22+
import useElementDimensions from 'hooks/useElementDimensions';
23+
2024
const Wrapper = styled.div`
2125
overflow: hidden;
2226
text-overflow: ellipsis;
@@ -33,11 +37,26 @@ type Props = {
3337
/**
3438
* Component that signals text overflow to users by using an ellipsis.
3539
* The parent component needs a concrete width.
40+
* Shows the full text in a tooltip on hover when it is actually truncated.
41+
* A `titleOverride` is always shown on hover, since it usually surfaces additional
42+
* information rather than just the untruncated version of the visible text.
3643
*/
37-
const TextOverflowEllipsis = ({ children, titleOverride = undefined, className = undefined }: Props) => (
38-
<Wrapper title={titleOverride || children} className={className}>
39-
{children}
40-
</Wrapper>
41-
);
44+
const TextOverflowEllipsis = ({ children, titleOverride = undefined, className = undefined }: Props) => {
45+
const ref = useRef<HTMLDivElement>(null);
46+
const { width } = useElementDimensions(ref);
47+
const [isTruncated, setIsTruncated] = useState(false);
48+
49+
useLayoutEffect(() => {
50+
setIsTruncated(!!ref.current && ref.current.scrollWidth > ref.current.clientWidth);
51+
}, [children, width]);
52+
53+
return (
54+
<Tooltip label={titleOverride || children} disabled={titleOverride === undefined && !isTruncated} multiline maw={400}>
55+
<Wrapper ref={ref} className={className}>
56+
{children}
57+
</Wrapper>
58+
</Tooltip>
59+
);
60+
};
4261

4362
export default TextOverflowEllipsis;

graylog2-web-interface/src/components/common/Tooltip.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import * as React from 'react';
1818
import { Tooltip as MantineTooltip } from '@mantine/core';
1919
import { useTheme } from 'styled-components';
2020

21+
import { COLOR_SCHEME_LIGHT } from 'theme/constants';
22+
2123
type Props = React.ComponentProps<typeof MantineTooltip>;
2224

2325
const Tooltip = ({ ...props }: Props) => {
@@ -27,7 +29,10 @@ const Tooltip = ({ ...props }: Props) => {
2729
backgroundColor: theme.colors.global.contentBackground,
2830
color: theme.colors.text.primary,
2931
fontWeight: 400,
30-
fontSize: theme.fonts.size.root,
32+
fontSize: theme.fonts.size.small,
33+
padding: `${theme.spacings.xs} ${theme.spacings.sm}`,
34+
borderRadius: '6px',
35+
boxShadow: `0 2px 8px rgb(0 0 0 / ${theme.mode === COLOR_SCHEME_LIGHT ? '10%' : '40%'})`,
3136
},
3237
});
3338

graylog2-web-interface/src/components/streams/StreamsOverview/Constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ const getStreamTableElements = (
4949

5050
const defaultCols = [
5151
'title',
52+
'description',
5253
'index_set_title',
5354
'rules',
5455
...(isPipelineColumnPermitted ? ['pipelines'] : []),

graylog2-web-interface/src/components/streams/StreamsOverview/StreamsOverview.test.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ const attributes = [
5353
id: 'description',
5454
title: 'Description',
5555
sortable: true,
56-
hidden: true,
5756
},
5857
];
5958

graylog2-web-interface/src/components/streams/StreamsOverview/cells/TitleCell.tsx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@
1515
* <http://www.mongodb.com/licensing/server-side-public-license>.
1616
*/
1717
import * as React from 'react';
18-
import styled, { css } from 'styled-components';
18+
import styled from 'styled-components';
1919

2020
import Routes from 'routing/Routes';
21-
import { Link, Text } from 'components/common';
21+
import { Link } from 'components/common';
2222
import type { Stream } from 'logic/streams/types';
2323
import { Label } from 'components/bootstrap';
2424

@@ -30,12 +30,6 @@ const DefaultLabel = styled(Label)`
3030
vertical-align: inherit;
3131
`;
3232

33-
const StyledText = styled(Text)(
34-
({ theme }) => css`
35-
color: ${theme.colors.text.secondary};
36-
`,
37-
);
38-
3933
const TitleCell = ({ stream }: Props) => (
4034
<>
4135
<Link to={Routes.stream_search(stream.id)}>{stream.title}</Link>
@@ -44,7 +38,6 @@ const TitleCell = ({ stream }: Props) => (
4438
Default
4539
</DefaultLabel>
4640
)}
47-
<StyledText>{stream.description}</StyledText>
4841
</>
4942
);
5043

graylog2-web-interface/src/views/components/widgets/TimerangeInfo.test.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ import OriginalTimerangeInfo from './TimerangeInfo';
3636

3737
jest.mock('views/hooks/useView');
3838
jest.mock('views/hooks/useGlobalOverride');
39+
jest.mock('components/common/Tooltip', () => ({ children, label }: { children: React.ReactNode; label: React.ReactNode }) => (
40+
<>
41+
{children}
42+
<div data-testid="tooltip-label">{label}</div>
43+
</>
44+
));
3945

4046
const defaultSearchResult = {
4147
execution: {
@@ -104,7 +110,9 @@ describe('TimerangeInfo', () => {
104110
const relativeWidget = widget.toBuilder().timerange({ type: 'relative', range: 3000 }).build();
105111
render(<TimerangeInfo widget={relativeWidget} activeQuery="active-query-id" widgetId="widget-id" />);
106112

107-
expect(screen.getByTitle('2021-04-26T14:32:48.000+02:00 - 2021-04-26T16:32:48.000+02:00')).toBeInTheDocument();
113+
expect(screen.getByTestId('tooltip-label')).toHaveTextContent(
114+
'2021-04-26T14:32:48.000+02:00 - 2021-04-26T16:32:48.000+02:00',
115+
);
108116
});
109117

110118
it('should display a relative timerange', () => {

0 commit comments

Comments
 (0)