mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: segments in pending CR screen (#4420)
This commit is contained in:
		
							parent
							
								
									e20e7df10f
								
							
						
					
					
						commit
						7a32eacecb
					
				@ -29,6 +29,7 @@ const pendingChangeRequest = (featureName: string) =>
 | 
			
		||||
                        'https://gravatar.com/avatar/21232f297a57a5a743894a0e4a801fc3?size=42&default=retro',
 | 
			
		||||
                },
 | 
			
		||||
                createdAt: '2022-12-02T09:19:12.242Z',
 | 
			
		||||
                segments: [],
 | 
			
		||||
                features: [
 | 
			
		||||
                    {
 | 
			
		||||
                        name: featureName,
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,7 @@ const changeRequestWithDefaultChange = (
 | 
			
		||||
            username: 'author',
 | 
			
		||||
            imageUrl: '',
 | 
			
		||||
        },
 | 
			
		||||
        segments: [],
 | 
			
		||||
        features: [
 | 
			
		||||
            {
 | 
			
		||||
                name: 'Feature Toggle Name',
 | 
			
		||||
 | 
			
		||||
@ -2,8 +2,10 @@ import React, { VFC } from 'react';
 | 
			
		||||
import { Box, Typography } from '@mui/material';
 | 
			
		||||
import type { IChangeRequest } from '../changeRequest.types';
 | 
			
		||||
import { FeatureToggleChanges } from './Changes/FeatureToggleChanges';
 | 
			
		||||
import { Change } from './Changes/Change/Change';
 | 
			
		||||
import { FeatureChange } from './Changes/Change/FeatureChange';
 | 
			
		||||
import { ChangeActions } from './Changes/Change/ChangeActions';
 | 
			
		||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
 | 
			
		||||
import { SegmentChange } from './Changes/Change/SegmentChange';
 | 
			
		||||
 | 
			
		||||
interface IChangeRequestProps {
 | 
			
		||||
    changeRequest: IChangeRequest;
 | 
			
		||||
@ -18,6 +20,30 @@ export const ChangeRequest: VFC<IChangeRequestProps> = ({
 | 
			
		||||
}) => {
 | 
			
		||||
    return (
 | 
			
		||||
        <Box>
 | 
			
		||||
            <ConditionallyRender
 | 
			
		||||
                condition={changeRequest.segments.length > 0}
 | 
			
		||||
                show={
 | 
			
		||||
                    <Typography variant="body2" color="text.secondary">
 | 
			
		||||
                        You request changes for these segments:
 | 
			
		||||
                    </Typography>
 | 
			
		||||
                }
 | 
			
		||||
            />
 | 
			
		||||
 | 
			
		||||
            {changeRequest.segments?.map(segment => (
 | 
			
		||||
                <SegmentChange
 | 
			
		||||
                    key={segment.payload.id}
 | 
			
		||||
                    segmentChange={segment}
 | 
			
		||||
                    onNavigate={onNavigate}
 | 
			
		||||
                />
 | 
			
		||||
            ))}
 | 
			
		||||
            <ConditionallyRender
 | 
			
		||||
                condition={changeRequest.features.length > 0}
 | 
			
		||||
                show={
 | 
			
		||||
                    <Typography variant="body2" color="text.secondary">
 | 
			
		||||
                        You request changes for these feature toggles:
 | 
			
		||||
                    </Typography>
 | 
			
		||||
                }
 | 
			
		||||
            />
 | 
			
		||||
            {changeRequest.features?.map(feature => (
 | 
			
		||||
                <FeatureToggleChanges
 | 
			
		||||
                    key={feature.name}
 | 
			
		||||
@ -27,7 +53,7 @@ export const ChangeRequest: VFC<IChangeRequestProps> = ({
 | 
			
		||||
                    conflict={feature.conflict}
 | 
			
		||||
                >
 | 
			
		||||
                    {feature.changes.map((change, index) => (
 | 
			
		||||
                        <Change
 | 
			
		||||
                        <FeatureChange
 | 
			
		||||
                            key={index}
 | 
			
		||||
                            discard={
 | 
			
		||||
                                <ChangeActions
 | 
			
		||||
@ -44,7 +70,7 @@ export const ChangeRequest: VFC<IChangeRequestProps> = ({
 | 
			
		||||
                        />
 | 
			
		||||
                    ))}
 | 
			
		||||
                    {feature.defaultChange ? (
 | 
			
		||||
                        <Change
 | 
			
		||||
                        <FeatureChange
 | 
			
		||||
                            discard={
 | 
			
		||||
                                <Typography
 | 
			
		||||
                                    variant="body2"
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import React, { FC, useState } from 'react';
 | 
			
		||||
import {
 | 
			
		||||
    IChange,
 | 
			
		||||
    IFeatureChange,
 | 
			
		||||
    IChangeRequest,
 | 
			
		||||
    IChangeRequestAddStrategy,
 | 
			
		||||
    IChangeRequestUpdateStrategy,
 | 
			
		||||
@ -26,7 +26,10 @@ import {
 | 
			
		||||
import { Delete, Edit, MoreVert } from '@mui/icons-material';
 | 
			
		||||
import { EditChange } from './EditChange';
 | 
			
		||||
 | 
			
		||||
const useShowActions = (changeRequest: IChangeRequest, change: IChange) => {
 | 
			
		||||
const useShowActions = (
 | 
			
		||||
    changeRequest: IChangeRequest,
 | 
			
		||||
    change: IFeatureChange
 | 
			
		||||
) => {
 | 
			
		||||
    const { isChangeRequestConfigured } = useChangeRequestsEnabled(
 | 
			
		||||
        changeRequest.project
 | 
			
		||||
    );
 | 
			
		||||
@ -57,7 +60,7 @@ const StyledPopover = styled(Popover)(({ theme }) => ({
 | 
			
		||||
export const ChangeActions: FC<{
 | 
			
		||||
    changeRequest: IChangeRequest;
 | 
			
		||||
    feature: string;
 | 
			
		||||
    change: IChange;
 | 
			
		||||
    change: IFeatureChange;
 | 
			
		||||
    onRefetch?: () => void;
 | 
			
		||||
}> = ({ changeRequest, feature, change, onRefetch }) => {
 | 
			
		||||
    const { showDiscard, showEdit } = useShowActions(changeRequest, change);
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { FC, ReactNode } from 'react';
 | 
			
		||||
import {
 | 
			
		||||
    IChange,
 | 
			
		||||
    IFeatureChange,
 | 
			
		||||
    IChangeRequest,
 | 
			
		||||
    IChangeRequestFeature,
 | 
			
		||||
} from '../../../changeRequest.types';
 | 
			
		||||
@ -54,11 +54,11 @@ const StyledAlert = styled(Alert)(({ theme }) => ({
 | 
			
		||||
    },
 | 
			
		||||
}));
 | 
			
		||||
 | 
			
		||||
export const Change: FC<{
 | 
			
		||||
export const FeatureChange: FC<{
 | 
			
		||||
    discard: ReactNode;
 | 
			
		||||
    index: number;
 | 
			
		||||
    changeRequest: IChangeRequest;
 | 
			
		||||
    change: IChange;
 | 
			
		||||
    change: IFeatureChange;
 | 
			
		||||
    feature: IChangeRequestFeature;
 | 
			
		||||
}> = ({ index, change, feature, changeRequest, discard }) => {
 | 
			
		||||
    const lastIndex = feature.defaultChange
 | 
			
		||||
@ -82,6 +82,7 @@ export const Change: FC<{
 | 
			
		||||
                    </StyledAlert>
 | 
			
		||||
                }
 | 
			
		||||
            />
 | 
			
		||||
 | 
			
		||||
            <Box sx={theme => ({ padding: theme.spacing(3) })}>
 | 
			
		||||
                {change.action === 'updateEnabled' && (
 | 
			
		||||
                    <ToggleStatusChange
 | 
			
		||||
@ -89,6 +90,7 @@ export const Change: FC<{
 | 
			
		||||
                        discard={discard}
 | 
			
		||||
                    />
 | 
			
		||||
                )}
 | 
			
		||||
 | 
			
		||||
                {change.action === 'addStrategy' ||
 | 
			
		||||
                change.action === 'deleteStrategy' ||
 | 
			
		||||
                change.action === 'updateStrategy' ? (
 | 
			
		||||
@ -0,0 +1,64 @@
 | 
			
		||||
import { FC } from 'react';
 | 
			
		||||
import { Link as RouterLink } from 'react-router-dom';
 | 
			
		||||
import { Box, Card, Typography, Link } from '@mui/material';
 | 
			
		||||
import { ISegmentChange } from '../../../changeRequest.types';
 | 
			
		||||
import { SegmentChangeDetails } from './SegmentChangeDetails';
 | 
			
		||||
 | 
			
		||||
interface ISegmentChangeProps {
 | 
			
		||||
    segmentChange: ISegmentChange;
 | 
			
		||||
    onNavigate?: () => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const SegmentChange: FC<ISegmentChangeProps> = ({
 | 
			
		||||
    segmentChange,
 | 
			
		||||
    onNavigate,
 | 
			
		||||
}) => (
 | 
			
		||||
    <Card
 | 
			
		||||
        elevation={0}
 | 
			
		||||
        sx={theme => ({
 | 
			
		||||
            marginTop: theme.spacing(2),
 | 
			
		||||
            marginBottom: theme.spacing(2),
 | 
			
		||||
            overflow: 'hidden',
 | 
			
		||||
        })}
 | 
			
		||||
    >
 | 
			
		||||
        <Box
 | 
			
		||||
            sx={theme => ({
 | 
			
		||||
                backgroundColor: theme.palette.neutral.light,
 | 
			
		||||
                borderRadius: theme =>
 | 
			
		||||
                    `${theme.shape.borderRadiusLarge}px ${theme.shape.borderRadiusLarge}px 0 0`,
 | 
			
		||||
                border: '1px solid',
 | 
			
		||||
                borderColor: theme => theme.palette.divider,
 | 
			
		||||
                borderBottom: 'none',
 | 
			
		||||
                overflow: 'hidden',
 | 
			
		||||
            })}
 | 
			
		||||
        >
 | 
			
		||||
            <Box
 | 
			
		||||
                sx={{
 | 
			
		||||
                    display: 'flex',
 | 
			
		||||
                    pt: 2,
 | 
			
		||||
                    pb: 2,
 | 
			
		||||
                    px: 3,
 | 
			
		||||
                }}
 | 
			
		||||
            >
 | 
			
		||||
                <Typography>Segment name: </Typography>
 | 
			
		||||
 | 
			
		||||
                <Link
 | 
			
		||||
                    component={RouterLink}
 | 
			
		||||
                    to={`/segments/${segmentChange.payload.id}`}
 | 
			
		||||
                    color="primary"
 | 
			
		||||
                    underline="hover"
 | 
			
		||||
                    sx={{
 | 
			
		||||
                        marginLeft: 1,
 | 
			
		||||
                        '& :hover': {
 | 
			
		||||
                            textDecoration: 'underline',
 | 
			
		||||
                        },
 | 
			
		||||
                    }}
 | 
			
		||||
                    onClick={onNavigate}
 | 
			
		||||
                >
 | 
			
		||||
                    <strong>{segmentChange.payload.name}</strong>
 | 
			
		||||
                </Link>
 | 
			
		||||
            </Box>
 | 
			
		||||
        </Box>
 | 
			
		||||
        <SegmentChangeDetails change={segmentChange} />
 | 
			
		||||
    </Card>
 | 
			
		||||
);
 | 
			
		||||
@ -0,0 +1,89 @@
 | 
			
		||||
import { VFC, FC, ReactNode } from 'react';
 | 
			
		||||
import { Box, styled, Typography } from '@mui/material';
 | 
			
		||||
import {
 | 
			
		||||
    IChangeRequestDeleteSegment,
 | 
			
		||||
    IChangeRequestUpdateSegment,
 | 
			
		||||
} from 'component/changeRequest/changeRequest.types';
 | 
			
		||||
import { useSegment } from 'hooks/api/getters/useSegment/useSegment';
 | 
			
		||||
import { SegmentDiff, SegmentTooltipLink } from '../../SegmentTooltipLink';
 | 
			
		||||
 | 
			
		||||
const ChangeItemCreateEditWrapper = styled(Box)(({ theme }) => ({
 | 
			
		||||
    display: 'grid',
 | 
			
		||||
    gridTemplateColumns: 'auto 40px',
 | 
			
		||||
    gap: theme.spacing(1),
 | 
			
		||||
    alignItems: 'center',
 | 
			
		||||
    width: '100%',
 | 
			
		||||
}));
 | 
			
		||||
 | 
			
		||||
export const ChangeItemWrapper = styled(Box)({
 | 
			
		||||
    display: 'flex',
 | 
			
		||||
    justifyContent: 'space-between',
 | 
			
		||||
    alignItems: 'center',
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const ChangeItemInfo: FC = styled(Box)(({ theme }) => ({
 | 
			
		||||
    display: 'grid',
 | 
			
		||||
    gridTemplateColumns: '150px auto',
 | 
			
		||||
    gridAutoFlow: 'column',
 | 
			
		||||
    alignItems: 'center',
 | 
			
		||||
    flexGrow: 1,
 | 
			
		||||
    gap: theme.spacing(1),
 | 
			
		||||
}));
 | 
			
		||||
 | 
			
		||||
const SegmentContainer = styled(Box)(({ theme }) => ({
 | 
			
		||||
    borderLeft: '1px solid',
 | 
			
		||||
    borderRight: '1px solid',
 | 
			
		||||
    borderTop: '1px solid',
 | 
			
		||||
    borderBottom: '1px solid',
 | 
			
		||||
    borderColor: theme.palette.divider,
 | 
			
		||||
    borderTopColor: theme.palette.divider,
 | 
			
		||||
    padding: theme.spacing(3),
 | 
			
		||||
}));
 | 
			
		||||
 | 
			
		||||
export const SegmentChangeDetails: VFC<{
 | 
			
		||||
    discard?: ReactNode;
 | 
			
		||||
    change: IChangeRequestUpdateSegment | IChangeRequestDeleteSegment;
 | 
			
		||||
}> = ({ discard, change }) => {
 | 
			
		||||
    const { segment: currentSegment } = useSegment(change.payload.id);
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <SegmentContainer>
 | 
			
		||||
            {change.action === 'deleteSegment' && (
 | 
			
		||||
                <ChangeItemWrapper>
 | 
			
		||||
                    <ChangeItemInfo>
 | 
			
		||||
                        <Typography
 | 
			
		||||
                            sx={theme => ({
 | 
			
		||||
                                color: theme.palette.error.main,
 | 
			
		||||
                            })}
 | 
			
		||||
                        >
 | 
			
		||||
                            - Deleting segment:
 | 
			
		||||
                        </Typography>
 | 
			
		||||
                        <SegmentTooltipLink change={change}>
 | 
			
		||||
                            <SegmentDiff
 | 
			
		||||
                                change={change}
 | 
			
		||||
                                currentSegment={currentSegment}
 | 
			
		||||
                            />
 | 
			
		||||
                        </SegmentTooltipLink>
 | 
			
		||||
                    </ChangeItemInfo>
 | 
			
		||||
                    <div>{discard}</div>
 | 
			
		||||
                </ChangeItemWrapper>
 | 
			
		||||
            )}
 | 
			
		||||
            {change.action === 'updateSegment' && (
 | 
			
		||||
                <>
 | 
			
		||||
                    <ChangeItemCreateEditWrapper>
 | 
			
		||||
                        <ChangeItemInfo>
 | 
			
		||||
                            <Typography>Editing segment:</Typography>
 | 
			
		||||
                            <SegmentTooltipLink change={change}>
 | 
			
		||||
                                <SegmentDiff
 | 
			
		||||
                                    change={change}
 | 
			
		||||
                                    currentSegment={currentSegment}
 | 
			
		||||
                                />
 | 
			
		||||
                            </SegmentTooltipLink>
 | 
			
		||||
                        </ChangeItemInfo>
 | 
			
		||||
                        <div>{discard}</div>
 | 
			
		||||
                    </ChangeItemCreateEditWrapper>
 | 
			
		||||
                </>
 | 
			
		||||
            )}
 | 
			
		||||
        </SegmentContainer>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,79 @@
 | 
			
		||||
import {
 | 
			
		||||
    IChangeRequestDeleteSegment,
 | 
			
		||||
    IChangeRequestUpdateSegment,
 | 
			
		||||
} from 'component/changeRequest/changeRequest.types';
 | 
			
		||||
import { FC } from 'react';
 | 
			
		||||
import { formatStrategyName } from 'utils/strategyNames';
 | 
			
		||||
import EventDiff from 'component/events/EventDiff/EventDiff';
 | 
			
		||||
import omit from 'lodash.omit';
 | 
			
		||||
import { TooltipLink } from 'component/common/TooltipLink/TooltipLink';
 | 
			
		||||
import { Typography, styled } from '@mui/material';
 | 
			
		||||
import { textTruncated } from 'themes/themeStyles';
 | 
			
		||||
import { ISegment } from 'interfaces/segment';
 | 
			
		||||
 | 
			
		||||
const StyledCodeSection = styled('div')(({ theme }) => ({
 | 
			
		||||
    overflowX: 'auto',
 | 
			
		||||
    '& code': {
 | 
			
		||||
        wordWrap: 'break-word',
 | 
			
		||||
        whiteSpace: 'pre-wrap',
 | 
			
		||||
        fontFamily: 'monospace',
 | 
			
		||||
        lineHeight: 1.5,
 | 
			
		||||
        fontSize: theme.fontSizes.smallBody,
 | 
			
		||||
    },
 | 
			
		||||
}));
 | 
			
		||||
 | 
			
		||||
export const SegmentDiff: FC<{
 | 
			
		||||
    change: IChangeRequestUpdateSegment | IChangeRequestDeleteSegment;
 | 
			
		||||
    currentSegment?: ISegment;
 | 
			
		||||
}> = ({ change, currentSegment }) => {
 | 
			
		||||
    const changeRequestStrategy =
 | 
			
		||||
        change.action === 'deleteSegment' ? undefined : change.payload;
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <StyledCodeSection>
 | 
			
		||||
            <EventDiff
 | 
			
		||||
                entry={{
 | 
			
		||||
                    preData: omit(currentSegment, 'sortOrder'),
 | 
			
		||||
                    data: changeRequestStrategy,
 | 
			
		||||
                }}
 | 
			
		||||
            />
 | 
			
		||||
        </StyledCodeSection>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
interface IStrategyTooltipLinkProps {
 | 
			
		||||
    change: IChangeRequestUpdateSegment | IChangeRequestDeleteSegment;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const StyledContainer: FC = styled('div')(({ theme }) => ({
 | 
			
		||||
    display: 'grid',
 | 
			
		||||
    gridAutoFlow: 'column',
 | 
			
		||||
    gridTemplateColumns: 'auto 1fr',
 | 
			
		||||
    gap: theme.spacing(1),
 | 
			
		||||
    alignItems: 'center',
 | 
			
		||||
}));
 | 
			
		||||
 | 
			
		||||
const Truncated = styled('div')(() => ({
 | 
			
		||||
    ...textTruncated,
 | 
			
		||||
    maxWidth: 500,
 | 
			
		||||
}));
 | 
			
		||||
 | 
			
		||||
export const SegmentTooltipLink: FC<IStrategyTooltipLinkProps> = ({
 | 
			
		||||
    change,
 | 
			
		||||
    children,
 | 
			
		||||
}) => (
 | 
			
		||||
    <StyledContainer>
 | 
			
		||||
        <Truncated>
 | 
			
		||||
            <TooltipLink
 | 
			
		||||
                tooltip={children}
 | 
			
		||||
                tooltipProps={{
 | 
			
		||||
                    maxWidth: 500,
 | 
			
		||||
                    maxHeight: 600,
 | 
			
		||||
                }}
 | 
			
		||||
            >
 | 
			
		||||
                <Typography component="span">
 | 
			
		||||
                    {formatStrategyName(change.payload.name)}
 | 
			
		||||
                </Typography>
 | 
			
		||||
            </TooltipLink>
 | 
			
		||||
        </Truncated>
 | 
			
		||||
    </StyledContainer>
 | 
			
		||||
);
 | 
			
		||||
@ -112,11 +112,7 @@ export const EnvironmentChangeRequest: FC<{
 | 
			
		||||
                </ChangeRequestTitle>
 | 
			
		||||
            </ChangeRequestHeader>
 | 
			
		||||
            <ChangeRequestContent>
 | 
			
		||||
                <Typography variant="body2" color="text.secondary">
 | 
			
		||||
                    You request changes for these feature toggles:
 | 
			
		||||
                </Typography>
 | 
			
		||||
                {children}
 | 
			
		||||
 | 
			
		||||
                <ConditionallyRender
 | 
			
		||||
                    condition={environmentChangeRequest?.state === 'Draft'}
 | 
			
		||||
                    show={
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,11 @@
 | 
			
		||||
import React, { FC, useState } from 'react';
 | 
			
		||||
import { screen } from '@testing-library/react';
 | 
			
		||||
import { ChangeRequestTitle } from './ChangeRequestTitle';
 | 
			
		||||
import { ChangeRequestState } from '../../changeRequest.types';
 | 
			
		||||
import { ChangeRequestState } from 'component/changeRequest/changeRequest.types';
 | 
			
		||||
import userEvent from '@testing-library/user-event';
 | 
			
		||||
import { testServerRoute, testServerSetup } from 'utils/testServer';
 | 
			
		||||
import { render } from 'utils/testRenderer';
 | 
			
		||||
import { UIProviderContainer } from '../../../providers/UIProvider/UIProviderContainer';
 | 
			
		||||
import { UIProviderContainer } from 'component/providers/UIProvider/UIProviderContainer';
 | 
			
		||||
 | 
			
		||||
const changeRequest = {
 | 
			
		||||
    id: 3,
 | 
			
		||||
@ -19,6 +19,7 @@ const changeRequest = {
 | 
			
		||||
    features: [],
 | 
			
		||||
    approvals: [],
 | 
			
		||||
    comments: [],
 | 
			
		||||
    segments: [],
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const server = testServerSetup();
 | 
			
		||||
 | 
			
		||||
@ -13,6 +13,7 @@ export interface IChangeRequest {
 | 
			
		||||
    createdBy: Pick<IUser, 'id' | 'username' | 'imageUrl'>;
 | 
			
		||||
    createdAt: Date;
 | 
			
		||||
    features: IChangeRequestFeature[];
 | 
			
		||||
    segments: ISegmentChange[];
 | 
			
		||||
    approvals: IChangeRequestApproval[];
 | 
			
		||||
    comments: IChangeRequestComment[];
 | 
			
		||||
    conflict?: string;
 | 
			
		||||
@ -28,7 +29,14 @@ export interface IChangeRequestEnvironmentConfig {
 | 
			
		||||
export interface IChangeRequestFeature {
 | 
			
		||||
    name: string;
 | 
			
		||||
    conflict?: string;
 | 
			
		||||
    changes: IChange[];
 | 
			
		||||
    changes: IFeatureChange[];
 | 
			
		||||
    defaultChange?: IChangeRequestAddStrategy | IChangeRequestEnabled;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface IChangeRequestSegment {
 | 
			
		||||
    name: string;
 | 
			
		||||
    conflict?: string;
 | 
			
		||||
    changes: IFeatureChange[];
 | 
			
		||||
    defaultChange?: IChangeRequestAddStrategy | IChangeRequestEnabled;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -44,7 +52,7 @@ export interface IChangeRequestComment {
 | 
			
		||||
    id: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface IChangeRequestBase {
 | 
			
		||||
export interface IChangeRequestChangeBase {
 | 
			
		||||
    id: number;
 | 
			
		||||
    action: ChangeRequestAction;
 | 
			
		||||
    payload: ChangeRequestPayload;
 | 
			
		||||
@ -66,39 +74,63 @@ type ChangeRequestPayload =
 | 
			
		||||
    | ChangeRequestEditStrategy
 | 
			
		||||
    | ChangeRequestDeleteStrategy
 | 
			
		||||
    | ChangeRequestVariantPatch
 | 
			
		||||
    | IChangeRequestUpdateSegment
 | 
			
		||||
    | IChangeRequestDeleteSegment
 | 
			
		||||
    | SetStrategySortOrderSchema;
 | 
			
		||||
 | 
			
		||||
export interface IChangeRequestAddStrategy extends IChangeRequestBase {
 | 
			
		||||
export interface IChangeRequestAddStrategy extends IChangeRequestChangeBase {
 | 
			
		||||
    action: 'addStrategy';
 | 
			
		||||
    payload: ChangeRequestAddStrategy;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface IChangeRequestDeleteStrategy extends IChangeRequestBase {
 | 
			
		||||
export interface IChangeRequestDeleteStrategy extends IChangeRequestChangeBase {
 | 
			
		||||
    action: 'deleteStrategy';
 | 
			
		||||
    payload: ChangeRequestDeleteStrategy;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface IChangeRequestUpdateStrategy extends IChangeRequestBase {
 | 
			
		||||
export interface IChangeRequestUpdateStrategy extends IChangeRequestChangeBase {
 | 
			
		||||
    action: 'updateStrategy';
 | 
			
		||||
    payload: ChangeRequestEditStrategy;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface IChangeRequestEnabled extends IChangeRequestBase {
 | 
			
		||||
export interface IChangeRequestEnabled extends IChangeRequestChangeBase {
 | 
			
		||||
    action: 'updateEnabled';
 | 
			
		||||
    payload: ChangeRequestEnabled;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface IChangeRequestPatchVariant extends IChangeRequestBase {
 | 
			
		||||
export interface IChangeRequestPatchVariant extends IChangeRequestChangeBase {
 | 
			
		||||
    action: 'patchVariant';
 | 
			
		||||
    payload: ChangeRequestVariantPatch;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface IChangeRequestReorderStrategy extends IChangeRequestBase {
 | 
			
		||||
export interface IChangeRequestReorderStrategy
 | 
			
		||||
    extends IChangeRequestChangeBase {
 | 
			
		||||
    action: 'reorderStrategy';
 | 
			
		||||
    payload: SetStrategySortOrderSchema;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type IChange =
 | 
			
		||||
export interface IChangeRequestUpdateSegment {
 | 
			
		||||
    action: 'updateSegment';
 | 
			
		||||
    payload: {
 | 
			
		||||
        id: number;
 | 
			
		||||
        name: string;
 | 
			
		||||
        description?: string;
 | 
			
		||||
        project?: string;
 | 
			
		||||
        constraints: IFeatureStrategy['constraints'];
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface IChangeRequestDeleteSegment {
 | 
			
		||||
    action: 'deleteSegment';
 | 
			
		||||
    payload: {
 | 
			
		||||
        id: number;
 | 
			
		||||
        name: string;
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type IChange = IFeatureChange | ISegmentChange;
 | 
			
		||||
 | 
			
		||||
export type IFeatureChange =
 | 
			
		||||
    | IChangeRequestAddStrategy
 | 
			
		||||
    | IChangeRequestDeleteStrategy
 | 
			
		||||
    | IChangeRequestUpdateStrategy
 | 
			
		||||
@ -106,6 +138,10 @@ export type IChange =
 | 
			
		||||
    | IChangeRequestPatchVariant
 | 
			
		||||
    | IChangeRequestReorderStrategy;
 | 
			
		||||
 | 
			
		||||
export type ISegmentChange =
 | 
			
		||||
    | IChangeRequestUpdateSegment
 | 
			
		||||
    | IChangeRequestDeleteSegment;
 | 
			
		||||
 | 
			
		||||
type ChangeRequestVariantPatch = {
 | 
			
		||||
    variants: IFeatureVariant[];
 | 
			
		||||
};
 | 
			
		||||
@ -132,4 +168,6 @@ export type ChangeRequestAction =
 | 
			
		||||
    | 'updateStrategy'
 | 
			
		||||
    | 'deleteStrategy'
 | 
			
		||||
    | 'patchVariant'
 | 
			
		||||
    | 'reorderStrategy';
 | 
			
		||||
    | 'reorderStrategy'
 | 
			
		||||
    | 'updateSegment'
 | 
			
		||||
    | 'deleteSegment';
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
import { IChangeRequest } from './changeRequest.types';
 | 
			
		||||
 | 
			
		||||
export const changesCount = (changeRequest: IChangeRequest) =>
 | 
			
		||||
    changeRequest.features.flatMap(feature => feature.changes).length;
 | 
			
		||||
    changeRequest.features.flatMap(feature => feature.changes).length +
 | 
			
		||||
    changeRequest.segments.length;
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,7 @@ import { IFeatureStrategy } from 'interfaces/strategy';
 | 
			
		||||
import { StrategyItem } from './StrategyItem/StrategyItem';
 | 
			
		||||
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
 | 
			
		||||
import { Badge } from 'component/common/Badge/Badge';
 | 
			
		||||
import { IChange } from 'component/changeRequest/changeRequest.types';
 | 
			
		||||
import { IFeatureChange } from 'component/changeRequest/changeRequest.types';
 | 
			
		||||
import { useStrategyChangeFromRequest } from './StrategyItem/useStrategyChangeFromRequest';
 | 
			
		||||
 | 
			
		||||
interface IStrategyDraggableItemProps {
 | 
			
		||||
@ -74,7 +74,7 @@ export const StrategyDraggableItem = ({
 | 
			
		||||
const ChangeRequestStatusBadge = ({
 | 
			
		||||
    change,
 | 
			
		||||
}: {
 | 
			
		||||
    change: IChange | undefined;
 | 
			
		||||
    change: IFeatureChange | undefined;
 | 
			
		||||
}) => {
 | 
			
		||||
    const theme = useTheme();
 | 
			
		||||
    const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm'));
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user