1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-26 13:48:33 +02:00

feat: parent and child info in feature overview header (#4901)

This commit is contained in:
Mateusz Kwasniewski 2023-10-02 11:47:48 +02:00 committed by GitHub
parent 3a6e38a7bd
commit 40dfb927e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 127 additions and 25 deletions

View File

@ -0,0 +1,4 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M1 12a5 5 0 0 1 5-5h4a5 5 0 0 1 4.584 7H14a1.993 1.993 0 0 1-1.375-.547A3 3 0 0 0 10 9H6a3 3 0 1 0 0 6h2.803a6.03 6.03 0 0 0 1.822 1.961A5.033 5.033 0 0 1 10 17H6a5 5 0 0 1-5-5Z" fill="#202021"/>
<path d="M9 12c0-.711.148-1.387.416-2H10c.532 0 1.016.208 1.375.547A3 3 0 0 0 14 15h4a3 3 0 1 0 0-6h-2.803a6.03 6.03 0 0 0-1.822-1.961C13.58 7.013 13.788 7 14 7h4a5 5 0 0 1 0 10h-4a5 5 0 0 1-5-5Z" fill="#202021"/>
</svg>

After

Width:  |  Height:  |  Size: 499 B

View File

@ -0,0 +1,3 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1 8a5 5 0 0 1 5-5h4a5 5 0 0 1 4.584 7H14a1.993 1.993 0 0 1-1.375-.547A3 3 0 0 0 10 5H6a3 3 0 0 0 0 6h2.803a6.03 6.03 0 0 0 1.822 1.961A5.033 5.033 0 0 1 10 13H8v3a1 1 0 0 0 1 1h1.17A3.001 3.001 0 0 1 13 15h7a3 3 0 1 1 0 6h-7a3.001 3.001 0 0 1-2.83-2H9a3 3 0 0 1-3-3v-3a5 5 0 0 1-5-5Zm8 0c0-.711.148-1.388.416-2H10c.532 0 1.016.208 1.375.547A3 3 0 0 0 14 11h4a3 3 0 1 0 0-6h-2.803a6.03 6.03 0 0 0-1.822-1.961C13.58 3.013 13.788 3 14 3h4a5 5 0 0 1 0 10h-4a5 5 0 0 1-5-5Z" fill="#202021"/>
</svg>

After

Width:  |  Height:  |  Size: 621 B

View File

@ -179,6 +179,8 @@ const feature = ({ name, enabled }: { name: string; enabled: boolean }) =>
lastSeenAt: null,
type: 'release',
archived: false,
dependencies: [],
children: [],
});
const otherRequests = (feature: string) => {

View File

@ -170,6 +170,8 @@ const featureEnvironments = (
lastSeenAt: null,
type: 'release',
archived: false,
children: [],
dependencies: [],
});
};

View File

@ -0,0 +1,24 @@
import { StyledLink } from './StyledRow';
import { TooltipLink } from 'component/common/TooltipLink/TooltipLink';
import { FC } from 'react';
export const ChildrenTooltip: FC<{
childFeatures: string[];
project: string;
}> = ({ childFeatures, project }) => (
<TooltipLink
tooltip={
<>
{childFeatures.map(child => (
<StyledLink to={`/projects/${project}/features/${child}`}>
<div>{child}</div>
</StyledLink>
))}
</>
}
>
{childFeatures.length === 1
? '1 feature'
: `${childFeatures.length} features`}
</TooltipLink>
);

View File

