mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	Feat/new strategy configuration targeting tab (#5643)
This PR sets up the new targeting tab for strategy configuration: <img width="1292" alt="Skjermbilde 2023-12-14 kl 11 24 11" src="https://github.com/Unleash/unleash/assets/16081982/5c2d8f02-b3ec-49d4-b8bd-90f93ef3931c">
This commit is contained in:
		
							parent
							
								
									1338496445
								
							
						
					
					
						commit
						53b32db278
					
				@ -1,8 +1,10 @@
 | 
				
			|||||||
import { useStyles } from 'component/common/AutocompleteBox/AutocompleteBox.styles';
 | 
					import { useStyles } from 'component/common/AutocompleteBox/AutocompleteBox.styles';
 | 
				
			||||||
import { Search, ArrowDropDown } from '@mui/icons-material';
 | 
					import { Search, ArrowDropDown, Add } from '@mui/icons-material';
 | 
				
			||||||
import { Autocomplete, styled } from '@mui/material';
 | 
					import { Autocomplete, styled, InputAdornment, useTheme } from '@mui/material';
 | 
				
			||||||
import { AutocompleteRenderInputParams } from '@mui/material/Autocomplete';
 | 
					import { AutocompleteRenderInputParams } from '@mui/material/Autocomplete';
 | 
				
			||||||
import { TextField } from '@mui/material';
 | 
					import { TextField } from '@mui/material';
 | 
				
			||||||
 | 
					import { useUiFlag } from 'hooks/useUiFlag';
 | 
				
			||||||
 | 
					import { useState } from 'react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IAutocompleteBoxProps {
 | 
					interface IAutocompleteBoxProps {
 | 
				
			||||||
    label: string;
 | 
					    label: string;
 | 
				
			||||||
@ -54,12 +56,80 @@ export const AutocompleteBox = ({
 | 
				
			|||||||
    onChange,
 | 
					    onChange,
 | 
				
			||||||
    disabled,
 | 
					    disabled,
 | 
				
			||||||
}: IAutocompleteBoxProps) => {
 | 
					}: IAutocompleteBoxProps) => {
 | 
				
			||||||
 | 
					    const [placeHolder, setPlaceholder] = useState('Add Segments');
 | 
				
			||||||
    const { classes: styles } = useStyles();
 | 
					    const { classes: styles } = useStyles();
 | 
				
			||||||
 | 
					    const theme = useTheme();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const newStrategyConfiguration = useUiFlag('newStrategyConfiguration');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const renderInput = (params: AutocompleteRenderInputParams) => {
 | 
					    const renderInput = (params: AutocompleteRenderInputParams) => {
 | 
				
			||||||
        return <TextField {...params} variant='outlined' label={label} />;
 | 
					        return <TextField {...params} variant='outlined' label={label} />;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const renderCustomInput = (params: AutocompleteRenderInputParams) => {
 | 
				
			||||||
 | 
					        const { InputProps } = params;
 | 
				
			||||||
 | 
					        return (
 | 
				
			||||||
 | 
					            <TextField
 | 
				
			||||||
 | 
					                {...params}
 | 
				
			||||||
 | 
					                InputProps={{
 | 
				
			||||||
 | 
					                    ...InputProps,
 | 
				
			||||||
 | 
					                    startAdornment: (
 | 
				
			||||||
 | 
					                        <InputAdornment position='start'>
 | 
				
			||||||
 | 
					                            <Add
 | 
				
			||||||
 | 
					                                sx={{
 | 
				
			||||||
 | 
					                                    height: 20,
 | 
				
			||||||
 | 
					                                    width: 20,
 | 
				
			||||||
 | 
					                                    color: theme.palette.primary.main,
 | 
				
			||||||
 | 
					                                }}
 | 
				
			||||||
 | 
					                            />
 | 
				
			||||||
 | 
					                        </InputAdornment>
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                }}
 | 
				
			||||||
 | 
					                variant='outlined'
 | 
				
			||||||
 | 
					                sx={{
 | 
				
			||||||
 | 
					                    width: '215px',
 | 
				
			||||||
 | 
					                    '& .MuiOutlinedInput-root': {
 | 
				
			||||||
 | 
					                        '& .MuiInputBase-input': {
 | 
				
			||||||
 | 
					                            color: theme.palette.primary.main,
 | 
				
			||||||
 | 
					                            opacity: 1,
 | 
				
			||||||
 | 
					                            '&::placeholder': {
 | 
				
			||||||
 | 
					                                color: theme.palette.primary.main,
 | 
				
			||||||
 | 
					                                fontWeight: 'bold',
 | 
				
			||||||
 | 
					                                opacity: 1,
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        '& .MuiOutlinedInput-notchedOutline': {
 | 
				
			||||||
 | 
					                            borderColor: theme.palette.primary.main,
 | 
				
			||||||
 | 
					                            opacity: 0.5,
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        '&.Mui-focused .MuiOutlinedInput-notchedOutline': {
 | 
				
			||||||
 | 
					                            borderWidth: '1px',
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                }}
 | 
				
			||||||
 | 
					                placeholder={placeHolder}
 | 
				
			||||||
 | 
					                onFocus={() => setPlaceholder('')}
 | 
				
			||||||
 | 
					                onBlur={() => setPlaceholder('Add Segments')}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    if (newStrategyConfiguration) {
 | 
				
			||||||
 | 
					        return (
 | 
				
			||||||
 | 
					            <StyledContainer>
 | 
				
			||||||
 | 
					                <StyledAutocomplete
 | 
				
			||||||
 | 
					                    options={options}
 | 
				
			||||||
 | 
					                    value={value}
 | 
				
			||||||
 | 
					                    onChange={(event, value) => onChange(value || [])}
 | 
				
			||||||
 | 
					                    renderInput={renderCustomInput}
 | 
				
			||||||
 | 
					                    getOptionLabel={(value) => value.label}
 | 
				
			||||||
 | 
					                    disabled={disabled}
 | 
				
			||||||
 | 
					                    size='small'
 | 
				
			||||||
 | 
					                    multiple
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					            </StyledContainer>
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <StyledContainer>
 | 
					        <StyledContainer>
 | 
				
			||||||
            <StyledIcon $disabled={Boolean(disabled)} aria-hidden>
 | 
					            <StyledIcon $disabled={Boolean(disabled)} aria-hidden>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
import React, { forwardRef, Fragment, useImperativeHandle } from 'react';
 | 
					import React, { forwardRef, Fragment, useImperativeHandle } from 'react';
 | 
				
			||||||
import { Button, styled, Tooltip } from '@mui/material';
 | 
					import { Box, Button, styled, Tooltip, Typography } from '@mui/material';
 | 
				
			||||||
import { HelpOutline } from '@mui/icons-material';
 | 
					import { Add, HelpOutline } from '@mui/icons-material';
 | 
				
			||||||
import { IConstraint } from 'interfaces/strategy';
 | 
					import { IConstraint } from 'interfaces/strategy';
 | 
				
			||||||
import { ConstraintAccordion } from 'component/common/ConstraintAccordion/ConstraintAccordion';
 | 
					import { ConstraintAccordion } from 'component/common/ConstraintAccordion/ConstraintAccordion';
 | 
				
			||||||
import produce from 'immer';
 | 
					import produce from 'immer';
 | 
				
			||||||
@ -10,6 +10,8 @@ import { objectId } from 'utils/objectId';
 | 
				
			|||||||
import { createEmptyConstraint } from 'component/common/ConstraintAccordion/ConstraintAccordionList/createEmptyConstraint';
 | 
					import { createEmptyConstraint } from 'component/common/ConstraintAccordion/ConstraintAccordionList/createEmptyConstraint';
 | 
				
			||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
 | 
					import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
 | 
				
			||||||
import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator';
 | 
					import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator';
 | 
				
			||||||
 | 
					import { useUiFlag } from 'hooks/useUiFlag';
 | 
				
			||||||
 | 
					import { HelpIcon } from 'component/common/HelpIcon/HelpIcon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IConstraintAccordionListProps {
 | 
					interface IConstraintAccordionListProps {
 | 
				
			||||||
    constraints: IConstraint[];
 | 
					    constraints: IConstraint[];
 | 
				
			||||||
@ -64,6 +66,13 @@ const StyledAddCustomLabel = styled('div')(({ theme }) => ({
 | 
				
			|||||||
    display: 'flex',
 | 
					    display: 'flex',
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyledHelpIconBox = styled(Box)(({ theme }) => ({
 | 
				
			||||||
 | 
					    display: 'flex',
 | 
				
			||||||
 | 
					    alignItems: 'center',
 | 
				
			||||||
 | 
					    marginTop: theme.spacing(1),
 | 
				
			||||||
 | 
					    marginBottom: theme.spacing(1),
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const ConstraintAccordionList = forwardRef<
 | 
					export const ConstraintAccordionList = forwardRef<
 | 
				
			||||||
    IConstraintAccordionListRef | undefined,
 | 
					    IConstraintAccordionListRef | undefined,
 | 
				
			||||||
    IConstraintAccordionListProps
 | 
					    IConstraintAccordionListProps
 | 
				
			||||||
@ -78,6 +87,8 @@ export const ConstraintAccordionList = forwardRef<
 | 
				
			|||||||
        >();
 | 
					        >();
 | 
				
			||||||
        const { context } = useUnleashContext();
 | 
					        const { context } = useUnleashContext();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const newStrategyConfiguration = useUiFlag('newStrategyConfiguration');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const addConstraint =
 | 
					        const addConstraint =
 | 
				
			||||||
            setConstraints &&
 | 
					            setConstraints &&
 | 
				
			||||||
            ((contextName: string) => {
 | 
					            ((contextName: string) => {
 | 
				
			||||||
@ -135,6 +146,86 @@ export const ConstraintAccordionList = forwardRef<
 | 
				
			|||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (newStrategyConfiguration) {
 | 
				
			||||||
 | 
					            return (
 | 
				
			||||||
 | 
					                <StyledContainer id={constraintAccordionListId}>
 | 
				
			||||||
 | 
					                    <ConditionallyRender
 | 
				
			||||||
 | 
					                        condition={Boolean(showCreateButton && onAdd)}
 | 
				
			||||||
 | 
					                        show={
 | 
				
			||||||
 | 
					                            <div>
 | 
				
			||||||
 | 
					                                <StyledHelpIconBox>
 | 
				
			||||||
 | 
					                                    <Typography>Constraints</Typography>
 | 
				
			||||||
 | 
					                                    <HelpIcon
 | 
				
			||||||
 | 
					                                        htmlTooltip
 | 
				
			||||||
 | 
					                                        tooltip={
 | 
				
			||||||
 | 
					                                            <Box>
 | 
				
			||||||
 | 
					                                                <Typography variant='body2'>
 | 
				
			||||||
 | 
					                                                    Constraints are advanced
 | 
				
			||||||
 | 
					                                                    targeting rules that you can
 | 
				
			||||||
 | 
					                                                    use to enable a feature
 | 
				
			||||||
 | 
					                                                    toggle for a subset of your
 | 
				
			||||||
 | 
					                                                    users. Read more about
 | 
				
			||||||
 | 
					                                                    constraints{' '}
 | 
				
			||||||
 | 
					                                                    <a
 | 
				
			||||||
 | 
					                                                        href='https://docs.getunleash.io/reference/strategy-constraints'
 | 
				
			||||||
 | 
					                                                        target='_blank'
 | 
				
			||||||
 | 
					                                                        rel='noopener noreferrer'
 | 
				
			||||||
 | 
					                                                    >
 | 
				
			||||||
 | 
					                                                        here
 | 
				
			||||||
 | 
					                                                    </a>
 | 
				
			||||||
 | 
					                                                </Typography>
 | 
				
			||||||
 | 
					                                            </Box>
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                    />
 | 
				
			||||||
 | 
					                                </StyledHelpIconBox>
 | 
				
			||||||
 | 
					                                {constraints.map((constraint, index) => (
 | 
				
			||||||
 | 
					                                    <Fragment key={objectId(constraint)}>
 | 
				
			||||||
 | 
					                                        <ConditionallyRender
 | 
				
			||||||
 | 
					                                            condition={index > 0}
 | 
				
			||||||
 | 
					                                            show={
 | 
				
			||||||
 | 
					                                                <StrategySeparator text='AND' />
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                        />
 | 
				
			||||||
 | 
					                                        <ConstraintAccordion
 | 
				
			||||||
 | 
					                                            constraint={constraint}
 | 
				
			||||||
 | 
					                                            onEdit={onEdit?.bind(
 | 
				
			||||||
 | 
					                                                null,
 | 
				
			||||||
 | 
					                                                constraint,
 | 
				
			||||||
 | 
					                                            )}
 | 
				
			||||||
 | 
					                                            onCancel={onCancel.bind(
 | 
				
			||||||
 | 
					                                                null,
 | 
				
			||||||
 | 
					                                                index,
 | 
				
			||||||
 | 
					                                            )}
 | 
				
			||||||
 | 
					                                            onDelete={onRemove?.bind(
 | 
				
			||||||
 | 
					                                                null,
 | 
				
			||||||
 | 
					                                                index,
 | 
				
			||||||
 | 
					                                            )}
 | 
				
			||||||
 | 
					                                            onSave={onSave?.bind(null, index)}
 | 
				
			||||||
 | 
					                                            editing={Boolean(
 | 
				
			||||||
 | 
					                                                state.get(constraint)?.editing,
 | 
				
			||||||
 | 
					                                            )}
 | 
				
			||||||
 | 
					                                            compact
 | 
				
			||||||
 | 
					                                        />
 | 
				
			||||||
 | 
					                                    </Fragment>
 | 
				
			||||||
 | 
					                                ))}
 | 
				
			||||||
 | 
					                                <Button
 | 
				
			||||||
 | 
					                                    sx={{ marginTop: '1rem' }}
 | 
				
			||||||
 | 
					                                    type='button'
 | 
				
			||||||
 | 
					                                    onClick={onAdd}
 | 
				
			||||||
 | 
					                                    startIcon={<Add />}
 | 
				
			||||||
 | 
					                                    variant='outlined'
 | 
				
			||||||
 | 
					                                    color='primary'
 | 
				
			||||||
 | 
					                                    data-testid='ADD_CONSTRAINT_BUTTON'
 | 
				
			||||||
 | 
					                                >
 | 
				
			||||||
 | 
					                                    Add constraint
 | 
				
			||||||
 | 
					                                </Button>
 | 
				
			||||||
 | 
					                            </div>
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                </StyledContainer>
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return (
 | 
					        return (
 | 
				
			||||||
            <StyledContainer id={constraintAccordionListId}>
 | 
					            <StyledContainer id={constraintAccordionListId}>
 | 
				
			||||||
                <ConditionallyRender
 | 
					                <ConditionallyRender
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,15 @@
 | 
				
			|||||||
import React, { useState } from 'react';
 | 
					import React, { useState } from 'react';
 | 
				
			||||||
import { useNavigate } from 'react-router-dom';
 | 
					import { useNavigate } from 'react-router-dom';
 | 
				
			||||||
import { Alert, Button, styled, Tabs, Tab } from '@mui/material';
 | 
					import {
 | 
				
			||||||
 | 
					    Alert,
 | 
				
			||||||
 | 
					    Button,
 | 
				
			||||||
 | 
					    styled,
 | 
				
			||||||
 | 
					    Tabs,
 | 
				
			||||||
 | 
					    Tab,
 | 
				
			||||||
 | 
					    Typography,
 | 
				
			||||||
 | 
					    Divider,
 | 
				
			||||||
 | 
					    Box,
 | 
				
			||||||
 | 
					} from '@mui/material';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    IFeatureStrategy,
 | 
					    IFeatureStrategy,
 | 
				
			||||||
    IFeatureStrategyParameters,
 | 
					    IFeatureStrategyParameters,
 | 
				
			||||||
@ -54,6 +63,19 @@ interface IFeatureStrategyFormProps {
 | 
				
			|||||||
    setTab: React.Dispatch<React.SetStateAction<number>>;
 | 
					    setTab: React.Dispatch<React.SetStateAction<number>>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyledDividerContent = styled(Box)(({ theme }) => ({
 | 
				
			||||||
 | 
					    padding: theme.spacing(0.75, 1),
 | 
				
			||||||
 | 
					    color: theme.palette.text.primary,
 | 
				
			||||||
 | 
					    fontSize: theme.fontSizes.smallerBody,
 | 
				
			||||||
 | 
					    backgroundColor: theme.palette.background.elevation2,
 | 
				
			||||||
 | 
					    borderRadius: theme.shape.borderRadius,
 | 
				
			||||||
 | 
					    width: '45px',
 | 
				
			||||||
 | 
					    position: 'absolute',
 | 
				
			||||||
 | 
					    top: '-10px',
 | 
				
			||||||
 | 
					    left: 'calc(50% - 45px)',
 | 
				
			||||||
 | 
					    lineHeight: 1,
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const StyledForm = styled('form')(({ theme }) => ({
 | 
					const StyledForm = styled('form')(({ theme }) => ({
 | 
				
			||||||
    display: 'grid',
 | 
					    display: 'grid',
 | 
				
			||||||
    gap: theme.spacing(2),
 | 
					    gap: theme.spacing(2),
 | 
				
			||||||
@ -74,6 +96,21 @@ const StyledButtons = styled('div')(({ theme }) => ({
 | 
				
			|||||||
    paddingBottom: theme.spacing(10),
 | 
					    paddingBottom: theme.spacing(10),
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyledBox = styled(Box)(({ theme }) => ({
 | 
				
			||||||
 | 
					    display: 'flex',
 | 
				
			||||||
 | 
					    position: 'relative',
 | 
				
			||||||
 | 
					    marginTop: theme.spacing(3.5),
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyledDivider = styled(Divider)(({ theme }) => ({
 | 
				
			||||||
 | 
					    width: '100%',
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyledTargetingHeader = styled('div')(({ theme }) => ({
 | 
				
			||||||
 | 
					    color: theme.palette.text.secondary,
 | 
				
			||||||
 | 
					    marginTop: theme.spacing(1.5),
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const NewFeatureStrategyForm = ({
 | 
					export const NewFeatureStrategyForm = ({
 | 
				
			||||||
    projectId,
 | 
					    projectId,
 | 
				
			||||||
    feature,
 | 
					    feature,
 | 
				
			||||||
@ -274,11 +311,22 @@ export const NewFeatureStrategyForm = ({
 | 
				
			|||||||
                condition={tab === 1}
 | 
					                condition={tab === 1}
 | 
				
			||||||
                show={
 | 
					                show={
 | 
				
			||||||
                    <>
 | 
					                    <>
 | 
				
			||||||
 | 
					                        <StyledTargetingHeader>
 | 
				
			||||||
 | 
					                            Segmentation and constraints allow you to set
 | 
				
			||||||
 | 
					                            filters on your strategies, so that they will only
 | 
				
			||||||
 | 
					                            be evaluated for users and applications that match
 | 
				
			||||||
 | 
					                            the specified preconditions.
 | 
				
			||||||
 | 
					                        </StyledTargetingHeader>
 | 
				
			||||||
                        <FeatureStrategySegment
 | 
					                        <FeatureStrategySegment
 | 
				
			||||||
                            segments={segments}
 | 
					                            segments={segments}
 | 
				
			||||||
                            setSegments={setSegments}
 | 
					                            setSegments={setSegments}
 | 
				
			||||||
                            projectId={projectId}
 | 
					                            projectId={projectId}
 | 
				
			||||||
                        />
 | 
					                        />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        <StyledBox>
 | 
				
			||||||
 | 
					                            <StyledDivider />
 | 
				
			||||||
 | 
					                            <StyledDividerContent>AND</StyledDividerContent>
 | 
				
			||||||
 | 
					                        </StyledBox>
 | 
				
			||||||
                        <FeatureStrategyConstraints
 | 
					                        <FeatureStrategyConstraints
 | 
				
			||||||
                            projectId={feature.project}
 | 
					                            projectId={feature.project}
 | 
				
			||||||
                            environmentId={environmentId}
 | 
					                            environmentId={environmentId}
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,9 @@ import {
 | 
				
			|||||||
import { FeatureStrategySegmentList } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegmentList';
 | 
					import { FeatureStrategySegmentList } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegmentList';
 | 
				
			||||||
import { SegmentDocsStrategyWarning } from 'component/segments/SegmentDocs';
 | 
					import { SegmentDocsStrategyWarning } from 'component/segments/SegmentDocs';
 | 
				
			||||||
import { useSegmentLimits } from 'hooks/api/getters/useSegmentLimits/useSegmentLimits';
 | 
					import { useSegmentLimits } from 'hooks/api/getters/useSegmentLimits/useSegmentLimits';
 | 
				
			||||||
import { Divider, styled, Typography } from '@mui/material';
 | 
					import { Box, Divider, styled, Typography } from '@mui/material';
 | 
				
			||||||
 | 
					import { useUiFlag } from 'hooks/useUiFlag';
 | 
				
			||||||
 | 
					import { HelpIcon } from 'component/common/HelpIcon/HelpIcon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IFeatureStrategySegmentProps {
 | 
					interface IFeatureStrategySegmentProps {
 | 
				
			||||||
    segments: ISegment[];
 | 
					    segments: ISegment[];
 | 
				
			||||||
@ -20,6 +22,13 @@ const StyledDivider = styled(Divider)(({ theme }) => ({
 | 
				
			|||||||
    fontSize: theme.fontSizes.smallBody,
 | 
					    fontSize: theme.fontSizes.smallBody,
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyledHelpIconBox = styled(Box)(({ theme }) => ({
 | 
				
			||||||
 | 
					    display: 'flex',
 | 
				
			||||||
 | 
					    alignItems: 'center',
 | 
				
			||||||
 | 
					    marginTop: theme.spacing(1),
 | 
				
			||||||
 | 
					    marginBottom: theme.spacing(1),
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const FeatureStrategySegment = ({
 | 
					export const FeatureStrategySegment = ({
 | 
				
			||||||
    segments: selectedSegments,
 | 
					    segments: selectedSegments,
 | 
				
			||||||
    setSegments: setSelectedSegments,
 | 
					    setSegments: setSelectedSegments,
 | 
				
			||||||
@ -28,6 +37,8 @@ export const FeatureStrategySegment = ({
 | 
				
			|||||||
    const { segments: allSegments } = useSegments();
 | 
					    const { segments: allSegments } = useSegments();
 | 
				
			||||||
    const { strategySegmentsLimit } = useSegmentLimits();
 | 
					    const { strategySegmentsLimit } = useSegmentLimits();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const newStrategyConfiguration = useUiFlag('newStrategyConfiguration');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const atStrategySegmentsLimit: boolean = Boolean(
 | 
					    const atStrategySegmentsLimit: boolean = Boolean(
 | 
				
			||||||
        strategySegmentsLimit &&
 | 
					        strategySegmentsLimit &&
 | 
				
			||||||
            selectedSegments.length >= strategySegmentsLimit,
 | 
					            selectedSegments.length >= strategySegmentsLimit,
 | 
				
			||||||
@ -59,6 +70,49 @@ export const FeatureStrategySegment = ({
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (newStrategyConfiguration) {
 | 
				
			||||||
 | 
					        return (
 | 
				
			||||||
 | 
					            <>
 | 
				
			||||||
 | 
					                <StyledHelpIconBox>
 | 
				
			||||||
 | 
					                    <Typography>Segments</Typography>
 | 
				
			||||||
 | 
					                    <HelpIcon
 | 
				
			||||||
 | 
					                        htmlTooltip
 | 
				
			||||||
 | 
					                        tooltip={
 | 
				
			||||||
 | 
					                            <Box>
 | 
				
			||||||
 | 
					                                <Typography variant='body2'>
 | 
				
			||||||
 | 
					                                    Segments are reusable sets of constraints
 | 
				
			||||||
 | 
					                                    that can be defined once and reused across
 | 
				
			||||||
 | 
					                                    feature toggle configurations. You can
 | 
				
			||||||
 | 
					                                    create a segment on the global or the
 | 
				
			||||||
 | 
					                                    project level. Read more about segments{' '}
 | 
				
			||||||
 | 
					                                    <a
 | 
				
			||||||
 | 
					                                        href='https://docs.getunleash.io/reference/segments'
 | 
				
			||||||
 | 
					                                        target='_blank'
 | 
				
			||||||
 | 
					                                        rel='noopener noreferrer'
 | 
				
			||||||
 | 
					                                    >
 | 
				
			||||||
 | 
					                                        here
 | 
				
			||||||
 | 
					                                    </a>
 | 
				
			||||||
 | 
					                                </Typography>
 | 
				
			||||||
 | 
					                            </Box>
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                </StyledHelpIconBox>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                {atStrategySegmentsLimit && <SegmentDocsStrategyWarning />}
 | 
				
			||||||
 | 
					                <AutocompleteBox
 | 
				
			||||||
 | 
					                    label='Select segments'
 | 
				
			||||||
 | 
					                    options={autocompleteOptions}
 | 
				
			||||||
 | 
					                    onChange={onChange}
 | 
				
			||||||
 | 
					                    disabled={atStrategySegmentsLimit}
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					                <FeatureStrategySegmentList
 | 
				
			||||||
 | 
					                    segments={selectedSegments}
 | 
				
			||||||
 | 
					                    setSegments={setSelectedSegments}
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					            </>
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <>
 | 
					        <>
 | 
				
			||||||
            <Typography component='h3' sx={{ m: 0 }} variant='h3'>
 | 
					            <Typography component='h3' sx={{ m: 0 }} variant='h3'>
 | 
				
			||||||
@ -76,6 +130,7 @@ export const FeatureStrategySegment = ({
 | 
				
			|||||||
                segments={selectedSegments}
 | 
					                segments={selectedSegments}
 | 
				
			||||||
                setSegments={setSelectedSegments}
 | 
					                setSegments={setSelectedSegments}
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <StyledDivider />
 | 
					            <StyledDivider />
 | 
				
			||||||
        </>
 | 
					        </>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
				
			|||||||
@ -35,7 +35,7 @@ const StyledBox = styled(Box)(({ theme }) => ({
 | 
				
			|||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const StyledOuterBox = styled(Box)(({ theme }) => ({
 | 
					const StyledOuterBox = styled(Box)(({ theme }) => ({
 | 
				
			||||||
    marginTop: '1rem',
 | 
					    marginTop: theme.spacing(1),
 | 
				
			||||||
    display: 'flex',
 | 
					    display: 'flex',
 | 
				
			||||||
    width: '100%',
 | 
					    width: '100%',
 | 
				
			||||||
    justifyContent: 'space-between',
 | 
					    justifyContent: 'space-between',
 | 
				
			||||||
 | 
				
			|||||||
@ -25,6 +25,15 @@ const StyledSlider = withStyles(Slider, (theme) => ({
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyledHeader = styled(Typography)(({ theme }) => ({
 | 
				
			||||||
 | 
					    marginBottom: theme.spacing(1),
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyledSubheader = styled(Typography)(({ theme }) => ({
 | 
				
			||||||
 | 
					    marginBottom: theme.spacing(1),
 | 
				
			||||||
 | 
					    marginTop: theme.spacing(1),
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const StyledBox = styled(Box)(({ theme }) => ({
 | 
					const StyledBox = styled(Box)(({ theme }) => ({
 | 
				
			||||||
    display: 'flex',
 | 
					    display: 'flex',
 | 
				
			||||||
    alignItems: 'center',
 | 
					    alignItems: 'center',
 | 
				
			||||||
@ -91,12 +100,9 @@ const RolloutSlider = ({
 | 
				
			|||||||
                    htmlTooltip
 | 
					                    htmlTooltip
 | 
				
			||||||
                    tooltip={
 | 
					                    tooltip={
 | 
				
			||||||
                        <Box>
 | 
					                        <Box>
 | 
				
			||||||
                            <Typography
 | 
					                            <StyledHeader variant='h3'>
 | 
				
			||||||
                                variant='h3'
 | 
					 | 
				
			||||||
                                sx={{ marginBottom: '1rem' }}
 | 
					 | 
				
			||||||
                            >
 | 
					 | 
				
			||||||
                                Rollout percentage
 | 
					                                Rollout percentage
 | 
				
			||||||
                            </Typography>
 | 
					                            </StyledHeader>
 | 
				
			||||||
                            <Typography variant='body2'>
 | 
					                            <Typography variant='body2'>
 | 
				
			||||||
                                The rollout percentage determines the proportion
 | 
					                                The rollout percentage determines the proportion
 | 
				
			||||||
                                of users exposed to a feature. It's based on the
 | 
					                                of users exposed to a feature. It's based on the
 | 
				
			||||||
@ -108,12 +114,9 @@ const RolloutSlider = ({
 | 
				
			|||||||
                                of the feature among users.
 | 
					                                of the feature among users.
 | 
				
			||||||
                            </Typography>
 | 
					                            </Typography>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            <Typography
 | 
					                            <StyledSubheader variant='h3'>
 | 
				
			||||||
                                variant='h3'
 | 
					 | 
				
			||||||
                                sx={{ marginBottom: '1rem', marginTop: '1rem' }}
 | 
					 | 
				
			||||||
                            >
 | 
					 | 
				
			||||||
                                Stickiness
 | 
					                                Stickiness
 | 
				
			||||||
                            </Typography>
 | 
					                            </StyledSubheader>
 | 
				
			||||||
                            <Typography variant='body2'>
 | 
					                            <Typography variant='body2'>
 | 
				
			||||||
                                Stickiness refers to the value used for hashing
 | 
					                                Stickiness refers to the value used for hashing
 | 
				
			||||||
                                to ensure a consistent user experience. It
 | 
					                                to ensure a consistent user experience. It
 | 
				
			||||||
@ -122,12 +125,9 @@ const RolloutSlider = ({
 | 
				
			|||||||
                                consistent across sessions.
 | 
					                                consistent across sessions.
 | 
				
			||||||
                            </Typography>
 | 
					                            </Typography>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            <Typography
 | 
					                            <StyledSubheader variant='h3'>
 | 
				
			||||||
                                variant='h3'
 | 
					 | 
				
			||||||
                                sx={{ marginBottom: '1rem', marginTop: '1rem' }}
 | 
					 | 
				
			||||||
                            >
 | 
					 | 
				
			||||||
                                GroupId
 | 
					                                GroupId
 | 
				
			||||||
                            </Typography>
 | 
					                            </StyledSubheader>
 | 
				
			||||||
                            <Typography variant='body2'>
 | 
					                            <Typography variant='body2'>
 | 
				
			||||||
                                The groupId is used as a seed for the hash
 | 
					                                The groupId is used as a seed for the hash
 | 
				
			||||||
                                function, ensuring consistent feature exposure
 | 
					                                function, ensuring consistent feature exposure
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user