Skip to content
This repository was archived by the owner on Jun 3, 2025. It is now read-only.

Commit f41153a

Browse files
feat: add save and load actions and init tutorial
1 parent 0831167 commit f41153a

23 files changed

+946
-146
lines changed

backend/src/main.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@
66
from routers.move import router as move_router
77
from routers.settings import router as settings_router
88
from utils.general import start_controller, stop_controller
9+
import logging
10+
11+
class IgnoreEndpointFilter(logging.Filter):
12+
def filter(self, record):
13+
return '/settings/status/' not in record.getMessage()
14+
15+
logging.basicConfig(level=logging.INFO)
16+
logging.getLogger('uvicorn.access').addFilter(IgnoreEndpointFilter())
917

1018

1119
@asynccontextmanager

backend/src/utils/general.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
CONFIG_FILE = PARENT_DIR / "config" / "main_arm.toml"
1010

1111

12-
PRINT_DEBUG = True
12+
PRINT_DEBUG = False
1313

1414

1515
def get_controller() -> ArmController:

frontend/package-lock.json

Lines changed: 108 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919
"@mui/icons-material": "^5.14.7",
2020
"@radix-ui/react-accordion": "^1.1.2",
2121
"@radix-ui/react-context-menu": "^2.1.5",
22+
"@radix-ui/react-dialog": "^1.0.5",
2223
"@radix-ui/react-dropdown-menu": "^2.0.6",
2324
"@radix-ui/react-label": "^2.0.2",
2425
"@radix-ui/react-slot": "^1.0.2",
2526
"@radix-ui/react-switch": "^1.0.3",
27+
"@radix-ui/react-toast": "^1.1.5",
2628
"@radix-ui/react-tooltip": "^1.0.7",
2729
"@reduxjs/toolkit": "^1.9.5",
2830
"autoprefixer": "10.4.15",
@@ -45,6 +47,7 @@
4547
"react-dnd": "^16.0.1",
4648
"react-dnd-html5-backend": "^16.0.1",
4749
"react-dom": "18.2.0",
50+
"react-dropzone": "^14.2.3",
4851
"react-redux": "^8.1.2",
4952
"redux-saga": "^1.2.3",
5053
"shadcn-ui": "^0.4.1",

frontend/src/assets/move_axis.gif

1.11 MB
Loading

frontend/src/assets/move_joints.gif

1.39 MB
Loading

frontend/src/components/actions/ActionContainer.jsx

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,56 +6,83 @@ import AddIcon from '@mui/icons-material/Add';
66
import PropTypes from 'prop-types';
77
import { useContext, useState } from 'react';
88
import { useDrop } from 'react-dnd';
9+
import { NativeTypes } from 'react-dnd-html5-backend';
910
import { useDispatch } from 'react-redux';
1011

11-
const ActionContainer = ({ actionList }) => {
12+
const ActionContainer = ({ actionList, action = null }) => {
1213
const dispatch = useDispatch();
1314
const byId = useContext(byIdContext);
1415
const [isOver, setIsOver] = useState(false);
16+
console.log('IN action container', action);
1517

1618
actionList = actionList.map(action => byId[action.id]);
1719
const [, drop] = useDrop({
18-
accept: ItemTypes.ACTION,
20+
accept: [ItemTypes.ACTION, NativeTypes.FILE],
1921
collect(monitor) {
2022
setIsOver(monitor.isOver());
2123
return {
2224
handlerId: monitor.getHandlerId(),
2325
};
2426
},
2527
drop(item) {
26-
dispatch(
27-
actionListActions.pushActionToValue({
28-
actionId: null,
29-
actionToAddId: item.id,
30-
type: item.type,
31-
value: item.value,
32-
})
33-
);
28+
if (item.files) {
29+
const file = item.files[0];
30+
const reader = new FileReader();
31+
reader.onload = event => {
32+
const actionToAdd = JSON.parse(event.target.result);
33+
console.log('action container drop', action);
34+
dispatch(
35+
actionListActions.addFromJson({
36+
actionId: action ? action.id : null,
37+
actionToAdd: actionToAdd,
38+
})
39+
);
40+
};
41+
42+
reader.readAsText(file);
43+
} else {
44+
dispatch(
45+
actionListActions.pushActionToValue({
46+
actionId: action ? action.id : null,
47+
actionToAddId: item.id,
48+
type: item.type,
49+
value: item.value,
50+
})
51+
);
52+
}
3453
},
3554
});
3655

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

39-
if (actionList.length > 0) {
40-
return (
41-
<div className="flex h-full w-full flex-col gap-y-4 p-4">
42-
{actionList && actionList.map(action => renderAction(action))}
43-
</div>
44-
);
45-
} else {
46-
return (
47-
<div
48-
className={`flex h-24 w-full items-center justify-center rounded-md ${dropAreaStyles}`}
49-
ref={drop}
50-
>
51-
<AddIcon className="scale-[2.0] transform text-gray-500"></AddIcon>
52-
</div>
53-
);
54-
}
58+
return (
59+
<div className="flex h-full w-full flex-col gap-y-4 p-4">
60+
{actionList && actionList.map(action => renderAction(action))}
61+
{((action && action.value.length === 0) || action == null) && (
62+
<div
63+
className={`flex h-24 w-full cursor-cell flex-col items-center justify-center rounded-md hover:bg-slate-200 ${dropAreaStyles}`}
64+
ref={drop}
65+
>
66+
<AddIcon className="scale-[2.0] transform text-gray-500"></AddIcon>
67+
<p className="select-none p-3 italic text-gray-700">
68+
Drag Actions or Action File here!
69+
</p>
70+
</div>
71+
)}
72+
</div>
73+
);
5574
};
5675

5776
ActionContainer.propTypes = {
5877
actionList: PropTypes.arrayOf(PropTypes.object).isRequired,
78+
action: PropTypes.shape({
79+
id: PropTypes.number,
80+
parentId: PropTypes.number,
81+
running: PropTypes.bool,
82+
valid: PropTypes.bool,
83+
type: PropTypes.string,
84+
value: PropTypes.any,
85+
}),
5986
};
6087

6188
export default ActionContainer;

0 commit comments

Comments
 (0)