2022-07-27 12:00:15 +02:00
|
|
|
import { Link } from 'react-router-dom';
|
|
|
|
import { Box } from '@mui/material';
|
|
|
|
import { SectionSeparator } from 'component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/SectionSeparator/SectionSeparator';
|
|
|
|
import useFeatureStrategyApi from 'hooks/api/actions/useFeatureStrategyApi/useFeatureStrategyApi';
|
|
|
|
import useToast from 'hooks/useToast';
|
|
|
|
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
|
2022-03-09 14:59:24 +01:00
|
|
|
import { FeatureStrategyMenu } from '../FeatureStrategyMenu/FeatureStrategyMenu';
|
2022-07-27 12:00:15 +02:00
|
|
|
import { PresetCard } from './PresetCard/PresetCard';
|
|
|
|
import { useStyles } from './FeatureStrategyEmpty.styles';
|
|
|
|
import { formatUnknownError } from 'utils/formatUnknownError';
|
2022-07-28 13:45:08 +02:00
|
|
|
import { useFeatureImmutable } from 'hooks/api/getters/useFeature/useFeatureImmutable';
|
2022-07-28 12:05:48 +02:00
|
|
|
import { getFeatureStrategyIcon } from 'utils/strategyNames';
|
2022-08-02 20:19:29 +02:00
|
|
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
|
|
|
import { CopyButton } from './CopyButton/CopyButton';
|
2022-03-09 14:59:24 +01:00
|
|
|
|
|
|
|
interface IFeatureStrategyEmptyProps {
|
|
|
|
projectId: string;
|
|
|
|
featureId: string;
|
|
|
|
environmentId: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
export const FeatureStrategyEmpty = ({
|
|
|
|
projectId,
|
|
|
|
featureId,
|
|
|
|
environmentId,
|
|
|
|
}: IFeatureStrategyEmptyProps) => {
|
2022-05-02 15:52:41 +02:00
|
|
|
const { classes: styles } = useStyles();
|
2022-07-27 12:00:15 +02:00
|
|
|
const { addStrategyToFeature } = useFeatureStrategyApi();
|
|
|
|
const { setToastData, setToastApiError } = useToast();
|
|
|
|
const { refetchFeature } = useFeature(projectId, featureId);
|
2022-07-28 13:45:08 +02:00
|
|
|
const { refetchFeature: refetchFeatureImmutable } = useFeatureImmutable(
|
|
|
|
projectId,
|
|
|
|
featureId
|
|
|
|
);
|
2022-08-02 20:19:29 +02:00
|
|
|
const { feature } = useFeature(projectId, featureId);
|
|
|
|
const otherAvailableEnvironments = feature?.environments.filter(
|
|
|
|
environment =>
|
|
|
|
environment.name !== environmentId &&
|
|
|
|
environment.strategies &&
|
|
|
|
environment.strategies.length > 0
|
|
|
|
);
|
2022-07-27 12:00:15 +02:00
|
|
|
|
2022-08-02 20:19:29 +02:00
|
|
|
const onAfterAddStrategy = (multiple = false) => {
|
2022-07-27 12:00:15 +02:00
|
|
|
refetchFeature();
|
2022-07-28 13:45:08 +02:00
|
|
|
refetchFeatureImmutable();
|
|
|
|
|
2022-07-27 12:00:15 +02:00
|
|
|
setToastData({
|
2022-08-02 20:19:29 +02:00
|
|
|
title: multiple ? 'Strategies created' : 'Strategy created',
|
|
|
|
text: multiple
|
|
|
|
? 'Successfully copied from another environment'
|
|
|
|
: 'Successfully created strategy',
|
2022-07-27 12:00:15 +02:00
|
|
|
type: 'success',
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2022-08-02 20:19:29 +02:00
|
|
|
const onCopyStrategies = async (fromEnvironmentName: string) => {
|
|
|
|
const strategies =
|
|
|
|
otherAvailableEnvironments?.find(
|
|
|
|
environment => environment.name === fromEnvironmentName
|
|
|
|
)?.strategies || [];
|
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-07-27 12:00:15 +02:00
|
|
|
const onAddSimpleStrategy = async () => {
|
|
|
|
try {
|
|
|
|
await addStrategyToFeature(projectId, featureId, environmentId, {
|
|
|
|
name: 'default',
|
|
|
|
parameters: {},
|
|
|
|
constraints: [],
|
|
|
|
});
|
|
|
|
onAfterAddStrategy();
|
|
|
|
} catch (error) {
|
|
|
|
setToastApiError(formatUnknownError(error));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const onAddGradualRolloutStrategy = async () => {
|
|
|
|
try {
|
|
|
|
await addStrategyToFeature(projectId, featureId, environmentId, {
|
|
|
|
name: 'flexibleRollout',
|
|
|
|
parameters: {
|
|
|
|
rollout: '50',
|
|
|
|
stickiness: 'default',
|
2022-09-06 14:32:28 +02:00
|
|
|
groupId: feature.name,
|
2022-07-27 12:00:15 +02:00
|
|
|
},
|
|
|
|
constraints: [],
|
|
|
|
});
|
|
|
|
onAfterAddStrategy();
|
|
|
|
} catch (error) {
|
|
|
|
setToastApiError(formatUnknownError(error));
|
|
|
|
}
|
|
|
|
};
|
2022-03-09 14:59:24 +01:00
|
|
|
|
2022-09-05 11:00:36 +02:00
|
|
|
const canCopyFromOtherEnvironment =
|
|
|
|
otherAvailableEnvironments && otherAvailableEnvironments.length > 0;
|
|
|
|
|
2022-03-09 14:59:24 +01:00
|
|
|
return (
|
2022-07-27 12:00:15 +02:00
|
|
|
<div className={styles.container}>
|
|
|
|
<div className={styles.title}>
|
|
|
|
You have not defined any strategies yet.
|
|
|
|
</div>
|
|
|
|
<p className={styles.description}>
|
2022-03-09 14:59:24 +01:00
|
|
|
Strategies added in this environment will only be executed if
|
2022-07-27 12:00:15 +02:00
|
|
|
the SDK is using an{' '}
|
|
|
|
<Link to="/admin/api">API key configured</Link> for this
|
|
|
|
environment.
|
2022-03-09 14:59:24 +01:00
|
|
|
</p>
|
2022-08-02 20:19:29 +02:00
|
|
|
<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}
|
2022-09-05 11:00:36 +02:00
|
|
|
matchWidth={canCopyFromOtherEnvironment}
|
2022-08-02 20:19:29 +02:00
|
|
|
/>
|
|
|
|
<ConditionallyRender
|
2022-09-05 11:00:36 +02:00
|
|
|
condition={canCopyFromOtherEnvironment}
|
2022-08-02 20:19:29 +02:00
|
|
|
show={
|
|
|
|
<CopyButton
|
|
|
|
environmentId={environmentId}
|
|
|
|
environments={otherAvailableEnvironments.map(
|
|
|
|
environment => environment.name
|
|
|
|
)}
|
|
|
|
onClick={onCopyStrategies}
|
|
|
|
/>
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
</Box>
|
2022-07-27 12:00:15 +02:00
|
|
|
<Box sx={{ width: '100%', mt: 3 }}>
|
|
|
|
<SectionSeparator>Or use a strategy template</SectionSeparator>
|
|
|
|
</Box>
|
|
|
|
<Box
|
|
|
|
sx={{
|
|
|
|
display: 'grid',
|
|
|
|
width: '100%',
|
|
|
|
gap: 2,
|
2022-08-04 10:13:07 +02:00
|
|
|
gridTemplateColumns: { xs: '1fr', sm: '1fr 1fr' },
|
2022-07-27 12:00:15 +02:00
|
|
|
}}
|
|
|
|
>
|
|
|
|
<PresetCard
|
|
|
|
title="Standard strategy"
|
2022-07-28 12:05:48 +02:00
|
|
|
Icon={getFeatureStrategyIcon('default')}
|
2022-07-27 12:00:15 +02:00
|
|
|
onClick={onAddSimpleStrategy}
|
2022-07-28 15:02:41 +02:00
|
|
|
projectId={projectId}
|
|
|
|
environmentId={environmentId}
|
2022-07-27 12:00:15 +02:00
|
|
|
>
|
|
|
|
The standard strategy is strictly on/off for your entire
|
|
|
|
userbase.
|
|
|
|
</PresetCard>
|
|
|
|
<PresetCard
|
|
|
|
title="Gradual rollout"
|
2022-07-28 12:05:48 +02:00
|
|
|
Icon={getFeatureStrategyIcon('flexibleRollout')}
|
2022-07-27 12:00:15 +02:00
|
|
|
onClick={onAddGradualRolloutStrategy}
|
2022-07-28 15:02:41 +02:00
|
|
|
projectId={projectId}
|
|
|
|
environmentId={environmentId}
|
2022-07-27 12:00:15 +02:00
|
|
|
>
|
|
|
|
Roll out to a percentage of your userbase.
|
|
|
|
</PresetCard>
|
|
|
|
</Box>
|
|
|
|
</div>
|
2022-03-09 14:59:24 +01:00
|
|
|
);
|
|
|
|
};
|