1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-06-09 01:17:06 +02:00

chore(1-3516): add release plan / strategy count to env header (#9589)

Adds an optional `environmentMetadata` property to the env header
component, which is used to populate the release plan / strategy
counter. If no env metadata is passed (such as for default strategy
configuration) nothing is rendered.


![image](https://github.com/user-attachments/assets/9be29a7a-aa11-46a4-87b4-4596c12552f6)

With long env names, the project name will be cut off before the chip:


![image](https://github.com/user-attachments/assets/0711972b-66d6-4874-9c47-0c4c768807ff)

There's some issues with narrow screens, but I'll handle that in a
follow-up:

![image](https://github.com/user-attachments/assets/0de8aeae-1025-4c7e-9fcb-86dd22952f97)
This commit is contained in:
Thomas Heartman 2025-03-21 14:54:13 +01:00 committed by GitHub
parent 3fa54f4465
commit 03699c8e80
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 68 additions and 5 deletions

View File

@ -36,15 +36,17 @@ const StyledHeader = styled('header')(({ theme }) => ({
})); }));
const StyledHeaderTitle = styled('hgroup')(({ theme }) => ({ const StyledHeaderTitle = styled('hgroup')(({ theme }) => ({
display: 'flex', display: 'grid',
gridTemplateColumns: 'auto 1fr',
flexDirection: 'column', flexDirection: 'column',
flex: 1, flex: 1,
columnGap: theme.spacing(1),
})); }));
const StyledHeaderTitleLabel = styled('p')(({ theme }) => ({ const StyledHeaderTitleLabel = styled('p')(({ theme }) => ({
fontSize: theme.fontSizes.smallerBody, fontSize: theme.fontSizes.smallerBody,
color: theme.palette.text.secondary, color: theme.palette.text.secondary,
margin: 0, gridColumn: '1/-1',
})); }));
const StyledTruncator = styled(Truncator)(({ theme }) => ({ const StyledTruncator = styled(Truncator)(({ theme }) => ({
@ -52,14 +54,68 @@ const StyledTruncator = styled(Truncator)(({ theme }) => ({
fontWeight: theme.typography.fontWeightMedium, fontWeight: theme.typography.fontWeightMedium,
})); }));
const StyledStrategyCount = styled('p')(({ theme }) => ({
fontSize: theme.fontSizes.smallerBody,
color: theme.palette.info.contrastText,
backgroundColor: theme.palette.info.light,
whiteSpace: 'nowrap',
width: 'min-content',
borderRadius: theme.shape.borderRadiusExtraLarge,
padding: theme.spacing(0.5, 1),
}));
const NeutralStrategyCount = styled(StyledStrategyCount)(({ theme }) => ({
fontSize: theme.fontSizes.smallerBody,
color: theme.palette.text.secondary,
backgroundColor: theme.palette.neutral.light,
}));
type EnvironmentMetadata = {
strategyCount: number;
releasePlanCount: number;
};
type EnvironmentHeaderProps = { type EnvironmentHeaderProps = {
environmentId: string; environmentId: string;
expandable?: boolean; expandable?: boolean;
environmentMetadata?: EnvironmentMetadata;
} & AccordionSummaryProps; } & AccordionSummaryProps;
const MetadataChip = ({
strategyCount,
releasePlanCount,
}: EnvironmentMetadata) => {
if (strategyCount === 0 && releasePlanCount === 0) {
return <NeutralStrategyCount>0 strategies added</NeutralStrategyCount>;
}
const releasePlanText = releasePlanCount > 0 ? 'Release plan' : undefined;
const strategyText = () => {
switch (strategyCount) {
case 0:
return undefined;
case 1:
return `1 strategy`;
default:
return `${strategyCount} strategies`;
}
};
const text = `${[releasePlanText, strategyText()].filter(Boolean).join(', ')} added`;
return <StyledStrategyCount>{text}</StyledStrategyCount>;
};
export const EnvironmentHeader: FC< export const EnvironmentHeader: FC<
PropsWithChildren<EnvironmentHeaderProps> PropsWithChildren<EnvironmentHeaderProps>
> = ({ environmentId, children, expandable = true, ...props }) => { > = ({
environmentId,
children,
expandable = true,
environmentMetadata,
...props
}) => {
const id = useId(); const id = useId();
return ( return (
<StyledAccordionSummary <StyledAccordionSummary
@ -79,6 +135,9 @@ export const EnvironmentHeader: FC<
<StyledTruncator component='h2'> <StyledTruncator component='h2'>
{environmentId} {environmentId}
</StyledTruncator> </StyledTruncator>
{environmentMetadata ? (
<MetadataChip {...environmentMetadata} />
) : null}
</StyledHeaderTitle> </StyledHeaderTitle>
{children} {children}
</StyledHeader> </StyledHeader>

View File

@ -66,7 +66,7 @@ export const FeatureOverviewEnvironment = ({
metrics = { yes: 0, no: 0 }, metrics = { yes: 0, no: 0 },
otherEnvironments = [], otherEnvironments = [],
}: FeatureOverviewEnvironmentProps) => { }: FeatureOverviewEnvironmentProps) => {
const [isOpen, setIsOopen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const projectId = useRequiredPathParam('projectId'); const projectId = useRequiredPathParam('projectId');
const featureId = useRequiredPathParam('featureId'); const featureId = useRequiredPathParam('featureId');
const { isOss } = useUiConfig(); const { isOss } = useUiConfig();
@ -83,9 +83,13 @@ export const FeatureOverviewEnvironment = ({
data-testid={`${FEATURE_ENVIRONMENT_ACCORDION}_${environment.name}`} data-testid={`${FEATURE_ENVIRONMENT_ACCORDION}_${environment.name}`}
expanded={isOpen && hasActivations} expanded={isOpen && hasActivations}
disabled={!hasActivations} disabled={!hasActivations}
onChange={() => setIsOopen(isOpen ? !isOpen : hasActivations)} onChange={() => setIsOpen(isOpen ? !isOpen : hasActivations)}
> >
<EnvironmentHeader <EnvironmentHeader
environmentMetadata={{
strategyCount: environment.strategies?.length ?? 0,
releasePlanCount: environment.releasePlans?.length ?? 0,
}}
environmentId={environment.name} environmentId={environment.name}
expandable={hasActivations} expandable={hasActivations}
> >