Skip to content

Commit

Permalink
Merge pull request #23 from alberto-abarzua/21-clean-up-drag-and-drop…
Browse files Browse the repository at this point in the history
…-logic
  • Loading branch information
alberto-abarzua authored Nov 6, 2023
2 parents ae23b27 + e629aa6 commit 5cfdd99
Show file tree
Hide file tree
Showing 16 changed files with 505 additions and 213 deletions.
62 changes: 62 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.14.7",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-slot": "^1.0.2",
Expand Down
55 changes: 50 additions & 5 deletions frontend/src/components/actions/ActionContainer.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,57 @@
import { actionListActions } from '@/redux/ActionListSlice';
import { renderAction } from '@/utils/actions';
import byIdContext from '@/utils/byIdContext';
import { ItemTypes } from '@/utils/ItemTypes';
import AddIcon from '@mui/icons-material/Add';
import PropTypes from 'prop-types';
import { useContext, useState } from 'react';
import { useDrop } from 'react-dnd';
import { useDispatch } from 'react-redux';

const ActionContainer = ({ actionList }) => {
return (
<div className="flex h-full w-full flex-col gap-y-4 p-4">
{actionList && actionList.map(action => renderAction(action))}
</div>
);
const dispatch = useDispatch();
const byId = useContext(byIdContext);
const [isOver, setIsOver] = useState(false);

actionList = actionList.map(action => byId[action.id]);
const [, drop] = useDrop({
accept: ItemTypes.ACTION,
collect(monitor) {
setIsOver(monitor.isOver());
return {
handlerId: monitor.getHandlerId(),
};
},
drop(item) {
dispatch(
actionListActions.pushActionToValue({
actionId: null,
actionToAddId: item.id,
type: item.type,
value: item.value,
})
);
},
});

const dropAreaStyles = isOver ? 'bg-blue-300 ' : '';

if (actionList.length > 0) {
return (
<div className="flex h-full w-full flex-col gap-y-4 p-4">
{actionList && actionList.map(action => renderAction(action))}
</div>
);
} else {
return (
<div
className={`flex h-24 w-full items-center justify-center rounded-md ${dropAreaStyles}`}
ref={drop}
>
<AddIcon className="scale-[2.0] transform text-gray-500"></AddIcon>
</div>
);
}
};

