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/free-solid-svg-icons": "^5.14.0", | ||||||
|         "@fortawesome/react-fontawesome": "^0.1.11", |         "@fortawesome/react-fontawesome": "^0.1.11", | ||||||
|         "@material-ui/core": "^4.11.0", |         "@material-ui/core": "^4.11.0", | ||||||
|  |         "@monaco-editor/react": "^4.3.1", | ||||||
|         "@sentry/react": "^6.0.0", |         "@sentry/react": "^6.0.0", | ||||||
|         "@sentry/tracing": "^6.0.0", |         "@sentry/tracing": "^6.0.0", | ||||||
|         "@testing-library/jest-dom": "^4.2.4", |         "@testing-library/jest-dom": "^4.2.4", | ||||||
| @ -3120,6 +3121,31 @@ | |||||||
|         "node": ">=8.0.0" |         "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": { |     "node_modules/@nodelib/fs.scandir": { | ||||||
|       "version": "2.1.4", |       "version": "2.1.4", | ||||||
|       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", |       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", | ||||||
| @ -16643,6 +16669,12 @@ | |||||||
|         "node": "*" |         "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": { |     "node_modules/move-concurrently": { | ||||||
|       "version": "1.0.1", |       "version": "1.0.1", | ||||||
|       "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", |       "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", |       "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz", | ||||||
|       "integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==" |       "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": { |     "node_modules/static-extend": { | ||||||
|       "version": "0.1.2", |       "version": "0.1.2", | ||||||
|       "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", |       "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", | ||||||
| @ -27515,6 +27552,23 @@ | |||||||
|         "react-is": "^16.8.0" |         "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": { |     "@nodelib/fs.scandir": { | ||||||
|       "version": "2.1.4", |       "version": "2.1.4", | ||||||
|       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", |       "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", |       "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.0.tgz", | ||||||
|       "integrity": "sha512-z6IJ5HXYiuxvFTI6eiQ9dm77uE0gyy1yXNApVHqTcnIKfY9tIwEjlzsZ6u1LQXvVgKeTnv9Xm7NDvJ7lso3MtA==" |       "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": { |     "move-concurrently": { | ||||||
|       "version": "1.0.1", |       "version": "1.0.1", | ||||||
|       "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", |       "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", |       "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz", | ||||||
|       "integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==" |       "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": { |     "static-extend": { | ||||||
|       "version": "0.1.2", |       "version": "0.1.2", | ||||||
|       "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", |       "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/free-solid-svg-icons": "^5.14.0", | ||||||
|     "@fortawesome/react-fontawesome": "^0.1.11", |     "@fortawesome/react-fontawesome": "^0.1.11", | ||||||
|     "@material-ui/core": "^4.11.0", |     "@material-ui/core": "^4.11.0", | ||||||
|  |     "@monaco-editor/react": "^4.3.1", | ||||||
|     "@sentry/react": "^6.0.0", |     "@sentry/react": "^6.0.0", | ||||||
|     "@sentry/tracing": "^6.0.0", |     "@sentry/tracing": "^6.0.0", | ||||||
|     "@testing-library/jest-dom": "^4.2.4", |     "@testing-library/jest-dom": "^4.2.4", | ||||||
|  | |||||||
							
								
								
									
										13
									
								
								src/App.css
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								src/App.css
									
									
									
									
									
								
							| @ -1,16 +1,17 @@ | |||||||
| .wrapper { | .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; |   overflow: hidden; | ||||||
|   display: block; |   display: block; | ||||||
|   position: relative; |   position: relative; | ||||||
|   padding-bottom: 60px; /* height of your footer + 30px*/ |   padding-bottom: 60px; /* height of your footer + 30px*/ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| .tutorial img { | .tutorial img { | ||||||
|   display: flex; |   display: flex; | ||||||
|   align-items: center; |   align-items: center; | ||||||
|   max-height: 40vH; |   max-height: 40vh; | ||||||
|   max-width: 100%; |   max-width: 100%; | ||||||
|   margin: auto; |   margin: auto; | ||||||
| } | } | ||||||
| @ -18,7 +19,7 @@ | |||||||
| .news img { | .news img { | ||||||
|   display: flex; |   display: flex; | ||||||
|   align-items: center; |   align-items: center; | ||||||
|   max-height: 40vH; |   max-height: 40vh; | ||||||
|   max-width: 100%; |   max-width: 100%; | ||||||
|   margin: auto; |   margin: auto; | ||||||
| } | } | ||||||
| @ -31,7 +32,7 @@ | |||||||
|   quotes: "\201C""\201D""\2018""\2019"; |   quotes: "\201C""\201D""\2018""\2019"; | ||||||
| } | } | ||||||
| blockquote:before { | blockquote:before { | ||||||
|     color:#4EAF47; |   color: #4eaf47; | ||||||
|   content: open-quote; |   content: open-quote; | ||||||
|   font-size: 4em; |   font-size: 4em; | ||||||
|   line-height: 0.1em; |   line-height: 0.1em; | ||||||
| @ -47,5 +48,3 @@ | |||||||
|   flex-direction: column; |   flex-direction: column; | ||||||
|   align-items: center; |   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 React, { Component } from "react"; | ||||||
| import PropTypes from 'prop-types'; | import PropTypes from "prop-types"; | ||||||
| import { connect } from 'react-redux'; | 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 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) => ({ | const Accordion = withStyles((theme) => ({ | ||||||
|   root: { |   root: { | ||||||
|     border: `1px solid ${theme.palette.secondary.main}`, |     border: `1px solid ${theme.palette.secondary.main}`, | ||||||
|     boxShadow: 'none', |     boxShadow: "none", | ||||||
|     '&:before': { |     "&:before": { | ||||||
|       display: 'none', |       display: "none", | ||||||
|     }, |     }, | ||||||
|     '&$expanded': { |     "&$expanded": { | ||||||
|       margin: 'auto', |       margin: "auto", | ||||||
|     }, |     }, | ||||||
|   }, |   }, | ||||||
|   expanded: {}, |   expanded: {}, | ||||||
| @ -34,15 +29,15 @@ const AccordionSummary = withStyles((theme) => ({ | |||||||
|   root: { |   root: { | ||||||
|     backgroundColor: theme.palette.secondary.main, |     backgroundColor: theme.palette.secondary.main, | ||||||
|     borderBottom: `1px solid white`, |     borderBottom: `1px solid white`, | ||||||
|     marginBottom: '-1px', |     marginBottom: "-1px", | ||||||
|     minHeight: '50px', |     minHeight: "50px", | ||||||
|     '&$expanded': { |     "&$expanded": { | ||||||
|       minHeight: '50px', |       minHeight: "50px", | ||||||
|     }, |     }, | ||||||
|   }, |   }, | ||||||
|   content: { |   content: { | ||||||
|     '&$expanded': { |     "&$expanded": { | ||||||
|       margin: '12px 0', |       margin: "12px 0", | ||||||
|     }, |     }, | ||||||
|   }, |   }, | ||||||
|   expanded: {}, |   expanded: {}, | ||||||
| @ -54,40 +49,60 @@ const AccordionDetails = withStyles((theme) => ({ | |||||||
|   }, |   }, | ||||||
| }))(MuiAccordionDetails); | }))(MuiAccordionDetails); | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| class CodeViewer extends Component { | class CodeViewer extends Component { | ||||||
| 
 |  | ||||||
|   constructor(props) { |   constructor(props) { | ||||||
|     super(props); |     super(props); | ||||||
|     this.state = { |     this.state = { | ||||||
|  |       code: this.props.arduino, | ||||||
|  |       changed: false, | ||||||
|       expanded: true, |       expanded: true, | ||||||
|       componentHeight: null |       componentHeight: null, | ||||||
|     }; |     }; | ||||||
|     this.myDiv = React.createRef(); |     this.myDiv = React.createRef(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   componentDidMount() { |   componentDidMount() { | ||||||
|     Prism.highlightAll(); |     this.setState({ componentHeight: this.myDiv.current.offsetHeight + "px" }); | ||||||
|     this.setState({ componentHeight: this.myDiv.current.offsetHeight + 'px' }); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   componentDidUpdate(props, state) { |   componentDidUpdate(prevProps, prevState) { | ||||||
|     if (this.myDiv.current && this.myDiv.current.offsetHeight + 'px' !== this.state.componentHeight) { |     // if (this.props.arduino !== prevProps.arduino) {
 | ||||||
|       this.setState({ componentHeight: this.myDiv.current.offsetHeight + 'px' }); |     //   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 = () => { |   onChange = () => { | ||||||
|     this.setState({ expanded: !this.state.expanded }); |     this.setState({ expanded: !this.state.expanded }); | ||||||
| 
 |   }; | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   render() { |   render() { | ||||||
|     var curlyBrackets = '{ }'; |     var curlyBrackets = "{ }"; | ||||||
|     var unequal = '<>'; |     var unequal = "<>"; | ||||||
|     return ( |     return ( | ||||||
|       <Card style={{ height: '100%', maxHeight: '60vH' }} ref={this.myDiv}> |       <Card style={{ height: "100%", maxHeight: "60vH" }} ref={this.myDiv}> | ||||||
|         <Accordion |         <Accordion | ||||||
|           square={true} |           square={true} | ||||||
|           style={{ margin: 0 }} |           style={{ margin: 0 }} | ||||||
| @ -95,15 +110,32 @@ class CodeViewer extends Component { | |||||||
|           onChange={this.onChange} |           onChange={this.onChange} | ||||||
|         > |         > | ||||||
|           <AccordionSummary> |           <AccordionSummary> | ||||||
|             <b style={{ fontSize: '20px', marginRight: '5px', width: '35px' }}>{curlyBrackets}</b> |             <b style={{ fontSize: "20px", marginRight: "5px", width: "35px" }}> | ||||||
|             <div style={{ margin: 'auto 5px 2px 0px' }}>{Blockly.Msg.codeviewer_arduino}</div> |               {curlyBrackets} | ||||||
|  |             </b> | ||||||
|  |             <div style={{ margin: "auto 5px 2px 0px" }}> | ||||||
|  |               {Blockly.Msg.codeviewer_arduino} | ||||||
|  |             </div> | ||||||
|           </AccordionSummary> |           </AccordionSummary> | ||||||
|           <AccordionDetails style={{ padding: 0, height: `calc(${this.state.componentHeight} - 50px - 50px)`, backgroundColor: 'white' }}> |           <AccordionDetails | ||||||
|             <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' }}> |             style={{ | ||||||
|               <code className="language-clike"> |               padding: 0, | ||||||
|                 {this.props.arduino} |               height: `calc(${this.state.componentHeight} - 50px - 50px)`, | ||||||
|               </code> |               backgroundColor: "white", | ||||||
|             </pre> |             }} | ||||||
|  |           > | ||||||
|  |             <MonacoEditor | ||||||
|  |               height="80vh" | ||||||
|  |               defaultLanguage="cpp" | ||||||
|  |               value={this.props.arduino} | ||||||
|  |               // modified={this.props.arduino}
 | ||||||
|  |               // original={this.state.code}
 | ||||||
|  |               options={{ | ||||||
|  |                 readOnly: true, | ||||||
|  | 
 | ||||||
|  |                 fontSize: "12px", | ||||||
|  |               }} | ||||||
|  |             /> | ||||||
|           </AccordionDetails> |           </AccordionDetails> | ||||||
|         </Accordion> |         </Accordion> | ||||||
|         <Accordion |         <Accordion | ||||||
| @ -113,32 +145,43 @@ class CodeViewer extends Component { | |||||||
|           onChange={this.onChange} |           onChange={this.onChange} | ||||||
|         > |         > | ||||||
|           <AccordionSummary> |           <AccordionSummary> | ||||||
|             <b style={{ fontSize: '20px', marginRight: '5px', width: '35px' }}>{unequal}</b> |             <b style={{ fontSize: "20px", marginRight: "5px", width: "35px" }}> | ||||||
|             <div style={{ margin: 'auto 5px 2px 0px' }}>{Blockly.Msg.codeviewer_xml}</div> |               {unequal} | ||||||
|  |             </b> | ||||||
|  |             <div style={{ margin: "auto 5px 2px 0px" }}> | ||||||
|  |               {Blockly.Msg.codeviewer_xml} | ||||||
|  |             </div> | ||||||
|           </AccordionSummary> |           </AccordionSummary> | ||||||
|           <AccordionDetails style={{ padding: 0, height: `calc(${this.state.componentHeight} - 50px - 50px)`, backgroundColor: 'white' }}> |           <AccordionDetails | ||||||
|             <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' }}> |             style={{ | ||||||
|               <code className="language-xml"> |               padding: 0, | ||||||
|                 {`${this.props.xml}`} |               height: `calc(${this.state.componentHeight} - 50px - 50px)`, | ||||||
|               </code> |               backgroundColor: "white", | ||||||
|             </pre> |             }} | ||||||
|  |           > | ||||||
|  |             <MonacoEditor | ||||||
|  |               height="80vh" | ||||||
|  |               defaultLanguage="xml" | ||||||
|  |               value={this.props.xml} | ||||||
|  |               readOnly={true} | ||||||
|  |             /> | ||||||
|           </AccordionDetails> |           </AccordionDetails> | ||||||
|         </Accordion> |         </Accordion> | ||||||
|       </Card> |       </Card> | ||||||
|     ); |     ); | ||||||
|   }; |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| CodeViewer.propTypes = { | CodeViewer.propTypes = { | ||||||
|   arduino: PropTypes.string.isRequired, |   arduino: PropTypes.string.isRequired, | ||||||
|   xml: 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, |   arduino: state.workspace.code.arduino, | ||||||
|   xml: state.workspace.code.xml, |   xml: state.workspace.code.xml, | ||||||
|   tooltip: state.workspace.code.tooltip |   tooltip: state.workspace.code.tooltip, | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| export default connect(mapStateToProps, null)(withWidth()(CodeViewer)); | 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 { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | ||||||
| import TooltipViewer from "./TooltipViewer"; | import TooltipViewer from "./TooltipViewer"; | ||||||
| import Dialog from "./Dialog"; | import Dialog from "./Dialog"; | ||||||
| 
 | // import Autosave from "./Workspace/AutoSave";
 | ||||||
| const styles = (theme) => ({ | const styles = (theme) => ({ | ||||||
|   codeOn: { |   codeOn: { | ||||||
|     backgroundColor: theme.palette.primary.main, |     backgroundColor: theme.palette.primary.main, | ||||||
| @ -54,6 +54,7 @@ class Home extends Component { | |||||||
|       key: "", |       key: "", | ||||||
|       message: "", |       message: "", | ||||||
|       open: true, |       open: true, | ||||||
|  |       initialXml: localStorage.getItem("autoSaveXML"), | ||||||
|     }; |     }; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -119,10 +120,12 @@ class Home extends Component { | |||||||
|             <WorkspaceStats /> |             <WorkspaceStats /> | ||||||
|           </div> |           </div> | ||||||
|         ) : null} |         ) : null} | ||||||
|  | 
 | ||||||
|         <div |         <div | ||||||
|           className="workspaceFunc" |           className="workspaceFunc" | ||||||
|           style={{ float: "right", height: "40px", marginBottom: "20px" }} |           style={{ float: "right", height: "40px", marginBottom: "20px" }} | ||||||
|         > |         > | ||||||
|  |           {/* <Autosave /> */} | ||||||
|           <WorkspaceFunc |           <WorkspaceFunc | ||||||
|             project={this.props.project} |             project={this.props.project} | ||||||
|             projectType={this.props.projectType} |             projectType={this.props.projectType} | ||||||
| @ -161,6 +164,7 @@ class Home extends Component { | |||||||
|                 <FontAwesomeIcon icon={faCode} size="xs" /> |                 <FontAwesomeIcon icon={faCode} size="xs" /> | ||||||
|               </IconButton> |               </IconButton> | ||||||
|             </Tooltip> |             </Tooltip> | ||||||
|  | 
 | ||||||
|             <TrashcanButtons /> |             <TrashcanButtons /> | ||||||
|             <div className="blocklyWindow"> |             <div className="blocklyWindow"> | ||||||
|               {this.props.project ? ( |               {this.props.project ? ( | ||||||
| @ -169,7 +173,10 @@ class Home extends Component { | |||||||
|                   initialXml={this.props.project.xml} |                   initialXml={this.props.project.xml} | ||||||
|                 /> |                 /> | ||||||
|               ) : ( |               ) : ( | ||||||
|                 <BlocklyWindow blocklyCSS={{ height: "80vH" }} /> |                 <BlocklyWindow | ||||||
|  |                   blocklyCSS={{ height: "80vH" }} | ||||||
|  |                   initialXml={this.state.initialXml} | ||||||
|  |                 /> | ||||||
|               )} |               )} | ||||||
|             </div> |             </div> | ||||||
|           </Grid> |           </Grid> | ||||||
|  | |||||||
| @ -21,6 +21,7 @@ import ListItemIcon from "@material-ui/core/ListItemIcon"; | |||||||
| import ListItemText from "@material-ui/core/ListItemText"; | import ListItemText from "@material-ui/core/ListItemText"; | ||||||
| import LinearProgress from "@material-ui/core/LinearProgress"; | import LinearProgress from "@material-ui/core/LinearProgress"; | ||||||
| import Tour from "reactour"; | import Tour from "reactour"; | ||||||
|  | import { Badge } from "@material-ui/core"; | ||||||
| import { home, assessment } from "./Tour"; | import { home, assessment } from "./Tour"; | ||||||
| import { | import { | ||||||
|   faBars, |   faBars, | ||||||
| @ -34,6 +35,7 @@ import { | |||||||
|   faChalkboardTeacher, |   faChalkboardTeacher, | ||||||
|   faTools, |   faTools, | ||||||
|   faLightbulb, |   faLightbulb, | ||||||
|  |   faCode, | ||||||
| } from "@fortawesome/free-solid-svg-icons"; | } from "@fortawesome/free-solid-svg-icons"; | ||||||
| import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | ||||||
| import * as Blockly from "blockly"; | import * as Blockly from "blockly"; | ||||||
| @ -230,6 +232,11 @@ class Navbar extends Component { | |||||||
|                 icon: faLightbulb, |                 icon: faLightbulb, | ||||||
|                 link: "/gallery", |                 link: "/gallery", | ||||||
|               }, |               }, | ||||||
|  |               { | ||||||
|  |                 text: "CodeEditor", | ||||||
|  |                 icon: faCode, | ||||||
|  |                 link: "/codeeditor", | ||||||
|  |               }, | ||||||
|               { |               { | ||||||
|                 text: Blockly.Msg.navbar_projects, |                 text: Blockly.Msg.navbar_projects, | ||||||
|                 icon: faLayerGroup, |                 icon: faLayerGroup, | ||||||
| @ -253,7 +260,13 @@ class Navbar extends Component { | |||||||
|                       <ListItemIcon> |                       <ListItemIcon> | ||||||
|                         <FontAwesomeIcon icon={item.icon} /> |                         <FontAwesomeIcon icon={item.icon} /> | ||||||
|                       </ListItemIcon> |                       </ListItemIcon> | ||||||
|  |                       {item.text === "CodeEditor" ? ( | ||||||
|  |                         <Badge badgeContent={"Experimental"} color="primary"> | ||||||
|                           <ListItemText primary={item.text} /> |                           <ListItemText primary={item.text} /> | ||||||
|  |                         </Badge> | ||||||
|  |                       ) : ( | ||||||
|  |                         <ListItemText primary={item.text} /> | ||||||
|  |                       )} | ||||||
|                     </ListItem> |                     </ListItem> | ||||||
|                   </Link> |                   </Link> | ||||||
|                 ); |                 ); | ||||||
|  | |||||||
| @ -24,6 +24,7 @@ import Login from "../User/Login"; | |||||||
| import Account from "../User/Account"; | import Account from "../User/Account"; | ||||||
| import News from "../News"; | import News from "../News"; | ||||||
| import Faq from "../Faq"; | import Faq from "../Faq"; | ||||||
|  | import CodeEditor from "../CodeEditor/CodeEditor"; | ||||||
| 
 | 
 | ||||||
| class Routes extends Component { | class Routes extends Component { | ||||||
|   componentDidUpdate() { |   componentDidUpdate() { | ||||||
| @ -47,6 +48,9 @@ class Routes extends Component { | |||||||
|           <Route path="/tutorial/:tutorialId" exact> |           <Route path="/tutorial/:tutorialId" exact> | ||||||
|             <Tutorial /> |             <Tutorial /> | ||||||
|           </Route> |           </Route> | ||||||
|  |           <Route path="/CodeEditor" exact> | ||||||
|  |             <CodeEditor /> | ||||||
|  |           </Route> | ||||||
|           {/* Sharing */} |           {/* Sharing */} | ||||||
|           <PublicRoute path="/share/:shareId" exact> |           <PublicRoute path="/share/:shareId" exact> | ||||||
|             <Project /> |             <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 { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | ||||||
| import * as Blockly from "blockly/core"; | import * as Blockly from "blockly/core"; | ||||||
| import Copy from "../copy.svg"; | 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 MuiDrawer from "@material-ui/core/Drawer"; | ||||||
| import Dialog from "../Dialog"; | import Dialog from "../Dialog"; | ||||||
| 
 | 
 | ||||||
| @ -71,15 +68,12 @@ class Compile extends Component { | |||||||
|     }; |     }; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   componentDidMount() { |   componentDidMount() {} | ||||||
|     Prism.highlightAll(); |  | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   componentDidUpdate(props) { |   componentDidUpdate(props) { | ||||||
|     if (props.name !== this.props.name) { |     if (props.name !== this.props.name) { | ||||||
|       this.setState({ name: this.props.name }); |       this.setState({ name: this.props.name }); | ||||||
|     } |     } | ||||||
|     Prism.highlightAll(); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   compile = () => { |   compile = () => { | ||||||
|  | |||||||
| @ -1,101 +1,113 @@ | |||||||
| import React, { Component } from 'react'; | import React, { Component } from "react"; | ||||||
| import PropTypes from 'prop-types'; | import PropTypes from "prop-types"; | ||||||
| import { connect } from 'react-redux'; | 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 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 { | class WorkspaceFunc extends Component { | ||||||
|  |   componentDidUpdate() { | ||||||
|  |     console.log(this.props.autosave); | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|   render() { |   render() { | ||||||
|     return ( |     return ( | ||||||
|       <div style={{ width: 'max-content', display: 'flex' }}> |       <div | ||||||
| 
 |         style={{ width: "max-content", display: "flex", alignItems: "center" }} | ||||||
|         {!this.props.assessment ? |       > | ||||||
|  |         {!this.props.assessment & !this.props.multiple ? <AutoSave /> : null} | ||||||
|  |         {!this.props.assessment ? ( | ||||||
|           <WorkspaceName |           <WorkspaceName | ||||||
|             style={{ marginRight: '5px' }} |             style={{ marginRight: "5px" }} | ||||||
|             multiple={this.props.multiple} |             multiple={this.props.multiple} | ||||||
|             project={this.props.project} |             project={this.props.project} | ||||||
|             projectType={this.props.projectType} |             projectType={this.props.projectType} | ||||||
|           /> |           /> | ||||||
|           : null} |         ) : null} | ||||||
| 
 | 
 | ||||||
|         {this.props.assessment ? |         {this.props.assessment ? ( | ||||||
|           <SolutionCheck /> |           <SolutionCheck /> | ||||||
|           : !this.props.multiple ? |         ) : !this.props.multiple ? ( | ||||||
|           <Compile iconButton /> |           <Compile iconButton /> | ||||||
|             : null} |         ) : null} | ||||||
| 
 | 
 | ||||||
|         {!this.props.multiple ? |         {!this.props.multiple ? <CopyCode iconButton /> : null} | ||||||
|           <CopyCode iconButton /> |  | ||||||
|           : null} |  | ||||||
| 
 | 
 | ||||||
| 
 |         {this.props.user && !this.props.multiple ? ( | ||||||
|         {this.props.user && !this.props.multiple ? |  | ||||||
|           <SaveProject |           <SaveProject | ||||||
|             style={{ marginRight: '5px' }} |             style={{ marginRight: "5px" }} | ||||||
|             projectType={this.props.projectType} |             projectType={this.props.projectType} | ||||||
|             project={this.props.project} |             project={this.props.project} | ||||||
|           /> |           /> | ||||||
|           : null} |         ) : null} | ||||||
| 
 | 
 | ||||||
|         {!this.props.multiple ? |         {!this.props.multiple ? ( | ||||||
|           <DownloadProject style={{ marginRight: '5px' }} /> |           <DownloadProject style={{ marginRight: "5px" }} /> | ||||||
|           : null} |         ) : null} | ||||||
| 
 | 
 | ||||||
| 
 |         {!this.props.assessment && !this.props.multiple ? ( | ||||||
|         {!this.props.assessment && !this.props.multiple ? |  | ||||||
|           <OpenProject |           <OpenProject | ||||||
|             style={{ marginRight: '5px' }} |             style={{ marginRight: "5px" }} | ||||||
|             assessment={this.props.assessment} |             assessment={this.props.assessment} | ||||||
|           /> |           /> | ||||||
|           : null} |         ) : null} | ||||||
| 
 | 
 | ||||||
|         {!this.props.assessment && !this.props.multiple ? |         {!this.props.assessment && !this.props.multiple ? ( | ||||||
|           <Screenshot style={{ marginRight: '5px' }} /> |           <Screenshot style={{ marginRight: "5px" }} /> | ||||||
|           : null} |         ) : null} | ||||||
| 
 | 
 | ||||||
|         {this.props.projectType !== 'gallery' && !this.props.assessment ? |         {this.props.projectType !== "gallery" && !this.props.assessment ? ( | ||||||
|           <ShareProject |           <ShareProject | ||||||
|             style={{ marginRight: '5px' }} |             style={{ marginRight: "5px" }} | ||||||
|             multiple={this.props.multiple} |             multiple={this.props.multiple} | ||||||
|             project={this.props.project} |             project={this.props.project} | ||||||
|             projectType={this.props.projectType} |             projectType={this.props.projectType} | ||||||
|           /> |           /> | ||||||
|           : null} |         ) : null} | ||||||
| 
 | 
 | ||||||
|         {!this.props.multiple ? |         {!this.props.multiple ? ( | ||||||
|           <ResetWorkspace style={this.props.projectType === 'project' || this.props.projectType === 'gallery' ? { marginRight: '5px' } : null} |           <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 |           <DeleteProject | ||||||
|             project={this.props.project} |             project={this.props.project} | ||||||
|             projectType={this.props.projectType} |             projectType={this.props.projectType} | ||||||
|           /> |           /> | ||||||
|           : null} |         ) : null} | ||||||
| 
 |  | ||||||
|       </div> |       </div> | ||||||
|     ); |     ); | ||||||
|   }; |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| WorkspaceFunc.propTypes = { | WorkspaceFunc.propTypes = { | ||||||
|   user: PropTypes.object |   user: PropTypes.object, | ||||||
|  |   autosave: PropTypes.bool.isRequired, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const mapStateToProps = state => ({ | const mapStateToProps = (state) => ({ | ||||||
|   user: state.auth.user |   user: state.auth.user, | ||||||
|  |   autosave: state.workspace.autosave, | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| export default connect(mapStateToProps, null)(WorkspaceFunc); | export default connect(mapStateToProps, null)(WorkspaceFunc); | ||||||
|  | |||||||
| @ -1,51 +1,50 @@ | |||||||
| import React, { Component } from 'react'; | import React, { Component } from "react"; | ||||||
| import PropTypes from 'prop-types'; | import PropTypes from "prop-types"; | ||||||
| import { connect } from 'react-redux'; | import { connect } from "react-redux"; | ||||||
| import { workspaceName } from '../../actions/workspaceActions'; | import { workspaceName } from "../../actions/workspaceActions"; | ||||||
| import { setDescription, updateProject } from '../../actions/projectActions'; | import { setDescription, updateProject } from "../../actions/projectActions"; | ||||||
| 
 | 
 | ||||||
| import Snackbar from '../Snackbar'; | import Snackbar from "../Snackbar"; | ||||||
| import Dialog from '../Dialog'; | import Dialog from "../Dialog"; | ||||||
| 
 | 
 | ||||||
| import withWidth, { isWidthDown } from '@material-ui/core/withWidth'; | import withWidth, { isWidthDown } from "@material-ui/core/withWidth"; | ||||||
| import { withStyles } from '@material-ui/core/styles'; | import { withStyles } from "@material-ui/core/styles"; | ||||||
| import Button from '@material-ui/core/Button'; | import Button from "@material-ui/core/Button"; | ||||||
| import Tooltip from '@material-ui/core/Tooltip'; | import Tooltip from "@material-ui/core/Tooltip"; | ||||||
| import TextField from '@material-ui/core/TextField'; | import TextField from "@material-ui/core/TextField"; | ||||||
| import Typography from '@material-ui/core/Typography'; | import Typography from "@material-ui/core/Typography"; | ||||||
| 
 | 
 | ||||||
| import { faPen } from "@fortawesome/free-solid-svg-icons"; | import { faPen } from "@fortawesome/free-solid-svg-icons"; | ||||||
| import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | ||||||
| import * as Blockly from 'blockly/core' | import * as Blockly from "blockly/core"; | ||||||
| 
 | 
 | ||||||
| const styles = (theme) => ({ | const styles = (theme) => ({ | ||||||
|   workspaceName: { |   workspaceName: { | ||||||
|  |     minHeight: "40px", | ||||||
|     backgroundColor: theme.palette.secondary.main, |     backgroundColor: theme.palette.secondary.main, | ||||||
|     borderRadius: '25px', |     borderRadius: "25px", | ||||||
|     display: 'inline-flex', |     display: "inline-flex", | ||||||
|     cursor: 'pointer', |     cursor: "pointer", | ||||||
|     '&:hover': { |     "&:hover": { | ||||||
|       color: theme.palette.primary.main, |       color: theme.palette.primary.main, | ||||||
|     } |     }, | ||||||
|   } |   }, | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| class WorkspaceName extends Component { | class WorkspaceName extends Component { | ||||||
| 
 |  | ||||||
|   constructor(props) { |   constructor(props) { | ||||||
|     super(props); |     super(props); | ||||||
|     this.inputRef = React.createRef(); |     this.inputRef = React.createRef(); | ||||||
|     this.state = { |     this.state = { | ||||||
|       title: '', |       title: "", | ||||||
|       content: '', |       content: "", | ||||||
|       open: false, |       open: false, | ||||||
|       name: props.name, |       name: props.name, | ||||||
|       description: props.description, |       description: props.description, | ||||||
|       snackbar: false, |       snackbar: false, | ||||||
|       type: '', |       type: "", | ||||||
|       key: '', |       key: "", | ||||||
|       message: '' |       message: "", | ||||||
|     }; |     }; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -59,47 +58,100 @@ class WorkspaceName extends Component { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   toggleDialog = () => { |   toggleDialog = () => { | ||||||
|     this.setState({ open: !this.state, title: '', content: '' }); |     this.setState({ open: !this.state, title: "", content: "" }); | ||||||
|   } |   }; | ||||||
| 
 | 
 | ||||||
|   setFileName = (e) => { |   setFileName = (e) => { | ||||||
|     this.setState({ name: e.target.value }); |     this.setState({ name: e.target.value }); | ||||||
|   } |   }; | ||||||
| 
 | 
 | ||||||
|   setDescription = (e) => { |   setDescription = (e) => { | ||||||
|     this.setState({ description: e.target.value }); |     this.setState({ description: e.target.value }); | ||||||
|   } |   }; | ||||||
| 
 | 
 | ||||||
|   renameWorkspace = () => { |   renameWorkspace = () => { | ||||||
|     this.props.workspaceName(this.state.name); |     this.props.workspaceName(this.state.name); | ||||||
|     this.toggleDialog(); |     this.toggleDialog(); | ||||||
|     if (this.props.projectType === 'project' || this.props.projectType === 'gallery' || this.state.projectType === 'gallery') { |     if ( | ||||||
|       if (this.props.projectType === 'gallery' || this.state.projectType === 'gallery') { |       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); |         this.props.setDescription(this.state.description); | ||||||
|       } |       } | ||||||
|       if (this.state.projectType === 'gallery') { |       if (this.state.projectType === "gallery") { | ||||||
|         this.saveGallery(); |         this.saveGallery(); | ||||||
|       } else { |       } else { | ||||||
|         this.props.updateProject(this.props.projectType, this.props.project._id); |         this.props.updateProject( | ||||||
|  |           this.props.projectType, | ||||||
|  |           this.props.project._id | ||||||
|  |         ); | ||||||
|       } |       } | ||||||
|     } else { |     } 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() { |   render() { | ||||||
|     return ( |     return ( | ||||||
|       <div style={this.props.style}> |       <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 |           <div | ||||||
|             className={this.props.classes.workspaceName} |             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) ? |             {this.props.name && | ||||||
|               <Typography style={{ margin: 'auto -3px auto 12px' }}>{this.props.name}</Typography> |             !isWidthDown( | ||||||
|               : null} |               this.props.projectType === "project" || | ||||||
|             <div style={{ width: '40px', display: 'flex' }}> |                 this.props.projectType === "gallery" | ||||||
|               <FontAwesomeIcon icon={faPen} style={{ height: '18px', width: '18px', margin: 'auto' }} /> |                 ? "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> | ||||||
|           </div> |           </div> | ||||||
|         </Tooltip> |         </Tooltip> | ||||||
| @ -114,23 +166,69 @@ class WorkspaceName extends Component { | |||||||
|           open={this.state.open} |           open={this.state.open} | ||||||
|           title={this.state.title} |           title={this.state.title} | ||||||
|           content={this.state.content} |           content={this.state.content} | ||||||
|           onClose={() => { this.toggleDialog(); this.setState({ name: this.props.name, description: this.props.description }); }} |           onClose={() => { | ||||||
|           onClick={() => { this.toggleDialog(); this.setState({ name: this.props.name, description: this.props.description }); }} |             this.toggleDialog(); | ||||||
|           button={'Abbrechen'} |             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' }}> |           <div style={{ marginTop: "10px" }}> | ||||||
|             {this.props.projectType === 'gallery' || this.state.projectType === 'gallery' ? |             {this.props.projectType === "gallery" || | ||||||
|  |             this.state.projectType === "gallery" ? ( | ||||||
|               <div> |               <div> | ||||||
|                 <TextField autoFocus placeholder={this.state.saveXml ? 'Dateiname' : 'Projekttitel'} value={this.state.name} onChange={this.setFileName} style={{ marginBottom: '10px' }} /> |                 <TextField | ||||||
|                 <TextField fullWidth multiline placeholder={'Projektbeschreibung'} value={this.state.description} onChange={this.setDescription} style={{ marginBottom: '10px' }} /> |                   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> |               </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> |           </div> | ||||||
|         </Dialog> |         </Dialog> | ||||||
|       </div> |       </div> | ||||||
|     ); |     ); | ||||||
|   }; |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| WorkspaceName.propTypes = { | WorkspaceName.propTypes = { | ||||||
| @ -142,10 +240,14 @@ WorkspaceName.propTypes = { | |||||||
|   message: PropTypes.object.isRequired, |   message: PropTypes.object.isRequired, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const mapStateToProps = state => ({ | const mapStateToProps = (state) => ({ | ||||||
|   name: state.workspace.name, |   name: state.workspace.name, | ||||||
|   description: state.project.description, |   description: state.project.description, | ||||||
|   message: state.message, |   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" |     "prop-types" "^15.7.2" | ||||||
|     "react-is" "^16.8.0" |     "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": | "@nodelib/fs.scandir@2.1.4": | ||||||
|   "integrity" "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==" |   "integrity" "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==" | ||||||
|   "resolved" "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz" |   "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" |   "resolved" "https://registry.npmjs.org/moment/-/moment-2.29.0.tgz" | ||||||
|   "version" "2.29.0" |   "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": | "move-concurrently@^1.0.1": | ||||||
|   "integrity" "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=" |   "integrity" "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=" | ||||||
|   "resolved" "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz" |   "resolved" "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz" | ||||||
| @ -10032,7 +10052,7 @@ | |||||||
|     "strip-ansi" "6.0.0" |     "strip-ansi" "6.0.0" | ||||||
|     "text-table" "0.2.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==" |   "integrity" "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==" | ||||||
|   "resolved" "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz" |   "resolved" "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz" | ||||||
|   "version" "17.0.2" |   "version" "17.0.2" | ||||||
| @ -10211,7 +10231,7 @@ | |||||||
|     "loose-envify" "^1.4.0" |     "loose-envify" "^1.4.0" | ||||||
|     "prop-types" "^15.6.2" |     "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==" |   "integrity" "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==" | ||||||
|   "resolved" "https://registry.npmjs.org/react/-/react-17.0.2.tgz" |   "resolved" "https://registry.npmjs.org/react/-/react-17.0.2.tgz" | ||||||
|   "version" "17.0.2" |   "version" "17.0.2" | ||||||
| @ -11408,6 +11428,11 @@ | |||||||
|   "resolved" "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz" |   "resolved" "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz" | ||||||
|   "version" "1.2.0" |   "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": | "static-extend@^0.1.1": | ||||||
|   "integrity" "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=" |   "integrity" "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=" | ||||||
|   "resolved" "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz" |   "resolved" "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz" | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user