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:
parent
3a6e38a7bd
commit
40dfb927e9
4
frontend/src/assets/icons/link-child.svg
Normal file
4
frontend/src/assets/icons/link-child.svg
Normal 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 |
3
frontend/src/assets/icons/link-parent.svg
Normal file
3
frontend/src/assets/icons/link-parent.svg
Normal 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 |
@ -179,6 +179,8 @@ const feature = ({ name, enabled }: { name: string; enabled: boolean }) =>
|
||||
lastSeenAt: null,
|
||||
type: 'release',
|
||||
archived: false,
|
||||
dependencies: [],
|
||||
children: [],
|
||||
});
|
||||
|
||||
const otherRequests = (feature: string) => {
|
||||
|
@ -170,6 +170,8 @@ const featureEnvironments = (
|
||||
lastSeenAt: null,
|
||||
type: 'release',
|
||||
archived: false,
|
||||
children: [],
|
||||
dependencies: [],
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -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>
|
||||
);
|
@ -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>
|
||||
}
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user