1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-08-27 13:49:10 +02:00

AI flag removal

This commit is contained in:
Thomas Heartman 2025-06-10 11:57:20 +02:00
parent 6d7a344ca3
commit dbc515a286
17 changed files with 46 additions and 341 deletions

View File

@ -8,9 +8,9 @@ import type {
} from 'component/changeRequest/changeRequest.types';
import { useSegment } from 'hooks/api/getters/useSegment/useSegment';
import { SegmentDiff, SegmentTooltipLink } from '../../SegmentTooltipLink.tsx';
import { ConstraintAccordionList } from 'component/common/LegacyConstraintAccordion/ConstraintAccordionList/ConstraintAccordionList';
import { ViewableConstraintsList } from 'component/common/NewConstraintAccordion/ConstraintsList/ViewableConstraintsList';
import { useUiFlag } from 'hooks/useUiFlag';
import { ChangeOverwriteWarning } from './ChangeOverwriteWarning/ChangeOverwriteWarning.tsx';
const ChangeItemCreateEditWrapper = styled(Box)(({ theme }) => ({
@ -67,7 +67,6 @@ export const SegmentChangeDetails: FC<{
: currentSegment?.name;
const referenceSegment =
changeRequestState === 'Applied' ? snapshotSegment : currentSegment;
const addEditStrategy = useUiFlag('addEditStrategy');
return (
<SegmentContainer conflict={change.conflict}>
@ -116,16 +115,9 @@ export const SegmentChangeDetails: FC<{
</ChangeItemInfo>
<div>{actions}</div>
</ChangeItemCreateEditWrapper>
{addEditStrategy ? (
<ViewableConstraintsList
constraints={change.payload.constraints}
/>
) : (
<ConstraintAccordionList
constraints={change.payload.constraints}
showLabel={false}
/>
)}
<ViewableConstraintsList
constraints={change.payload.constraints}
/>
</>
)}
</SegmentContainer>

View File

@ -3,8 +3,6 @@ import { Chip, styled } from '@mui/material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import StringTruncator from 'component/common/StringTruncator/StringTruncator';
import { ConstraintValueSearch as NewConstraintValueSearch } from 'component/feature/FeatureStrategy/FeatureStrategyConstraints/EditableConstraint/ConstraintValueSearch';
import { useUiFlag } from 'hooks/useUiFlag';
import { ConstraintValueSearch } from 'component/common/NewConstraintAccordion/ConstraintValueSearch/ConstraintValueSearch';
interface IMultipleValuesProps {
values: string[] | undefined;
@ -25,7 +23,6 @@ const SearchWrapper = styled('div')(({ theme }) => ({
export const MultipleValues = ({ values }: IMultipleValuesProps) => {
const [filter, setFilter] = useState('');
const useNewSearchComponent = useUiFlag('addEditStrategy');
if (!values || values.length === 0) return null;
@ -34,19 +31,12 @@ export const MultipleValues = ({ values }: IMultipleValuesProps) => {
<ConditionallyRender
condition={values.length > 20}
show={
useNewSearchComponent ? (
<SearchWrapper>
<NewConstraintValueSearch
filter={filter}
setFilter={setFilter}
/>
</SearchWrapper>
) : (
<ConstraintValueSearch
<SearchWrapper>
<NewConstraintValueSearch
filter={filter}
setFilter={setFilter}
/>
)
</SearchWrapper>
}
/>
{values

View File

@ -6,9 +6,7 @@ import produce from 'immer';
import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext';
import type { IUseWeakMap } from 'hooks/useWeakMap';
import { constraintId } from 'component/common/LegacyConstraintAccordion/ConstraintAccordionList/createEmptyConstraint';
import { NewConstraintAccordion } from 'component/common/NewConstraintAccordion/NewConstraintAccordion';
import { ConstraintsList } from 'component/common/ConstraintsList/ConstraintsList';
import { useUiFlag } from 'hooks/useUiFlag';
import { ConstraintAccordionView } from 'component/common/NewConstraintAccordion/ConstraintAccordionView/ConstraintAccordionView';
import { EditableConstraint } from 'component/feature/FeatureStrategy/FeatureStrategyConstraints/EditableConstraint/EditableConstraint';
@ -52,7 +50,6 @@ export const NewConstraintAccordionList = forwardRef<
IConstraintList
>(({ constraints, setConstraints, state }, ref) => {
const { context } = useUnleashContext();
const addEditStrategy = useUiFlag('addEditStrategy');
const onEdit =
setConstraints &&
@ -113,34 +110,20 @@ export const NewConstraintAccordionList = forwardRef<
<StyledContainer id={constraintAccordionListId}>
<ConstraintsList>
{constraints.map((constraint, index) =>
addEditStrategy ? (
state.get(constraint)?.editing &&
Boolean(setConstraints) ? (
<EditableConstraint
key={constraint[constraintId]}
constraint={constraint}
// @ts-ignore todo: find a better way to do this
onDelete={() => onRemove(index)}
// @ts-ignore
onUpdate={onAutoSave(constraintId)}
/>
) : (
<ConstraintAccordionView
key={constraint[constraintId]}
constraint={constraint}
/>
)
) : (
<NewConstraintAccordion
state.get(constraint)?.editing &&
Boolean(setConstraints) ? (
<EditableConstraint
key={constraint[constraintId]}
constraint={constraint}
// @ts-ignore todo: find a better way to do this
onDelete={() => onRemove(index)}
// @ts-ignore
onUpdate={onAutoSave(constraintId)}
/>
) : (
<ConstraintAccordionView
key={constraint[constraintId]}
constraint={constraint}
onEdit={onEdit?.bind(null, constraint)}
onCancel={onCancel.bind(null, index)}
onDelete={onRemove?.bind(null, index)}
onSave={onSave?.bind(null, index)}
onAutoSave={onAutoSave?.(constraint[constraintId])}
editing={Boolean(state.get(constraint)?.editing)}
compact
/>
),
)}

View File

@ -10,11 +10,9 @@ import {
type IConstraintAccordionListRef,
useConstraintAccordionList,
} from 'component/common/LegacyConstraintAccordion/ConstraintAccordionList/ConstraintAccordionList';
import { NewConstraintAccordionList } from 'component/common/NewConstraintAccordion/NewConstraintAccordionList/NewConstraintAccordionList';
import { EditableConstraintsList } from 'component/common/NewConstraintAccordion/ConstraintsList/EditableConstraintsList';
import { Limit } from 'component/common/Limit/Limit';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { useUiFlag } from 'hooks/useUiFlag';
import { RecentlyUsedConstraints } from '../RecentlyUsedConstraints/RecentlyUsedConstraints.tsx';
interface IConstraintAccordionListProps {
@ -58,7 +56,6 @@ export const FeatureStrategyConstraintAccordionList = forwardRef<
ref as RefObject<IConstraintAccordionListRef>,
);
const { limit, limitReached } = useConstraintLimit(constraints.length);
const addEditStrategy = useUiFlag('addEditStrategy');
if (context.length === 0) {
return null;
@ -93,22 +90,13 @@ export const FeatureStrategyConstraintAccordionList = forwardRef<
}
/>
</StyledHelpIconBox>
{addEditStrategy ? (
setConstraints ? (
<EditableConstraintsList
ref={ref}
setConstraints={setConstraints}
constraints={constraints}
/>
) : null
) : (
<NewConstraintAccordionList
{setConstraints ? (
<EditableConstraintsList
ref={ref}
setConstraints={setConstraints}
constraints={constraints}
state={state}
/>
)}
) : null}
<Box
sx={(theme) => ({
marginTop: theme.spacing(2),
@ -134,14 +122,9 @@ export const FeatureStrategyConstraintAccordionList = forwardRef<
>
Add constraint
</Button>
<ConditionallyRender
condition={Boolean(addEditStrategy)}
show={
<RecentlyUsedConstraints
setConstraints={setConstraints}
constraints={constraints}
/>
}
<RecentlyUsedConstraints
setConstraints={setConstraints}
constraints={constraints}
/>
</div>
}

View File

@ -87,7 +87,6 @@ export const setupUiConfigEndpoint = () => {
environment: 'enterprise',
flags: {
newStrategyConfiguration: true,
addEditStrategy: true,
},
resourceLimits: {
featureEnvironmentStrategies: 2,

View File

@ -45,10 +45,8 @@ import { FeatureStrategyEnabledDisabled } from './FeatureStrategyEnabledDisabled
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
import { BuiltInStrategies, formatStrategyName } from 'utils/strategyNames';
import { Badge } from 'component/common/Badge/Badge';
import EnvironmentIcon from 'component/common/EnvironmentIcon/EnvironmentIcon';
import { UpgradeChangeRequests } from '../../FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/UpgradeChangeRequests/UpgradeChangeRequests.tsx';
import { ConstraintSeparator } from 'component/common/ConstraintsList/ConstraintSeparator/ConstraintSeparator';
import { useUiFlag } from 'hooks/useUiFlag.ts';
interface IFeatureStrategyFormProps {
feature: IFeatureToggle;
@ -211,7 +209,6 @@ export const FeatureStrategyForm = ({
environmentId,
);
const { strategyDefinition } = useStrategy(strategy?.name);
const addEditStrategy = useUiFlag('addEditStrategy');
useEffect(() => {
trackEvent('new-strategy-form', {
@ -350,35 +347,7 @@ export const FeatureStrategyForm = ({
<StyledHeaderBox>
<StyledTitle>
{formatStrategyName(strategy.name || '')}
<ConditionallyRender
condition={
!addEditStrategy &&
strategy.name === 'flexibleRollout'
}
show={
<Badge color='success' sx={{ marginLeft: '1rem' }}>
{strategy.parameters?.rollout}%
</Badge>
}
/>
</StyledTitle>
{foundEnvironment && !addEditStrategy ? (
<StyledEnvironmentBox>
<EnvironmentTypographyHeader>
Environment:
</EnvironmentTypographyHeader>
<EnvironmentIconBox>
<EnvironmentIcon
enabled={foundEnvironment.enabled}
/>{' '}
<EnvironmentTypography
enabled={foundEnvironment.enabled}
>
{foundEnvironment.name}
</EnvironmentTypography>
</EnvironmentIconBox>
</StyledEnvironmentBox>
) : null}
</StyledHeaderBox>
<StyledAlertBox>

View File

@ -10,7 +10,7 @@ import { SegmentDocsStrategyWarning } from 'component/segments/SegmentDocs';
import { useSegmentLimits } from 'hooks/api/getters/useSegmentLimits/useSegmentLimits';
import { Box, styled, Typography } from '@mui/material';
import { HelpIcon } from 'component/common/HelpIcon/HelpIcon';
import { useUiFlag } from 'hooks/useUiFlag';
import { RecentlyUsedSegments } from './RecentlyUsedSegments/RecentlyUsedSegments.tsx';
interface IFeatureStrategySegmentProps {
@ -31,7 +31,6 @@ export const FeatureStrategySegment = ({
setSegments: setSelectedSegments,
projectId,
}: IFeatureStrategySegmentProps) => {
const addEditStrategy = useUiFlag('addEditStrategy');
const { segments: allSegments } = useSegments();
const { strategySegmentsLimit } = useSegmentLimits();
@ -99,7 +98,7 @@ export const FeatureStrategySegment = ({
options={autocompleteOptions}
onChange={onChange}
disabled={atStrategySegmentsLimit}
icon={addEditStrategy ? null : undefined}
icon={null}
width={'175px'}
/>
<FeatureStrategySegmentList

View File

@ -3,7 +3,6 @@ import { useRecentlyUsedSegments } from './useRecentlyUsedSegments.ts';
import type { ISegment } from 'interfaces/segment';
import { RecentlyUsedSegmentChip } from './RecentlyUsedSegmentChip.tsx';
import { useSegments } from 'hooks/api/getters/useSegments/useSegments';
import { useUiFlag } from 'hooks/useUiFlag';
type RecentlyUsedSegmentsProps = {
setSegments?: React.Dispatch<React.SetStateAction<ISegment[]>>;
@ -32,14 +31,7 @@ export const RecentlyUsedSegments = ({
}: RecentlyUsedSegmentsProps) => {
const { items: recentlyUsedSegmentIds } = useRecentlyUsedSegments();
const { segments: allSegments } = useSegments();
const addEditStrategyEnabled = useUiFlag('addEditStrategy');
if (
!addEditStrategyEnabled ||
recentlyUsedSegmentIds.length === 0 ||
!setSegments ||
!allSegments
) {
if (recentlyUsedSegmentIds.length === 0 || !setSegments || !allSegments) {
return null;
}

View File

@ -1,6 +1,4 @@
import RolloutSlider from './RolloutSlider.tsx';
import LegacyRolloutSlider from './LegacyRolloutSlider.tsx';
import { useUiFlag } from 'hooks/useUiFlag';
interface IRolloutSliderProps {
name: string;
@ -12,13 +10,7 @@ interface IRolloutSliderProps {
}
const ConditionalRolloutSlider = (props: IRolloutSliderProps) => {
const addEditStrategy = useUiFlag('addEditStrategy');
if (addEditStrategy) {
return <RolloutSlider {...props} />;
}
return <LegacyRolloutSlider {...props} />;
return <RolloutSlider {...props} />;
};
export default ConditionalRolloutSlider;

View File

@ -1,162 +0,0 @@
import { makeStyles, withStyles } from 'tss-react/mui';
import { Slider, Typography, Box, styled } from '@mui/material';
import { ROLLOUT_SLIDER_ID } from 'utils/testIds';
import { HelpIcon } from 'component/common/HelpIcon/HelpIcon';
const StyledSlider = withStyles(Slider, (theme) => ({
root: {
height: 8,
},
thumb: {
height: 24,
width: 24,
backgroundColor: theme.palette.background.paper,
border: '2px solid currentColor',
},
active: {},
valueLabel: {},
track: {
height: 8,
borderRadius: theme.shape.borderRadius,
},
rail: {
height: 8,
borderRadius: theme.shape.borderRadius,
},
}));
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 }) => ({
display: 'flex',
alignItems: 'center',
marginBottom: theme.spacing(1),
}));
const useStyles = makeStyles()((theme) => ({
slider: {
width: '100%',
maxWidth: '100%',
},
margin: {
height: theme.spacing(3),
},
}));
const marks = [
{
value: 0,
label: '0%',
},
{
value: 25,
label: '25%',
},
{
value: 50,
label: '50%',
},
{
value: 75,
label: '75%',
},
{
value: 100,
label: '100%',
},
];
interface IRolloutSliderProps {
name: string;
minLabel?: string;
maxLabel?: string;
value: number;
onChange: (e: Event, newValue: number | number[]) => void;
disabled?: boolean;
}
const LegacyRolloutSlider = ({
name,
value,
onChange,
disabled = false,
}: IRolloutSliderProps) => {
const { classes } = useStyles();
const valuetext = (value: number) => `${value}%`;
return (
<div className={classes.slider}>
<StyledBox>
<Typography id='discrete-slider-always'>{name}</Typography>
<HelpIcon
htmlTooltip
tooltip={
<Box>
<StyledHeader variant='h3'>
Rollout percentage
</StyledHeader>
<Typography variant='body2'>
The rollout percentage determines the proportion
of users exposed to a feature. It's based on the
MurmurHash of a user's unique identifier,
normalized to a number between 1 and 100. If the
normalized hash is less than or equal to the
rollout percentage, the user sees the feature.
This ensures a consistent, random distribution
of the feature among users.
</Typography>
<StyledSubheader variant='h3'>
Stickiness
</StyledSubheader>
<Typography variant='body2'>
Stickiness refers to the value used for hashing
to ensure a consistent user experience. It
determines the input for the MurmurHash,
ensuring that a user's feature exposure remains
consistent across sessions.
<br />
By default Unleash will use the first value
present in the context in the order of{' '}
<b>userId, sessionId and random</b>.
</Typography>
<StyledSubheader variant='h3'>
GroupId
</StyledSubheader>
<Typography variant='body2'>
The groupId is used as a seed for the hash
function, ensuring consistent feature exposure
across different feature flags for a uniform
user experience.
</Typography>
</Box>
}
/>
</StyledBox>
<StyledSlider
min={0}
max={100}
value={value}
getAriaValueText={valuetext}
aria-labelledby='discrete-slider-always'
step={1}
data-testid={ROLLOUT_SLIDER_ID}
marks={marks}
onChange={onChange}
valueLabelDisplay='on'
disabled={disabled}
/>
</div>
);
};
export default LegacyRolloutSlider;

View File

@ -9,7 +9,6 @@ import {
type IAutocompleteBoxOption,
} from 'component/common/AutocompleteBox/AutocompleteBox';
import { MilestoneStrategySegmentList } from './MilestoneStrategySegmentList.tsx';
import { useUiFlag } from 'hooks/useUiFlag';
const StyledHelpIconBox = styled(Box)(({ theme }) => ({
display: 'flex',
@ -27,7 +26,6 @@ export const MilestoneStrategySegment = ({
segments: selectedSegments,
setSegments: setSelectedSegments,
}: IMilestoneStrategySegmentProps) => {
const addEditStrategy = useUiFlag('addEditStrategy');
const { segments: allSegments } = useSegments();
const { strategySegmentsLimit } = useSegmentLimits();
@ -90,7 +88,7 @@ export const MilestoneStrategySegment = ({
options={autocompleteOptions}
onChange={onChange}
disabled={atStrategySegmentsLimit}
icon={addEditStrategy ? null : undefined}
icon={null}
width={'175px'}
/>
<MilestoneStrategySegmentList

View File

@ -20,9 +20,7 @@ const setupRoutes = () => {
]);
testServerRoute(server, '/api/admin/ui-config', {
flags: {
addEditStrategy: true,
},
flags: {},
});
};

View File

@ -15,7 +15,6 @@ import {
import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext';
import type { IConstraint } from 'interfaces/strategy';
import { useNavigate } from 'react-router-dom';
import { ConstraintAccordionList } from 'component/common/LegacyConstraintAccordion/ConstraintAccordionList/ConstraintAccordionList';
import { EditableConstraintsList } from 'component/common/NewConstraintAccordion/ConstraintsList/EditableConstraintsList';
import type { IEditableConstraintsListRef } from 'component/common/NewConstraintAccordion/ConstraintsList/EditableConstraintsList';
import type { SegmentFormStep, SegmentFormMode } from './SegmentForm.tsx';
@ -31,7 +30,6 @@ import { useSegmentValuesCount } from 'component/segments/hooks/useSegmentValues
import AccessContext from 'contexts/AccessContext';
import { useSegmentLimits } from 'hooks/api/getters/useSegmentLimits/useSegmentLimits';
import { GO_BACK } from 'constants/navigate';
import { useUiFlag } from 'hooks/useUiFlag';
interface ISegmentFormPartTwoProps {
project?: string;
@ -122,7 +120,6 @@ export const SegmentFormStepTwo: React.FC<ISegmentFormPartTwoProps> = ({
? [CREATE_SEGMENT, UPDATE_PROJECT_SEGMENT]
: [UPDATE_SEGMENT, UPDATE_PROJECT_SEGMENT];
const { segmentValuesLimit } = useSegmentLimits();
const addEditStrategy = useUiFlag('addEditStrategy');
const overSegmentValuesLimit: boolean = Boolean(
segmentValuesLimit && segmentValuesCount > segmentValuesLimit,
@ -202,25 +199,13 @@ export const SegmentFormStepTwo: React.FC<ISegmentFormPartTwoProps> = ({
}
/>
<StyledConstraintContainer>
{addEditStrategy ? (
hasAccess(modePermission, project) && setConstraints ? (
<EditableConstraintsList
ref={constraintsAccordionListRef}
constraints={constraints}
setConstraints={setConstraints}
/>
) : null
) : (
<ConstraintAccordionList
{hasAccess(modePermission, project) && setConstraints ? (
<EditableConstraintsList
ref={constraintsAccordionListRef}
constraints={constraints}
setConstraints={
hasAccess(modePermission, project)
? setConstraints
: undefined
}
setConstraints={setConstraints}
/>
)}
) : null}
</StyledConstraintContainer>
</StyledForm>
<StyledButtonContainer>

View File

@ -6,7 +6,6 @@ import type {
import useAPI from '../useApi/useApi.js';
import { useRecentlyUsedConstraints } from 'component/feature/FeatureStrategy/FeatureStrategyConstraints/RecentlyUsedConstraints/useRecentlyUsedConstraints';
import { useRecentlyUsedSegments } from 'component/feature/FeatureStrategy/FeatureStrategySegment/RecentlyUsedSegments/useRecentlyUsedSegments';
import { useUiFlag } from 'hooks/useUiFlag';
const useFeatureStrategyApi = () => {
const { makeRequest, createRequest, errors, loading } = useAPI({
@ -16,7 +15,6 @@ const useFeatureStrategyApi = () => {
const { addItem: addToRecentlyUsedConstraints } =
useRecentlyUsedConstraints();
const { addItem: addToRecentlyUsedSegments } = useRecentlyUsedSegments();
const addEditStrategyEnabled = useUiFlag('addEditStrategy');
const addStrategyToFeature = async (
projectId: string,
@ -24,14 +22,12 @@ const useFeatureStrategyApi = () => {
environmentId: string,
payload: IFeatureStrategyPayload,
): Promise<IFeatureStrategy> => {
if (addEditStrategyEnabled) {
if (payload.constraints && payload.constraints.length > 0) {
addToRecentlyUsedConstraints(payload.constraints);
}
if (payload.constraints && payload.constraints.length > 0) {
addToRecentlyUsedConstraints(payload.constraints);
}
if (payload.segments && payload.segments.length > 0) {
addToRecentlyUsedSegments(payload.segments);
}
if (payload.segments && payload.segments.length > 0) {
addToRecentlyUsedSegments(payload.segments);
}
const path = `api/admin/projects/${projectId}/features/${featureId}/environments/${environmentId}/strategies`;
@ -67,14 +63,12 @@ const useFeatureStrategyApi = () => {
strategyId: string,
payload: IFeatureStrategyPayload,
): Promise<void> => {
if (addEditStrategyEnabled) {
if (payload.constraints && payload.constraints.length > 0) {
addToRecentlyUsedConstraints(payload.constraints);
}
if (payload.constraints && payload.constraints.length > 0) {
addToRecentlyUsedConstraints(payload.constraints);
}
if (payload.segments && payload.segments.length > 0) {
addToRecentlyUsedSegments(payload.segments);
}
if (payload.segments && payload.segments.length > 0) {
addToRecentlyUsedSegments(payload.segments);
}
const path = `api/admin/projects/${projectId}/features/${featureId}/environments/${environmentId}/strategies/${strategyId}`;

View File

@ -86,7 +86,6 @@ export type UiFlags = {
showUserDeviceCount?: boolean;
consumptionModel?: boolean;
edgeObservability?: boolean;
addEditStrategy?: boolean;
registerFrontendClient?: boolean;
customMetrics?: boolean;
lifecycleMetrics?: boolean;

View File

@ -56,7 +56,6 @@ export type IFlagKey =
| 'uniqueSdkTracking'
| 'consumptionModel'
| 'edgeObservability'
| 'addEditStrategy'
| 'registerFrontendClient'
| 'reportUnknownFlags'
| 'lastSeenBulkQuery'
@ -269,10 +268,6 @@ const flags: IFlags = {
process.env.EXPERIMENTAL_EDGE_OBSERVABILITY,
false,
),
addEditStrategy: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_ADD_EDIT_STRATEGY,
false,
),
registerFrontendClient: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_REGISTER_FRONTEND_CLIENT,
false,

View File

@ -50,7 +50,6 @@ process.nextTick(async () => {
showUserDeviceCount: true,
deltaApi: true,
uniqueSdkTracking: true,
addEditStrategy: true,
strictSchemaValidation: true,
registerFrontendClient: true,
reportUnknownFlags: true,