1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-31 13:47:02 +02:00

more cleanup jobs

This commit is contained in:
Thomas Heartman 2025-06-10 13:50:49 +02:00
parent 5403ac0751
commit 5a793f9c3e
6 changed files with 161 additions and 128 deletions

View File

@ -23,7 +23,6 @@ const StyledWrapper = styled('div')(({ theme }) => ({
/**
* @deprecated use `component/feature/FeatureStrategy/FeatureStrategyConstraints/ConstraintDateInput.tsx`
* Remove with flag `addEditStrategy`
*/
export const DateSingleValue = ({
setValue,

View File

@ -1,27 +1,21 @@
import type {
ILegalValue,
IUnleashContextDefinition,
} from 'interfaces/context';
import type { IUnleashContextDefinition } from 'interfaces/context';
import type { IConstraint } from 'interfaces/strategy';
import { DateSingleValue } from '../DateSingleValue/DateSingleValue.tsx';
import { FreeTextInput } from '../FreeTextInput/FreeTextInput.tsx';
import { RestrictiveLegalValues } from '../RestrictiveLegalValues/RestrictiveLegalValues.tsx';
import { SingleLegalValue } from '../SingleLegalValue/SingleLegalValue.tsx';
import { SingleValue } from '../SingleValue/SingleValue.tsx';
import {
IN_OPERATORS_LEGAL_VALUES,
STRING_OPERATORS_FREETEXT,
STRING_OPERATORS_LEGAL_VALUES,
SEMVER_OPERATORS_SINGLE_VALUE,
NUM_OPERATORS_LEGAL_VALUES,
NUM_OPERATORS_SINGLE_VALUE,
SEMVER_OPERATORS_LEGAL_VALUES,
DATE_OPERATORS_SINGLE_VALUE,
IN_OPERATORS_FREETEXT,
type Input,
} from '../useConstraintInput/useConstraintInput.tsx';
import type React from 'react';
type ActionFilterItemInput =
| typeof STRING_OPERATORS_FREETEXT
| typeof SEMVER_OPERATORS_SINGLE_VALUE
| typeof NUM_OPERATORS_SINGLE_VALUE
| typeof IN_OPERATORS_FREETEXT;
interface IResolveInputProps {
contextDefinition: Pick<IUnleashContextDefinition, 'legalValues'>;
localConstraint: Pick<IConstraint, 'value' | 'values'>;
@ -32,38 +26,12 @@ interface IResolveInputProps {
setValuesWithRecord: (values: string[]) => void;
setError: React.Dispatch<React.SetStateAction<string>>;
removeValue: (index: number) => void;
input: Input;
input: ActionFilterItemInput;
error: string;
}
const resolveLegalValues = (
values: IConstraint['values'],
legalValues: IUnleashContextDefinition['legalValues'],
): { legalValues: ILegalValue[]; deletedLegalValues: ILegalValue[] } => {
if (legalValues?.length === 0) {
return {
legalValues: [],
deletedLegalValues: [],
};
}
const deletedLegalValues = (values || [])
.filter(
(value) =>
!(legalValues || []).some(
({ value: legalValue }) => legalValue === value,
),
)
.map((v) => ({ value: v, description: '' }));
return {
legalValues: legalValues || [],
deletedLegalValues,
};
};
/**
* @deprecated; remove with `addEditStrategy` flag. Need an input? Prefer using specific input components.
* @deprecated; Need an input? Prefer using specific input components.
*
* For the case of `ProjectActionsFilterItem.tsx`: it already excludes legal
* values and date operators. This leaves only free text and single value
@ -71,12 +39,8 @@ const resolveLegalValues = (
*/
export const ResolveInput = ({
input,
contextDefinition,
constraintValues,
constraintValue,
localConstraint,
setValue,
setValues,
setValuesWithRecord,
setError,
removeValue,
@ -84,72 +48,8 @@ export const ResolveInput = ({
}: IResolveInputProps) => {
const resolveInput = () => {
switch (input) {
case IN_OPERATORS_LEGAL_VALUES:
case STRING_OPERATORS_LEGAL_VALUES:
return (
<RestrictiveLegalValues
data={resolveLegalValues(
constraintValues,
contextDefinition.legalValues,
)}
constraintValues={constraintValues}
values={localConstraint.values || []}
setValuesWithRecord={setValuesWithRecord}
setValues={setValues}
error={error}
setError={setError}
/>
);
case NUM_OPERATORS_LEGAL_VALUES:
return (
<>
<SingleLegalValue
data={resolveLegalValues(
[constraintValue],
contextDefinition.legalValues,
)}
setValue={setValue}
value={localConstraint.value}
constraintValue={constraintValue}
type='number'
legalValues={
contextDefinition.legalValues?.filter(
(legalValue) => Number(legalValue.value),
) || []
}
error={error}
setError={setError}
/>
</>
);
case SEMVER_OPERATORS_LEGAL_VALUES:
return (
<>
<SingleLegalValue
data={resolveLegalValues(
[constraintValue],
contextDefinition.legalValues,
)}
setValue={setValue}
value={localConstraint.value}
constraintValue={constraintValue}
type='semver'
legalValues={contextDefinition.legalValues || []}
error={error}
setError={setError}
/>
</>
);
case DATE_OPERATORS_SINGLE_VALUE:
return (
<DateSingleValue
value={localConstraint.value}
setValue={setValue}
error={error}
setError={setError}
/>
);
case IN_OPERATORS_FREETEXT:
case STRING_OPERATORS_FREETEXT:
return (
<FreeTextInput
values={localConstraint.values || []}
@ -159,18 +59,6 @@ export const ResolveInput = ({
setError={setError}
/>
);
case STRING_OPERATORS_FREETEXT:
return (
<>
<FreeTextInput
values={localConstraint.values || []}
removeValue={removeValue}
setValues={setValuesWithRecord}
error={error}
setError={setError}
/>
</>
);
case NUM_OPERATORS_SINGLE_VALUE:
return (
<SingleValue

View File

@ -65,7 +65,7 @@ type Validator =
| 'DATE_VALIDATOR';
/**
* @deprecated; remove with `addEditStrategy` flag. This component requires a lot of state and mixes many components. Better off using dedicated pieces where you need them.
* @deprecated; This component requires a lot of state and mixes many components. Better off using dedicated pieces where you need them.
*/
export const useConstraintInput = ({
contextDefinition,

View File

@ -5,12 +5,12 @@ import { styled } from '@mui/material';
import type { IConstraint } from 'interfaces/strategy';
import produce from 'immer';
import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext';
import { ConstraintsList } from 'component/common/ConstraintsList/ConstraintsList';
import { EditableConstraint } from 'component/feature/FeatureStrategy/FeatureStrategyConstraints/EditableConstraint/EditableConstraint';
import {
constraintId,
createEmptyConstraint,
} from 'component/common/LegacyConstraintAccordion/ConstraintAccordionList/createEmptyConstraint';
import { ConstraintsList } from 'component/common/ConstraintsList/ConstraintsList';
import { EditableConstraint } from 'component/feature/FeatureStrategy/FeatureStrategyConstraints/EditableConstraint/EditableConstraint';
} from 'utils/createEmptyConstraint';
export interface IEditableConstraintsListRef {
addConstraint?: (contextName: string) => void;
}

View File

@ -0,0 +1,145 @@
import { useId, useMemo, useState, type FC } from 'react';
import { Link } from 'react-router-dom';
import type { ISegment } from 'interfaces/segment';
import {
Accordion,
AccordionDetails,
AccordionSummary,
Button,
styled,
} from '@mui/material';
import { StrategyEvaluationItem } from 'component/common/ConstraintsList/StrategyEvaluationItem/StrategyEvaluationItem';
import { objectId } from 'utils/objectId';
import {
ConstraintListItem,
ConstraintsList,
} from 'component/common/ConstraintsList/ConstraintsList';
import { ConstraintAccordionView } from '../NewConstraintAccordion/ConstraintAccordionView/ConstraintAccordionView.tsx';
type SegmentItemProps = {
segment: Partial<ISegment>;
isExpanded?: boolean;
disabled?: boolean | null;
constraintList?: JSX.Element;
headerContent?: JSX.Element;
};
const StyledConstraintListItem = styled(ConstraintListItem)(() => ({
padding: 0,
}));
const StyledAccordion = styled(Accordion)(() => ({
boxShadow: 'none',
margin: 0,
padding: 0,
'::before': {
// MUI separator between accordions
display: 'none',
},
}));
const StyledAccordionSummary = styled(AccordionSummary)(({ theme }) => ({
fontSize: theme.typography.body2.fontSize,
minHeight: 'unset',
':focus-within': {
backgroundColor: 'inherit',
},
}));
const StyledAccordionDetails = styled(AccordionDetails)(({ theme }) => ({
padding: theme.spacing(0.5, 3, 2.5),
}));
const StyledLink = styled(Link)(({ theme }) => ({
textDecoration: 'none',
paddingRight: theme.spacing(0.5),
'&:hover': {
textDecoration: 'underline',
},
}));
const StyledActionsContainer = styled('div')(({ theme }) => ({
display: 'flex',
alignItems: 'center',
marginLeft: 'auto',
}));
const StyledButton = styled(Button)(({ theme }) => ({
fontSize: theme.typography.body2.fontSize,
}));
const StyledNoConstraintsText = styled('p')(({ theme }) => ({
fontSize: theme.typography.body2.fontSize,
color: theme.palette.text.secondary,
}));
export const SegmentItem: FC<SegmentItemProps> = ({
segment,
isExpanded,
headerContent,
constraintList,
}) => {
const [isOpen, setIsOpen] = useState(isExpanded || false);
const segmentDetailsId = useId();
const constraints = useMemo(() => {
if (constraintList) {
return constraintList;
}
if (segment.constraints?.length) {
return (
<ConstraintsList>
{segment.constraints.map((constraint, index) => (
<ConstraintAccordionView
key={`${objectId(constraint)}-${index}`}
constraint={constraint}
/>
))}
</ConstraintsList>
);
}
return (
<StyledNoConstraintsText>
This segment has no constraints.
</StyledNoConstraintsText>
);
}, [constraintList, segment.constraints]);
return (
<StyledConstraintListItem>
<StyledAccordion
expanded={isOpen}
disableGutters
TransitionProps={{ mountOnEnter: true, unmountOnExit: true }}
>
<StyledAccordionSummary
id={`segment-accordion-${segment.id}`}
tabIndex={-1}
aria-controls={segmentDetailsId}
>
<StrategyEvaluationItem type='Segment'>
<StyledLink to={`/segments/edit/${segment.id}`}>
{segment.name}
</StyledLink>
</StrategyEvaluationItem>
{headerContent ? headerContent : null}
{!isExpanded ? (
<StyledActionsContainer>
<StyledButton
aria-controls={segmentDetailsId}
size='small'
variant='outlined'
onClick={() => setIsOpen((value) => !value)}
>
{isOpen ? 'Close preview' : 'Preview'}
</StyledButton>
</StyledActionsContainer>
) : null}
</StyledAccordionSummary>
<StyledAccordionDetails>{constraints}</StyledAccordionDetails>
</StyledAccordion>
</StyledConstraintListItem>
);
};

View File

@ -28,13 +28,14 @@ import { usePendingChangeRequests } from 'hooks/api/getters/usePendingChangeRequ
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
import { FeatureStrategyForm } from '../FeatureStrategyForm/FeatureStrategyForm.tsx';
import { NewStrategyVariants } from 'component/feature/StrategyTypes/NewStrategyVariants';
import { constraintId } from 'component/common/LegacyConstraintAccordion/ConstraintAccordionList/createEmptyConstraint';
import { v4 as uuidv4 } from 'uuid';
import { useScheduledChangeRequestsWithStrategy } from 'hooks/api/getters/useScheduledChangeRequestsWithStrategy/useScheduledChangeRequestsWithStrategy';
import {
getChangeRequestConflictCreatedData,
getChangeRequestConflictCreatedDataFromScheduleData,
} from './change-request-conflict-data.ts';
import { constraintId } from 'utils/createEmptyConstraint.ts';
const useTitleTracking = () => {
const [previousTitle, setPreviousTitle] = useState<string>('');