1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-03-23 00:16:25 +01:00
unleash.unleash/frontend/src/component/feature/FeatureStrategy/FeatureStrategyEmpty/FeatureStrategyEmpty.tsx
Thomas Heartman 51c9617da8
Fix: weird strategy spacing on envs without release plans (#9466)
Fixes a visual bug where envs without release plans would get too much
spacing on the top of their first strategy.

It does this flattening the list of strategies if there are no release
plans. In doing so, I have extracted the strategy list rendering into a
separate component (to make things more legible and re-usable) and have
also removed the FeatureStrategyEmpty component and marked it as
deprecated. In the new designs, you can't expand envs without
strategies, so the component is no longer needed.

Before (what looks like a shadow is actually the extra list being
rendered with a bit of padding):

![image](https://github.com/user-attachments/assets/5ba06ac9-046c-4fbd-8b46-b077b8a0570b)

After:

![image](https://github.com/user-attachments/assets/64270582-1221-4bdf-a85b-c24ce23bd4a3)
2025-03-10 14:49:26 +01:00

188 lines
6.8 KiB
TypeScript

// deprecated; remove with the `flagOverviewRedesign` flag
import { Link } from 'react-router-dom';
import { Box, styled } from '@mui/material';
import useFeatureStrategyApi from 'hooks/api/actions/useFeatureStrategyApi/useFeatureStrategyApi';
import useToast from 'hooks/useToast';
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
import { formatUnknownError } from 'utils/formatUnknownError';
import { useFeatureImmutable } from 'hooks/api/getters/useFeature/useFeatureImmutable';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { CopyButton } from './CopyButton/CopyButton';
import { useChangeRequestAddStrategy } from 'hooks/useChangeRequestAddStrategy';
import { ChangeRequestDialogue } from 'component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestConfirmDialog';
import { CopyStrategiesMessage } from 'component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/CopyStrategiesMessage';
import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
import { FeatureStrategyMenu } from '../FeatureStrategyMenu/FeatureStrategyMenu';
interface IFeatureStrategyEmptyProps {
projectId: string;
featureId: string;
environmentId: string;
}
const StyledContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
paddingTop: theme.spacing(2),
}));
const StyledTitle = styled('div')(({ theme }) => ({
fontSize: theme.fontSizes.bodySize,
textAlign: 'center',
color: theme.palette.text.primary,
marginBottom: theme.spacing(1),
}));
const StyledDescription = styled('p')(({ theme }) => ({
color: theme.palette.text.secondary,
fontSize: theme.fontSizes.smallBody,
textAlign: 'center',
marginBottom: theme.spacing(3),
a: {
color: theme.palette.links,
},
}));
export const FeatureStrategyEmpty = ({
projectId,
featureId,
environmentId,
}: IFeatureStrategyEmptyProps) => {
const { addStrategyToFeature } = useFeatureStrategyApi();
const { setToastData, setToastApiError } = useToast();
const { refetchFeature } = useFeature(projectId, featureId);
const { refetchFeature: refetchFeatureImmutable } = useFeatureImmutable(
projectId,
featureId,
);
const { feature } = useFeature(projectId, featureId);
const otherAvailableEnvironments = feature?.environments.filter(
(environment) =>
environment.name !== environmentId &&
environment.strategies &&
environment.strategies.length > 0,
);
const { isChangeRequestConfigured } = useChangeRequestsEnabled(projectId);
const {
changeRequestDialogDetails,
onChangeRequestAddStrategies,
onChangeRequestAddStrategiesConfirm,
onChangeRequestAddStrategyClose,
} = useChangeRequestAddStrategy(projectId, featureId, 'addStrategy');
const onAfterAddStrategy = (multiple = false) => {
refetchFeature();
refetchFeatureImmutable();
setToastData({
text: multiple ? 'Strategies created' : 'Strategy created',
type: 'success',
});
};
const onCopyStrategies = async (fromEnvironmentName: string) => {
const strategies =
otherAvailableEnvironments?.find(
(environment) => environment.name === fromEnvironmentName,
)?.strategies || [];
if (isChangeRequestConfigured(environmentId)) {
await onChangeRequestAddStrategies(
environmentId,
strategies,
fromEnvironmentName,
);
return;
}
try {
await Promise.all(
strategies.map((strategy) => {
const { id, ...strategyCopy } = {
...strategy,
environment: environmentId,
};
return addStrategyToFeature(
projectId,
featureId,
environmentId,
strategyCopy,
);
}),
);
onAfterAddStrategy(true);
} catch (error) {
setToastApiError(formatUnknownError(error));
}
};
const canCopyFromOtherEnvironment =
otherAvailableEnvironments && otherAvailableEnvironments.length > 0;
return (
<>
<ChangeRequestDialogue
isOpen={changeRequestDialogDetails.isOpen}
onClose={onChangeRequestAddStrategyClose}
environment={changeRequestDialogDetails?.environment}
onConfirm={onChangeRequestAddStrategiesConfirm}
messageComponent={
<CopyStrategiesMessage
fromEnvironment={
changeRequestDialogDetails.fromEnvironment!
}
payload={changeRequestDialogDetails.strategies!}
/>
}
/>
<StyledContainer>
<StyledTitle>
You have not defined any strategies yet.
</StyledTitle>
<StyledDescription>
Strategies added in this environment will only be executed
if the SDK is using an{' '}
<Link to='/admin/api'>API key configured</Link> for this
environment.
</StyledDescription>
<Box
sx={{
w: '100%',
display: 'flex',
flexWrap: 'wrap',
gap: 2,
alignItems: 'center',
justifyContent: 'center',
}}
>
<FeatureStrategyMenu
label='Add your first strategy'
projectId={projectId}
featureId={featureId}
environmentId={environmentId}
matchWidth={canCopyFromOtherEnvironment}
/>
<ConditionallyRender
condition={canCopyFromOtherEnvironment}
show={
<CopyButton
environmentId={environmentId}
environments={otherAvailableEnvironments.map(
(environment) => environment.name,
)}
onClick={onCopyStrategies}
/>
}
/>
</Box>
</StyledContainer>
</>
);
};