mirror of
https://github.com/Unleash/unleash.git
synced 2025-03-18 00:19:49 +01:00
feat: Change request applied diff for update strategy (#8859)
This commit is contained in:
parent
41fb95dd56
commit
570f8d2c34
@ -0,0 +1,197 @@
|
|||||||
|
import { render } from 'utils/testRenderer';
|
||||||
|
import { StrategyChange } from './StrategyChange';
|
||||||
|
import { testServerRoute, testServerSetup } from 'utils/testServer';
|
||||||
|
import { screen } from '@testing-library/react';
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
|
||||||
|
const server = testServerSetup();
|
||||||
|
|
||||||
|
const feature = 'my_feature';
|
||||||
|
const projectId = 'default';
|
||||||
|
const environmentName = 'production';
|
||||||
|
const snapshotRollout = '70';
|
||||||
|
const currentRollout = '80';
|
||||||
|
const changeRequestRollout = '90';
|
||||||
|
const strategy = {
|
||||||
|
name: 'flexibleRollout',
|
||||||
|
constraints: [],
|
||||||
|
variants: [],
|
||||||
|
parameters: {
|
||||||
|
groupId: 'child_1',
|
||||||
|
stickiness: 'default',
|
||||||
|
},
|
||||||
|
segments: [],
|
||||||
|
id: '8e25e369-6424-4dad-b17f-5d32cceb2fbe',
|
||||||
|
disabled: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const setupApi = () => {
|
||||||
|
testServerRoute(
|
||||||
|
server,
|
||||||
|
`/api/admin/projects/${projectId}/features/${feature}`,
|
||||||
|
{
|
||||||
|
environments: [
|
||||||
|
{
|
||||||
|
name: environmentName,
|
||||||
|
strategies: [
|
||||||
|
{
|
||||||
|
...strategy,
|
||||||
|
title: 'current_title',
|
||||||
|
parameters: {
|
||||||
|
...strategy.parameters,
|
||||||
|
rollout: currentRollout,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(setupApi);
|
||||||
|
|
||||||
|
test('Editing strategy before change request is applied diffs against current strategy', async () => {
|
||||||
|
render(
|
||||||
|
<StrategyChange
|
||||||
|
featureName={feature}
|
||||||
|
environmentName={environmentName}
|
||||||
|
projectId={projectId}
|
||||||
|
changeRequestState='Approved'
|
||||||
|
change={{
|
||||||
|
action: 'updateStrategy',
|
||||||
|
id: 1,
|
||||||
|
payload: {
|
||||||
|
...strategy,
|
||||||
|
title: 'change_request_title',
|
||||||
|
parameters: {
|
||||||
|
...strategy.parameters,
|
||||||
|
rollout: changeRequestRollout,
|
||||||
|
},
|
||||||
|
snapshot: {
|
||||||
|
...strategy,
|
||||||
|
title: 'snapshot_title',
|
||||||
|
parameters: {
|
||||||
|
...strategy.parameters,
|
||||||
|
rollout: snapshotRollout,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
await screen.findByText('Editing strategy:');
|
||||||
|
await screen.findByText('change_request_title');
|
||||||
|
await screen.findByText('current_title');
|
||||||
|
expect(screen.queryByText('snapshot_title')).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
const viewDiff = await screen.findByText('View Diff');
|
||||||
|
await userEvent.hover(viewDiff);
|
||||||
|
await screen.findByText(`- parameters.rollout: "${currentRollout}"`);
|
||||||
|
await screen.findByText(`+ parameters.rollout: "${changeRequestRollout}"`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Editing strategy after change request is applied diffs against the snapshot', async () => {
|
||||||
|
render(
|
||||||
|
<StrategyChange
|
||||||
|
featureName='my_feature'
|
||||||
|
environmentName='production'
|
||||||
|
projectId='default'
|
||||||
|
changeRequestState='Applied'
|
||||||
|
change={{
|
||||||
|
action: 'updateStrategy',
|
||||||
|
id: 1,
|
||||||
|
payload: {
|
||||||
|
...strategy,
|
||||||
|
title: 'change_request_title',
|
||||||
|
parameters: {
|
||||||
|
...strategy.parameters,
|
||||||
|
rollout: changeRequestRollout,
|
||||||
|
},
|
||||||
|
snapshot: {
|
||||||
|
...strategy,
|
||||||
|
title: 'snapshot_title',
|
||||||
|
parameters: {
|
||||||
|
...strategy.parameters,
|
||||||
|
rollout: snapshotRollout,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
await screen.findByText('Editing strategy:');
|
||||||
|
await screen.findByText('change_request_title');
|
||||||
|
await screen.findByText('snapshot_title');
|
||||||
|
expect(screen.queryByText('current_title')).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
const viewDiff = await screen.findByText('View Diff');
|
||||||
|
await userEvent.hover(viewDiff);
|
||||||
|
await screen.findByText(`- parameters.rollout: "${snapshotRollout}"`);
|
||||||
|
await screen.findByText(`+ parameters.rollout: "${changeRequestRollout}"`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Deleting strategy before change request is applied diffs against current strategy', async () => {
|
||||||
|
render(
|
||||||
|
<StrategyChange
|
||||||
|
featureName={feature}
|
||||||
|
environmentName={environmentName}
|
||||||
|
projectId={projectId}
|
||||||
|
changeRequestState='Approved'
|
||||||
|
change={{
|
||||||
|
action: 'deleteStrategy',
|
||||||
|
id: 1,
|
||||||
|
payload: {
|
||||||
|
id: strategy.id,
|
||||||
|
name: strategy.name,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
await screen.findByText('- Deleting strategy:');
|
||||||
|
await screen.findByText('Gradual rollout');
|
||||||
|
await screen.findByText('current_title');
|
||||||
|
|
||||||
|
const viewDiff = await screen.findByText('View Diff');
|
||||||
|
await userEvent.hover(viewDiff);
|
||||||
|
await screen.findByText('- constraints (deleted)');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Deleting strategy after change request is applied diffs against the snapshot', async () => {
|
||||||
|
render(
|
||||||
|
<StrategyChange
|
||||||
|
featureName={feature}
|
||||||
|
environmentName={environmentName}
|
||||||
|
projectId={projectId}
|
||||||
|
changeRequestState='Applied'
|
||||||
|
change={{
|
||||||
|
action: 'deleteStrategy',
|
||||||
|
id: 1,
|
||||||
|
payload: {
|
||||||
|
id: strategy.id,
|
||||||
|
// name is gone
|
||||||
|
snapshot: {
|
||||||
|
...strategy,
|
||||||
|
title: 'snapshot_title',
|
||||||
|
parameters: {
|
||||||
|
...strategy.parameters,
|
||||||
|
rollout: snapshotRollout,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
await screen.findByText('- Deleting strategy:');
|
||||||
|
await screen.findByText('Gradual rollout');
|
||||||
|
await screen.findByText('snapshot_title');
|
||||||
|
expect(screen.queryByText('current_title')).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
const viewDiff = await screen.findByText('View Diff');
|
||||||
|
await userEvent.hover(viewDiff);
|
||||||
|
await screen.findByText('- constraints (deleted)');
|
||||||
|
});
|
@ -1,5 +1,5 @@
|
|||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
import type { VFC, FC, ReactNode } from 'react';
|
import type { FC, ReactNode } from 'react';
|
||||||
import { Box, styled, Tooltip, Typography } from '@mui/material';
|
import { Box, styled, Tooltip, Typography } from '@mui/material';
|
||||||
import BlockIcon from '@mui/icons-material/Block';
|
import BlockIcon from '@mui/icons-material/Block';
|
||||||
import TrackChangesIcon from '@mui/icons-material/TrackChanges';
|
import TrackChangesIcon from '@mui/icons-material/TrackChanges';
|
||||||
@ -20,6 +20,7 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit
|
|||||||
import { flexRow } from 'themes/themeStyles';
|
import { flexRow } from 'themes/themeStyles';
|
||||||
import { EnvironmentVariantsTable } from 'component/feature/FeatureView/FeatureVariants/FeatureEnvironmentVariants/EnvironmentVariantsCard/EnvironmentVariantsTable/EnvironmentVariantsTable';
|
import { EnvironmentVariantsTable } from 'component/feature/FeatureView/FeatureVariants/FeatureEnvironmentVariants/EnvironmentVariantsCard/EnvironmentVariantsTable/EnvironmentVariantsTable';
|
||||||
import { ChangeOverwriteWarning } from './ChangeOverwriteWarning/ChangeOverwriteWarning';
|
import { ChangeOverwriteWarning } from './ChangeOverwriteWarning/ChangeOverwriteWarning';
|
||||||
|
import type { IFeatureStrategy } from 'interfaces/strategy';
|
||||||
|
|
||||||
export const ChangeItemWrapper = styled(Box)({
|
export const ChangeItemWrapper = styled(Box)({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -60,10 +61,7 @@ const StyledTypography: FC<{ children?: React.ReactNode }> = styled(Typography)(
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const hasNameField = (payload: unknown): payload is { name: string } =>
|
const DisabledEnabledState: FC<{ show?: boolean; disabled: boolean }> = ({
|
||||||
typeof payload === 'object' && payload !== null && 'name' in payload;
|
|
||||||
|
|
||||||
const DisabledEnabledState: VFC<{ show?: boolean; disabled: boolean }> = ({
|
|
||||||
show = true,
|
show = true,
|
||||||
disabled,
|
disabled,
|
||||||
}) => {
|
}) => {
|
||||||
@ -98,7 +96,7 @@ const DisabledEnabledState: VFC<{ show?: boolean; disabled: boolean }> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const EditHeader: VFC<{
|
const EditHeader: FC<{
|
||||||
wasDisabled?: boolean;
|
wasDisabled?: boolean;
|
||||||
willBeDisabled?: boolean;
|
willBeDisabled?: boolean;
|
||||||
}> = ({ wasDisabled = false, willBeDisabled = false }) => {
|
}> = ({ wasDisabled = false, willBeDisabled = false }) => {
|
||||||
@ -119,7 +117,157 @@ const EditHeader: VFC<{
|
|||||||
return <Typography>Editing strategy:</Typography>;
|
return <Typography>Editing strategy:</Typography>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const StrategyChange: VFC<{
|
const hasDiff = (object: unknown, objectToCompare: unknown) =>
|
||||||
|
JSON.stringify(object) !== JSON.stringify(objectToCompare);
|
||||||
|
|
||||||
|
const DeleteStrategy: FC<{
|
||||||
|
change: IChangeRequestDeleteStrategy;
|
||||||
|
changeRequestState: ChangeRequestState;
|
||||||
|
currentStrategy: IFeatureStrategy | undefined;
|
||||||
|
actions?: ReactNode;
|
||||||
|
}> = ({ change, changeRequestState, currentStrategy, actions }) => {
|
||||||
|
const name =
|
||||||
|
changeRequestState === 'Applied'
|
||||||
|
? change.payload?.snapshot?.name
|
||||||
|
: currentStrategy?.name;
|
||||||
|
const title =
|
||||||
|
changeRequestState === 'Applied'
|
||||||
|
? change.payload?.snapshot?.title
|
||||||
|
: currentStrategy?.title;
|
||||||
|
const referenceStrategy =
|
||||||
|
changeRequestState === 'Applied'
|
||||||
|
? change.payload.snapshot
|
||||||
|
: currentStrategy;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ChangeItemCreateEditDeleteWrapper className='delete-strategy-information-wrapper'>
|
||||||
|
<ChangeItemInfo>
|
||||||
|
<Typography
|
||||||
|
sx={(theme) => ({
|
||||||
|
color: theme.palette.error.main,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
- Deleting strategy:
|
||||||
|
</Typography>
|
||||||
|
<StrategyTooltipLink name={name || ''} title={title}>
|
||||||
|
<StrategyDiff
|
||||||
|
change={change}
|
||||||
|
currentStrategy={referenceStrategy}
|
||||||
|
/>
|
||||||
|
</StrategyTooltipLink>
|
||||||
|
</ChangeItemInfo>
|
||||||
|
<div>{actions}</div>
|
||||||
|
</ChangeItemCreateEditDeleteWrapper>
|
||||||
|
{referenceStrategy && (
|
||||||
|
<StrategyExecution strategy={referenceStrategy} />
|
||||||
|
)}
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={Boolean(referenceStrategy?.variants?.length)}
|
||||||
|
show={
|
||||||
|
referenceStrategy?.variants && (
|
||||||
|
<StyledBox>
|
||||||
|
<StyledTypography>
|
||||||
|
Deleting strategy variants:
|
||||||
|
</StyledTypography>
|
||||||
|
<EnvironmentVariantsTable
|
||||||
|
variants={referenceStrategy.variants}
|
||||||
|
/>
|
||||||
|
</StyledBox>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const UpdateStrategy: FC<{
|
||||||
|
change: IChangeRequestUpdateStrategy;
|
||||||
|
changeRequestState: ChangeRequestState;
|
||||||
|
currentStrategy: IFeatureStrategy | undefined;
|
||||||
|
actions?: ReactNode;
|
||||||
|
}> = ({ change, changeRequestState, currentStrategy, actions }) => {
|
||||||
|
const hasVariantDiff = hasDiff(
|
||||||
|
currentStrategy?.variants || [],
|
||||||
|
change.payload.variants || [],
|
||||||
|
);
|
||||||
|
const previousTitle =
|
||||||
|
changeRequestState === 'Applied'
|
||||||
|
? change.payload.snapshot?.title
|
||||||
|
: currentStrategy?.title;
|
||||||
|
const referenceStrategy =
|
||||||
|
changeRequestState === 'Applied'
|
||||||
|
? change.payload.snapshot
|
||||||
|
: currentStrategy;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ChangeOverwriteWarning
|
||||||
|
data={{
|
||||||
|
current: currentStrategy,
|
||||||
|
change,
|
||||||
|
changeType: 'strategy',
|
||||||
|
}}
|
||||||
|
changeRequestState={changeRequestState}
|
||||||
|
/>
|
||||||
|
<ChangeItemCreateEditDeleteWrapper>
|
||||||
|
<ChangeItemInfo>
|
||||||
|
<EditHeader
|
||||||
|
wasDisabled={currentStrategy?.disabled}
|
||||||
|
willBeDisabled={change.payload?.disabled}
|
||||||
|
/>
|
||||||
|
<StrategyTooltipLink
|
||||||
|
name={change.payload.name}
|
||||||
|
title={change.payload.title}
|
||||||
|
previousTitle={previousTitle}
|
||||||
|
>
|
||||||
|
<StrategyDiff
|
||||||
|
change={change}
|
||||||
|
currentStrategy={referenceStrategy}
|
||||||
|
/>
|
||||||
|
</StrategyTooltipLink>
|
||||||
|
</ChangeItemInfo>
|
||||||
|
<div>{actions}</div>
|
||||||
|
</ChangeItemCreateEditDeleteWrapper>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={
|
||||||
|
change.payload?.disabled !== currentStrategy?.disabled
|
||||||
|
}
|
||||||
|
show={
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
marginTop: (theme) => theme.spacing(2),
|
||||||
|
marginBottom: (theme) => theme.spacing(2),
|
||||||
|
...flexRow,
|
||||||
|
gap: (theme) => theme.spacing(1),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
This strategy will be{' '}
|
||||||
|
<DisabledEnabledState
|
||||||
|
disabled={change.payload?.disabled || false}
|
||||||
|
/>
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<StrategyExecution strategy={change.payload} />
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={Boolean(hasVariantDiff)}
|
||||||
|
show={
|
||||||
|
<StyledBox>
|
||||||
|
<StyledTypography>
|
||||||
|
Updating feature variants to:
|
||||||
|
</StyledTypography>
|
||||||
|
<EnvironmentVariantsTable
|
||||||
|
variants={change.payload.variants || []}
|
||||||
|
/>
|
||||||
|
</StyledBox>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const StrategyChange: FC<{
|
||||||
actions?: ReactNode;
|
actions?: ReactNode;
|
||||||
change:
|
change:
|
||||||
| IChangeRequestAddStrategy
|
| IChangeRequestAddStrategy
|
||||||
@ -144,16 +292,6 @@ export const StrategyChange: VFC<{
|
|||||||
environmentName,
|
environmentName,
|
||||||
);
|
);
|
||||||
|
|
||||||
const hasDiff = (object: unknown, objectToCompare: unknown) =>
|
|
||||||
JSON.stringify(object) !== JSON.stringify(objectToCompare);
|
|
||||||
|
|
||||||
const isStrategyAction =
|
|
||||||
change.action === 'addStrategy' || change.action === 'updateStrategy';
|
|
||||||
|
|
||||||
const hasVariantDiff =
|
|
||||||
isStrategyAction &&
|
|
||||||
hasDiff(currentStrategy?.variants || [], change.payload.variants || []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{change.action === 'addStrategy' && (
|
{change.action === 'addStrategy' && (
|
||||||
@ -169,7 +307,10 @@ export const StrategyChange: VFC<{
|
|||||||
>
|
>
|
||||||
+ Adding strategy:
|
+ Adding strategy:
|
||||||
</Typography>
|
</Typography>
|
||||||
<StrategyTooltipLink change={change}>
|
<StrategyTooltipLink
|
||||||
|
name={change.payload.name}
|
||||||
|
title={change.payload.title}
|
||||||
|
>
|
||||||
<StrategyDiff
|
<StrategyDiff
|
||||||
change={change}
|
change={change}
|
||||||
currentStrategy={currentStrategy}
|
currentStrategy={currentStrategy}
|
||||||
@ -185,139 +326,35 @@ export const StrategyChange: VFC<{
|
|||||||
<div>{actions}</div>
|
<div>{actions}</div>
|
||||||
</ChangeItemCreateEditDeleteWrapper>
|
</ChangeItemCreateEditDeleteWrapper>
|
||||||
<StrategyExecution strategy={change.payload} />
|
<StrategyExecution strategy={change.payload} />
|
||||||
<ConditionallyRender
|
{change.payload.variants &&
|
||||||
condition={hasVariantDiff}
|
change.payload.variants.length > 0 && (
|
||||||
show={
|
|
||||||
change.payload.variants && (
|
|
||||||
<StyledBox>
|
|
||||||
<StyledTypography>
|
|
||||||
Updating feature variants to:
|
|
||||||
</StyledTypography>
|
|
||||||
<EnvironmentVariantsTable
|
|
||||||
variants={change.payload.variants}
|
|
||||||
/>
|
|
||||||
</StyledBox>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{change.action === 'deleteStrategy' && (
|
|
||||||
<>
|
|
||||||
<ChangeItemCreateEditDeleteWrapper className='delete-strategy-information-wrapper'>
|
|
||||||
<ChangeItemInfo>
|
|
||||||
<Typography
|
|
||||||
sx={(theme) => ({
|
|
||||||
color: theme.palette.error.main,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
- Deleting strategy:
|
|
||||||
</Typography>
|
|
||||||
{hasNameField(change.payload) && (
|
|
||||||
<StrategyTooltipLink change={change}>
|
|
||||||
<StrategyDiff
|
|
||||||
change={change}
|
|
||||||
currentStrategy={currentStrategy}
|
|
||||||
/>
|
|
||||||
</StrategyTooltipLink>
|
|
||||||
)}
|
|
||||||
</ChangeItemInfo>
|
|
||||||
<div>{actions}</div>
|
|
||||||
</ChangeItemCreateEditDeleteWrapper>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={Boolean(currentStrategy)}
|
|
||||||
show={
|
|
||||||
<Typography>
|
|
||||||
{
|
|
||||||
<StrategyExecution
|
|
||||||
strategy={currentStrategy!}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
</Typography>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={Boolean(currentStrategy?.variants?.length)}
|
|
||||||
show={
|
|
||||||
currentStrategy?.variants && (
|
|
||||||
<StyledBox>
|
|
||||||
<StyledTypography>
|
|
||||||
Deleting strategy variants:
|
|
||||||
</StyledTypography>
|
|
||||||
<EnvironmentVariantsTable
|
|
||||||
variants={currentStrategy.variants}
|
|
||||||
/>
|
|
||||||
</StyledBox>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{change.action === 'updateStrategy' && (
|
|
||||||
<>
|
|
||||||
<ChangeOverwriteWarning
|
|
||||||
data={{
|
|
||||||
current: currentStrategy,
|
|
||||||
change,
|
|
||||||
changeType: 'strategy',
|
|
||||||
}}
|
|
||||||
changeRequestState={changeRequestState}
|
|
||||||
/>
|
|
||||||
<ChangeItemCreateEditDeleteWrapper>
|
|
||||||
<ChangeItemInfo>
|
|
||||||
<EditHeader
|
|
||||||
wasDisabled={currentStrategy?.disabled}
|
|
||||||
willBeDisabled={change.payload?.disabled}
|
|
||||||
/>
|
|
||||||
<StrategyTooltipLink
|
|
||||||
change={change}
|
|
||||||
previousTitle={currentStrategy?.title}
|
|
||||||
>
|
|
||||||
<StrategyDiff
|
|
||||||
change={change}
|
|
||||||
currentStrategy={currentStrategy}
|
|
||||||
/>
|
|
||||||
</StrategyTooltipLink>
|
|
||||||
</ChangeItemInfo>
|
|
||||||
<div>{actions}</div>
|
|
||||||
</ChangeItemCreateEditDeleteWrapper>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={
|
|
||||||
change.payload?.disabled !==
|
|
||||||
currentStrategy?.disabled
|
|
||||||
}
|
|
||||||
show={
|
|
||||||
<Typography
|
|
||||||
sx={{
|
|
||||||
marginTop: (theme) => theme.spacing(2),
|
|
||||||
marginBottom: (theme) => theme.spacing(2),
|
|
||||||
...flexRow,
|
|
||||||
gap: (theme) => theme.spacing(1),
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
This strategy will be{' '}
|
|
||||||
<DisabledEnabledState
|
|
||||||
disabled={change.payload?.disabled || false}
|
|
||||||
/>
|
|
||||||
</Typography>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<StrategyExecution strategy={change.payload} />
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={Boolean(hasVariantDiff)}
|
|
||||||
show={
|
|
||||||
<StyledBox>
|
<StyledBox>
|
||||||
<StyledTypography>
|
<StyledTypography>
|
||||||
Updating feature variants to:
|
Updating feature variants to:
|
||||||
</StyledTypography>
|
</StyledTypography>
|
||||||
<EnvironmentVariantsTable
|
<EnvironmentVariantsTable
|
||||||
variants={change.payload.variants || []}
|
variants={change.payload.variants}
|
||||||
/>
|
/>
|
||||||
</StyledBox>
|
</StyledBox>
|
||||||
}
|
)}
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{change.action === 'deleteStrategy' && (
|
||||||
|
<DeleteStrategy
|
||||||
|
change={change}
|
||||||
|
changeRequestState={changeRequestState}
|
||||||
|
currentStrategy={currentStrategy}
|
||||||
|
actions={actions}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{change.action === 'updateStrategy' && (
|
||||||
|
<UpdateStrategy
|
||||||
|
change={change}
|
||||||
|
changeRequestState={changeRequestState}
|
||||||
|
currentStrategy={currentStrategy}
|
||||||
|
actions={actions}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -51,10 +51,8 @@ export const StrategyDiff: FC<{
|
|||||||
};
|
};
|
||||||
|
|
||||||
interface IStrategyTooltipLinkProps {
|
interface IStrategyTooltipLinkProps {
|
||||||
change:
|
name: string;
|
||||||
| IChangeRequestAddStrategy
|
title?: string;
|
||||||
| IChangeRequestUpdateStrategy
|
|
||||||
| IChangeRequestDeleteStrategy;
|
|
||||||
previousTitle?: string;
|
previousTitle?: string;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
}
|
}
|
||||||
@ -80,29 +78,32 @@ const Truncated = styled('div')(() => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
export const StrategyTooltipLink: FC<IStrategyTooltipLinkProps> = ({
|
export const StrategyTooltipLink: FC<IStrategyTooltipLinkProps> = ({
|
||||||
change,
|
name,
|
||||||
|
title,
|
||||||
previousTitle,
|
previousTitle,
|
||||||
children,
|
children,
|
||||||
}) => (
|
}) => {
|
||||||
<StyledContainer>
|
return (
|
||||||
<GetFeatureStrategyIcon strategyName={change.payload.name} />
|
<StyledContainer>
|
||||||
<Truncated>
|
<GetFeatureStrategyIcon strategyName={name} />
|
||||||
<Typography component='span'>
|
<Truncated>
|
||||||
{formatStrategyName(change.payload.name)}
|
<Typography component='span'>
|
||||||
</Typography>
|
{formatStrategyName(name)}
|
||||||
<TooltipLink
|
</Typography>
|
||||||
tooltip={children}
|
<TooltipLink
|
||||||
tooltipProps={{
|
tooltip={children}
|
||||||
maxWidth: 500,
|
tooltipProps={{
|
||||||
maxHeight: 600,
|
maxWidth: 500,
|
||||||
}}
|
maxHeight: 600,
|
||||||
>
|
}}
|
||||||
<ViewDiff>View Diff</ViewDiff>
|
>
|
||||||
</TooltipLink>
|
<ViewDiff>View Diff</ViewDiff>
|
||||||
<NameWithChangeInfo
|
</TooltipLink>
|
||||||
newName={change.payload.title}
|
<NameWithChangeInfo
|
||||||
previousName={previousTitle}
|
newName={title}
|
||||||
/>
|
previousName={previousTitle}
|
||||||
</Truncated>
|
/>
|
||||||
</StyledContainer>
|
</Truncated>
|
||||||
);
|
</StyledContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
@ -241,14 +241,15 @@ export type ChangeRequestAddStrategy = Pick<
|
|||||||
|
|
||||||
export type ChangeRequestEditStrategy = ChangeRequestAddStrategy & {
|
export type ChangeRequestEditStrategy = ChangeRequestAddStrategy & {
|
||||||
id: string;
|
id: string;
|
||||||
snapshot?: Omit<IFeatureStrategy, 'title'> & { title?: string | null };
|
snapshot?: IFeatureStrategy;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ChangeRequestDeleteStrategy = {
|
type ChangeRequestDeleteStrategy = {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name?: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
snapshot?: IFeatureStrategy;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ChangeRequestAction =
|
export type ChangeRequestAction =
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Fragment, useMemo, type VFC } from 'react';
|
import { type FC, Fragment, useMemo } from 'react';
|
||||||
import { Alert, Box, Chip, Link, styled } from '@mui/material';
|
import { Alert, Box, Chip, Link, styled } from '@mui/material';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import PercentageCircle from 'component/common/PercentageCircle/PercentageCircle';
|
import PercentageCircle from 'component/common/PercentageCircle/PercentageCircle';
|
||||||
@ -56,7 +56,7 @@ const CustomStrategyDeprecationWarning = () => (
|
|||||||
</Alert>
|
</Alert>
|
||||||
);
|
);
|
||||||
|
|
||||||
const NoItems: VFC = () => (
|
const NoItems: FC = () => (
|
||||||
<Box sx={{ px: 3, color: 'text.disabled' }}>
|
<Box sx={{ px: 3, color: 'text.disabled' }}>
|
||||||
This strategy does not have constraints or parameters.
|
This strategy does not have constraints or parameters.
|
||||||
</Box>
|
</Box>
|
||||||
@ -73,7 +73,7 @@ const StyledValueSeparator = styled('span')(({ theme }) => ({
|
|||||||
color: theme.palette.neutral.main,
|
color: theme.palette.neutral.main,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const StrategyExecution: VFC<IStrategyExecutionProps> = ({
|
export const StrategyExecution: FC<IStrategyExecutionProps> = ({
|
||||||
strategy,
|
strategy,
|
||||||
}) => {
|
}) => {
|
||||||
const { parameters, constraints = [] } = strategy;
|
const { parameters, constraints = [] } = strategy;
|
||||||
|
Loading…
Reference in New Issue
Block a user