commit
04b15dae0e
65
package-lock.json
generated
65
package-lock.json
generated
@ -17,6 +17,7 @@
|
||||
"@fortawesome/free-solid-svg-icons": "^5.14.0",
|
||||
"@fortawesome/react-fontawesome": "^0.1.11",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@monaco-editor/react": "^4.3.1",
|
||||
"@sentry/react": "^6.0.0",
|
||||
"@sentry/tracing": "^6.0.0",
|
||||
"@testing-library/jest-dom": "^4.2.4",
|
||||
@ -3120,6 +3121,31 @@
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@monaco-editor/loader": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.2.0.tgz",
|
||||
"integrity": "sha512-cJVCG/T/KxXgzYnjKqyAgsKDbH9mGLjcXxN6AmwumBwa2rVFkwvGcUj1RJtD0ko4XqLqJxwqsN/Z/KURB5f1OQ==",
|
||||
"dependencies": {
|
||||
"state-local": "^1.0.6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"monaco-editor": ">= 0.21.0 < 1"
|
||||
}
|
||||
},
|
||||
"node_modules/@monaco-editor/react": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.3.1.tgz",
|
||||
"integrity": "sha512-f+0BK1PP/W5I50hHHmwf11+Ea92E5H1VZXs+wvKplWUWOfyMa1VVwqkJrXjRvbcqHL+XdIGYWhWNdi4McEvnZg==",
|
||||
"dependencies": {
|
||||
"@monaco-editor/loader": "^1.2.0",
|
||||
"prop-types": "^15.7.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"monaco-editor": ">= 0.25.0 < 1",
|
||||
"react": "^16.8.0 || ^17.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz",
|
||||
@ -16643,6 +16669,12 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/monaco-editor": {
|
||||
"version": "0.31.1",
|
||||
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.31.1.tgz",
|
||||
"integrity": "sha512-FYPwxGZAeP6mRRyrr5XTGHD9gRXVjy7GUzF4IPChnyt3fS5WrNxIkS8DNujWf6EQy0Zlzpxw8oTVE+mWI2/D1Q==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/move-concurrently": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
||||
@ -21503,6 +21535,11 @@
|
||||
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz",
|
||||
"integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA=="
|
||||
},
|
||||
"node_modules/state-local": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz",
|
||||
"integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w=="
|
||||
},
|
||||
"node_modules/static-extend": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
|
||||
@ -27515,6 +27552,23 @@
|
||||
"react-is": "^16.8.0"
|
||||
}
|
||||
},
|
||||
"@monaco-editor/loader": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.2.0.tgz",
|
||||
"integrity": "sha512-cJVCG/T/KxXgzYnjKqyAgsKDbH9mGLjcXxN6AmwumBwa2rVFkwvGcUj1RJtD0ko4XqLqJxwqsN/Z/KURB5f1OQ==",
|
||||
"requires": {
|
||||
"state-local": "^1.0.6"
|
||||
}
|
||||
},
|
||||
"@monaco-editor/react": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.3.1.tgz",
|
||||
"integrity": "sha512-f+0BK1PP/W5I50hHHmwf11+Ea92E5H1VZXs+wvKplWUWOfyMa1VVwqkJrXjRvbcqHL+XdIGYWhWNdi4McEvnZg==",
|
||||
"requires": {
|
||||
"@monaco-editor/loader": "^1.2.0",
|
||||
"prop-types": "^15.7.2"
|
||||
}
|
||||
},
|
||||
"@nodelib/fs.scandir": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz",
|
||||
@ -38126,6 +38180,12 @@
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.0.tgz",
|
||||
"integrity": "sha512-z6IJ5HXYiuxvFTI6eiQ9dm77uE0gyy1yXNApVHqTcnIKfY9tIwEjlzsZ6u1LQXvVgKeTnv9Xm7NDvJ7lso3MtA=="
|
||||
},
|
||||
"monaco-editor": {
|
||||
"version": "0.31.1",
|
||||
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.31.1.tgz",
|
||||
"integrity": "sha512-FYPwxGZAeP6mRRyrr5XTGHD9gRXVjy7GUzF4IPChnyt3fS5WrNxIkS8DNujWf6EQy0Zlzpxw8oTVE+mWI2/D1Q==",
|
||||
"peer": true
|
||||
},
|
||||
"move-concurrently": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
||||
@ -42087,6 +42147,11 @@
|
||||
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz",
|
||||
"integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA=="
|
||||
},
|
||||
"state-local": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz",
|
||||
"integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w=="
|
||||
},
|
||||
"static-extend": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
|
||||
|
@ -12,6 +12,7 @@
|
||||
"@fortawesome/free-solid-svg-icons": "^5.14.0",
|
||||
"@fortawesome/react-fontawesome": "^0.1.11",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@monaco-editor/react": "^4.3.1",
|
||||
"@sentry/react": "^6.0.0",
|
||||
"@sentry/tracing": "^6.0.0",
|
||||
"@testing-library/jest-dom": "^4.2.4",
|
||||
|
75
src/App.css
75
src/App.css
@ -1,51 +1,50 @@
|
||||
.wrapper {
|
||||
min-height: calc(100vh - 60px); /* will cover the 100% of viewport - height of footer (padding-bottom) */
|
||||
min-height: calc(
|
||||
100vh - 60px
|
||||
); /* will cover the 100% of viewport - height of footer (padding-bottom) */
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
position: relative;
|
||||
padding-bottom: 60px; /* height of your footer + 30px*/
|
||||
}
|
||||
|
||||
|
||||
.tutorial img{
|
||||
.tutorial img {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-height: 40vH;
|
||||
max-height: 40vh;
|
||||
max-width: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.news img{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-height: 40vH;
|
||||
max-width: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.tutorial blockquote{
|
||||
background: #f9f9f9;
|
||||
border-left: 10px solid#4EAF47;
|
||||
margin: 1.5em 10px;
|
||||
padding: 0.5em 10px;
|
||||
quotes: "\201C""\201D""\2018""\2019";
|
||||
}
|
||||
blockquote:before {
|
||||
color:#4EAF47;
|
||||
content: open-quote;
|
||||
font-size: 4em;
|
||||
line-height: 0.1em;
|
||||
margin-right: 0.25em;
|
||||
vertical-align: -0.4em;
|
||||
}
|
||||
blockquote p {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
|
||||
.news img {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-height: 40vh;
|
||||
max-width: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.tutorial blockquote {
|
||||
background: #f9f9f9;
|
||||
border-left: 10px solid#4EAF47;
|
||||
margin: 1.5em 10px;
|
||||
padding: 0.5em 10px;
|
||||
quotes: "\201C""\201D""\2018""\2019";
|
||||
}
|
||||
blockquote:before {
|
||||
color: #4eaf47;
|
||||
content: open-quote;
|
||||
font-size: 4em;
|
||||
line-height: 0.1em;
|
||||
margin-right: 0.25em;
|
||||
vertical-align: -0.4em;
|
||||
}
|
||||
blockquote p {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
294
src/components/CodeEditor/CodeEditor.js
Normal file
294
src/components/CodeEditor/CodeEditor.js
Normal file
@ -0,0 +1,294 @@
|
||||
import React from "react";
|
||||
import { useState, useRef } from "react";
|
||||
import { default as MonacoEditor } from "@monaco-editor/react";
|
||||
import { withRouter } from "react-router-dom";
|
||||
import { Button, Grid } from "@material-ui/core";
|
||||
import Blockly from "blockly/core";
|
||||
import Divider from "@material-ui/core/Divider";
|
||||
import { saveAs } from "file-saver";
|
||||
import Drawer from "@material-ui/core/Drawer";
|
||||
import Sidebar from "./Sidebar";
|
||||
import Dialog from "../Dialog";
|
||||
import SaveIcon from "./SaveIcon";
|
||||
import store from "../../store";
|
||||
|
||||
const CodeEditor = (props) => {
|
||||
const [fileHandle, setFileHandle] = useState();
|
||||
const [fileContent, setFileContent] = useState("");
|
||||
const [progress, setProgress] = useState(false);
|
||||
const [id, setId] = useState("");
|
||||
const [open, setOpen] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
const editorRef = useRef(null);
|
||||
const [autoSave, setAutoSave] = useState(false);
|
||||
const [time, setTime] = useState(null);
|
||||
const [value, setValue] = useState("");
|
||||
const [resetDialog, setResetDialog] = useState(false);
|
||||
const [blocklyCode, setBlocklyCode] = useState("");
|
||||
const [defaultValue, setDefaultValue] = useState(
|
||||
localStorage.getItem("ArduinoCode")
|
||||
? localStorage.getItem("ArduinoCode")
|
||||
: `
|
||||
#include <senseBoxIO.h> //needs to be always included
|
||||
|
||||
void setup () {
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
}`
|
||||
);
|
||||
|
||||
const compile = () => {
|
||||
setProgress(true);
|
||||
const data = {
|
||||
board: process.env.REACT_APP_BOARD,
|
||||
sketch: editorRef.current.getValue(),
|
||||
};
|
||||
fetch(`${process.env.REACT_APP_COMPILER_URL}/compile`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
console.log(data);
|
||||
if (data.code === "Internal Server Error") {
|
||||
setProgress(false);
|
||||
setOpen(true);
|
||||
setError(data.message);
|
||||
}
|
||||
setProgress(false);
|
||||
const result = data.data.id;
|
||||
setId(result);
|
||||
console.log(result);
|
||||
const filename = "sketch";
|
||||
window.open(
|
||||
`${process.env.REACT_APP_COMPILER_URL}/download?id=${result}&board=${process.env.REACT_APP_BOARD}&filename=${filename}`,
|
||||
"_self"
|
||||
);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
const saveIno = () => {
|
||||
var filename = "sketch";
|
||||
var code = editorRef.current.getValue();
|
||||
|
||||
filename = `${filename}.ino`;
|
||||
var blob = new Blob([code], { type: "text/plain;charset=utf-8" });
|
||||
saveAs(blob, filename);
|
||||
};
|
||||
|
||||
const openIno = async () => {
|
||||
const [myFileHandle] = await window.showOpenFilePicker();
|
||||
setFileHandle(myFileHandle);
|
||||
|
||||
const file = await myFileHandle.getFile();
|
||||
const contents = await file.text();
|
||||
setFileContent(contents);
|
||||
};
|
||||
|
||||
const toggleDrawer = (anchor, open) => (event) => {
|
||||
if (
|
||||
event.type === "keydown" &&
|
||||
(event.key === "Tab" || event.key === "Shift")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
const resetCode = () => {
|
||||
const resetCode = `
|
||||
#include <senseBoxIO.h> //needs to be always included
|
||||
|
||||
void setup () {
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
}`;
|
||||
|
||||
editorRef.current.setValue(resetCode);
|
||||
};
|
||||
|
||||
const resetTimeout = (id, newID) => {
|
||||
clearTimeout(id);
|
||||
return newID;
|
||||
};
|
||||
|
||||
const editValue = (value) => {
|
||||
setTime(resetTimeout(time, setTimeout(saveValue, 400)));
|
||||
setValue(value);
|
||||
};
|
||||
|
||||
const saveValue = () => {
|
||||
localStorage.setItem("ArduinoCode", value);
|
||||
setAutoSave(true);
|
||||
setTimeout(() => setAutoSave(false), 1000);
|
||||
};
|
||||
|
||||
const handleClose = (event, reason) => {
|
||||
if (reason === "clickaway") {
|
||||
return;
|
||||
}
|
||||
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
const getBlocklyCode = () => {
|
||||
var code = store.getState().workspace.code.arduino;
|
||||
editorRef.current.setValue(code);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Grid container spacing={2}>
|
||||
<Drawer
|
||||
anchor={"bottom"}
|
||||
open={open}
|
||||
onClose={toggleDrawer("bottom", false)}
|
||||
>
|
||||
<h2
|
||||
style={{
|
||||
color: "#4EAF47",
|
||||
paddingLeft: "1rem",
|
||||
paddingRight: "1rem",
|
||||
}}
|
||||
>
|
||||
{Blockly.Msg.drawer_ideerror_head}
|
||||
</h2>
|
||||
<p
|
||||
style={{
|
||||
color: "#4EAF47",
|
||||
paddingLeft: "1rem",
|
||||
paddingRight: "1rem",
|
||||
}}
|
||||
>
|
||||
{Blockly.Msg.drawer_ideerror_text}
|
||||
</p>
|
||||
<Divider style={{ backgroundColor: "white" }} />
|
||||
<p
|
||||
style={{
|
||||
backgroundColor: "black",
|
||||
color: "#E47128",
|
||||
padding: "1rem",
|
||||
}}
|
||||
>
|
||||
{" "}
|
||||
{`${error}`}{" "}
|
||||
</p>
|
||||
</Drawer>
|
||||
<Grid item lg={8}>
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
<h1>Code Editor</h1>
|
||||
<SaveIcon loading={autoSave} />
|
||||
</div>
|
||||
|
||||
<MonacoEditor
|
||||
height="80vh"
|
||||
onChange={(value) => {
|
||||
editValue(value);
|
||||
}}
|
||||
defaultLanguage="cpp"
|
||||
defaultValue={defaultValue}
|
||||
value={fileContent}
|
||||
onMount={(editor, monaco) => {
|
||||
editorRef.current = editor;
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item lg={4}>
|
||||
<Button
|
||||
style={{ padding: "1rem", margin: "1rem" }}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => compile()}
|
||||
>
|
||||
Kompilieren
|
||||
</Button>
|
||||
<Button
|
||||
style={{ padding: "1rem", margin: "1rem" }}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => saveIno()}
|
||||
>
|
||||
Save Code
|
||||
</Button>
|
||||
<Button
|
||||
style={{ padding: "1rem", margin: "1rem" }}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => openIno()}
|
||||
>
|
||||
Open Code
|
||||
</Button>
|
||||
<Button
|
||||
style={{ padding: "1rem", margin: "1rem" }}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => setResetDialog(true)}
|
||||
>
|
||||
Reset Editor
|
||||
</Button>
|
||||
<Button
|
||||
style={{ padding: "1rem", margin: "1rem" }}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => getBlocklyCode()}
|
||||
>
|
||||
getBlocklyCode
|
||||
</Button>
|
||||
<Sidebar />
|
||||
<Dialog
|
||||
style={{ zIndex: 9999999 }}
|
||||
fullWidth
|
||||
maxWidth={"sm"}
|
||||
open={progress}
|
||||
title={"Code wird kompiliert"}
|
||||
content={""}
|
||||
>
|
||||
<div>
|
||||
Dein Code wird nun kompiliert und anschließend auf deinen Computer
|
||||
heruntergeladen
|
||||
</div>
|
||||
</Dialog>{" "}
|
||||
<Dialog
|
||||
open={resetDialog}
|
||||
title={Blockly.Msg.resetDialog_headline}
|
||||
content={Blockly.Msg.resetDialog_text}
|
||||
onClose={() => {
|
||||
setResetDialog(false);
|
||||
}}
|
||||
onClick={() => {
|
||||
setResetDialog(false);
|
||||
}}
|
||||
button={Blockly.Msg.button_cancel}
|
||||
>
|
||||
{" "}
|
||||
<div style={{ marginTop: "10px" }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
resetCode();
|
||||
setResetDialog(false);
|
||||
}}
|
||||
>
|
||||
Zurücksetzen
|
||||
</Button>
|
||||
</div>
|
||||
</Dialog>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default withRouter(CodeEditor);
|
332
src/components/CodeEditor/Compile.js
Normal file
332
src/components/CodeEditor/Compile.js
Normal file
@ -0,0 +1,332 @@
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { connect } from "react-redux";
|
||||
import { workspaceName } from "../../actions/workspaceActions";
|
||||
|
||||
import { detectWhitespacesAndReturnReadableResult } from "../../helpers/whitespace";
|
||||
|
||||
import { withStyles } from "@material-ui/core/styles";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Backdrop from "@material-ui/core/Backdrop";
|
||||
import CircularProgress from "@material-ui/core/CircularProgress";
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
import Tooltip from "@material-ui/core/Tooltip";
|
||||
import Divider from "@material-ui/core/Divider";
|
||||
import { faClipboardCheck } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import * as Blockly from "blockly/core";
|
||||
import Copy from "../copy.svg";
|
||||
|
||||
import MuiDrawer from "@material-ui/core/Drawer";
|
||||
import Dialog from "../Dialog";
|
||||
|
||||
const styles = (theme) => ({
|
||||
backdrop: {
|
||||
zIndex: theme.zIndex.drawer + 1,
|
||||
color: "#fff",
|
||||
},
|
||||
iconButton: {
|
||||
backgroundColor: theme.palette.button.compile,
|
||||
color: theme.palette.primary.contrastText,
|
||||
width: "40px",
|
||||
height: "40px",
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.button.compile,
|
||||
color: theme.palette.primary.contrastText,
|
||||
},
|
||||
},
|
||||
button: {
|
||||
backgroundColor: theme.palette.button.compile,
|
||||
color: theme.palette.primary.contrastText,
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.button.compile,
|
||||
color: theme.palette.primary.contrastText,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const Drawer = withStyles((theme) => ({
|
||||
paperAnchorBottom: {
|
||||
backgroundColor: "black",
|
||||
height: "20vH",
|
||||
},
|
||||
}))(MuiDrawer);
|
||||
|
||||
class Compile extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
progress: false,
|
||||
open: false,
|
||||
file: false,
|
||||
title: "",
|
||||
content: "",
|
||||
name: props.name,
|
||||
error: "",
|
||||
appLink: "",
|
||||
appDialog: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {}
|
||||
|
||||
componentDidUpdate(props) {
|
||||
if (props.name !== this.props.name) {
|
||||
this.setState({ name: this.props.name });
|
||||
}
|
||||
}
|
||||
|
||||
compile = () => {
|
||||
this.setState({ progress: true });
|
||||
const data = {
|
||||
board: process.env.REACT_APP_BOARD,
|
||||
sketch: this.props.arduino,
|
||||
};
|
||||
fetch(`${process.env.REACT_APP_COMPILER_URL}/compile`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
console.log(data);
|
||||
if (data.code === "Internal Server Error") {
|
||||
this.setState({
|
||||
progress: false,
|
||||
file: false,
|
||||
open: true,
|
||||
title: Blockly.Msg.compiledialog_headline,
|
||||
content: Blockly.Msg.compiledialog_text,
|
||||
error: data.message,
|
||||
});
|
||||
}
|
||||
this.setState({ id: data.data.id }, () => {
|
||||
this.createFileName();
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
//this.setState({ progress: false, file: false, open: true, title: Blockly.Msg.compiledialog_headline, content: Blockly.Msg.compiledialog_text });
|
||||
});
|
||||
};
|
||||
|
||||
download = () => {
|
||||
const id = this.state.id;
|
||||
const filename = detectWhitespacesAndReturnReadableResult(this.state.name);
|
||||
this.toggleDialog();
|
||||
this.props.workspaceName(this.state.name);
|
||||
window.open(
|
||||
`${process.env.REACT_APP_COMPILER_URL}/download?id=${id}&board=${process.env.REACT_APP_BOARD}&filename=${filename}`,
|
||||
"_self"
|
||||
);
|
||||
this.setState({ progress: false });
|
||||
};
|
||||
|
||||
toggleDialog = () => {
|
||||
this.setState({ open: !this.state, progress: false, appDialog: false });
|
||||
};
|
||||
|
||||
createFileName = () => {
|
||||
if (this.props.platform === true) {
|
||||
const filename = detectWhitespacesAndReturnReadableResult(
|
||||
this.state.name
|
||||
);
|
||||
this.setState({
|
||||
link: `blocklyconnect-app://sketch/${filename}/${this.state.id}`,
|
||||
});
|
||||
this.setState({ appDialog: true });
|
||||
} else {
|
||||
if (this.state.name) {
|
||||
this.download();
|
||||
} else {
|
||||
this.setState({
|
||||
file: true,
|
||||
open: true,
|
||||
title: "Projekt kompilieren",
|
||||
content:
|
||||
"Bitte gib einen Namen für die Bennenung des zu kompilierenden Programms ein und bestätige diesen mit einem Klick auf 'Eingabe'.",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// if (this.state.name) {
|
||||
// this.download();
|
||||
// } else {
|
||||
// this.setState({
|
||||
// file: true,
|
||||
// open: true,
|
||||
// title: "Projekt kompilieren",
|
||||
// content:
|
||||
// "Bitte gib einen Namen für die Bennenung des zu kompilierenden Programms ein und bestätige diesen mit einem Klick auf 'Eingabe'.",
|
||||
// });
|
||||
// }
|
||||
};
|
||||
|
||||
setFileName = (e) => {
|
||||
this.setState({ name: e.target.value });
|
||||
};
|
||||
|
||||
toggleDrawer = (anchor, open) => (event) => {
|
||||
if (
|
||||
event.type === "keydown" &&
|
||||
(event.key === "Tab" || event.key === "Shift")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({ open: false });
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{}}>
|
||||
{this.props.iconButton ? (
|
||||
<Tooltip
|
||||
title={Blockly.Msg.tooltip_compile_code}
|
||||
arrow
|
||||
style={{ marginRight: "5px" }}
|
||||
>
|
||||
<IconButton
|
||||
className={`compileBlocks ${this.props.classes.iconButton}`}
|
||||
onClick={() => this.compile()}
|
||||
>
|
||||
<FontAwesomeIcon icon={faClipboardCheck} size="l" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Button
|
||||
style={{ float: "right", color: "white" }}
|
||||
variant="contained"
|
||||
className={this.props.classes.button}
|
||||
onClick={() => this.compile()}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={faClipboardCheck}
|
||||
style={{ marginRight: "5px" }}
|
||||
/>{" "}
|
||||
Kompilieren
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{this.props.platform === false ? (
|
||||
<Backdrop
|
||||
className={this.props.classes.backdrop}
|
||||
open={this.state.progress}
|
||||
>
|
||||
<div className="overlay">
|
||||
<img src={Copy} width="400" alt="copyimage"></img>
|
||||
<h2>{Blockly.Msg.compile_overlay_head}</h2>
|
||||
<p>{Blockly.Msg.compile_overlay_text}</p>
|
||||
<p>
|
||||
{Blockly.Msg.compile_overlay_help}
|
||||
<a href="/faq" target="_blank">
|
||||
FAQ
|
||||
</a>
|
||||
</p>
|
||||
<CircularProgress color="inherit" />
|
||||
</div>
|
||||
</Backdrop>
|
||||
) : (
|
||||
<Backdrop
|
||||
className={this.props.classes.backdrop}
|
||||
open={this.state.progress}
|
||||
>
|
||||
<div className="overlay">
|
||||
{/* <img src={Copy} width="400" alt="copyimage"></img> */}
|
||||
<h2>Dein Code wird kompiliert!</h2>
|
||||
<p>übertrage ihn anschließend mithlfe der senseBoxConnect-App</p>
|
||||
<p>
|
||||
{Blockly.Msg.compile_overlay_help}
|
||||
<a href="/faq" target="_blank">
|
||||
FAQ
|
||||
</a>
|
||||
</p>
|
||||
<CircularProgress color="inherit" />
|
||||
</div>
|
||||
</Backdrop>
|
||||
)}
|
||||
<Drawer
|
||||
anchor={"bottom"}
|
||||
open={this.state.open}
|
||||
onClose={this.toggleDrawer("bottom", false)}
|
||||
>
|
||||
<h2
|
||||
style={{
|
||||
color: "#4EAF47",
|
||||
paddingLeft: "1rem",
|
||||
paddingRight: "1rem",
|
||||
}}
|
||||
>
|
||||
{Blockly.Msg.drawer_ideerror_head}
|
||||
</h2>
|
||||
<p
|
||||
style={{
|
||||
color: "#4EAF47",
|
||||
paddingLeft: "1rem",
|
||||
paddingRight: "1rem",
|
||||
}}
|
||||
>
|
||||
{Blockly.Msg.drawer_ideerror_text}
|
||||
</p>
|
||||
<Divider style={{ backgroundColor: "white" }} />
|
||||
<p
|
||||
style={{
|
||||
backgroundColor: "black",
|
||||
color: "#E47128",
|
||||
padding: "1rem",
|
||||
}}
|
||||
>
|
||||
{" "}
|
||||
{`${this.state.error}`}{" "}
|
||||
</p>
|
||||
</Drawer>
|
||||
<Dialog
|
||||
style={{ zIndex: 9999999 }}
|
||||
fullWidth
|
||||
maxWidth={"sm"}
|
||||
open={this.state.appDialog}
|
||||
title=""
|
||||
content={""}
|
||||
onClose={this.toggleDialog}
|
||||
onClick={this.toggleDialog}
|
||||
button={Blockly.Msg.button_close}
|
||||
>
|
||||
<div>
|
||||
<p>Dein Code wurde erfolgreich kompiliert</p>
|
||||
<a href={this.state.link}>
|
||||
<Button
|
||||
style={{ color: "white" }}
|
||||
variant="contained"
|
||||
className={this.props.classes.button}
|
||||
onClick={() => this.toggleDialog()}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={faClipboardCheck}
|
||||
style={{ marginRight: "5px" }}
|
||||
/>{" "}
|
||||
Starte Übertragung
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Compile.propTypes = {
|
||||
arduino: PropTypes.string.isRequired,
|
||||
name: PropTypes.string,
|
||||
workspaceName: PropTypes.func.isRequired,
|
||||
platform: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
arduino: state.workspace.code.arduino,
|
||||
name: state.workspace.name,
|
||||
platform: state.general.platform,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, { workspaceName })(
|
||||
withStyles(styles, { withTheme: true })(Compile)
|
||||
);
|
40
src/components/CodeEditor/SaveIcon.js
Normal file
40
src/components/CodeEditor/SaveIcon.js
Normal file
@ -0,0 +1,40 @@
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faCircleNotch, faSave } from "@fortawesome/free-solid-svg-icons";
|
||||
import Tooltip from "@material-ui/core/Tooltip";
|
||||
import React from "react";
|
||||
|
||||
const SaveIcon = ({ loading }) => (
|
||||
<Tooltip title={"Auto save enabled"} arrow placement="right">
|
||||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
width: "2rem",
|
||||
height: "2rem",
|
||||
margin: "1rem",
|
||||
}}
|
||||
>
|
||||
{loading && (
|
||||
<FontAwesomeIcon
|
||||
style={{ position: "absolute" }}
|
||||
icon={faCircleNotch}
|
||||
spin={true}
|
||||
size="2x"
|
||||
color="grey"
|
||||
/>
|
||||
)}
|
||||
<FontAwesomeIcon
|
||||
style={{
|
||||
position: "absolute",
|
||||
left: "50%",
|
||||
top: "50%",
|
||||
transform: "translate(-50%,-50%)",
|
||||
}}
|
||||
icon={faSave}
|
||||
color={loading ? "grey" : "green"}
|
||||
size={loading ? "1x" : "lg"}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
export default SaveIcon;
|
92
src/components/CodeEditor/SerialMonitor.js
Normal file
92
src/components/CodeEditor/SerialMonitor.js
Normal file
@ -0,0 +1,92 @@
|
||||
import { useState } from "react";
|
||||
import Button from "@material-ui/core/Button";
|
||||
|
||||
const SerialMonitor = () => {
|
||||
const [serialPortContent, setSerialPortContent] = useState([]);
|
||||
|
||||
const [checked, setChecked] = useState(false);
|
||||
const handleClick = () => setChecked(!checked);
|
||||
|
||||
const connectPort = async () => {
|
||||
try {
|
||||
const port = await navigator.serial.requestPort();
|
||||
|
||||
await port.open({ baudRate: 9600 });
|
||||
|
||||
while (port.readable) {
|
||||
const reader = port.readable.getReader();
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
const { value, done } = await reader.read();
|
||||
if (done) {
|
||||
// Allow the serial port to be closed later.
|
||||
reader.releaseLock();
|
||||
break;
|
||||
}
|
||||
if (value) {
|
||||
// byte array to string: https://stackoverflow.com/a/37542820
|
||||
const text = String.fromCharCode.apply(null, value);
|
||||
console.log(text);
|
||||
setSerialPortContent((prevContent) => [
|
||||
...prevContent,
|
||||
[new Date(), text],
|
||||
]);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
setSerialPortContent((prevContent) => [
|
||||
...prevContent,
|
||||
[new Date(), error],
|
||||
]);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
setSerialPortContent((prevContent) => [
|
||||
...prevContent,
|
||||
[new Date(), error],
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex items-center">
|
||||
<Button type="button" variant="outlined" onClick={() => connectPort()}>
|
||||
Connect to senseBox
|
||||
</Button>
|
||||
<label className="m-4 text-gray-700 text-base font-semibold px-6 py-3 rounded-lg">
|
||||
Show timestamps
|
||||
<input
|
||||
onChange={handleClick}
|
||||
checked={checked}
|
||||
type="checkbox"
|
||||
className="mx-4"
|
||||
/>
|
||||
</label>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outlined"
|
||||
onClick={() => setSerialPortContent([])}
|
||||
>
|
||||
Clear
|
||||
</Button>
|
||||
</div>
|
||||
<div className="font-mono">
|
||||
{serialPortContent.map((log) => {
|
||||
return (
|
||||
<p>
|
||||
{checked && (
|
||||
<span className="font-medium mr-4">{log[0].toISOString()}</span>
|
||||
)}
|
||||
|
||||
<span>{log[1]}</span>
|
||||
</p>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SerialMonitor;
|
145
src/components/CodeEditor/Sidebar.js
Normal file
145
src/components/CodeEditor/Sidebar.js
Normal file
@ -0,0 +1,145 @@
|
||||
import React, { useEffect } from "react";
|
||||
import Blockly from "blockly";
|
||||
import Accordion from "@material-ui/core/Accordion";
|
||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import { LibraryVersions } from "../../data/versions.js";
|
||||
import { useMonaco } from "@monaco-editor/react";
|
||||
import { Button } from "@material-ui/core";
|
||||
import Dialog from "../Dialog";
|
||||
import SerialMonitor from "./SerialMonitor.js";
|
||||
import axios from "axios";
|
||||
|
||||
const Sidebar = () => {
|
||||
const [alert, setAlert] = React.useState(false);
|
||||
const [examples, setExamples] = React.useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
axios
|
||||
.get("https://coelho.opensensemap.org/items/blocklysamples")
|
||||
.then((res) => {
|
||||
setExamples(res.data.data);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const monaco = useMonaco();
|
||||
const loadCode = (code) => {
|
||||
console.log(code);
|
||||
console.log(monaco);
|
||||
const defaultCode = `
|
||||
void setup () {
|
||||
|
||||
}
|
||||
|
||||
void loop(){
|
||||
|
||||
}`;
|
||||
var currentCode = monaco.editor.getModels()[0].getValue();
|
||||
|
||||
setAlert(true);
|
||||
monaco.editor.getModels()[0].setValue(code);
|
||||
};
|
||||
|
||||
const toggleDialog = () => {
|
||||
setAlert(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
{"serial" in navigator ? (
|
||||
<Accordion>
|
||||
<AccordionSummary
|
||||
expandIcon={""}
|
||||
aria-controls="panel1a-content"
|
||||
id="panel1a-header"
|
||||
>
|
||||
<Typography>Serial Monitor</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<Typography>
|
||||
<SerialMonitor />
|
||||
</Typography>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
) : null}
|
||||
|
||||
<Accordion>
|
||||
<AccordionSummary
|
||||
expandIcon={""}
|
||||
aria-controls="panel1a-content"
|
||||
id="panel1a-header"
|
||||
>
|
||||
<Typography>Beispiele</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<Typography>
|
||||
{examples.map((object, i) => {
|
||||
return (
|
||||
<Button
|
||||
style={{ padding: "1rem", margin: "1rem" }}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => loadCode(object.code)}
|
||||
>
|
||||
{object.name}
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</Typography>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
<Accordion>
|
||||
<AccordionSummary
|
||||
expandIcon={""}
|
||||
aria-controls="panel2a-content"
|
||||
id="panel2a-header"
|
||||
>
|
||||
<Typography>Installierte Libraries</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails
|
||||
style={{ padding: 0, height: "60vH", backgroundColor: "white" }}
|
||||
>
|
||||
<Typography
|
||||
style={{ overflow: "auto", width: "100%", padding: "1rem" }}
|
||||
>
|
||||
<p>
|
||||
For Dokumentation take a look at the installed libraries and their
|
||||
source
|
||||
</p>
|
||||
{LibraryVersions().map((object, i) => {
|
||||
return (
|
||||
<p>
|
||||
<a href={object.link} target="_blank" rel="noreferrer">
|
||||
{object.library} {object.version}
|
||||
</a>
|
||||
</p>
|
||||
);
|
||||
})}
|
||||
</Typography>
|
||||
</AccordionDetails>
|
||||
<Dialog
|
||||
style={{ zIndex: 9999999 }}
|
||||
fullWidth
|
||||
maxWidth={"sm"}
|
||||
open={alert}
|
||||
title={Blockly.Msg.tabletDialog_headline}
|
||||
content={""}
|
||||
onClose={() => toggleDialog()}
|
||||
onClick={() => toggleDialog()}
|
||||
button={Blockly.Msg.button_close}
|
||||
>
|
||||
<div>{Blockly.Msg.tabletDialog_text}</div>
|
||||
<div>
|
||||
{Blockly.Msg.tabletDialog_more}{" "}
|
||||
<a href="https://sensebox.de/app" target="_blank" rel="noreferrer">
|
||||
https://sensebox.de/app
|
||||
</a>
|
||||
</div>
|
||||
</Dialog>
|
||||
</Accordion>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Sidebar;
|
@ -1,30 +1,25 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Prism from "prismjs";
|
||||
import "prismjs/themes/prism.css";
|
||||
import "prismjs/plugins/line-numbers/prism-line-numbers";
|
||||
import "prismjs/plugins/line-numbers/prism-line-numbers.css";
|
||||
|
||||
import withWidth from '@material-ui/core/withWidth';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import MuiAccordion from '@material-ui/core/Accordion';
|
||||
import MuiAccordionSummary from '@material-ui/core/AccordionSummary';
|
||||
import MuiAccordionDetails from '@material-ui/core/AccordionDetails';
|
||||
import { Card } from '@material-ui/core';
|
||||
import * as Blockly from 'blockly'
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import withWidth from "@material-ui/core/withWidth";
|
||||
import { withStyles } from "@material-ui/core/styles";
|
||||
import MuiAccordion from "@material-ui/core/Accordion";
|
||||
import MuiAccordionSummary from "@material-ui/core/AccordionSummary";
|
||||
import MuiAccordionDetails from "@material-ui/core/AccordionDetails";
|
||||
import { Card } from "@material-ui/core";
|
||||
import * as Blockly from "blockly";
|
||||
import { default as MonacoEditor } from "@monaco-editor/react";
|
||||
|
||||
const Accordion = withStyles((theme) => ({
|
||||
root: {
|
||||
border: `1px solid ${theme.palette.secondary.main}`,
|
||||
boxShadow: 'none',
|
||||
'&:before': {
|
||||
display: 'none',
|
||||
boxShadow: "none",
|
||||
"&:before": {
|
||||
display: "none",
|
||||
},
|
||||
'&$expanded': {
|
||||
margin: 'auto',
|
||||
"&$expanded": {
|
||||
margin: "auto",
|
||||
},
|
||||
},
|
||||
expanded: {},
|
||||
@ -34,15 +29,15 @@ const AccordionSummary = withStyles((theme) => ({
|
||||
root: {
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
borderBottom: `1px solid white`,
|
||||
marginBottom: '-1px',
|
||||
minHeight: '50px',
|
||||
'&$expanded': {
|
||||
minHeight: '50px',
|
||||
marginBottom: "-1px",
|
||||
minHeight: "50px",
|
||||
"&$expanded": {
|
||||
minHeight: "50px",
|
||||
},
|
||||
},
|
||||
content: {
|
||||
'&$expanded': {
|
||||
margin: '12px 0',
|
||||
"&$expanded": {
|
||||
margin: "12px 0",
|
||||
},
|
||||
},
|
||||
expanded: {},
|
||||
@ -54,40 +49,60 @@ const AccordionDetails = withStyles((theme) => ({
|
||||
},
|
||||
}))(MuiAccordionDetails);
|
||||
|
||||
|
||||
class CodeViewer extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
code: this.props.arduino,
|
||||
changed: false,
|
||||
expanded: true,
|
||||
componentHeight: null
|
||||
componentHeight: null,
|
||||
};
|
||||
this.myDiv = React.createRef();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
Prism.highlightAll();
|
||||
this.setState({ componentHeight: this.myDiv.current.offsetHeight + 'px' });
|
||||
this.setState({ componentHeight: this.myDiv.current.offsetHeight + "px" });
|
||||
}
|
||||
|
||||
componentDidUpdate(props, state) {
|
||||
if (this.myDiv.current && this.myDiv.current.offsetHeight + 'px' !== this.state.componentHeight) {
|
||||
this.setState({ componentHeight: this.myDiv.current.offsetHeight + 'px' });
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
// if (this.props.arduino !== prevProps.arduino) {
|
||||
// this.setState({ changed: true });
|
||||
|
||||
// console.log(`code changed: ${this.state.changed}`);
|
||||
// if (this.state.changed && prevState.code !== this.props.arduino) {
|
||||
// this.setState({ code: this.props.arduino });
|
||||
// this.setState({ changed: false });
|
||||
// }
|
||||
|
||||
// if (this.state.code !== prevState.code && this.state.changed) {
|
||||
// this.setState({ changed: false });
|
||||
// }
|
||||
|
||||
// if (this.props.arduino !== this.state.code) {
|
||||
// this.setState({ changed: true });
|
||||
// //this.setState({ code: this.props.arduino });
|
||||
// }
|
||||
|
||||
if (
|
||||
this.myDiv.current &&
|
||||
this.myDiv.current.offsetHeight + "px" !== this.state.componentHeight
|
||||
) {
|
||||
this.setState({
|
||||
componentHeight: this.myDiv.current.offsetHeight + "px",
|
||||
});
|
||||
}
|
||||
Prism.highlightAll();
|
||||
}
|
||||
|
||||
onChange = () => {
|
||||
this.setState({ expanded: !this.state.expanded });
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
var curlyBrackets = '{ }';
|
||||
var unequal = '<>';
|
||||
var curlyBrackets = "{ }";
|
||||
var unequal = "<>";
|
||||
return (
|
||||
<Card style={{ height: '100%', maxHeight: '60vH' }} ref={this.myDiv}>
|
||||
<Card style={{ height: "100%", maxHeight: "60vH" }} ref={this.myDiv}>
|
||||
<Accordion
|
||||
square={true}
|
||||
style={{ margin: 0 }}
|
||||
@ -95,15 +110,32 @@ class CodeViewer extends Component {
|
||||
onChange={this.onChange}
|
||||
>
|
||||
<AccordionSummary>
|
||||
<b style={{ fontSize: '20px', marginRight: '5px', width: '35px' }}>{curlyBrackets}</b>
|
||||
<div style={{ margin: 'auto 5px 2px 0px' }}>{Blockly.Msg.codeviewer_arduino}</div>
|
||||
<b style={{ fontSize: "20px", marginRight: "5px", width: "35px" }}>
|
||||
{curlyBrackets}
|
||||
</b>
|
||||
<div style={{ margin: "auto 5px 2px 0px" }}>
|
||||
{Blockly.Msg.codeviewer_arduino}
|
||||
</div>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails style={{ padding: 0, height: `calc(${this.state.componentHeight} - 50px - 50px)`, backgroundColor: 'white' }}>
|
||||
<pre className="line-numbers" style={{ paddingBottom: 0, width: '100%', overflow: 'auto', scrollbarWidth: 'thin', height: 'calc(100% - 30px)', margin: '15px 0', paddingTop: 0, whiteSpace: 'pre-wrap', backgroundColor: 'white' }}>
|
||||
<code className="language-clike">
|
||||
{this.props.arduino}
|
||||
</code>
|
||||
</pre>
|
||||
<AccordionDetails
|
||||
style={{
|
||||
padding: 0,
|
||||
height: `calc(${this.state.componentHeight} - 50px - 50px)`,
|
||||
backgroundColor: "white",
|
||||
}}
|
||||
>
|
||||
<MonacoEditor
|
||||
height="80vh"
|
||||
defaultLanguage="cpp"
|
||||
value={this.props.arduino}
|
||||
// modified={this.props.arduino}
|
||||
// original={this.state.code}
|
||||
options={{
|
||||
readOnly: true,
|
||||
|
||||
fontSize: "12px",
|
||||
}}
|
||||
/>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
<Accordion
|
||||
@ -113,32 +145,43 @@ class CodeViewer extends Component {
|
||||
onChange={this.onChange}
|
||||
>
|
||||
<AccordionSummary>
|
||||
<b style={{ fontSize: '20px', marginRight: '5px', width: '35px' }}>{unequal}</b>
|
||||
<div style={{ margin: 'auto 5px 2px 0px' }}>{Blockly.Msg.codeviewer_xml}</div>
|
||||
<b style={{ fontSize: "20px", marginRight: "5px", width: "35px" }}>
|
||||
{unequal}
|
||||
</b>
|
||||
<div style={{ margin: "auto 5px 2px 0px" }}>
|
||||
{Blockly.Msg.codeviewer_xml}
|
||||
</div>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails style={{ padding: 0, height: `calc(${this.state.componentHeight} - 50px - 50px)`, backgroundColor: 'white' }}>
|
||||
<pre className="line-numbers" style={{ paddingBottom: 0, width: '100%', overflow: 'auto', scrollbarWidth: 'thin', height: 'calc(100% - 30px)', margin: '15px 0', paddingTop: 0, whiteSpace: 'pre-wrap', backgroundColor: 'white' }}>
|
||||
<code className="language-xml">
|
||||
{`${this.props.xml}`}
|
||||
</code>
|
||||
</pre>
|
||||
<AccordionDetails
|
||||
style={{
|
||||
padding: 0,
|
||||
height: `calc(${this.state.componentHeight} - 50px - 50px)`,
|
||||
backgroundColor: "white",
|
||||
}}
|
||||
>
|
||||
<MonacoEditor
|
||||
height="80vh"
|
||||
defaultLanguage="xml"
|
||||
value={this.props.xml}
|
||||
readOnly={true}
|
||||
/>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
CodeViewer.propTypes = {
|
||||
arduino: PropTypes.string.isRequired,
|
||||
xml: PropTypes.string.isRequired,
|
||||
tooltip: PropTypes.string.isRequired
|
||||
tooltip: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
const mapStateToProps = (state) => ({
|
||||
arduino: state.workspace.code.arduino,
|
||||
xml: state.workspace.code.xml,
|
||||
tooltip: state.workspace.code.tooltip
|
||||
tooltip: state.workspace.code.tooltip,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, null)(withWidth()(CodeViewer));
|
||||
|
@ -22,7 +22,7 @@ import { faCode } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import TooltipViewer from "./TooltipViewer";
|
||||
import Dialog from "./Dialog";
|
||||
|
||||
// import Autosave from "./Workspace/AutoSave";
|
||||
const styles = (theme) => ({
|
||||
codeOn: {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
@ -54,6 +54,7 @@ class Home extends Component {
|
||||
key: "",
|
||||
message: "",
|
||||
open: true,
|
||||
initialXml: localStorage.getItem("autoSaveXML"),
|
||||
};
|
||||
}
|
||||
|
||||
@ -119,10 +120,12 @@ class Home extends Component {
|
||||
<WorkspaceStats />
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div
|
||||
className="workspaceFunc"
|
||||
style={{ float: "right", height: "40px", marginBottom: "20px" }}
|
||||
>
|
||||
{/* <Autosave /> */}
|
||||
<WorkspaceFunc
|
||||
project={this.props.project}
|
||||
projectType={this.props.projectType}
|
||||
@ -161,6 +164,7 @@ class Home extends Component {
|
||||
<FontAwesomeIcon icon={faCode} size="xs" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
||||
<TrashcanButtons />
|
||||
<div className="blocklyWindow">
|
||||
{this.props.project ? (
|
||||
@ -169,7 +173,10 @@ class Home extends Component {
|
||||
initialXml={this.props.project.xml}
|
||||
/>
|
||||
) : (
|
||||
<BlocklyWindow blocklyCSS={{ height: "80vH" }} />
|
||||
<BlocklyWindow
|
||||
blocklyCSS={{ height: "80vH" }}
|
||||
initialXml={this.state.initialXml}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Grid>
|
||||
|
@ -21,6 +21,7 @@ import ListItemIcon from "@material-ui/core/ListItemIcon";
|
||||
import ListItemText from "@material-ui/core/ListItemText";
|
||||
import LinearProgress from "@material-ui/core/LinearProgress";
|
||||
import Tour from "reactour";
|
||||
import { Badge } from "@material-ui/core";
|
||||
import { home, assessment } from "./Tour";
|
||||
import {
|
||||
faBars,
|
||||
@ -34,6 +35,7 @@ import {
|
||||
faChalkboardTeacher,
|
||||
faTools,
|
||||
faLightbulb,
|
||||
faCode,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import * as Blockly from "blockly";
|
||||
@ -230,6 +232,11 @@ class Navbar extends Component {
|
||||
icon: faLightbulb,
|
||||
link: "/gallery",
|
||||
},
|
||||
{
|
||||
text: "CodeEditor",
|
||||
icon: faCode,
|
||||
link: "/codeeditor",
|
||||
},
|
||||
{
|
||||
text: Blockly.Msg.navbar_projects,
|
||||
icon: faLayerGroup,
|
||||
@ -253,7 +260,13 @@ class Navbar extends Component {
|
||||
<ListItemIcon>
|
||||
<FontAwesomeIcon icon={item.icon} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={item.text} />
|
||||
{item.text === "CodeEditor" ? (
|
||||
<Badge badgeContent={"Experimental"} color="primary">
|
||||
<ListItemText primary={item.text} />
|
||||
</Badge>
|
||||
) : (
|
||||
<ListItemText primary={item.text} />
|
||||
)}
|
||||
</ListItem>
|
||||
</Link>
|
||||
);
|
||||
|
@ -24,6 +24,7 @@ import Login from "../User/Login";
|
||||
import Account from "../User/Account";
|
||||
import News from "../News";
|
||||
import Faq from "../Faq";
|
||||
import CodeEditor from "../CodeEditor/CodeEditor";
|
||||
|
||||
class Routes extends Component {
|
||||
componentDidUpdate() {
|
||||
@ -47,6 +48,9 @@ class Routes extends Component {
|
||||
<Route path="/tutorial/:tutorialId" exact>
|
||||
<Tutorial />
|
||||
</Route>
|
||||
<Route path="/CodeEditor" exact>
|
||||
<CodeEditor />
|
||||
</Route>
|
||||
{/* Sharing */}
|
||||
<PublicRoute path="/share/:shareId" exact>
|
||||
<Project />
|
||||
|
72
src/components/Workspace/AutoSave.js
Normal file
72
src/components/Workspace/AutoSave.js
Normal file
@ -0,0 +1,72 @@
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { connect } from "react-redux";
|
||||
import { workspaceName } from "../../actions/workspaceActions";
|
||||
import SaveIcon from "../CodeEditor/SaveIcon";
|
||||
|
||||
const resetTimeout = (id, newID) => {
|
||||
clearTimeout(id);
|
||||
return newID;
|
||||
};
|
||||
|
||||
class AutoSave extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
timeout: null,
|
||||
value: "",
|
||||
saved: false,
|
||||
autosave: false,
|
||||
};
|
||||
}
|
||||
|
||||
editValue = (value) => {
|
||||
this.setState({
|
||||
timeout: resetTimeout(
|
||||
this.state.timeout,
|
||||
setTimeout(this.saveValue, 400)
|
||||
),
|
||||
value: value,
|
||||
});
|
||||
};
|
||||
|
||||
saveValue = () => {
|
||||
this.setState({ ...this.state, saved: true });
|
||||
localStorage.setItem("autoSaveXML", this.props.xml);
|
||||
setTimeout(() => this.setState({ ...this.state, saved: false }), 1000);
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
console.log(this.props.xml);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (prevProps.xml !== this.props.xml) {
|
||||
this.editValue(this.props.xml);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<SaveIcon loading={this.state.saved} autosave={this.props.autosave} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AutoSave.propTypes = {
|
||||
xml: PropTypes.string.isRequired,
|
||||
name: PropTypes.string,
|
||||
workspaceName: PropTypes.func.isRequired,
|
||||
setAutosave: PropTypes.func.isRequired,
|
||||
autosave: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
auto: state.general.autosave,
|
||||
xml: state.workspace.code.xml,
|
||||
name: state.workspace.name,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, { workspaceName })(AutoSave);
|
@ -16,10 +16,7 @@ import { faClipboardCheck } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import * as Blockly from "blockly/core";
|
||||
import Copy from "../copy.svg";
|
||||
import Prism from "prismjs";
|
||||
import "prismjs/themes/prism.css";
|
||||
import "prismjs/plugins/line-numbers/prism-line-numbers";
|
||||
import "prismjs/plugins/line-numbers/prism-line-numbers.css";
|
||||
|
||||
import MuiDrawer from "@material-ui/core/Drawer";
|
||||
import Dialog from "../Dialog";
|
||||
|
||||
@ -71,15 +68,12 @@ class Compile extends Component {
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
Prism.highlightAll();
|
||||
}
|
||||
componentDidMount() {}
|
||||
|
||||
componentDidUpdate(props) {
|
||||
if (props.name !== this.props.name) {
|
||||
this.setState({ name: this.props.name });
|
||||
}
|
||||
Prism.highlightAll();
|
||||
}
|
||||
|
||||
compile = () => {
|
||||
|
@ -1,101 +1,113 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import WorkspaceName from './WorkspaceName';
|
||||
import SaveProject from './SaveProject';
|
||||
import Compile from './Compile';
|
||||
import SolutionCheck from '../Tutorial/SolutionCheck';
|
||||
import DownloadProject from './DownloadProject';
|
||||
import OpenProject from './OpenProject';
|
||||
import Screenshot from './Screenshot';
|
||||
import ShareProject from './ShareProject';
|
||||
import ResetWorkspace from './ResetWorkspace';
|
||||
import DeleteProject from './DeleteProject';
|
||||
import CopyCode from './CopyCode';
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import WorkspaceName from "./WorkspaceName";
|
||||
import SaveProject from "./SaveProject";
|
||||
import Compile from "./Compile";
|
||||
import SolutionCheck from "../Tutorial/SolutionCheck";
|
||||
import DownloadProject from "./DownloadProject";
|
||||
import OpenProject from "./OpenProject";
|
||||
import Screenshot from "./Screenshot";
|
||||
import ShareProject from "./ShareProject";
|
||||
import ResetWorkspace from "./ResetWorkspace";
|
||||
import DeleteProject from "./DeleteProject";
|
||||
import CopyCode from "./CopyCode";
|
||||
import AutoSave from "./AutoSave";
|
||||
class WorkspaceFunc extends Component {
|
||||
componentDidUpdate() {
|
||||
console.log(this.props.autosave);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{ width: 'max-content', display: 'flex' }}>
|
||||
|
||||
{!this.props.assessment ?
|
||||
<div
|
||||
style={{ width: "max-content", display: "flex", alignItems: "center" }}
|
||||
>
|
||||
{!this.props.assessment & !this.props.multiple ? <AutoSave /> : null}
|
||||
{!this.props.assessment ? (
|
||||
<WorkspaceName
|
||||
style={{ marginRight: '5px' }}
|
||||
style={{ marginRight: "5px" }}
|
||||
multiple={this.props.multiple}
|
||||
project={this.props.project}
|
||||
projectType={this.props.projectType}
|
||||
/>
|
||||
: null}
|
||||
) : null}
|
||||
|
||||
{this.props.assessment ?
|
||||
{this.props.assessment ? (
|
||||
<SolutionCheck />
|
||||
: !this.props.multiple ?
|
||||
<Compile iconButton />
|
||||
: null}
|
||||
) : !this.props.multiple ? (
|
||||
<Compile iconButton />
|
||||
) : null}
|
||||
|
||||
{!this.props.multiple ?
|
||||
<CopyCode iconButton />
|
||||
: null}
|
||||
{!this.props.multiple ? <CopyCode iconButton /> : null}
|
||||
|
||||
|
||||
{this.props.user && !this.props.multiple ?
|
||||
{this.props.user && !this.props.multiple ? (
|
||||
<SaveProject
|
||||
style={{ marginRight: '5px' }}
|
||||
style={{ marginRight: "5px" }}
|
||||
projectType={this.props.projectType}
|
||||
project={this.props.project}
|
||||
/>
|
||||
: null}
|
||||
) : null}
|
||||
|
||||
{!this.props.multiple ?
|
||||
<DownloadProject style={{ marginRight: '5px' }} />
|
||||
: null}
|
||||
{!this.props.multiple ? (
|
||||
<DownloadProject style={{ marginRight: "5px" }} />
|
||||
) : null}
|
||||
|
||||
|
||||
{!this.props.assessment && !this.props.multiple ?
|
||||
{!this.props.assessment && !this.props.multiple ? (
|
||||
<OpenProject
|
||||
style={{ marginRight: '5px' }}
|
||||
style={{ marginRight: "5px" }}
|
||||
assessment={this.props.assessment}
|
||||
/>
|
||||
: null}
|
||||
) : null}
|
||||
|
||||
{!this.props.assessment && !this.props.multiple ?
|
||||
<Screenshot style={{ marginRight: '5px' }} />
|
||||
: null}
|
||||
{!this.props.assessment && !this.props.multiple ? (
|
||||
<Screenshot style={{ marginRight: "5px" }} />
|
||||
) : null}
|
||||
|
||||
{this.props.projectType !== 'gallery' && !this.props.assessment ?
|
||||
{this.props.projectType !== "gallery" && !this.props.assessment ? (
|
||||
<ShareProject
|
||||
style={{ marginRight: '5px' }}
|
||||
style={{ marginRight: "5px" }}
|
||||
multiple={this.props.multiple}
|
||||
project={this.props.project}
|
||||
projectType={this.props.projectType}
|
||||
/>
|
||||
: null}
|
||||
) : null}
|
||||
|
||||
{!this.props.multiple ?
|
||||
<ResetWorkspace style={this.props.projectType === 'project' || this.props.projectType === 'gallery' ? { marginRight: '5px' } : null}
|
||||
{!this.props.multiple ? (
|
||||
<ResetWorkspace
|
||||
style={
|
||||
this.props.projectType === "project" ||
|
||||
this.props.projectType === "gallery"
|
||||
? { marginRight: "5px" }
|
||||
: null
|
||||
}
|
||||
/>
|
||||
: null}
|
||||
) : null}
|
||||
|
||||
{!this.props.assessment && (this.props.projectType === 'project' || this.props.projectType === 'gallery') && this.props.user && this.props.user.email === this.props.project.creator ?
|
||||
{!this.props.assessment &&
|
||||
(this.props.projectType === "project" ||
|
||||
this.props.projectType === "gallery") &&
|
||||
this.props.user &&
|
||||
this.props.user.email === this.props.project.creator ? (
|
||||
<DeleteProject
|
||||
project={this.props.project}
|
||||
projectType={this.props.projectType}
|
||||
/>
|
||||
: null}
|
||||
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
WorkspaceFunc.propTypes = {
|
||||
user: PropTypes.object
|
||||
user: PropTypes.object,
|
||||
autosave: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
user: state.auth.user
|
||||
const mapStateToProps = (state) => ({
|
||||
user: state.auth.user,
|
||||
autosave: state.workspace.autosave,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, null)(WorkspaceFunc);
|
||||
|
@ -1,51 +1,50 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { workspaceName } from '../../actions/workspaceActions';
|
||||
import { setDescription, updateProject } from '../../actions/projectActions';
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { connect } from "react-redux";
|
||||
import { workspaceName } from "../../actions/workspaceActions";
|
||||
import { setDescription, updateProject } from "../../actions/projectActions";
|
||||
|
||||
import Snackbar from '../Snackbar';
|
||||
import Dialog from '../Dialog';
|
||||
import Snackbar from "../Snackbar";
|
||||
import Dialog from "../Dialog";
|
||||
|
||||
import withWidth, { isWidthDown } from '@material-ui/core/withWidth';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import withWidth, { isWidthDown } from "@material-ui/core/withWidth";
|
||||
import { withStyles } from "@material-ui/core/styles";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Tooltip from "@material-ui/core/Tooltip";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
|
||||
import { faPen } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import * as Blockly from 'blockly/core'
|
||||
import * as Blockly from "blockly/core";
|
||||
|
||||
const styles = (theme) => ({
|
||||
workspaceName: {
|
||||
minHeight: "40px",
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
borderRadius: '25px',
|
||||
display: 'inline-flex',
|
||||
cursor: 'pointer',
|
||||
'&:hover': {
|
||||
borderRadius: "25px",
|
||||
display: "inline-flex",
|
||||
cursor: "pointer",
|
||||
"&:hover": {
|
||||
color: theme.palette.primary.main,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
class WorkspaceName extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.inputRef = React.createRef();
|
||||
this.state = {
|
||||
title: '',
|
||||
content: '',
|
||||
title: "",
|
||||
content: "",
|
||||
open: false,
|
||||
name: props.name,
|
||||
description: props.description,
|
||||
snackbar: false,
|
||||
type: '',
|
||||
key: '',
|
||||
message: ''
|
||||
type: "",
|
||||
key: "",
|
||||
message: "",
|
||||
};
|
||||
}
|
||||
|
||||
@ -59,47 +58,100 @@ class WorkspaceName extends Component {
|
||||
}
|
||||
|
||||
toggleDialog = () => {
|
||||
this.setState({ open: !this.state, title: '', content: '' });
|
||||
}
|
||||
this.setState({ open: !this.state, title: "", content: "" });
|
||||
};
|
||||
|
||||
setFileName = (e) => {
|
||||
this.setState({ name: e.target.value });
|
||||
}
|
||||
};
|
||||
|
||||
setDescription = (e) => {
|
||||
this.setState({ description: e.target.value });
|
||||
}
|
||||
};
|
||||
|
||||
renameWorkspace = () => {
|
||||
this.props.workspaceName(this.state.name);
|
||||
this.toggleDialog();
|
||||
if (this.props.projectType === 'project' || this.props.projectType === 'gallery' || this.state.projectType === 'gallery') {
|
||||
if (this.props.projectType === 'gallery' || this.state.projectType === 'gallery') {
|
||||
if (
|
||||
this.props.projectType === "project" ||
|
||||
this.props.projectType === "gallery" ||
|
||||
this.state.projectType === "gallery"
|
||||
) {
|
||||
if (
|
||||
this.props.projectType === "gallery" ||
|
||||
this.state.projectType === "gallery"
|
||||
) {
|
||||
this.props.setDescription(this.state.description);
|
||||
}
|
||||
if (this.state.projectType === 'gallery') {
|
||||
if (this.state.projectType === "gallery") {
|
||||
this.saveGallery();
|
||||
} else {
|
||||
this.props.updateProject(this.props.projectType, this.props.project._id);
|
||||
this.props.updateProject(
|
||||
this.props.projectType,
|
||||
this.props.project._id
|
||||
);
|
||||
}
|
||||
} else {
|
||||
this.setState({ snackbar: true, type: 'success', key: Date.now(), message: `${Blockly.Msg.messages_rename_success_01} ${this.state.name} ${Blockly.Msg.messages_rename_success_02}` });
|
||||
this.setState({
|
||||
snackbar: true,
|
||||
type: "success",
|
||||
key: Date.now(),
|
||||
message: `${Blockly.Msg.messages_rename_success_01} ${this.state.name} ${Blockly.Msg.messages_rename_success_02}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={this.props.style}>
|
||||
<Tooltip title={`${Blockly.Msg.tooltip_project_title} ${this.props.name ? `: ${this.props.name}` : ''}`} arrow style={{ height: '100%' }}>
|
||||
<Tooltip
|
||||
title={`${Blockly.Msg.tooltip_project_title} ${
|
||||
this.props.name ? `: ${this.props.name}` : ""
|
||||
}`}
|
||||
arrow
|
||||
style={{ height: "100%" }}
|
||||
>
|
||||
<div
|
||||
className={this.props.classes.workspaceName}
|
||||
onClick={() => { if (this.props.multiple) { this.props.workspaceName(this.props.project.title); if (this.props.projectType === 'gallery') { this.props.setDescription(this.props.project.description); } } this.setState({ open: true, title: this.props.projectType === 'gallery' ? 'Projektdaten ändern' : this.props.projectType === 'project' ? 'Projekt umbenennen' : 'Projekt benennen', content: this.props.projectType === 'gallery' ? 'Bitte gib einen Titel und eine Beschreibung für das Galerie-Projekt ein und bestätige die Angaben mit einem Klick auf \'Eingabe\'.' : 'Bitte gib einen Namen für das Projekt ein und bestätige diesen mit einem Klick auf \'Eingabe\'.' }) }}
|
||||
onClick={() => {
|
||||
if (this.props.multiple) {
|
||||
this.props.workspaceName(this.props.project.title);
|
||||
if (this.props.projectType === "gallery") {
|
||||
this.props.setDescription(this.props.project.description);
|
||||
}
|
||||
}
|
||||
this.setState({
|
||||
open: true,
|
||||
title:
|
||||
this.props.projectType === "gallery"
|
||||
? "Projektdaten ändern"
|
||||
: this.props.projectType === "project"
|
||||
? "Projekt umbenennen"
|
||||
: "Projekt benennen",
|
||||
content:
|
||||
this.props.projectType === "gallery"
|
||||
? "Bitte gib einen Titel und eine Beschreibung für das Galerie-Projekt ein und bestätige die Angaben mit einem Klick auf 'Eingabe'."
|
||||
: "Bitte gib einen Namen für das Projekt ein und bestätige diesen mit einem Klick auf 'Eingabe'.",
|
||||
});
|
||||
}}
|
||||
>
|
||||
{this.props.name && !isWidthDown(this.props.projectType === 'project' || this.props.projectType === 'gallery' ? 'xl' : 'xs', this.props.width) ?
|
||||
<Typography style={{ margin: 'auto -3px auto 12px' }}>{this.props.name}</Typography>
|
||||
: null}
|
||||
<div style={{ width: '40px', display: 'flex' }}>
|
||||
<FontAwesomeIcon icon={faPen} style={{ height: '18px', width: '18px', margin: 'auto' }} />
|
||||
{this.props.name &&
|
||||
!isWidthDown(
|
||||
this.props.projectType === "project" ||
|
||||
this.props.projectType === "gallery"
|
||||
? "xl"
|
||||
: "xs",
|
||||
this.props.width
|
||||
) ? (
|
||||
<Typography style={{ margin: "auto -3px auto 12px" }}>
|
||||
{this.props.name}
|
||||
</Typography>
|
||||
) : null}
|
||||
<div style={{ width: "40px", display: "flex" }}>
|
||||
<FontAwesomeIcon
|
||||
icon={faPen}
|
||||
style={{ height: "18px", width: "18px", margin: "auto" }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
@ -114,23 +166,69 @@ class WorkspaceName extends Component {
|
||||
open={this.state.open}
|
||||
title={this.state.title}
|
||||
content={this.state.content}
|
||||
onClose={() => { this.toggleDialog(); this.setState({ name: this.props.name, description: this.props.description }); }}
|
||||
onClick={() => { this.toggleDialog(); this.setState({ name: this.props.name, description: this.props.description }); }}
|
||||
button={'Abbrechen'}
|
||||
onClose={() => {
|
||||
this.toggleDialog();
|
||||
this.setState({
|
||||
name: this.props.name,
|
||||
description: this.props.description,
|
||||
});
|
||||
}}
|
||||
onClick={() => {
|
||||
this.toggleDialog();
|
||||
this.setState({
|
||||
name: this.props.name,
|
||||
description: this.props.description,
|
||||
});
|
||||
}}
|
||||
button={"Abbrechen"}
|
||||
>
|
||||
<div style={{ marginTop: '10px' }}>
|
||||
{this.props.projectType === 'gallery' || this.state.projectType === 'gallery' ?
|
||||
<div style={{ marginTop: "10px" }}>
|
||||
{this.props.projectType === "gallery" ||
|
||||
this.state.projectType === "gallery" ? (
|
||||
<div>
|
||||
<TextField autoFocus placeholder={this.state.saveXml ? 'Dateiname' : 'Projekttitel'} value={this.state.name} onChange={this.setFileName} style={{ marginBottom: '10px' }} />
|
||||
<TextField fullWidth multiline placeholder={'Projektbeschreibung'} value={this.state.description} onChange={this.setDescription} style={{ marginBottom: '10px' }} />
|
||||
<TextField
|
||||
autoFocus
|
||||
placeholder={
|
||||
this.state.saveXml ? "Dateiname" : "Projekttitel"
|
||||
}
|
||||
value={this.state.name}
|
||||
onChange={this.setFileName}
|
||||
style={{ marginBottom: "10px" }}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
multiline
|
||||
placeholder={"Projektbeschreibung"}
|
||||
value={this.state.description}
|
||||
onChange={this.setDescription}
|
||||
style={{ marginBottom: "10px" }}
|
||||
/>
|
||||
</div>
|
||||
: <TextField autoFocus placeholder={this.state.saveXml ? 'Dateiname' : 'Projekttitel'} value={this.state.name} onChange={this.setFileName} style={{ marginRight: '10px' }} />}
|
||||
<Button disabled={!this.state.name} variant='contained' color='primary' onClick={() => { this.renameWorkspace(); this.toggleDialog(); }}>Eingabe</Button>
|
||||
) : (
|
||||
<TextField
|
||||
autoFocus
|
||||
placeholder={this.state.saveXml ? "Dateiname" : "Projekttitel"}
|
||||
value={this.state.name}
|
||||
onChange={this.setFileName}
|
||||
style={{ marginRight: "10px" }}
|
||||
/>
|
||||
)}
|
||||
<Button
|
||||
disabled={!this.state.name}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
this.renameWorkspace();
|
||||
this.toggleDialog();
|
||||
}}
|
||||
>
|
||||
Eingabe
|
||||
</Button>
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
WorkspaceName.propTypes = {
|
||||
@ -142,10 +240,14 @@ WorkspaceName.propTypes = {
|
||||
message: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
const mapStateToProps = (state) => ({
|
||||
name: state.workspace.name,
|
||||
description: state.project.description,
|
||||
message: state.message,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, { workspaceName, setDescription, updateProject })(withStyles(styles, { withTheme: true })(withWidth()(WorkspaceName)));
|
||||
export default connect(mapStateToProps, {
|
||||
workspaceName,
|
||||
setDescription,
|
||||
updateProject,
|
||||
})(withStyles(styles, { withTheme: true })(withWidth()(WorkspaceName)));
|
||||
|
14
src/data/arduinoExamples.js
Normal file
14
src/data/arduinoExamples.js
Normal file
File diff suppressed because one or more lines are too long
102
src/data/versions.js
Normal file
102
src/data/versions.js
Normal file
@ -0,0 +1,102 @@
|
||||
export const LibraryVersions = () => {
|
||||
return [
|
||||
{
|
||||
version: "1.4.2",
|
||||
library: "sensebox/SenseBoxMCU-Lib",
|
||||
link: "https://github.com/sensebox/SenseBoxMCU-Lib",
|
||||
},
|
||||
{
|
||||
version: "1.0.12",
|
||||
library: "sparkfun/SparkFun_SCD30_Arduino_Library",
|
||||
},
|
||||
{ version: "1.2.3", library: "adafruit/Adafruit-GFX-Library" },
|
||||
{
|
||||
version: "2.1.2",
|
||||
library: "adafruit/Adafruit_BME280_Library",
|
||||
},
|
||||
{
|
||||
version: "2.1.0",
|
||||
library: "adafruit/Adafruit_BMP280_Library",
|
||||
},
|
||||
{
|
||||
version: "1.1.1",
|
||||
library: "adafruit/Adafruit_BME680",
|
||||
},
|
||||
{
|
||||
version: "2.0.1",
|
||||
library: "adafruit/Adafruit_BMP3XX",
|
||||
},
|
||||
{
|
||||
version: "2.0.0",
|
||||
library: "adafruit/Adafruit_HDC1000_Library",
|
||||
},
|
||||
{
|
||||
version: "1.7.1",
|
||||
library: "adafruit/Adafruit_BusIO",
|
||||
},
|
||||
{
|
||||
version: "1.0.6",
|
||||
library: "adafruit/Adafruit_NeoPixel",
|
||||
},
|
||||
{
|
||||
version: "1.1.2",
|
||||
library: "adafruit/Adafruit_SSD1306",
|
||||
},
|
||||
{
|
||||
version: "1.0.2",
|
||||
library: "adafruit/Adafruit_Sensor",
|
||||
},
|
||||
{
|
||||
version: "3.8.0",
|
||||
library: "milesburton/Arduino-Temperature-Control-Library",
|
||||
},
|
||||
{
|
||||
version: "1.5.0",
|
||||
library: "arduino-libraries/ArduinoBearSSL",
|
||||
},
|
||||
{
|
||||
version: "1.3.4",
|
||||
library: "arduino-libraries/ArduinoECCX08",
|
||||
},
|
||||
{
|
||||
version: "2.0.0",
|
||||
library: "arduino-libraries/ArduinoECCX08", //todo
|
||||
},
|
||||
{
|
||||
version: "0.7.1",
|
||||
library: "cmaglie/FlashStorage",
|
||||
},
|
||||
{
|
||||
version: "1.5.1",
|
||||
library: "matthijskooijman/arduino-lmic",
|
||||
},
|
||||
{
|
||||
version: "3.0.1",
|
||||
library: "thesolarnomad/lora-serialization ",
|
||||
},
|
||||
{
|
||||
version: "todo",
|
||||
library: "TSL45xxx",
|
||||
},
|
||||
{
|
||||
version: "2.3.4",
|
||||
library: "teensy/td_libs_OneWire.html",
|
||||
},
|
||||
{
|
||||
version: "1.0.0",
|
||||
library: "watterott/Arduino-Libs/tree/master/RV8523",
|
||||
},
|
||||
{
|
||||
version: "1.0.0",
|
||||
library: "sensebox/SDS011-select-serial ",
|
||||
},
|
||||
{
|
||||
version: "1.0.0",
|
||||
library: "Lucas-Steinmann/SSD1306-Plot-Library",
|
||||
},
|
||||
{
|
||||
version: "1.0.0",
|
||||
library: "senseBoxIO",
|
||||
},
|
||||
];
|
||||
};
|
29
yarn.lock
29
yarn.lock
@ -1542,6 +1542,21 @@
|
||||
"prop-types" "^15.7.2"
|
||||
"react-is" "^16.8.0"
|
||||
|
||||
"@monaco-editor/loader@^1.2.0":
|
||||
"integrity" "sha512-cJVCG/T/KxXgzYnjKqyAgsKDbH9mGLjcXxN6AmwumBwa2rVFkwvGcUj1RJtD0ko4XqLqJxwqsN/Z/KURB5f1OQ=="
|
||||
"resolved" "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.2.0.tgz"
|
||||
"version" "1.2.0"
|
||||
dependencies:
|
||||
"state-local" "^1.0.6"
|
||||
|
||||
"@monaco-editor/react@^4.3.1":
|
||||
"integrity" "sha512-f+0BK1PP/W5I50hHHmwf11+Ea92E5H1VZXs+wvKplWUWOfyMa1VVwqkJrXjRvbcqHL+XdIGYWhWNdi4McEvnZg=="
|
||||
"resolved" "https://registry.npmjs.org/@monaco-editor/react/-/react-4.3.1.tgz"
|
||||
"version" "4.3.1"
|
||||
dependencies:
|
||||
"@monaco-editor/loader" "^1.2.0"
|
||||
"prop-types" "^15.7.2"
|
||||
|
||||
"@nodelib/fs.scandir@2.1.4":
|
||||
"integrity" "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA=="
|
||||
"resolved" "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz"
|
||||
@ -8224,6 +8239,11 @@
|
||||
"resolved" "https://registry.npmjs.org/moment/-/moment-2.29.0.tgz"
|
||||
"version" "2.29.0"
|
||||
|
||||
"monaco-editor@>= 0.21.0 < 1", "monaco-editor@>= 0.25.0 < 1":
|
||||
"integrity" "sha512-FYPwxGZAeP6mRRyrr5XTGHD9gRXVjy7GUzF4IPChnyt3fS5WrNxIkS8DNujWf6EQy0Zlzpxw8oTVE+mWI2/D1Q=="
|
||||
"resolved" "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.31.1.tgz"
|
||||
"version" "0.31.1"
|
||||
|
||||
"move-concurrently@^1.0.1":
|
||||
"integrity" "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I="
|
||||
"resolved" "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz"
|
||||
@ -10032,7 +10052,7 @@
|
||||
"strip-ansi" "6.0.0"
|
||||
"text-table" "0.2.0"
|
||||
|
||||
"react-dom@^17.0.0", "react-dom@^17.0.2":
|
||||
"react-dom@^16.8.0 || ^17.0.0", "react-dom@^17.0.0", "react-dom@^17.0.2":
|
||||
"integrity" "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA=="
|
||||
"resolved" "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz"
|
||||
"version" "17.0.2"
|
||||
@ -10211,7 +10231,7 @@
|
||||
"loose-envify" "^1.4.0"
|
||||
"prop-types" "^15.6.2"
|
||||
|
||||
"react@^16.8.3 || ^17", "react@^17.0.0", "react@^17.0.2", "react@>= 16", "react@17.0.2":
|
||||
"react@^16.8.0 || ^17.0.0", "react@^16.8.3 || ^17", "react@^17.0.0", "react@^17.0.2", "react@>= 16", "react@17.0.2":
|
||||
"integrity" "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA=="
|
||||
"resolved" "https://registry.npmjs.org/react/-/react-17.0.2.tgz"
|
||||
"version" "17.0.2"
|
||||
@ -11408,6 +11428,11 @@
|
||||
"resolved" "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz"
|
||||
"version" "1.2.0"
|
||||
|
||||
"state-local@^1.0.6":
|
||||
"integrity" "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w=="
|
||||
"resolved" "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz"
|
||||
"version" "1.0.7"
|
||||
|
||||
"static-extend@^0.1.1":
|
||||
"integrity" "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY="
|
||||
"resolved" "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz"
|
||||
|
Loading…
x
Reference in New Issue
Block a user