diff --git a/frontend/src/component/common/NewConstraintAccordion/ConstraintAccordionEdit/ConstraintAccordionEditBody/DateSingleValue/DateSingleValue.tsx b/frontend/src/component/common/NewConstraintAccordion/ConstraintAccordionEdit/ConstraintAccordionEditBody/DateSingleValue/DateSingleValue.tsx index c0313f1f55..af80d0081c 100644 --- a/frontend/src/component/common/NewConstraintAccordion/ConstraintAccordionEdit/ConstraintAccordionEditBody/DateSingleValue/DateSingleValue.tsx +++ b/frontend/src/component/common/NewConstraintAccordion/ConstraintAccordionEdit/ConstraintAccordionEditBody/DateSingleValue/DateSingleValue.tsx @@ -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, diff --git a/frontend/src/component/common/NewConstraintAccordion/ConstraintAccordionEdit/ConstraintAccordionEditBody/ResolveInput/ResolveInput.tsx b/frontend/src/component/common/NewConstraintAccordion/ConstraintAccordionEdit/ConstraintAccordionEditBody/ResolveInput/ResolveInput.tsx index bb89979581..ba49c47141 100644 --- a/frontend/src/component/common/NewConstraintAccordion/ConstraintAccordionEdit/ConstraintAccordionEditBody/ResolveInput/ResolveInput.tsx +++ b/frontend/src/component/common/NewConstraintAccordion/ConstraintAccordionEdit/ConstraintAccordionEditBody/ResolveInput/ResolveInput.tsx @@ -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; localConstraint: Pick; @@ -32,38 +26,12 @@ interface IResolveInputProps { setValuesWithRecord: (values: string[]) => void; setError: React.Dispatch>; 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 ( - - ); - case NUM_OPERATORS_LEGAL_VALUES: - return ( - <> - Number(legalValue.value), - ) || [] - } - error={error} - setError={setError} - /> - - ); - case SEMVER_OPERATORS_LEGAL_VALUES: - return ( - <> - - - ); - case DATE_OPERATORS_SINGLE_VALUE: - return ( - - ); case IN_OPERATORS_FREETEXT: + case STRING_OPERATORS_FREETEXT: return ( ); - case STRING_OPERATORS_FREETEXT: - return ( - <> - - - ); case NUM_OPERATORS_SINGLE_VALUE: return ( void; } diff --git a/frontend/src/component/common/SegmentItem/SegmentItem.tsx b/frontend/src/component/common/SegmentItem/SegmentItem.tsx new file mode 100644 index 0000000000..ff7666d9fb --- /dev/null +++ b/frontend/src/component/common/SegmentItem/SegmentItem.tsx @@ -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; + 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 = ({ + 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 ( + + {segment.constraints.map((constraint, index) => ( + + ))} + + ); + } + + return ( + + This segment has no constraints. + + ); + }, [constraintList, segment.constraints]); + + return ( + + + + + + {segment.name} + + + {headerContent ? headerContent : null} + {!isExpanded ? ( + + setIsOpen((value) => !value)} + > + {isOpen ? 'Close preview' : 'Preview'} + + + ) : null} + + {constraints} + + + ); +}; diff --git a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyEdit/FeatureStrategyEdit.tsx b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyEdit/FeatureStrategyEdit.tsx index a05cca7724..b8d896a7e3 100644 --- a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyEdit/FeatureStrategyEdit.tsx +++ b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyEdit/FeatureStrategyEdit.tsx @@ -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('');