ActionContainer.propTypes = {
Expand Down
57 changes: 43 additions & 14 deletions frontend/src/components/actions/ActionSet.jsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,76 @@
import ActionContainer from '@/components/actions/ActionContainer';
import BaseAction from '@/components/actions/BaseAction';
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from '@/components/ui/accordion';
import { actionListActions } from '@/redux/ActionListSlice';
import { ItemTypes } from '@/utils/ItemTypes';
import AddIcon from '@mui/icons-material/Add';
import DashboardCustomizeIcon from '@mui/icons-material/DashboardCustomize';
import PropTypes from 'prop-types';
import { useState } from 'react';
import { useDrop } from 'react-dnd';
import { useSelector, useDispatch } from 'react-redux';
const ActionSet = ({ ...props }) => {
import { useDispatch } from 'react-redux';

const ActionSet = ({ action, ...props }) => {
const dispatch = useDispatch();

const action = useSelector(state => state.actionList.byId[props.id]);
const id = action.id;
const [isOver, setIsOver] = useState(false);

const actionList = action.value;

const [, drop] = useDrop({
accept: ItemTypes.ACTION,
collect(monitor) {
setIsOver(monitor.isOver());
return {
handlerId: monitor.getHandlerId(),
};
},
drop(item) {
if (item.id === props.id) {
if (item.id === id) {
return;
}
dispatch(
actionListActions.pushActionToValue({ actionId: props.id, actionToAddId: item.id })
);
dispatch(actionListActions.pushActionToValue({ actionId: id, actionToAddId: item.id }));
},
});

const dropAreaStyles = isOver ? 'bg-blue-300 ' : '';

const body =
actionList.length === 0 ? (
<div ref={drop}>Drag here</div>
<div
className={`flex h-24 w-full items-center justify-center rounded-md ${dropAreaStyles}`}
ref={drop}
>
<AddIcon className="scale-[2.0] transform text-gray-500"></AddIcon>
</div>
) : (
<ActionContainer actionList={actionList}></ActionContainer>
<div className="w-full px-2">
<Accordion type="single" collapsible>
<AccordionItem value="item-1">
<AccordionTrigger>Sub Actions</AccordionTrigger>
<AccordionContent>
<ActionContainer actionList={actionList}></ActionContainer>
</AccordionContent>
</AccordionItem>
</Accordion>
</div>
);

return (
<BaseAction
className={' bg-action-set'}
icon={<DashboardCustomizeIcon className="text-6xl"></DashboardCustomizeIcon>}
action={action}
{...props}
>
<div className="flex flex-1 items-center justify-end">
<div className="flex items-center justify-end text-black">
<div className=" flex items-center justify-center rounded-md bg-action-data p-2 shadow">
<div className=" flex flex-1 items-center justify-end">
<div className="flex w-full items-center justify-end text-black">
<div className="my-3 flex w-full flex-1 items-center justify-center rounded-md bg-action-data shadow">
{body}
</div>
</div>
Expand All @@ -55,7 +80,11 @@ const ActionSet = ({ ...props }) => {
};

ActionSet.propTypes = {
id: PropTypes.number.isRequired,
action: PropTypes.shape({
type: PropTypes.string.isRequired,
id: PropTypes.number.isRequired,
value: PropTypes.arrayOf(PropTypes.any).isRequired,
}).isRequired,
};

export default ActionSet;
55 changes: 27 additions & 28 deletions frontend/src/components/actions/ActionsPanel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import ActionContainer from '@/components/actions/ActionContainer';
import ToolBar from '@/components/actions/ToolBar';
import { Button } from '@/components/ui/button';
import { actionListActions } from '@/redux/ActionListSlice';
import { ActionTypes, runAction } from '@/utils/actions';
import { runAction } from '@/utils/actions';
import byIdContext from '@/utils/byIdContext';
import ErrorIcon from '@mui/icons-material/Error';
import PlayArrowIcon from '@mui/icons-material/PlayArrow';
import StopIcon from '@mui/icons-material/Stop';
Expand All @@ -11,10 +12,11 @@ import { useSelector, useDispatch } from 'react-redux';

const ActionPanel = () => {
const dispatch = useDispatch();
const actionList = useSelector(state => state.actionList.actions);
const byId = useSelector(state => state.actionList.byId);
console.log('byId', byId);
console.log('actionList', actionList);

const actionSlice = useSelector(state => state.actionList);

const actionList = actionSlice.actions;
const byId = actionSlice.byId;

const [running, setRunning] = useState(false);
const runningRef = useRef(false);
Expand All @@ -28,21 +30,16 @@ const ActionPanel = () => {
const runActions = async () => {
for (let action of actionList) {
if (!runningRef.current) return;

action = byId[action.id];
dispatch(actionListActions.setRunningStatus({ actionId: action.id, running: true }));
console.log('running action', action);
if (action.type === ActionTypes.ACTIONSET) {
action = byId[action.id];
}
await runAction(action, dispatch);
console.log('finished running action', action);

dispatch(actionListActions.setRunningStatus({ actionId: action.id, running: false }));
}
console.log('finished running all actions');

setRunning(false);
};
console.log('rendering ActionPanel');

const handleClickPlayStop = () => {
setRunning(prev => !prev);
Expand Down Expand Up @@ -79,23 +76,25 @@ const ActionPanel = () => {
}

return (
<div className="relative m-0 flex h-full max-h-screen w-full flex-col items-center space-y-4 ">
<ToolBar />
<div className="flex h-full max-h-screen w-full flex-col items-center gap-4 overflow-y-auto pt-14">
<ActionContainer actionList={actionList} />
</div>
<div className="absolute bottom-10 right-8 z-20">
<Button
color={play_or_stop.color}
hoverColor={play_or_stop.hoverColor}
onClick={handleClickPlayStop}
disabled={!valid}
>
{play_or_stop.icon}
<div className="text-lg text-white"> {play_or_stop.text}</div>
</Button>
<byIdContext.Provider value={byId}>
<div className="relative m-0 flex h-full max-h-screen w-full flex-col items-center space-y-4 ">
<ToolBar />
<div className="flex h-full max-h-screen w-full flex-col items-center gap-4 overflow-y-auto pt-14">
<ActionContainer actionList={actionList} />
</div>
<div className="absolute bottom-10 right-8 z-20">
<Button
color={play_or_stop.color}
hoverColor={play_or_stop.hoverColor}
onClick={handleClickPlayStop}
disabled={!valid}
>
{play_or_stop.icon}
<div className="text-lg text-white"> {play_or_stop.text}</div>
</Button>
</div>
</div>
</div>
</byIdContext.Provider>
);
};

Expand Down
Loading

0 comments on commit 5cfdd99

Please sign in to comment.