mirror of
https://github.com/Unleash/unleash.git
synced 2025-04-24 01:18:01 +02:00
chore: use new designs for project default strategies (#9447)
Implements the new strategy list design for default strategies. Moves the old impl into a legacy file. Also: removes the description from the strategy item. From my digging, we only showed this for default strategy items and it didn't really provide any useful information. The only other place you can add a description is for custom strategies (at least that I could find), but these are deprecated and we never show the description when you apply the strategy anyway. Rendered:  Without the flag (nothing changes): 
This commit is contained in:
parent
c26c040fc1
commit
7dd89034aa
@ -35,14 +35,8 @@ test('should render strategy name, custom title and description', async () => {
|
||||
parameters: {},
|
||||
};
|
||||
|
||||
render(
|
||||
<StrategyItemContainer
|
||||
strategy={strategy}
|
||||
description={'description'}
|
||||
/>,
|
||||
);
|
||||
render(<StrategyItemContainer strategy={strategy} />);
|
||||
|
||||
expect(screen.getByText('strategy name:')).toBeInTheDocument();
|
||||
expect(screen.getByText('description')).toBeInTheDocument();
|
||||
await screen.findByText('custom title'); // behind async flag
|
||||
});
|
||||
|
@ -12,13 +12,12 @@ import { Truncator } from '../Truncator/Truncator';
|
||||
|
||||
type StrategyItemContainerProps = {
|
||||
strategyHeaderLevel?: 1 | 2 | 3 | 4 | 5 | 6;
|
||||
strategy: IFeatureStrategy | PlaygroundStrategySchema;
|
||||
strategy: Omit<IFeatureStrategy, 'id'> | PlaygroundStrategySchema;
|
||||
onDragStart?: DragEventHandler<HTMLButtonElement>;
|
||||
onDragEnd?: DragEventHandler<HTMLButtonElement>;
|
||||
headerItemsRight?: ReactNode;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
description?: string;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
@ -28,23 +27,6 @@ const DragIcon = styled(IconButton)({
|
||||
transition: 'color 0.2s ease-in-out',
|
||||
});
|
||||
|
||||
const StyledDescription = styled('div')(({ theme }) => ({
|
||||
fontSize: theme.typography.fontSize,
|
||||
fontWeight: 'normal',
|
||||
color: theme.palette.text.secondary,
|
||||
display: 'none',
|
||||
top: theme.spacing(2.5),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
display: 'block',
|
||||
},
|
||||
}));
|
||||
const StyledCustomTitle = styled('div')(({ theme }) => ({
|
||||
fontWeight: 'normal',
|
||||
display: 'none',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
display: 'block',
|
||||
},
|
||||
}));
|
||||
const StyledHeaderContainer = styled('hgroup')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
flexFlow: 'row nowrap',
|
||||
@ -66,7 +48,7 @@ const StyledTruncator = styled(Truncator)(({ theme }) => ({
|
||||
margin: 0,
|
||||
}));
|
||||
|
||||
const NewStyledHeader = styled('div', {
|
||||
const StyledHeader = styled('div', {
|
||||
shouldForwardProp: (prop) => prop !== 'draggable' && prop !== 'disabled',
|
||||
})<{ draggable: boolean; disabled: boolean }>(
|
||||
({ theme, draggable, disabled }) => ({
|
||||
@ -89,7 +71,6 @@ export const StrategyItemContainer: FC<StrategyItemContainerProps> = ({
|
||||
strategyHeaderLevel = 3,
|
||||
children,
|
||||
style = {},
|
||||
description,
|
||||
}) => {
|
||||
const StrategyHeaderLink: React.FC<{ children?: React.ReactNode }> =
|
||||
'links' in strategy // todo: revisit this when we get to playground, related to flag `flagOverviewRedesign`
|
||||
@ -99,7 +80,7 @@ export const StrategyItemContainer: FC<StrategyItemContainerProps> = ({
|
||||
return (
|
||||
<Box sx={{ position: 'relative' }}>
|
||||
<StyledContainer style={style}>
|
||||
<NewStyledHeader
|
||||
<StyledHeader
|
||||
draggable={Boolean(onDragStart)}
|
||||
disabled={Boolean(strategy?.disabled)}
|
||||
>
|
||||
@ -146,25 +127,12 @@ export const StrategyItemContainer: FC<StrategyItemContainerProps> = ({
|
||||
{formatStrategyName(String(strategy.name))}
|
||||
</Typography>
|
||||
)}
|
||||
<ConditionallyRender
|
||||
condition={Boolean(description)}
|
||||
show={
|
||||
<StyledDescription>
|
||||
{description}
|
||||
</StyledDescription>
|
||||
}
|
||||
/>
|
||||
</StyledHeaderContainer>
|
||||
</StrategyHeaderLink>
|
||||
|
||||
<ConditionallyRender
|
||||
condition={Boolean(strategy?.disabled)}
|
||||
show={() => (
|
||||
<>
|
||||
<Badge color='disabled'>Disabled</Badge>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
{strategy.disabled ? (
|
||||
<Badge color='disabled'>Disabled</Badge>
|
||||
) : null}
|
||||
<Box
|
||||
sx={{
|
||||
marginLeft: 'auto',
|
||||
@ -175,7 +143,7 @@ export const StrategyItemContainer: FC<StrategyItemContainerProps> = ({
|
||||
>
|
||||
{headerItemsRight}
|
||||
</Box>
|
||||
</NewStyledHeader>
|
||||
</StyledHeader>
|
||||
<Box sx={{ p: 2, pt: 0 }}>{children}</Box>
|
||||
</StyledContainer>
|
||||
</Box>
|
||||
|
@ -3,11 +3,11 @@ import type { IFeatureStrategy } from 'interfaces/strategy';
|
||||
import { StrategyExecution } from './StrategyExecution/StrategyExecution';
|
||||
import SplitPreviewSlider from 'component/feature/StrategyTypes/SplitPreviewSlider/SplitPreviewSlider';
|
||||
import { Box } from '@mui/material';
|
||||
import { StrategyItemContainer as NewStrategyItemContainer } from 'component/common/StrategyItemContainer/StrategyItemContainer';
|
||||
import { StrategyItemContainer } from 'component/common/StrategyItemContainer/StrategyItemContainer';
|
||||
|
||||
type StrategyItemProps = {
|
||||
headerItemsRight?: ReactNode;
|
||||
strategy: IFeatureStrategy;
|
||||
strategy: Omit<IFeatureStrategy, 'id'>;
|
||||
onDragStart?: DragEventHandler<HTMLButtonElement>;
|
||||
onDragEnd?: DragEventHandler<HTMLButtonElement>;
|
||||
strategyHeaderLevel?: 1 | 2 | 3 | 4 | 5 | 6;
|
||||
@ -21,7 +21,7 @@ export const StrategyItem: FC<StrategyItemProps> = ({
|
||||
strategyHeaderLevel,
|
||||
}) => {
|
||||
return (
|
||||
<NewStrategyItemContainer
|
||||
<StrategyItemContainer
|
||||
strategyHeaderLevel={strategyHeaderLevel}
|
||||
strategy={strategy}
|
||||
onDragStart={onDragStart}
|
||||
@ -39,6 +39,6 @@ export const StrategyItem: FC<StrategyItemProps> = ({
|
||||
) : (
|
||||
<SplitPreviewSlider variants={strategy.variants} />
|
||||
))}
|
||||
</NewStrategyItemContainer>
|
||||
</StrategyItemContainer>
|
||||
);
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { FC, ReactNode } from 'react';
|
||||
import type { FC, PropsWithChildren } from 'react';
|
||||
import {
|
||||
AccordionSummary,
|
||||
type AccordionSummaryProps,
|
||||
@ -6,6 +6,7 @@ import {
|
||||
} from '@mui/material';
|
||||
import ExpandMore from '@mui/icons-material/ExpandMore';
|
||||
import { Truncator } from 'component/common/Truncator/Truncator';
|
||||
import { useId } from 'hooks/useId';
|
||||
|
||||
const StyledAccordionSummary = styled(AccordionSummary, {
|
||||
shouldForwardProp: (prop) => prop !== 'expandable',
|
||||
@ -47,22 +48,19 @@ const StyledHeaderTitleLabel = styled('p')(({ theme }) => ({
|
||||
}));
|
||||
|
||||
const StyledTruncator = styled(Truncator)(({ theme }) => ({
|
||||
fontSize: theme.typography.body1.fontSize,
|
||||
fontSize: theme.typography.h2.fontSize,
|
||||
fontWeight: theme.typography.fontWeightMedium,
|
||||
}));
|
||||
|
||||
type EnvironmentHeaderProps = {
|
||||
environmentId: string;
|
||||
children: ReactNode;
|
||||
expandable?: boolean;
|
||||
} & AccordionSummaryProps;
|
||||
|
||||
export const EnvironmentHeader: FC<EnvironmentHeaderProps> = ({
|
||||
environmentId,
|
||||
children,
|
||||
expandable = true,
|
||||
...props
|
||||
}) => {
|
||||
export const EnvironmentHeader: FC<
|
||||
PropsWithChildren<EnvironmentHeaderProps>
|
||||
> = ({ environmentId, children, expandable = true, ...props }) => {
|
||||
const id = useId();
|
||||
return (
|
||||
<StyledAccordionSummary
|
||||
{...props}
|
||||
@ -71,6 +69,8 @@ export const EnvironmentHeader: FC<EnvironmentHeaderProps> = ({
|
||||
sx={{ visibility: expandable ? 'visible' : 'hidden' }}
|
||||
/>
|
||||
}
|
||||
id={id}
|
||||
aria-controls={`environment-accordion-${id}-content`}
|
||||
expandable={expandable}
|
||||
>
|
||||
<StyledHeader data-loading>
|
||||
|
@ -10,13 +10,15 @@ import {
|
||||
UPDATE_PROJECT,
|
||||
} from 'component/providers/AccessProvider/permissions';
|
||||
import { Alert, styled } from '@mui/material';
|
||||
import ProjectEnvironment from './ProjectEnvironment/ProjectEnvironment';
|
||||
import LegacyProjectEnvironment from './ProjectEnvironment/LegacyProjectEnvironment';
|
||||
import { Route, Routes, useNavigate } from 'react-router-dom';
|
||||
import { SidebarModal } from 'component/common/SidebarModal/SidebarModal';
|
||||
import EditDefaultStrategy from './ProjectEnvironment/ProjectEnvironmentDefaultStrategy/EditDefaultStrategy';
|
||||
import useProjectOverview, {
|
||||
useProjectOverviewNameOrId,
|
||||
} from 'hooks/api/getters/useProjectOverview/useProjectOverview';
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
import { ProjectEnvironment } from './ProjectEnvironment/ProjectEnvironment';
|
||||
|
||||
const StyledAlert = styled(Alert)(({ theme }) => ({
|
||||
marginBottom: theme.spacing(4),
|
||||
@ -28,6 +30,7 @@ export const ProjectDefaultStrategySettings = () => {
|
||||
const { project } = useProjectOverview(projectId);
|
||||
const navigate = useNavigate();
|
||||
usePageTitle(`Project default strategy configuration – ${projectName}`);
|
||||
const flagOverviewRedesign = useUiFlag('flagOverviewRedesign');
|
||||
|
||||
if (
|
||||
!hasAccess(
|
||||
@ -61,12 +64,19 @@ export const ProjectDefaultStrategySettings = () => {
|
||||
specific environment. These will be used when you enable a
|
||||
toggle environment that has no strategies defined
|
||||
</StyledAlert>
|
||||
{project?.environments.map((environment) => (
|
||||
<ProjectEnvironment
|
||||
environment={environment}
|
||||
key={environment.environment}
|
||||
/>
|
||||
))}
|
||||
{project?.environments.map((environment) =>
|
||||
flagOverviewRedesign ? (
|
||||
<ProjectEnvironment
|
||||
environment={environment}
|
||||
key={environment.environment}
|
||||
/>
|
||||
) : (
|
||||
<LegacyProjectEnvironment
|
||||
environment={environment}
|
||||
key={environment.environment}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
</PageContent>
|
||||
<Routes>
|
||||
<Route
|
||||
|
@ -0,0 +1,149 @@
|
||||
import {
|
||||
Accordion,
|
||||
AccordionDetails,
|
||||
AccordionSummary,
|
||||
styled,
|
||||
useTheme,
|
||||
} from '@mui/material';
|
||||
import EnvironmentIcon from 'component/common/EnvironmentIcon/EnvironmentIcon';
|
||||
import StringTruncator from 'component/common/StringTruncator/StringTruncator';
|
||||
import { PROJECT_ENVIRONMENT_ACCORDION } from 'utils/testIds';
|
||||
import type { ProjectEnvironmentType } from '../../../../../../interfaces/environments';
|
||||
import LegacyProjectEnvironmentDefaultStrategy from './ProjectEnvironmentDefaultStrategy/LegacyProjectEnvironmentDefaultStrategy';
|
||||
|
||||
interface IProjectEnvironmentProps {
|
||||
environment: ProjectEnvironmentType;
|
||||
}
|
||||
|
||||
const StyledProjectEnvironmentOverview = styled('div', {
|
||||
shouldForwardProp: (prop) => prop !== 'enabled',
|
||||
})<{ enabled: boolean }>(({ theme, enabled }) => ({
|
||||
borderRadius: theme.shape.borderRadiusLarge,
|
||||
marginBottom: theme.spacing(2),
|
||||
backgroundColor: enabled
|
||||
? theme.palette.background.paper
|
||||
: theme.palette.envAccordion.disabled,
|
||||
}));
|
||||
|
||||
const StyledAccordion = styled(Accordion)({
|
||||
boxShadow: 'none',
|
||||
background: 'none',
|
||||
});
|
||||
|
||||
const StyledAccordionSummary = styled(AccordionSummary)(({ theme }) => ({
|
||||
boxShadow: 'none',
|
||||
padding: theme.spacing(2, 4),
|
||||
pointerEvents: 'none',
|
||||
[theme.breakpoints.down(400)]: {
|
||||
padding: theme.spacing(1, 2),
|
||||
},
|
||||
}));
|
||||
|
||||
const StyledAccordionDetails = styled(AccordionDetails)(({ theme }) => ({
|
||||
padding: theme.spacing(3),
|
||||
background: theme.palette.envAccordion.expanded,
|
||||
borderBottomLeftRadius: theme.shape.borderRadiusLarge,
|
||||
borderBottomRightRadius: theme.shape.borderRadiusLarge,
|
||||
boxShadow: theme.boxShadows.accordionFooter,
|
||||
|
||||
[theme.breakpoints.down('md')]: {
|
||||
padding: theme.spacing(2, 1),
|
||||
},
|
||||
}));
|
||||
|
||||
const StyledAccordionBody = styled('div')(({ theme }) => ({
|
||||
width: '100%',
|
||||
position: 'relative',
|
||||
paddingBottom: theme.spacing(2),
|
||||
}));
|
||||
|
||||
const StyledAccordionBodyInnerContainer = styled('div')(({ theme }) => ({
|
||||
[theme.breakpoints.down(400)]: {
|
||||
padding: theme.spacing(1),
|
||||
},
|
||||
}));
|
||||
|
||||
const StyledHeader = styled('div', {
|
||||
shouldForwardProp: (prop) => prop !== 'enabled',
|
||||
})<{ enabled: boolean }>(({ theme, enabled }) => ({
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'column',
|
||||
color: enabled ? theme.palette.text.primary : theme.palette.text.secondary,
|
||||
}));
|
||||
|
||||
const StyledHeaderTitle = styled('div')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
fontWeight: 'bold',
|
||||
[theme.breakpoints.down(560)]: {
|
||||
flexDirection: 'column',
|
||||
textAlign: 'center',
|
||||
},
|
||||
}));
|
||||
|
||||
const StyledEnvironmentIcon = styled(EnvironmentIcon)(({ theme }) => ({
|
||||
[theme.breakpoints.down(560)]: {
|
||||
marginBottom: '0.5rem',
|
||||
},
|
||||
}));
|
||||
|
||||
const StyledStringTruncator = styled(StringTruncator)(({ theme }) => ({
|
||||
fontSize: theme.fontSizes.bodySize,
|
||||
fontWeight: theme.typography.fontWeightMedium,
|
||||
[theme.breakpoints.down(560)]: {
|
||||
textAlign: 'center',
|
||||
},
|
||||
}));
|
||||
|
||||
const ProjectEnvironment = ({ environment }: IProjectEnvironmentProps) => {
|
||||
const { environment: name } = environment;
|
||||
const description = `Default strategy configuration in the ${name} environment`;
|
||||
const theme = useTheme();
|
||||
const enabled = false;
|
||||
|
||||
return (
|
||||
<StyledProjectEnvironmentOverview enabled={false}>
|
||||
<StyledAccordion
|
||||
expanded={true}
|
||||
onChange={(e) => e.stopPropagation()}
|
||||
data-testid={`${PROJECT_ENVIRONMENT_ACCORDION}_${name}`}
|
||||
className={`environment-accordion ${
|
||||
enabled ? '' : 'accordion-disabled'
|
||||
}`}
|
||||
style={{
|
||||
outline: `2px solid ${theme.palette.divider}`,
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
}}
|
||||
>
|
||||
<StyledAccordionSummary>
|
||||
<StyledHeader data-loading enabled={enabled}>
|
||||
<StyledHeaderTitle>
|
||||
<StyledEnvironmentIcon enabled />
|
||||
<div>
|
||||
<StyledStringTruncator
|
||||
text={name}
|
||||
maxWidth='100'
|
||||
maxLength={15}
|
||||
/>
|
||||
</div>
|
||||
</StyledHeaderTitle>
|
||||
</StyledHeader>
|
||||
</StyledAccordionSummary>
|
||||
|
||||
<StyledAccordionDetails>
|
||||
<StyledAccordionBody>
|
||||
<StyledAccordionBodyInnerContainer>
|
||||
<LegacyProjectEnvironmentDefaultStrategy
|
||||
environment={environment}
|
||||
description={description}
|
||||
/>
|
||||
</StyledAccordionBodyInnerContainer>
|
||||
</StyledAccordionBody>
|
||||
</StyledAccordionDetails>
|
||||
</StyledAccordion>
|
||||
</StyledProjectEnvironmentOverview>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectEnvironment;
|
@ -1,150 +1,47 @@
|
||||
import {
|
||||
Accordion,
|
||||
AccordionDetails,
|
||||
AccordionSummary,
|
||||
styled,
|
||||
useTheme,
|
||||
} from '@mui/material';
|
||||
import EnvironmentIcon from 'component/common/EnvironmentIcon/EnvironmentIcon';
|
||||
import StringTruncator from 'component/common/StringTruncator/StringTruncator';
|
||||
import { Accordion, AccordionDetails, styled } from '@mui/material';
|
||||
import { PROJECT_ENVIRONMENT_ACCORDION } from 'utils/testIds';
|
||||
import type { ProjectEnvironmentType } from '../../../../../../interfaces/environments';
|
||||
import ProjectEnvironmentDefaultStrategy from './ProjectEnvironmentDefaultStrategy/ProjectEnvironmentDefaultStrategy';
|
||||
import { ProjectEnvironmentDefaultStrategy } from './ProjectEnvironmentDefaultStrategy/ProjectEnvironmentDefaultStrategy';
|
||||
import { EnvironmentHeader } from 'component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentHeader/EnvironmentHeader';
|
||||
|
||||
interface IProjectEnvironmentProps {
|
||||
environment: ProjectEnvironmentType;
|
||||
}
|
||||
|
||||
const StyledProjectEnvironmentOverview = styled('div', {
|
||||
shouldForwardProp: (prop) => prop !== 'enabled',
|
||||
})<{ enabled: boolean }>(({ theme, enabled }) => ({
|
||||
borderRadius: theme.shape.borderRadiusLarge,
|
||||
const StyledProjectEnvironmentOverview = styled('div')(({ theme }) => ({
|
||||
marginBottom: theme.spacing(2),
|
||||
backgroundColor: enabled
|
||||
? theme.palette.background.paper
|
||||
: theme.palette.envAccordion.disabled,
|
||||
}));
|
||||
|
||||
const StyledAccordion = styled(Accordion)({
|
||||
const StyledAccordion = styled(Accordion)(({ theme }) => ({
|
||||
boxShadow: 'none',
|
||||
background: 'none',
|
||||
});
|
||||
|
||||
const StyledAccordionSummary = styled(AccordionSummary)(({ theme }) => ({
|
||||
boxShadow: 'none',
|
||||
padding: theme.spacing(2, 4),
|
||||
pointerEvents: 'none',
|
||||
[theme.breakpoints.down(400)]: {
|
||||
padding: theme.spacing(1, 2),
|
||||
},
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
overflow: 'hidden',
|
||||
}));
|
||||
|
||||
const StyledAccordionDetails = styled(AccordionDetails, {
|
||||
shouldForwardProp: (prop) => prop !== 'enabled',
|
||||
})<{ enabled: boolean }>(({ theme }) => ({
|
||||
padding: theme.spacing(3),
|
||||
background: theme.palette.envAccordion.expanded,
|
||||
borderBottomLeftRadius: theme.shape.borderRadiusLarge,
|
||||
borderBottomRightRadius: theme.shape.borderRadiusLarge,
|
||||
boxShadow: theme.boxShadows.accordionFooter,
|
||||
|
||||
[theme.breakpoints.down('md')]: {
|
||||
padding: theme.spacing(2, 1),
|
||||
},
|
||||
const StyledAccordionDetails = styled(AccordionDetails)(({ theme }) => ({
|
||||
padding: 0,
|
||||
background: theme.palette.background.elevation1,
|
||||
}));
|
||||
|
||||
const StyledAccordionBody = styled('div')(({ theme }) => ({
|
||||
width: '100%',
|
||||
position: 'relative',
|
||||
paddingBottom: theme.spacing(2),
|
||||
}));
|
||||
|
||||
const StyledAccordionBodyInnerContainer = styled('div')(({ theme }) => ({
|
||||
[theme.breakpoints.down(400)]: {
|
||||
padding: theme.spacing(1),
|
||||
},
|
||||
}));
|
||||
|
||||
const StyledHeader = styled('div', {
|
||||
shouldForwardProp: (prop) => prop !== 'enabled',
|
||||
})<{ enabled: boolean }>(({ theme, enabled }) => ({
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'column',
|
||||
color: enabled ? theme.palette.text.primary : theme.palette.text.secondary,
|
||||
}));
|
||||
|
||||
const StyledHeaderTitle = styled('div')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
fontWeight: 'bold',
|
||||
[theme.breakpoints.down(560)]: {
|
||||
flexDirection: 'column',
|
||||
textAlign: 'center',
|
||||
},
|
||||
}));
|
||||
|
||||
const StyledEnvironmentIcon = styled(EnvironmentIcon)(({ theme }) => ({
|
||||
[theme.breakpoints.down(560)]: {
|
||||
marginBottom: '0.5rem',
|
||||
},
|
||||
}));
|
||||
|
||||
const StyledStringTruncator = styled(StringTruncator)(({ theme }) => ({
|
||||
fontSize: theme.fontSizes.bodySize,
|
||||
fontWeight: theme.typography.fontWeightMedium,
|
||||
[theme.breakpoints.down(560)]: {
|
||||
textAlign: 'center',
|
||||
},
|
||||
}));
|
||||
|
||||
const ProjectEnvironment = ({ environment }: IProjectEnvironmentProps) => {
|
||||
export const ProjectEnvironment = ({
|
||||
environment,
|
||||
}: IProjectEnvironmentProps) => {
|
||||
const { environment: name } = environment;
|
||||
const description = `Default strategy configuration in the ${name} environment`;
|
||||
const theme = useTheme();
|
||||
const enabled = false;
|
||||
|
||||
return (
|
||||
<StyledProjectEnvironmentOverview enabled={false}>
|
||||
<StyledProjectEnvironmentOverview>
|
||||
<StyledAccordion
|
||||
expanded={true}
|
||||
onChange={(e) => e.stopPropagation()}
|
||||
data-testid={`${PROJECT_ENVIRONMENT_ACCORDION}_${name}`}
|
||||
className={`environment-accordion ${
|
||||
enabled ? '' : 'accordion-disabled'
|
||||
}`}
|
||||
style={{
|
||||
outline: `2px solid ${theme.palette.divider}`,
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
}}
|
||||
>
|
||||
<StyledAccordionSummary>
|
||||
<StyledHeader data-loading enabled={enabled}>
|
||||
<StyledHeaderTitle>
|
||||
<StyledEnvironmentIcon enabled />
|
||||
<div>
|
||||
<StyledStringTruncator
|
||||
text={name}
|
||||
maxWidth='100'
|
||||
maxLength={15}
|
||||
/>
|
||||
</div>
|
||||
</StyledHeaderTitle>
|
||||
</StyledHeader>
|
||||
</StyledAccordionSummary>
|
||||
|
||||
<StyledAccordionDetails enabled>
|
||||
<StyledAccordionBody>
|
||||
<StyledAccordionBodyInnerContainer>
|
||||
<ProjectEnvironmentDefaultStrategy
|
||||
environment={environment}
|
||||
description={description}
|
||||
/>
|
||||
</StyledAccordionBodyInnerContainer>
|
||||
</StyledAccordionBody>
|
||||
<EnvironmentHeader environmentId={name} expandable={false} />
|
||||
<StyledAccordionDetails>
|
||||
<ProjectEnvironmentDefaultStrategy
|
||||
environment={environment}
|
||||
/>
|
||||
</StyledAccordionDetails>
|
||||
</StyledAccordion>
|
||||
</StyledProjectEnvironmentOverview>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectEnvironment;
|
||||
|
@ -0,0 +1,94 @@
|
||||
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
||||
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Edit from '@mui/icons-material/Edit';
|
||||
import { StrategyExecution } from 'component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/StrategyExecution';
|
||||
import type { ProjectEnvironmentType } from 'interfaces/environments';
|
||||
import { useMemo } from 'react';
|
||||
import type { CreateFeatureStrategySchema } from 'openapi';
|
||||
import {
|
||||
PROJECT_DEFAULT_STRATEGY_WRITE,
|
||||
UPDATE_PROJECT,
|
||||
} from '@server/types/permissions';
|
||||
import SplitPreviewSlider from 'component/feature/StrategyTypes/SplitPreviewSlider/SplitPreviewSlider';
|
||||
import { StrategyItemContainer } from 'component/common/StrategyItemContainer/LegacyStrategyItemContainer';
|
||||
|
||||
interface ProjectEnvironmentDefaultStrategyProps {
|
||||
environment: ProjectEnvironmentType;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export const formatEditProjectEnvironmentStrategyPath = (
|
||||
projectId: string,
|
||||
environmentId: string,
|
||||
): string => {
|
||||
const params = new URLSearchParams({ environmentId });
|
||||
|
||||
return `/projects/${projectId}/settings/default-strategy/edit?${params}`;
|
||||
};
|
||||
|
||||
const DEFAULT_STRATEGY: CreateFeatureStrategySchema = {
|
||||
name: 'flexibleRollout',
|
||||
disabled: false,
|
||||
constraints: [],
|
||||
title: '',
|
||||
parameters: {
|
||||
rollout: '100',
|
||||
stickiness: 'default',
|
||||
groupId: '',
|
||||
},
|
||||
};
|
||||
|
||||
const ProjectEnvironmentDefaultStrategy = ({
|
||||
environment,
|
||||
description,
|
||||
}: ProjectEnvironmentDefaultStrategyProps) => {
|
||||
const projectId = useRequiredPathParam('projectId');
|
||||
const { environment: environmentId, defaultStrategy } = environment;
|
||||
|
||||
const editStrategyPath = formatEditProjectEnvironmentStrategyPath(
|
||||
projectId,
|
||||
environmentId,
|
||||
);
|
||||
|
||||
const strategy: CreateFeatureStrategySchema = useMemo(() => {
|
||||
return defaultStrategy ? defaultStrategy : DEFAULT_STRATEGY;
|
||||
}, [JSON.stringify(defaultStrategy)]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<StrategyItemContainer
|
||||
strategy={strategy as any}
|
||||
description={description}
|
||||
actions={
|
||||
<>
|
||||
<PermissionIconButton
|
||||
permission={[
|
||||
PROJECT_DEFAULT_STRATEGY_WRITE,
|
||||
UPDATE_PROJECT,
|
||||
]}
|
||||
environmentId={environmentId}
|
||||
projectId={projectId}
|
||||
component={Link}
|
||||
to={editStrategyPath}
|
||||
tooltipProps={{
|
||||
title: `Edit default strategy for "${environmentId}"`,
|
||||
}}
|
||||
data-testid={`STRATEGY_EDIT-${strategy?.name}`}
|
||||
>
|
||||
<Edit />
|
||||
</PermissionIconButton>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<StrategyExecution strategy={strategy} />
|
||||
|
||||
{strategy.variants && strategy.variants.length > 0 ? (
|
||||
<SplitPreviewSlider variants={strategy.variants} />
|
||||
) : null}
|
||||
</StrategyItemContainer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectEnvironmentDefaultStrategy;
|
@ -2,7 +2,6 @@ import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
||||
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Edit from '@mui/icons-material/Edit';
|
||||
import { StrategyExecution } from 'component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/StrategyExecution';
|
||||
import type { ProjectEnvironmentType } from 'interfaces/environments';
|
||||
import { useMemo } from 'react';
|
||||
import type { CreateFeatureStrategySchema } from 'openapi';
|
||||
@ -10,12 +9,11 @@ import {
|
||||
PROJECT_DEFAULT_STRATEGY_WRITE,
|
||||
UPDATE_PROJECT,
|
||||
} from '@server/types/permissions';
|
||||
import SplitPreviewSlider from 'component/feature/StrategyTypes/SplitPreviewSlider/SplitPreviewSlider';
|
||||
import { StrategyItemContainer } from 'component/common/StrategyItemContainer/LegacyStrategyItemContainer';
|
||||
import { StrategyItem } from 'component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyItem';
|
||||
import type { IFeatureStrategy } from 'interfaces/strategy';
|
||||
|
||||
interface ProjectEnvironmentDefaultStrategyProps {
|
||||
environment: ProjectEnvironmentType;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export const formatEditProjectEnvironmentStrategyPath = (
|
||||
@ -39,9 +37,8 @@ const DEFAULT_STRATEGY: CreateFeatureStrategySchema = {
|
||||
},
|
||||
};
|
||||
|
||||
const ProjectEnvironmentDefaultStrategy = ({
|
||||
export const ProjectEnvironmentDefaultStrategy = ({
|
||||
environment,
|
||||
description,
|
||||
}: ProjectEnvironmentDefaultStrategyProps) => {
|
||||
const projectId = useRequiredPathParam('projectId');
|
||||
const { environment: environmentId, defaultStrategy } = environment;
|
||||
@ -51,44 +48,42 @@ const ProjectEnvironmentDefaultStrategy = ({
|
||||
environmentId,
|
||||
);
|
||||
|
||||
const strategy: CreateFeatureStrategySchema = useMemo(() => {
|
||||
return defaultStrategy ? defaultStrategy : DEFAULT_STRATEGY;
|
||||
const strategy: Omit<IFeatureStrategy, 'id'> = useMemo(() => {
|
||||
const baseDefaultStrategy = defaultStrategy
|
||||
? defaultStrategy
|
||||
: DEFAULT_STRATEGY;
|
||||
return {
|
||||
...baseDefaultStrategy,
|
||||
disabled: false,
|
||||
constraints: baseDefaultStrategy.constraints ?? [],
|
||||
title: baseDefaultStrategy.title ?? '',
|
||||
parameters: baseDefaultStrategy.parameters ?? {},
|
||||
};
|
||||
}, [JSON.stringify(defaultStrategy)]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<StrategyItemContainer
|
||||
strategy={strategy as any}
|
||||
description={description}
|
||||
actions={
|
||||
<>
|
||||
<PermissionIconButton
|
||||
permission={[
|
||||
PROJECT_DEFAULT_STRATEGY_WRITE,
|
||||
UPDATE_PROJECT,
|
||||
]}
|
||||
environmentId={environmentId}
|
||||
projectId={projectId}
|
||||
component={Link}
|
||||
to={editStrategyPath}
|
||||
tooltipProps={{
|
||||
title: `Edit default strategy for "${environmentId}"`,
|
||||
}}
|
||||
data-testid={`STRATEGY_EDIT-${strategy?.name}`}
|
||||
>
|
||||
<Edit />
|
||||
</PermissionIconButton>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<StrategyExecution strategy={strategy} />
|
||||
|
||||
{strategy.variants && strategy.variants.length > 0 ? (
|
||||
<SplitPreviewSlider variants={strategy.variants} />
|
||||
) : null}
|
||||
</StrategyItemContainer>
|
||||
</>
|
||||
<StrategyItem
|
||||
strategy={strategy}
|
||||
headerItemsRight={
|
||||
<>
|
||||
<PermissionIconButton
|
||||
permission={[
|
||||
PROJECT_DEFAULT_STRATEGY_WRITE,
|
||||
UPDATE_PROJECT,
|
||||
]}
|
||||
environmentId={environmentId}
|
||||
projectId={projectId}
|
||||
component={Link}
|
||||
to={editStrategyPath}
|
||||
tooltipProps={{
|
||||
title: `Edit default strategy for "${environmentId}"`,
|
||||
}}
|
||||
data-testid={`STRATEGY_EDIT-${strategy.name}`}
|
||||
>
|
||||
<Edit />
|
||||
</PermissionIconButton>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectEnvironmentDefaultStrategy;
|
||||
|
Loading…
Reference in New Issue
Block a user