Skip to content
This repository has been archived by the owner on Oct 27, 2022. It is now read-only.

Commit

Permalink
Merge remote-tracking branch 'origin/task/Add_strategy_information_to…
Browse files Browse the repository at this point in the history
…_playground_results' into task/Add_strategy_information_to_playground_results
  • Loading branch information
andreas-unleash committed Aug 5, 2022
2 parents 400a9ca + 30171cc commit 3d18701
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 60 deletions.
8 changes: 3 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "unleash-frontend",
"description": "unleash your features",
"version": "4.14.2",
"version": "4.14.3",
"keywords": [
"unleash",
"feature toggle",
Expand Down Expand Up @@ -63,7 +63,7 @@
"@types/react-timeago": "4.1.3",
"@types/semver": "7.3.10",
"@vitejs/plugin-react": "1.3.2",
"chart.js": "3.8.2",
"chart.js": "3.9.1",
"chartjs-adapter-date-fns": "2.0.0",
"classnames": "2.3.1",
"copy-to-clipboard": "3.3.2",
Expand Down Expand Up @@ -103,9 +103,7 @@
"vitest": "0.20.3",
"whatwg-fetch": "^3.6.2",
"@codemirror/lang-json": "6.0.0",
"@codemirror/state": "6.1.1",
"@uiw/react-codemirror": "^4.11.4",
"codemirror": "^6.0.1"
"@uiw/react-codemirror": "^4.11.4"
},
"jest": {
"moduleNameMapper": {
Expand Down
2 changes: 1 addition & 1 deletion src/component/common/SegmentItem/SegmentItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export const SegmentItem: VFC<ISegmentItemProps> = ({
condition={segment!.constraints?.length > 0}
show={
<ConstraintAccordionList
constraints={segment!.constraints}
constraints={segment.constraints}
showLabel={false}
/>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,7 @@ export const FeatureStrategySegmentList = ({
</div>
<ConditionallyRender
condition={Boolean(preview)}
show={() => (
<SegmentItem segment={preview as ISegment} isExpanded />
)}
show={() => <SegmentItem segment={preview!} isExpanded />}
/>
</>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react';
import { DragEventHandler, RefObject, useEffect, useState } from 'react';
import { Alert } from '@mui/material';
import useFeatureStrategyApi from 'hooks/api/actions/useFeatureStrategyApi/useFeatureStrategyApi';
import { formatUnknownError } from 'utils/formatUnknownError';
Expand Down Expand Up @@ -27,10 +27,14 @@ const EnvironmentAccordionBody = ({
const { setStrategiesSortOrder } = useFeatureStrategyApi();
const { setToastData, setToastApiError } = useToast();
const { refetchFeature } = useFeature(projectId, featureId);

const [strategies, setStrategies] = useState(
featureEnvironment?.strategies || []
);
const [dragItem, setDragItem] = useState<{
id: string;
index: number;
height: number;
} | null>(null);
const { classes: styles } = useStyles();
useEffect(() => {
// Use state to enable drag and drop, but switch to API output when it arrives
Expand All @@ -41,35 +45,86 @@ const EnvironmentAccordionBody = ({
return null;
}

const onDragAndDrop = async (
from: number,
to: number,
dropped?: boolean
) => {
if (from !== to && dropped) {
const newStrategies = [...strategies];
const movedStrategy = newStrategies.splice(from, 1)[0];
newStrategies.splice(to, 0, movedStrategy);
setStrategies(newStrategies);
try {
await setStrategiesSortOrder(
projectId,
featureId,
featureEnvironment.name,
[...newStrategies].map((strategy, sortOrder) => ({
id: strategy.id,
sortOrder,
}))
);
refetchFeature();
setToastData({
title: 'Order of strategies updated',
type: 'success',
const onReorder = async (payload: { id: string; sortOrder: number }[]) => {
try {
await setStrategiesSortOrder(
projectId,
featureId,
featureEnvironment.name,
payload
);
refetchFeature();
setToastData({
title: 'Order of strategies updated',
type: 'success',
});
} catch (error: unknown) {
setToastApiError(formatUnknownError(error));
}
};

const onDragStartRef =
(
ref: RefObject<HTMLDivElement>,
index: number
): DragEventHandler<HTMLButtonElement> =>
event => {
setDragItem({
id: strategies[index].id,
index,
height: ref.current?.offsetHeight || 0,
});

if (ref?.current) {
event.dataTransfer.effectAllowed = 'move';
event.dataTransfer.setData('text/html', ref.current.outerHTML);
event.dataTransfer.setDragImage(ref.current, 20, 20);
}
};

const onDragOver =
(targetId: string) =>
(
ref: RefObject<HTMLDivElement>,
targetIndex: number
): DragEventHandler<HTMLDivElement> =>
event => {
if (dragItem === null || ref.current === null) return;
if (dragItem.index === targetIndex || targetId === dragItem.id)
return;

const { top, bottom } = ref.current.getBoundingClientRect();
const overTargetTop = event.clientY - top < dragItem.height;
const overTargetBottom = bottom - event.clientY < dragItem.height;
const draggingUp = dragItem.index > targetIndex;

// prevent oscillating by only reordering if there is sufficient space
if (
(overTargetTop && draggingUp) ||
(overTargetBottom && !draggingUp)
) {
const newStrategies = [...strategies];
const movedStrategy = newStrategies.splice(
dragItem.index,
1
)[0];
newStrategies.splice(targetIndex, 0, movedStrategy);
setStrategies(newStrategies);
setDragItem({
...dragItem,
index: targetIndex,
});
} catch (error: unknown) {
setToastApiError(formatUnknownError(error));
}
}
};

const onDragEnd = () => {
setDragItem(null);
onReorder(
strategies.map((strategy, sortOrder) => ({
id: strategy.id,
sortOrder,
}))
);
};

return (
Expand All @@ -91,11 +146,14 @@ const EnvironmentAccordionBody = ({
{strategies.map((strategy, index) => (
<StrategyDraggableItem
key={strategy.id}
onDragAndDrop={onDragAndDrop}
strategy={strategy}
index={index}
environmentName={featureEnvironment.name}
otherEnvironments={otherEnvironments}
isDragging={dragItem?.id === strategy.id}
onDragStartRef={onDragStartRef}
onDragOver={onDragOver(strategy.id)}
onDragEnd={onDragEnd}
/>
))}
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
import { Box, styled } from '@mui/material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator';
import { MoveListItem, useDragItem } from 'hooks/useDragItem';
import { IFeatureEnvironment } from 'interfaces/featureToggle';
import { IFeatureStrategy } from 'interfaces/strategy';
import { DragEventHandler, RefObject, useRef } from 'react';
import { StrategyItem } from './StrategyItem/StrategyItem';

interface IStrategyDraggableItemProps {
strategy: IFeatureStrategy;
environmentName: string;
index: number;
otherEnvironments?: IFeatureEnvironment['name'][];
onDragAndDrop: MoveListItem;
isDragging?: boolean;
onDragStartRef: (
ref: RefObject<HTMLDivElement>,
index: number
) => DragEventHandler<HTMLButtonElement>;
onDragOver: (
ref: RefObject<HTMLDivElement>,
index: number
) => DragEventHandler<HTMLDivElement>;
onDragEnd: () => void;
}

const StyledIndexLabel = styled('div')(({ theme }) => ({
Expand All @@ -31,12 +40,20 @@ export const StrategyDraggableItem = ({
index,
environmentName,
otherEnvironments,
onDragAndDrop,
isDragging,
onDragStartRef,
onDragOver,
onDragEnd,
}: IStrategyDraggableItemProps) => {
const ref = useDragItem(index, onDragAndDrop);
const ref = useRef<HTMLDivElement>(null);

return (
<Box key={strategy.id} ref={ref}>
<Box
key={strategy.id}
ref={ref}
onDragOver={onDragOver(ref, index)}
sx={{ opacity: isDragging ? '0.5' : '1' }}
>
<ConditionallyRender
condition={index > 0}
show={<StrategySeparator text="OR" />}
Expand All @@ -47,7 +64,8 @@ export const StrategyDraggableItem = ({
strategy={strategy}
environmentId={environmentName}
otherEnvironments={otherEnvironments}
isDraggable
onDragStart={onDragStartRef(ref, index)}
onDragEnd={onDragEnd}
/>
</Box>
</Box>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { DragEventHandler } from 'react';
import { DragIndicator, Edit } from '@mui/icons-material';
import { styled, useTheme, IconButton } from '@mui/material';
import { Link } from 'react-router-dom';
Expand All @@ -22,7 +23,8 @@ import { useStyles } from './StrategyItem.styles';
interface IStrategyItemProps {
environmentId: string;
strategy: IFeatureStrategy;
isDraggable?: boolean;
onDragStart?: DragEventHandler<HTMLButtonElement>;
onDragEnd?: DragEventHandler<HTMLButtonElement>;
otherEnvironments?: IFeatureEnvironment['name'][];
}

Expand All @@ -35,7 +37,8 @@ const DragIcon = styled(IconButton)(({ theme }) => ({
export const StrategyItem = ({
environmentId,
strategy,
isDraggable,
onDragStart,
onDragEnd,
otherEnvironments,
}: IStrategyItemProps) => {
const projectId = useRequiredPathParam('projectId');
Expand All @@ -55,13 +58,20 @@ export const StrategyItem = ({
<div className={styles.container}>
<div
className={classNames(styles.header, {
[styles.headerDraggable]: isDraggable,
[styles.headerDraggable]: Boolean(onDragStart),
})}
>
<ConditionallyRender
condition={Boolean(isDraggable)}
condition={Boolean(onDragStart)}
show={() => (
<DragIcon disableRipple disabled size="small">
<DragIcon
draggable
disableRipple
size="small"
onDragStart={onDragStart}
onDragEnd={onDragEnd}
sx={{ cursor: 'move' }}
>
<DragIndicator
titleAccess="Drag to reorder"
cursor="grab"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,10 @@ export const ProjectAccessAssign = ({
return option.entity.name;
}
}}
isOptionEqualToValue={(option, value) =>
option.type === value.type &&
option.entity.id === value.entity.id
}
renderInput={params => (
<TextField
{...params}
Expand Down
15 changes: 5 additions & 10 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1318,11 +1318,6 @@
"@codemirror/view" "^6.0.0"
crelt "^1.0.5"

"@codemirror/[email protected]":
version "6.1.1"
resolved "https://registry.yarnpkg.com/@codemirror/state/-/state-6.1.1.tgz#4f512e5e34ea23a5e10b2c1fe43f6195e90417bb"
integrity sha512-2s+aXsxmAwnR3Rd+JDHPG/1lw0YsA9PEwl7Re88gHJHGfxyfEzKBmsN4rr53RyPIR4lzbbhJX0DCq0WlqlBIRw==

"@codemirror/state@^6.0.0":
version "6.1.0"
resolved "https://registry.yarnpkg.com/@codemirror/state/-/state-6.1.0.tgz#c0f1d80f61908c9dcf5e2a3fe931e9dd78f3df8a"
Expand Down Expand Up @@ -2924,10 +2919,10 @@ chardet@^0.7.0:
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==

chart.js@3.8.2:
version "3.8.2"
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-3.8.2.tgz#e3ebb88f7072780eec4183a788a990f4a58ba7a1"
integrity sha512-7rqSlHWMUKFyBDOJvmFGW2lxULtcwaPLegDjX/Nu5j6QybY+GCiQkEY+6cqHw62S5tcwXMD8Y+H5OBGoR7d+ZQ==
chart.js@3.9.1:
version "3.9.1"
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-3.9.1.tgz#3abf2c775169c4c71217a107163ac708515924b8"
integrity sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w==

[email protected]:
version "2.0.0"
Expand Down Expand Up @@ -3027,7 +3022,7 @@ clsx@^1.2.1:
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==

codemirror@^6.0.0, codemirror@^6.0.1:
codemirror@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-6.0.1.tgz#62b91142d45904547ee3e0e0e4c1a79158035a29"
integrity sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==
Expand Down

0 comments on commit 3d18701

Please sign in to comment.