@ -9,6 +9,7 @@ import { FlexRow, StyledDetail, StyledLabel, StyledLink } from './StyledRow';
import { DependencyActions } from './DependencyActions';
import { useDependentFeaturesApi } from 'hooks/api/actions/useDependentFeaturesApi/useDependentFeaturesApi';
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
import { ChildrenTooltip } from './ChildrenTooltip';
export const DependencyRow: FC<{ feature: IFeatureToggle }> = ({ feature }) => {
const { removeDependencies } = useDependentFeaturesApi(feature.project);
@ -71,23 +72,10 @@ export const DependencyRow: FC<{ feature: IFeatureToggle }> = ({ feature }) => {
<FlexRow>
<StyledDetail>
<StyledLabel>Children:</StyledLabel>
<TooltipLink
tooltip={
<>
{feature.children.map(child => (
<StyledLink
to={`/projects/${feature.project}/features/${child}`}
>
<div>{child}</div>
</StyledLink>
))}
</>
}
>
{feature.children.length === 1
? '1 feature'
: `${feature.children.length} features`}
</TooltipLink>
<ChildrenTooltip
childFeatures={feature.children}
project={feature.project}
/>
</StyledDetail>
</FlexRow>
}

View File

@ -1,5 +1,5 @@
import { useState } from 'react';
import { styled, Tab, Tabs, useMediaQuery } from '@mui/material';
import { styled, Tab, Tabs, useMediaQuery, Box, Card } from '@mui/material';
import { Archive, FileCopy, Label, WatchLater } from '@mui/icons-material';
import {
Link,
@ -31,6 +31,11 @@ import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { FeatureArchiveDialog } from 'component/common/FeatureArchiveDialog/FeatureArchiveDialog';
import { useFavoriteFeaturesApi } from 'hooks/api/actions/useFavoriteFeaturesApi/useFavoriteFeaturesApi';
import { FavoriteIconButton } from 'component/common/FavoriteIconButton/FavoriteIconButton';
import { ReactComponent as ChildLinkIcon } from 'assets/icons/link-child.svg';
import { ReactComponent as ParentLinkIcon } from 'assets/icons/link-parent.svg';
import { TooltipLink } from '../../common/TooltipLink/TooltipLink';
import { ChildrenTooltip } from './FeatureOverview/FeatureOverviewSidePanel/FeatureOverviewSidePanelDetails/ChildrenTooltip';
import { useUiFlag } from '../../../hooks/useUiFlag';
const StyledHeader = styled('div')(({ theme }) => ({
backgroundColor: theme.palette.background.paper,
@ -53,6 +58,28 @@ const StyledToggleInfoContainer = styled('div')({
alignItems: 'center',
});
const StyledDependency = styled('div')(({ theme }) => ({
display: 'flex',
alignItems: 'center',
gap: theme.spacing(1),
marginTop: theme.spacing(1),
fontSize: theme.fontSizes.smallBody,
padding: theme.spacing(0.75, 1.5),
backgroundColor: theme.palette.background.elevation2,
borderRadius: `${theme.shape.borderRadiusMedium}px`,
width: 'max-content',
}));
const StyleChildLinkIcon = styled(ChildLinkIcon)(({ theme }) => ({
width: theme.fontSizes.smallBody,
height: theme.fontSizes.smallBody,
}));
const StyledParentLinkIcon = styled(ParentLinkIcon)(({ theme }) => ({
width: theme.fontSizes.smallBody,
height: theme.fontSizes.smallBody,
}));
const StyledFeatureViewHeader = styled('h1')(({ theme }) => ({
fontSize: theme.fontSizes.mainHeader,
fontWeight: 'normal',
@ -86,12 +113,21 @@ const StyledTabButton = styled(Tab)(({ theme }) => ({
},
}));
export const StyledLink = styled(Link)(({ theme }) => ({
maxWidth: '100%',
textDecoration: 'none',
'&:hover, &:focus': {
textDecoration: 'underline',
},
}));
export const FeatureView = () => {
const projectId = useRequiredPathParam('projectId');
const featureId = useRequiredPathParam('featureId');
const { refetch: projectRefetch } = useProject(projectId);
const { favorite, unfavorite } = useFavoriteFeaturesApi();
const { refetchFeature } = useFeature(projectId, featureId);
const dependentFeatures = useUiFlag('dependentFeatures');
const [openTagDialog, setOpenTagDialog] = useState(false);
const [showDelDialog, setShowDelDialog] = useState(false);
@ -157,13 +193,56 @@ export const FeatureView = () => {
onClick={onFavorite}
isFavorite={feature?.favorite}
/>
<StyledFeatureViewHeader data-loading>
{feature.name}{' '}
</StyledFeatureViewHeader>
<ConditionallyRender
condition={!smallScreen}
show={<FeatureStatusChip stale={feature?.stale} />}
/>
<div>
<StyledToggleInfoContainer>
<StyledFeatureViewHeader data-loading>
{feature.name}{' '}
</StyledFeatureViewHeader>
<ConditionallyRender
condition={!smallScreen}
show={
<FeatureStatusChip
stale={feature?.stale}
/>
}
/>
</StyledToggleInfoContainer>
<ConditionallyRender
condition={
dependentFeatures &&
feature.dependencies.length > 0
}
show={
<StyledDependency>
<StyleChildLinkIcon />{' '}
<b>Child feature</b>
<span>{' < '}</span>
<StyledLink
to={`/projects/${feature.project}/features/${feature?.dependencies[0]?.feature}`}
>
{feature?.dependencies[0]?.feature}
</StyledLink>
</StyledDependency>
}
/>
<ConditionallyRender
condition={
dependentFeatures &&
feature.children.length > 0
}
show={
<StyledDependency>
<StyledParentLinkIcon />{' '}
<b>Parent feature</b>
<span>{' > '}</span>
<ChildrenTooltip
childFeatures={feature.children}
project={feature.project}
/>
</StyledDependency>
}
/>
</div>
</StyledToggleInfoContainer>
<StyledToolbarContainer>