import type { FC, ReactElement } from 'react'; import type { FeatureSearchResponseSchema } from '../../../../../openapi'; import { Box, IconButton, styled } from '@mui/material'; import useFeatureTypes from 'hooks/api/getters/useFeatureTypes/useFeatureTypes'; import { getFeatureTypeIcons } from 'utils/getFeatureTypeIcons'; import { useSearchHighlightContext } from '../../SearchHighlightContext/SearchHighlightContext'; import { Highlighter } from '../../../Highlighter/Highlighter'; import { StyledDescription, StyledTitle } from '../LinkCell/LinkCell.styles'; import { Link } from 'react-router-dom'; import { Badge } from '../../../Badge/Badge'; import { HtmlTooltip } from '../../../HtmlTooltip/HtmlTooltip'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { useFeature } from 'hooks/api/getters/useFeature/useFeature'; interface IFeatureNameCellProps { row: { original: Pick< FeatureSearchResponseSchema, | 'name' | 'description' | 'project' | 'tags' | 'type' | 'dependencyType' | 'archivedAt' >; }; } const StyledFeatureLink = styled(Link)({ textDecoration: 'none', '&:hover, &:focus': { textDecoration: 'underline', }, }); const Tag = styled('button')(({ theme }) => ({ marginRight: theme.spacing(0.5), border: `1px solid ${theme.palette.divider}`, borderRadius: theme.shape.borderRadius, fontSize: theme.fontSizes.smallerBody, textOverflow: 'ellipsis', overflow: 'hidden', textWrap: 'nowrap', maxWidth: '250px', padding: theme.spacing(0.25, 0.5), cursor: 'pointer', background: 'inherit', color: 'inherit', })); const CappedDescription: FC<{ text: string; searchQuery: string }> = ({ text, searchQuery, }) => { return ( 40)} show={ {text} } placement='bottom-start' arrow > {text} } elseShow={ {text} } /> ); }; const CappedTag: FC<{ tag: string; children: ReactElement }> = ({ tag, children, }) => { return ( 30} show={{children}} elseShow={children} /> ); }; const Container = styled(Box)(({ theme }) => ({ display: 'flex', flexDirection: 'column', gap: theme.spacing(0.5), margin: theme.spacing(1.25, 0, 1, 0), paddingLeft: theme.spacing(2), })); const FeatureNameAndType = styled(Box)(({ theme }) => ({ display: 'flex', alignItems: 'center', gap: theme.spacing(1), color: theme.palette.primary.dark, })); const TagsContainer = styled(Box)(({ theme }) => ({ display: 'flex', flexWrap: 'wrap', gap: theme.spacing(0.25), })); const DependencyBadge = styled(Badge)(({ theme }) => ({ padding: theme.spacing(0.5), border: 0, textTransform: 'capitalize', })); const FeatureName: FC<{ project: string; feature: string; searchQuery: string; }> = ({ project, feature, searchQuery }) => { return ( ({ fontWeight: theme.typography.fontWeightBold })}> {feature} ); }; const ArchivedFeatureName: FC<{ feature: string; searchQuery: string; }> = ({ feature, searchQuery }) => { return ( ({ fontWeight: theme.typography.fontWeightBold, color: theme.palette.neutral.main, })} > {feature} ); }; const RestTags: FC<{ tags: string[]; onClick: (tag: string) => void }> = ({ tags, onClick, }) => { return ( ( onClick(tag)} key={tag} > {tag} ))} > {tags.length} more... ); }; const Tags: FC<{ tags: FeatureSearchResponseSchema['tags']; onClick: (tag: string) => void; }> = ({ tags, onClick }) => { const [tag1, tag2, tag3, ...restTags] = (tags || []).map( ({ type, value }) => `${type}:${value}`, ); return ( {tag1 && ( onClick(tag1)}>{tag1} )} {tag2 && ( onClick(tag2)}>{tag2} )} {tag3 && ( onClick(tag3)}>{tag3} )} 0} show={} /> ); }; const StyledDependencyLink = styled(Link)({ display: 'block', }); const DependencyPreview: FC<{ feature: string; project: string }> = ({ feature, project, }) => { const { feature: fetchedFeature } = useFeature(project, feature); const children = fetchedFeature.children; const parents = fetchedFeature.dependencies; if (children.length > 0) { return ( <> Children {children.map((child) => ( {child} ))} ); } else if (parents[0]) { const parentFeature = parents[0].feature; return ( <> Parent {parentFeature} ); } return <>Loading...; }; export const PrimaryFeatureInfo: FC<{ project: string; feature: string; archivedAt: string | null; searchQuery: string; type: string; dependencyType: string; onTypeClick: (type: string) => void; delay?: number; }> = ({ project, feature, archivedAt, type, searchQuery, dependencyType, onTypeClick, delay = 500, }) => { const { featureTypes } = useFeatureTypes(); const IconComponent = getFeatureTypeIcons(type); const typeName = featureTypes.find( (featureType) => featureType.id === type, )?.name; const title = `${typeName || type} flag`; const TypeIcon = () => ( onTypeClick(type)} > ({ fontSize: theme.spacing(2) })} data-testid='feature-type-icon' /> ); return ( {archivedAt ? ( ) : ( )} } enterDelay={delay} enterNextDelay={delay} > {dependencyType} } /> {archivedAt && ( Archived )} ); }; const SecondaryFeatureInfo: FC<{ description: string; searchQuery: string; }> = ({ description, searchQuery }) => { return ( ({ display: 'flex', gap: theme.spacing(1) })} > } /> ); }; export const FeatureOverviewCell = ( onTagClick: (tag: string) => void, onFlagTypeClick: (type: string) => void, ): FC => ({ row }) => { const { searchQuery } = useSearchHighlightContext(); return ( ); };