1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-25 00:07:47 +01:00

feat: Preview dependency (#7284)

This commit is contained in:
Mateusz Kwasniewski 2024-06-05 10:05:41 +02:00 committed by GitHub
parent c129541df6
commit e621c7a2a5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 144 additions and 18 deletions

View File

@ -0,0 +1,62 @@
import { screen } from '@testing-library/react';
import { render } from 'utils/testRenderer';
import { PrimaryFeatureInfo } from './FeatureOverviewCell';
import userEvent from '@testing-library/user-event';
import { testServerRoute, testServerSetup } from 'utils/testServer';
const server = testServerSetup();
test('Preview parent feature', async () => {
testServerRoute(server, '/api/admin/projects/default/features/featureA', {
children: [],
dependencies: [{ feature: 'featureB' }],
});
render(
<PrimaryFeatureInfo
feature='featureA'
project='default'
type='release'
searchQuery=''
dependencyType='child'
onTypeClick={() => {}}
delay={0}
/>,
);
const childBadge = screen.getByText('child');
userEvent.hover(childBadge);
await screen.findByText('Loading...');
await screen.findByText('Parent');
await screen.findByText('featureB');
});
test('Preview child features', async () => {
testServerRoute(server, '/api/admin/projects/default/features/featureA', {
children: ['featureB', 'featureC'],
dependencies: [],
});
render(
<PrimaryFeatureInfo
feature='featureA'
project='default'
type='release'
searchQuery=''
dependencyType='parent'
onTypeClick={() => {}}
delay={0}
/>,
);
const parentBadge = screen.getByText('parent');
userEvent.hover(parentBadge);
await screen.findByText('Loading...');
await screen.findByText('Children');
await screen.findByText('featureB');
await screen.findByText('featureC');
});

View File

@ -1,6 +1,6 @@
import type { FC, ReactElement } from 'react'; import type { FC, ReactElement } from 'react';
import type { FeatureSearchResponseSchema } from '../../../../../openapi'; import type { FeatureSearchResponseSchema } from '../../../../../openapi';
import { Box, styled } from '@mui/material'; import { Box, IconButton, styled } from '@mui/material';
import useFeatureTypes from 'hooks/api/getters/useFeatureTypes/useFeatureTypes'; import useFeatureTypes from 'hooks/api/getters/useFeatureTypes/useFeatureTypes';
import { getFeatureTypeIcons } from 'utils/getFeatureTypeIcons'; import { getFeatureTypeIcons } from 'utils/getFeatureTypeIcons';
import { useSearchHighlightContext } from '../../SearchHighlightContext/SearchHighlightContext'; import { useSearchHighlightContext } from '../../SearchHighlightContext/SearchHighlightContext';
@ -9,7 +9,8 @@ import { StyledDescription, StyledTitle } from '../LinkCell/LinkCell.styles';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { Badge } from '../../../Badge/Badge'; import { Badge } from '../../../Badge/Badge';
import { HtmlTooltip } from '../../../HtmlTooltip/HtmlTooltip'; import { HtmlTooltip } from '../../../HtmlTooltip/HtmlTooltip';
import { ConditionallyRender } from '../../../ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
interface IFeatureNameCellProps { interface IFeatureNameCellProps {
row: { row: {
@ -191,14 +192,64 @@ const Tags: FC<{
); );
}; };
const PrimaryFeatureInfo: FC<{ 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 (
<>
<Box>Children</Box>
{children.map((child) => (
<StyledDependencyLink
to={`/projects/${project}/features/${child}`}
key={child}
>
{child}
</StyledDependencyLink>
))}
</>
);
} else if (parents[0]) {
const parentFeature = parents[0].feature;
return (
<>
<Box>Parent</Box>
<Link to={`/projects/${project}/features/${parentFeature}`}>
{parentFeature}
</Link>
</>
);
}
return <>Loading...</>;
};
export const PrimaryFeatureInfo: FC<{
project: string; project: string;
feature: string; feature: string;
searchQuery: string; searchQuery: string;
type: string; type: string;
dependencyType: string; dependencyType: string;
onTypeClick: (type: string) => void; onTypeClick: (type: string) => void;
}> = ({ project, feature, type, searchQuery, dependencyType, onTypeClick }) => { delay?: number;
}> = ({
project,
feature,
type,
searchQuery,
dependencyType,
onTypeClick,
delay = 500,
}) => {
const { featureTypes } = useFeatureTypes(); const { featureTypes } = useFeatureTypes();
const IconComponent = getFeatureTypeIcons(type); const IconComponent = getFeatureTypeIcons(type);
const typeName = featureTypes.find( const typeName = featureTypes.find(
@ -208,14 +259,16 @@ const PrimaryFeatureInfo: FC<{
const TypeIcon = () => ( const TypeIcon = () => (
<HtmlTooltip arrow title={title} describeChild> <HtmlTooltip arrow title={title} describeChild>
<IconComponent <IconButton
data-testid='feature-type-icon' sx={{ p: 0 }}
sx={(theme) => ({ aria-label={`add ${type} flag to filter`}
cursor: 'pointer',
fontSize: theme.spacing(2),
})}
onClick={() => onTypeClick(type)} onClick={() => onTypeClick(type)}
/> >
<IconComponent
sx={(theme) => ({ fontSize: theme.spacing(2) })}
data-testid='feature-type-icon'
/>
</IconButton>
</HtmlTooltip> </HtmlTooltip>
); );
@ -230,15 +283,26 @@ const PrimaryFeatureInfo: FC<{
<ConditionallyRender <ConditionallyRender
condition={Boolean(dependencyType)} condition={Boolean(dependencyType)}
show={ show={
<DependencyBadge <HtmlTooltip
color={ title={
dependencyType === 'parent' <DependencyPreview
? 'warning' feature={feature}
: 'secondary' project={project}
/>
} }
enterDelay={delay}
enterNextDelay={delay}
> >
{dependencyType} <DependencyBadge
</DependencyBadge> color={
dependencyType === 'parent'
? 'warning'
: 'secondary'
}
>
{dependencyType}
</DependencyBadge>
</HtmlTooltip>
} }
/> />
</FeatureNameAndType> </FeatureNameAndType>