1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-08-18 13:48:58 +02:00

feat: add truncation and tooltips (#10498)

This PR uses the existing Truncator component to add truncation and
tooltips for long names.
This commit is contained in:
Fredrik Strand Oseberg 2025-08-18 13:16:52 +02:00 committed by GitHub
parent 05ea405bf6
commit a99e5bc4b4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 122 additions and 93 deletions

1
.gitignore vendored
View File

@ -4,6 +4,7 @@ npm-debug
.DS_Store
/dist
.vscode
.claude
# Logs
logs

View File

@ -5,6 +5,7 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit
import { TooltipLink } from 'component/common/TooltipLink/TooltipLink';
import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
import { Highlighter } from 'component/common/Highlighter/Highlighter';
import { Truncator } from 'component/common/Truncator/Truncator';
const StyledBox = styled(Box)(({ theme }) => ({
display: 'flex',
@ -13,10 +14,7 @@ const StyledBox = styled(Box)(({ theme }) => ({
padding: theme.spacing(1, 0, 1, 2),
}));
const StyledLink = styled(Link)(({ theme }) => ({
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
const StyledLink = styled(Link)(() => ({
textDecoration: 'none',
'&:hover, &:focus': {
textDecoration: 'underline',
@ -53,12 +51,13 @@ export const FeaturesCell: VFC<FeaturesCellProps> = ({ value, project }) => {
show={featureNames?.map((featureName: string) => (
<StyledLink
key={featureName}
title={featureName}
to={`/projects/${project}/features/${featureName}`}
>
<Highlighter search={searchQuery}>
{featureName}
</Highlighter>
<Truncator lines={1} title={featureName} arrow>
<Highlighter search={searchQuery}>
{featureName}
</Highlighter>
</Truncator>
</StyledLink>
))}
elseShow={
@ -69,12 +68,17 @@ export const FeaturesCell: VFC<FeaturesCellProps> = ({ value, project }) => {
{featureNames?.map((featureName: string) => (
<StyledTooltipLink
key={featureName}
title={featureName}
to={`/projects/${project}/features/${featureName}`}
>
<Highlighter search={searchQuery}>
{featureName}
</Highlighter>
<Truncator
lines={1}
title={featureName}
arrow
>
<Highlighter search={searchQuery}>
{featureName}
</Highlighter>
</Truncator>
</StyledTooltipLink>
))}
</StyledTooltipContainer>

View File

@ -5,7 +5,7 @@ import useFeatureTypes from 'hooks/api/getters/useFeatureTypes/useFeatureTypes';
import { getFeatureTypeIcons } from 'utils/getFeatureTypeIcons';
import { useSearchHighlightContext } from '../../SearchHighlightContext/SearchHighlightContext.tsx';
import { Highlighter } from '../../../Highlighter/Highlighter.tsx';
import { StyledDescription, StyledTitle } from '../LinkCell/LinkCell.styles';
import { StyledDescription } from '../LinkCell/LinkCell.styles';
import { Link } from 'react-router-dom';
import { Badge } from '../../../Badge/Badge.tsx';
import { HtmlTooltip } from '../../../HtmlTooltip/HtmlTooltip.tsx';
@ -15,6 +15,7 @@ import { useLocationSettings } from 'hooks/useLocationSettings';
import { getLocalizedDateString } from '../../../util.ts';
import { Tag } from 'component/common/Tag/Tag';
import { formatTag } from 'utils/format-tag';
import { Truncator } from 'component/common/Truncator/Truncator';
interface IFeatureNameCellProps {
row: {
@ -135,15 +136,20 @@ const FeatureName: FC<{
return (
<Box sx={(theme) => ({ fontWeight: theme.typography.fontWeightBold })}>
<StyledFeatureLink to={`/projects/${project}/features/${feature}`}>
<StyledTitle
style={{
WebkitLineClamp: 1,
lineClamp: 1,
<Truncator
lines={1}
title={feature}
arrow
sx={{
overflowWrap: 'anywhere',
}}
>
<Highlighter search={searchQuery}>{feature}</Highlighter>
</StyledTitle>
<span>
<Highlighter search={searchQuery}>
{feature}
</Highlighter>
</span>
</Truncator>
</StyledFeatureLink>
</Box>
);
@ -154,14 +160,18 @@ const ArchivedFeatureName: FC<{
searchQuery: string;
}> = ({ feature, searchQuery }) => {
return (
<Box
<Truncator
lines={1}
title={feature}
arrow
sx={(theme) => ({
fontWeight: theme.typography.fontWeightBold,
color: theme.palette.neutral.main,
overflowWrap: 'anywhere',
})}
>
<Highlighter search={searchQuery}>{feature}</Highlighter>
</Box>
</Truncator>
);
};

View File

@ -5,6 +5,7 @@ import { useSearchHighlightContext } from 'component/common/Table/SearchHighligh
import { Box, styled } from '@mui/material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { HtmlTooltip } from 'component/common/HtmlTooltip/HtmlTooltip';
import { Truncator } from 'component/common/Truncator/Truncator';
interface IHighlightCellProps {
value: string;
@ -21,14 +22,7 @@ const StyledContainer = styled(Box)(({ theme }) => ({
padding: theme.spacing(1, 2),
}));
const StyledTitle = styled('span')(({ theme }) => ({
overflow: 'hidden',
textOverflow: 'ellipsis',
display: '-webkit-box',
WebkitBoxOrient: 'vertical',
WebkitLineClamp: '1',
lineClamp: '1',
}));
const StyledTitle = styled('span')(() => ({}));
const StyledSubtitle = styled('span')(({ theme }) => ({
color: theme.palette.text.secondary,
@ -73,16 +67,17 @@ export const HighlightCell: FC<IHighlightCellProps> = ({
return (
<StyledContainer>
<StyledTitle
style={{
WebkitLineClamp: subtitle ? 1 : 2,
lineClamp: subtitle ? 1 : 2,
}}
<Truncator
lines={subtitle ? 1 : 2}
title={value}
arrow
data-loading
>
<Highlighter search={searchQuery}>{value}</Highlighter>
{afterTitle}
</StyledTitle>
<StyledTitle>
<Highlighter search={searchQuery}>{value}</Highlighter>
{afterTitle}
</StyledTitle>
</Truncator>
<ConditionallyRender
condition={Boolean(subtitle)}
show={renderSubtitle}

View File

@ -33,13 +33,6 @@ export const StyledContainer = styled('div')(({ theme }) => ({
wordBreak: 'break-all',
}));
export const StyledTitle = styled('span')(({ theme }) => ({
overflow: 'hidden',
textOverflow: 'ellipsis',
display: '-webkit-box',
WebkitBoxOrient: 'vertical',
}));
export const StyledDescription = styled('span')(({ theme }) => ({
color: theme.palette.text.secondary,
textDecoration: 'none',

View File

@ -4,11 +4,11 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit
import { Highlighter } from 'component/common/Highlighter/Highlighter';
import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
import { HtmlTooltip } from 'component/common/HtmlTooltip/HtmlTooltip';
import { Truncator } from 'component/common/Truncator/Truncator';
import {
StyledWrapper,
StyledLink,
StyledContainer,
StyledTitle,
StyledDescription,
} from './LinkCell.styles';
@ -51,16 +51,17 @@ export const LinkCell: React.FC<ILinkCellProps> = ({
const content = (
<StyledContainer>
<StyledTitle
<Truncator
lines={subtitle ? 1 : 2}
title={title}
arrow
data-loading
style={{
WebkitLineClamp: subtitle ? 1 : 2,
lineClamp: subtitle ? 1 : 2,
}}
>
<Highlighter search={searchQuery}>{title}</Highlighter>
{children}
</StyledTitle>
<span>
<Highlighter search={searchQuery}>{title}</Highlighter>
{children}
</span>
</Truncator>
<ConditionallyRender
condition={Boolean(subtitle)}
show={renderSubtitle}

View File

@ -275,16 +275,21 @@ exports[`renders an empty list correctly 1`] = `
className="css-u8cmsa"
>
<span
className="css-697v50"
aria-label=""
aria-labelledby={null}
className=" MuiBox-root css-gzore8"
data-loading={true}
style={
{
"WebkitLineClamp": 1,
"lineClamp": 1,
}
}
data-mui-internal-clone-element={true}
onBlur={[Function]}
onFocus={[Function]}
onMouseLeave={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
onTouchStart={[Function]}
>
Tag type name
<span>
Tag type name
</span>
</span>
<span
className="css-1121jr7"
@ -449,16 +454,21 @@ exports[`renders an empty list correctly 1`] = `
className="css-u8cmsa"
>
<span
className="css-697v50"
aria-label=""
aria-labelledby={null}
className=" MuiBox-root css-gzore8"
data-loading={true}
style={
{
"WebkitLineClamp": 1,
"lineClamp": 1,
}
}
data-mui-internal-clone-element={true}
onBlur={[Function]}
onFocus={[Function]}
onMouseLeave={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
onTouchStart={[Function]}
>
Tag type name
<span>
Tag type name
</span>
</span>
<span
className="css-1121jr7"
@ -623,16 +633,21 @@ exports[`renders an empty list correctly 1`] = `
className="css-u8cmsa"
>
<span
className="css-697v50"
aria-label=""
aria-labelledby={null}
className=" MuiBox-root css-gzore8"
data-loading={true}
style={
{
"WebkitLineClamp": 1,
"lineClamp": 1,
}
}
data-mui-internal-clone-element={true}
onBlur={[Function]}
onFocus={[Function]}
onMouseLeave={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
onTouchStart={[Function]}
>
Tag type name
<span>
Tag type name
</span>
</span>
<span
className="css-1121jr7"
@ -797,16 +812,21 @@ exports[`renders an empty list correctly 1`] = `
className="css-u8cmsa"
>
<span
className="css-697v50"
aria-label=""
aria-labelledby={null}
className=" MuiBox-root css-gzore8"
data-loading={true}
style={
{
"WebkitLineClamp": 1,
"lineClamp": 1,
}
}
data-mui-internal-clone-element={true}
onBlur={[Function]}
onFocus={[Function]}
onMouseLeave={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
onTouchStart={[Function]}
>
Tag type name
<span>
Tag type name
</span>
</span>
<span
className="css-1121jr7"
@ -971,16 +991,21 @@ exports[`renders an empty list correctly 1`] = `
className="css-u8cmsa"
>
<span
className="css-697v50"
aria-label=""
aria-labelledby={null}
className=" MuiBox-root css-gzore8"
data-loading={true}
style={
{
"WebkitLineClamp": 1,
"lineClamp": 1,
}
}
data-mui-internal-clone-element={true}
onBlur={[Function]}
onFocus={[Function]}
onMouseLeave={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
onTouchStart={[Function]}
>
Tag type name
<span>
Tag type name
</span>
</span>
<span
className="css-1121jr7"