Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0388e5c627 | ||
|
|
9c33bc4c0d | ||
|
|
32372bc222 | ||
|
|
dbc7fdc7ab |
@@ -2,7 +2,5 @@ REACT_APP_COMPILER_URL=https://compiler.sensebox.de
|
|||||||
REACT_APP_BOARD=sensebox-mcu
|
REACT_APP_BOARD=sensebox-mcu
|
||||||
REACT_APP_BLOCKLY_API=https://api.blockly.sensebox.de
|
REACT_APP_BLOCKLY_API=https://api.blockly.sensebox.de
|
||||||
|
|
||||||
GENERATE_SOURCEMAP=false
|
|
||||||
|
|
||||||
# in days
|
# in days
|
||||||
REACT_APP_SHARE_LINK_EXPIRES=30
|
REACT_APP_SHARE_LINK_EXPIRES=30
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Create a report to help us improve
|
|
||||||
title: ''
|
|
||||||
labels: ''
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Describe the bug**
|
|
||||||
A clear and concise description of what the bug is.
|
|
||||||
|
|
||||||
**To Reproduce**
|
|
||||||
Steps to reproduce the behavior:
|
|
||||||
1. Go to '...'
|
|
||||||
2. Click on '....'
|
|
||||||
3. Scroll down to '....'
|
|
||||||
4. See error
|
|
||||||
|
|
||||||
**Expected behavior**
|
|
||||||
A clear and concise description of what you expected to happen.
|
|
||||||
|
|
||||||
**Screenshots**
|
|
||||||
If applicable, add screenshots to help explain your problem.
|
|
||||||
|
|
||||||
**Desktop (please complete the following information):**
|
|
||||||
- OS: [e.g. iOS]
|
|
||||||
- Browser [e.g. chrome, safari]
|
|
||||||
- Version [e.g. 22]
|
|
||||||
|
|
||||||
**Smartphone (please complete the following information):**
|
|
||||||
- Device: [e.g. iPhone6]
|
|
||||||
- OS: [e.g. iOS8.1]
|
|
||||||
- Browser [e.g. stock browser, safari]
|
|
||||||
- Version [e.g. 22]
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context about the problem here.
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature request
|
|
||||||
about: Suggest an idea for this project
|
|
||||||
title: ''
|
|
||||||
labels: ''
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Is your feature request related to a problem? Please describe.**
|
|
||||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
|
||||||
|
|
||||||
**Describe the solution you'd like**
|
|
||||||
A clear and concise description of what you want to happen.
|
|
||||||
|
|
||||||
**Describe alternatives you've considered**
|
|
||||||
A clear and concise description of any alternative solutions or features you've considered.
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context or screenshots about the feature request here.
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
---
|
|
||||||
name: Short Issue
|
|
||||||
about: Template for Short Issues
|
|
||||||
title: ''
|
|
||||||
labels: ''
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Current behaviour
|
|
||||||
Describe the current behaviour
|
|
||||||
|
|
||||||
### Expected behaviour
|
|
||||||
Describe how it is supposed to work
|
|
||||||
+1
-1
@@ -22,4 +22,4 @@ npm-debug.log*
|
|||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
package-lock.json
|
||||||
|
|||||||
Generated
+44160
File diff suppressed because it is too large
Load Diff
+34
-40
@@ -1,58 +1,45 @@
|
|||||||
{
|
{
|
||||||
"name": "blockly-react",
|
"name": "blockly-react",
|
||||||
"version": "1.0.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blockly/block-plus-minus": "^3.0.5",
|
"@blockly/block-plus-minus": "^2.0.10",
|
||||||
"@blockly/field-grid-dropdown": "^1.0.31",
|
"@blockly/field-grid-dropdown": "^1.0.25",
|
||||||
"@blockly/field-slider": "^3.0.5",
|
"@blockly/field-slider": "^2.1.1",
|
||||||
"@blockly/plugin-scroll-options": "^2.0.5",
|
"@blockly/plugin-scroll-options": "^1.0.2",
|
||||||
"@blockly/plugin-typed-variable-modal": "^4.0.5",
|
"@blockly/plugin-typed-variable-modal": "^3.1.26",
|
||||||
"@blockly/workspace-backpack": "^2.0.12",
|
"@blockly/zoom-to-fit": "^2.0.7",
|
||||||
"@blockly/zoom-to-fit": "^2.0.14",
|
"@fortawesome/fontawesome-svg-core": "^1.2.30",
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.36",
|
"@fortawesome/free-solid-svg-icons": "^5.14.0",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
"@fortawesome/react-fontawesome": "^0.1.11",
|
||||||
"@fortawesome/react-fontawesome": "^0.1.19",
|
"@material-ui/core": "^4.11.0",
|
||||||
"@material-ui/core": "^4.12.4",
|
"@sentry/react": "^6.0.0",
|
||||||
"@monaco-editor/react": "^4.3.1",
|
"@sentry/tracing": "^6.0.0",
|
||||||
"@testing-library/jest-dom": "^5.16.1",
|
"@testing-library/jest-dom": "^5.16.1",
|
||||||
"@testing-library/react": "^12.1.2",
|
"@testing-library/react": "^12.1.2",
|
||||||
"@testing-library/user-event": "^7.2.1",
|
"@testing-library/user-event": "^7.2.1",
|
||||||
"axios": "^0.22.0",
|
"axios": "^0.22.0",
|
||||||
"blockly": "^8.0.3",
|
"blockly": "^6.20210701.0",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.2",
|
||||||
"markdown-it": "^12.3.2",
|
|
||||||
"mnemonic-id": "^3.2.7",
|
"mnemonic-id": "^3.2.7",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.28.0",
|
||||||
"prismjs": "^1.27.0",
|
"prismjs": "^1.27.0",
|
||||||
"qrcode.react": "^3.1.0",
|
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-cookie-consent": "^7.2.1",
|
"react-cookie-consent": "^7.0.0",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-markdown": "^8.0.0",
|
"react-markdown": "^5.0.2",
|
||||||
"react-markdown-editor-lite": "^1.3.3",
|
|
||||||
"react-mde": "^11.5.0",
|
"react-mde": "^11.5.0",
|
||||||
"react-rating-stars-component": "^2.2.0",
|
"react-redux": "^7.2.4",
|
||||||
"react-redux": "^7.2.9",
|
"react-router-dom": "^5.2.0",
|
||||||
"react-router-dom": "^5.3.3",
|
"react-scripts": "^4.0.3",
|
||||||
"react-scripts": "^5.0.0",
|
"reactour": "^1.18.0",
|
||||||
"react-share": "^4.4.0",
|
"redux": "^4.0.5",
|
||||||
"react-spinners": "^0.13.3",
|
"redux-thunk": "^2.3.0",
|
||||||
"reactour": "^1.18.7",
|
|
||||||
"redux": "^4.2.0",
|
|
||||||
"redux-thunk": "^2.4.1",
|
|
||||||
"remark-gemoji": "^7.0.1",
|
|
||||||
"remark-gfm": "^3.0.1",
|
|
||||||
"styled-components": "^4.4.1",
|
"styled-components": "^4.4.1",
|
||||||
"uuid": "^8.3.1",
|
"uuid": "^8.3.1"
|
||||||
"watchpack": "^2.3.1"
|
|
||||||
},
|
|
||||||
"resolutions": {
|
|
||||||
"//": "See https://github.com/facebook/create-react-app/issues/11773",
|
|
||||||
"react-error-overlay": "6.0.9"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node_modules/react-scripts/bin/react-scripts.js start",
|
"start": "react-scripts start",
|
||||||
"dev": "set \"REACT_APP_BLOCKLY_API=http://localhost:8080\" && npm start",
|
"dev": "set \"REACT_APP_BLOCKLY_API=http://localhost:8080\" && npm start",
|
||||||
"build": "react-scripts build",
|
"build": "react-scripts build",
|
||||||
"test": "react-scripts test",
|
"test": "react-scripts test",
|
||||||
@@ -61,9 +48,16 @@
|
|||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": "react-app"
|
"extends": "react-app"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": {
|
||||||
|
"production": [
|
||||||
">0.2%",
|
">0.2%",
|
||||||
"not dead",
|
"not dead",
|
||||||
"not op_mini all"
|
"not op_mini all"
|
||||||
|
],
|
||||||
|
"development": [
|
||||||
|
"last 1 chrome version",
|
||||||
|
"last 1 firefox version",
|
||||||
|
"last 1 safari version"
|
||||||
]
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 122 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 777 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 728 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 343 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 77 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 79 KiB |
+15
-28
@@ -1,64 +1,51 @@
|
|||||||
.wrapper {
|
.wrapper {
|
||||||
min-height: calc(
|
min-height: calc(100vh - 60px); /* will cover the 100% of viewport - height of footer (padding-bottom) */
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
.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;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tutorial blockquote {
|
.tutorial blockquote{
|
||||||
background: #f9f9f9;
|
background: #f9f9f9;
|
||||||
border-left: 10px solid#4EAF47;
|
border-left: 10px solid#4EAF47;
|
||||||
margin: 1.5em 10px;
|
margin: 1.5em 10px;
|
||||||
padding: 0.5em 10px;
|
padding: 0.5em 10px;
|
||||||
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;
|
||||||
margin-right: 0.25em;
|
margin-right: 0.25em;
|
||||||
vertical-align: -0.4em;
|
vertical-align: -0.4em;
|
||||||
}
|
}
|
||||||
blockquote p {
|
blockquote p {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tutorial table,
|
|
||||||
th,
|
|
||||||
td {
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tutorial th {
|
|
||||||
padding-top: 12px;
|
|
||||||
padding-bottom: 12px;
|
|
||||||
text-align: left;
|
|
||||||
background-color: #4eaf47;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.overlay {
|
.overlay {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+16
-15
@@ -1,34 +1,35 @@
|
|||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
import { Router } from "react-router-dom";
|
import { BrowserRouter as Router } from 'react-router-dom';
|
||||||
import { createBrowserHistory } from "history";
|
import { createBrowserHistory } from "history";
|
||||||
|
|
||||||
import { Provider } from "react-redux";
|
import { Provider } from 'react-redux';
|
||||||
import store from "./store";
|
import store from './store';
|
||||||
import { loadUser } from "./actions/authActions";
|
import { loadUser } from './actions/authActions';
|
||||||
|
|
||||||
import "./App.css";
|
import './App.css';
|
||||||
|
|
||||||
import { ThemeProvider, createTheme } from "@material-ui/core/styles";
|
import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles';
|
||||||
|
|
||||||
import Content from "./components/Content";
|
import Content from './components/Content';
|
||||||
|
|
||||||
const theme = createTheme({
|
const theme = createMuiTheme({
|
||||||
palette: {
|
palette: {
|
||||||
primary: {
|
primary: {
|
||||||
main: "#4EAF47",
|
main: '#4EAF47',
|
||||||
contrastText: "#ffffff",
|
contrastText: '#ffffff'
|
||||||
},
|
},
|
||||||
secondary: {
|
secondary: {
|
||||||
main: "#DDDDDD",
|
main: '#DDDDDD'
|
||||||
},
|
},
|
||||||
button: {
|
button: {
|
||||||
compile: "#e27136",
|
compile: '#e27136'
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
class App extends Component {
|
class App extends Component {
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
store.dispatch(loadUser());
|
store.dispatch(loadUser());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,6 +63,9 @@ export const loadUser = () => (dispatch) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var logoutTimerId;
|
||||||
|
const timeToLogout = 14.9 * 60 * 1000; // nearly 15 minutes corresponding to the API
|
||||||
|
|
||||||
// Login user
|
// Login user
|
||||||
export const login =
|
export const login =
|
||||||
({ email, password }) =>
|
({ email, password }) =>
|
||||||
@@ -81,6 +84,10 @@ export const login =
|
|||||||
axios
|
axios
|
||||||
.post(`${process.env.REACT_APP_BLOCKLY_API}/user`, body, config)
|
.post(`${process.env.REACT_APP_BLOCKLY_API}/user`, body, config)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
|
// Logout automatically if refreshToken "expired"
|
||||||
|
const logoutTimer = () =>
|
||||||
|
setTimeout(() => dispatch(logout()), timeToLogout);
|
||||||
|
logoutTimerId = logoutTimer();
|
||||||
dispatch(setLanguage(res.data.user.language));
|
dispatch(setLanguage(res.data.user.language));
|
||||||
dispatch({
|
dispatch({
|
||||||
type: LOGIN_SUCCESS,
|
type: LOGIN_SUCCESS,
|
||||||
@@ -137,6 +144,7 @@ export const logout = () => (dispatch) => {
|
|||||||
}
|
}
|
||||||
dispatch(setLanguage(locale));
|
dispatch(setLanguage(locale));
|
||||||
dispatch(returnSuccess(res.data.message, res.status, "LOGOUT_SUCCESS"));
|
dispatch(returnSuccess(res.data.message, res.status, "LOGOUT_SUCCESS"));
|
||||||
|
clearTimeout(logoutTimerId);
|
||||||
},
|
},
|
||||||
error: (err) => {
|
error: (err) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
@@ -157,6 +165,7 @@ export const logout = () => (dispatch) => {
|
|||||||
type: GET_STATUS,
|
type: GET_STATUS,
|
||||||
payload: status,
|
payload: status,
|
||||||
});
|
});
|
||||||
|
clearTimeout(logoutTimerId);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
axios
|
axios
|
||||||
@@ -213,6 +222,10 @@ export const authInterceptor = () => (dispatch, getState) => {
|
|||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
|
clearTimeout(logoutTimerId);
|
||||||
|
const logoutTimer = () =>
|
||||||
|
setTimeout(() => dispatch(logout()), timeToLogout);
|
||||||
|
logoutTimerId = logoutTimer();
|
||||||
dispatch({
|
dispatch({
|
||||||
type: REFRESH_TOKEN_SUCCESS,
|
type: REFRESH_TOKEN_SUCCESS,
|
||||||
payload: res.data,
|
payload: res.data,
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
import {
|
|
||||||
BOARD,
|
|
||||||
} from "./types";
|
|
||||||
|
|
||||||
export const setBoard = (board) => (dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: BOARD,
|
|
||||||
payload: board,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -84,77 +84,6 @@ export const getTutorials = () => (dispatch, getState) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getAllTutorials = () => (dispatch, getState) => {
|
|
||||||
axios
|
|
||||||
.get(`${process.env.REACT_APP_BLOCKLY_API}/tutorial/getAllTutorials`)
|
|
||||||
.then((res) => {
|
|
||||||
var tutorials = res.data.tutorials;
|
|
||||||
existingTutorials(tutorials, getState().tutorial.status).then(
|
|
||||||
(status) => {
|
|
||||||
dispatch({
|
|
||||||
type: TUTORIAL_SUCCESS,
|
|
||||||
payload: status,
|
|
||||||
});
|
|
||||||
dispatch(updateStatus(status));
|
|
||||||
dispatch({
|
|
||||||
type: GET_TUTORIALS,
|
|
||||||
payload: tutorials,
|
|
||||||
});
|
|
||||||
dispatch({ type: TUTORIAL_PROGRESS });
|
|
||||||
dispatch(returnSuccess(res.data.message, res.status));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
if (err.response) {
|
|
||||||
dispatch(
|
|
||||||
returnErrors(
|
|
||||||
err.response.data.message,
|
|
||||||
err.response.status,
|
|
||||||
"GET_TUTORIALS_FAIL"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
dispatch({ type: TUTORIAL_PROGRESS });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getUserTutorials = () => (dispatch, getState) => {
|
|
||||||
axios
|
|
||||||
.get(`${process.env.REACT_APP_BLOCKLY_API}/tutorial/getUserTutorials`)
|
|
||||||
.then((res) => {
|
|
||||||
var tutorials = res.data.tutorials;
|
|
||||||
existingTutorials(tutorials, getState().tutorial.status).then(
|
|
||||||
(status) => {
|
|
||||||
dispatch({
|
|
||||||
type: TUTORIAL_SUCCESS,
|
|
||||||
payload: status,
|
|
||||||
});
|
|
||||||
dispatch(updateStatus(status));
|
|
||||||
dispatch({
|
|
||||||
type: GET_TUTORIALS,
|
|
||||||
payload: tutorials,
|
|
||||||
});
|
|
||||||
dispatch({ type: TUTORIAL_PROGRESS });
|
|
||||||
dispatch(returnSuccess(res.data.message, res.status));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err);
|
|
||||||
if (err.response) {
|
|
||||||
dispatch(
|
|
||||||
returnErrors(
|
|
||||||
err.response.data.message,
|
|
||||||
err.response.status,
|
|
||||||
"GET_TUTORIALS_FAIL"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
dispatch({ type: TUTORIAL_PROGRESS });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updateStatus = (status) => (dispatch, getState) => {
|
export const updateStatus = (status) => (dispatch, getState) => {
|
||||||
if (getState().auth.isAuthenticated) {
|
if (getState().auth.isAuthenticated) {
|
||||||
// update user account in database - sync with redux store
|
// update user account in database - sync with redux store
|
||||||
|
|||||||
@@ -4,9 +4,6 @@ import {
|
|||||||
BUILDER_CHANGE,
|
BUILDER_CHANGE,
|
||||||
BUILDER_ERROR,
|
BUILDER_ERROR,
|
||||||
BUILDER_TITLE,
|
BUILDER_TITLE,
|
||||||
BUILDER_PUBLIC,
|
|
||||||
BUILDER_DIFFICULTY,
|
|
||||||
BUILDER_REVIEW,
|
|
||||||
BUILDER_ID,
|
BUILDER_ID,
|
||||||
BUILDER_ADD_STEP,
|
BUILDER_ADD_STEP,
|
||||||
BUILDER_DELETE_STEP,
|
BUILDER_DELETE_STEP,
|
||||||
@@ -38,30 +35,6 @@ export const tutorialTitle = (title) => (dispatch) => {
|
|||||||
dispatch(changeTutorialBuilder());
|
dispatch(changeTutorialBuilder());
|
||||||
};
|
};
|
||||||
|
|
||||||
export const tutorialPublic = (pub) => (dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: BUILDER_PUBLIC,
|
|
||||||
payload: pub,
|
|
||||||
});
|
|
||||||
dispatch(changeTutorialBuilder());
|
|
||||||
};
|
|
||||||
|
|
||||||
export const tutorialDifficulty = (difficulty) => (dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: BUILDER_DIFFICULTY,
|
|
||||||
payload: difficulty,
|
|
||||||
});
|
|
||||||
dispatch(changeTutorialBuilder());
|
|
||||||
};
|
|
||||||
|
|
||||||
export const tutorialReview = (review) => (dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: BUILDER_REVIEW,
|
|
||||||
payload: review,
|
|
||||||
});
|
|
||||||
dispatch(changeTutorialBuilder());
|
|
||||||
};
|
|
||||||
|
|
||||||
export const tutorialSteps = (steps) => (dispatch) => {
|
export const tutorialSteps = (steps) => (dispatch) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: BUILDER_ADD_STEP,
|
type: BUILDER_ADD_STEP,
|
||||||
@@ -347,7 +320,6 @@ export const readJSON = (json) => (dispatch, getState) => {
|
|||||||
return object;
|
return object;
|
||||||
});
|
});
|
||||||
dispatch(tutorialTitle(json.title));
|
dispatch(tutorialTitle(json.title));
|
||||||
dispatch(tutorialDifficulty(json.difficulty));
|
|
||||||
dispatch(tutorialSteps(steps));
|
dispatch(tutorialSteps(steps));
|
||||||
dispatch(setSubmitError());
|
dispatch(setSubmitError());
|
||||||
dispatch(progress(false));
|
dispatch(progress(false));
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ export const NAME = "NAME";
|
|||||||
export const TUTORIAL_PROGRESS = "TUTORIAL_PROGRESS";
|
export const TUTORIAL_PROGRESS = "TUTORIAL_PROGRESS";
|
||||||
export const GET_TUTORIAL = "GET_TUTORIAL";
|
export const GET_TUTORIAL = "GET_TUTORIAL";
|
||||||
export const GET_TUTORIALS = "GET_TUTORIALS";
|
export const GET_TUTORIALS = "GET_TUTORIALS";
|
||||||
export const GET_USERTUTORIALS = "GET_USERTUTORIALS";
|
|
||||||
export const GET_STATUS = "GET_STATUS";
|
export const GET_STATUS = "GET_STATUS";
|
||||||
export const TUTORIAL_SUCCESS = "TUTORIAL_SUCCESS";
|
export const TUTORIAL_SUCCESS = "TUTORIAL_SUCCESS";
|
||||||
export const TUTORIAL_ERROR = "TUTORIAL_ERROR";
|
export const TUTORIAL_ERROR = "TUTORIAL_ERROR";
|
||||||
@@ -33,9 +32,6 @@ export const JSON_STRING = "JSON_STRING";
|
|||||||
|
|
||||||
export const BUILDER_CHANGE = "BUILDER_CHANGE";
|
export const BUILDER_CHANGE = "BUILDER_CHANGE";
|
||||||
export const BUILDER_TITLE = "BUILDER_TITLE";
|
export const BUILDER_TITLE = "BUILDER_TITLE";
|
||||||
export const BUILDER_DIFFICULTY = "BUILDER_DIFFICULTY";
|
|
||||||
export const BUILDER_PUBLIC = "BUILDER_PUBLIC";
|
|
||||||
export const BUILDER_REVIEW = "BUILDER_REVIEW";
|
|
||||||
export const BUILDER_ID = "BUILDER_ID";
|
export const BUILDER_ID = "BUILDER_ID";
|
||||||
export const BUILDER_ADD_STEP = "BUILDER_ADD_STEP";
|
export const BUILDER_ADD_STEP = "BUILDER_ADD_STEP";
|
||||||
export const BUILDER_DELETE_STEP = "BUILDER_DELETE_STEP";
|
export const BUILDER_DELETE_STEP = "BUILDER_DELETE_STEP";
|
||||||
@@ -63,6 +59,3 @@ export const GET_PROJECT = "GET_PROJECT";
|
|||||||
export const GET_PROJECTS = "GET_PROJECTS";
|
export const GET_PROJECTS = "GET_PROJECTS";
|
||||||
export const PROJECT_TYPE = "PROJECT_TYPE";
|
export const PROJECT_TYPE = "PROJECT_TYPE";
|
||||||
export const PROJECT_DESCRIPTION = "PROJECT_DESCRIPTION";
|
export const PROJECT_DESCRIPTION = "PROJECT_DESCRIPTION";
|
||||||
|
|
||||||
//board
|
|
||||||
export const BOARD = "BOARD";
|
|
||||||
|
|||||||
+18
-13
@@ -1,29 +1,34 @@
|
|||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
import { withStyles } from "@material-ui/core/styles";
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import { alpha } from "@material-ui/core/styles";
|
import { fade } from '@material-ui/core/styles/colorManipulator';
|
||||||
|
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
|
||||||
const styles = (theme) => ({
|
const styles = (theme) => ({
|
||||||
alert: {
|
alert: {
|
||||||
marginBottom: "20px",
|
marginBottom: '20px',
|
||||||
border: `1px solid ${theme.palette.primary.main}`,
|
border: `1px solid ${theme.palette.primary.main}`,
|
||||||
padding: "10px 20px",
|
padding: '10px 20px',
|
||||||
borderRadius: "4px",
|
borderRadius: '4px',
|
||||||
background: alpha(theme.palette.primary.main, 0.3),
|
background: fade(theme.palette.primary.main, 0.3),
|
||||||
color: "rgb(70,70,70)",
|
color: 'rgb(70,70,70)'
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
export class Alert extends Component {
|
export class Alert extends Component {
|
||||||
render() {
|
|
||||||
return (
|
render(){
|
||||||
|
return(
|
||||||
<div className={this.props.classes.alert}>
|
<div className={this.props.classes.alert}>
|
||||||
<Typography>{this.props.children}</Typography>
|
<Typography>
|
||||||
|
{this.props.children}
|
||||||
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default withStyles(styles, { withTheme: true })(Alert);
|
export default withStyles(styles, { withTheme: true })(Alert);
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import "./generator/index";
|
|||||||
import { ZoomToFitControl } from "@blockly/zoom-to-fit";
|
import { ZoomToFitControl } from "@blockly/zoom-to-fit";
|
||||||
import { initialXml } from "./initialXml.js";
|
import { initialXml } from "./initialXml.js";
|
||||||
import { getMaxInstances } from "./helpers/maxInstances";
|
import { getMaxInstances } from "./helpers/maxInstances";
|
||||||
import { Backpack } from "@blockly/workspace-backpack";
|
|
||||||
|
|
||||||
class BlocklyWindow extends Component {
|
class BlocklyWindow extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -36,23 +35,12 @@ class BlocklyWindow extends Component {
|
|||||||
Blockly.svgResize(workspace);
|
Blockly.svgResize(workspace);
|
||||||
const zoomToFit = new ZoomToFitControl(workspace);
|
const zoomToFit = new ZoomToFitControl(workspace);
|
||||||
zoomToFit.init();
|
zoomToFit.init();
|
||||||
// Initialize plugin.
|
|
||||||
const backpack = new Backpack(workspace);
|
|
||||||
backpack.init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(props) {
|
componentDidUpdate(props) {
|
||||||
const workspace = Blockly.getMainWorkspace();
|
const workspace = Blockly.getMainWorkspace();
|
||||||
var xml = this.props.initialXml;
|
|
||||||
if (props.selectedBoard !== this.props.selectedBoard) {
|
|
||||||
// change board
|
|
||||||
if(!xml) xml = initialXml;
|
|
||||||
var xmlDom = Blockly.Xml.textToDom(xml);
|
|
||||||
Blockly.Xml.clearWorkspaceAndLoadFromXml(xmlDom, workspace);
|
|
||||||
// var toolbox = workspace.getToolbox();
|
|
||||||
// workspace.updateToolbox(toolbox.toolboxDef_);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
var xml = this.props.initialXml;
|
||||||
// if svg is true, then the update process is done in the BlocklySvg component
|
// if svg is true, then the update process is done in the BlocklySvg component
|
||||||
if (props.initialXml !== xml && !this.props.svg) {
|
if (props.initialXml !== xml && !this.props.svg) {
|
||||||
// guarantees that the current xml-code (this.props.initialXml) is rendered
|
// guarantees that the current xml-code (this.props.initialXml) is rendered
|
||||||
@@ -63,7 +51,7 @@ class BlocklyWindow extends Component {
|
|||||||
if (props.language !== this.props.language) {
|
if (props.language !== this.props.language) {
|
||||||
// change language
|
// change language
|
||||||
if (!xml) xml = initialXml;
|
if (!xml) xml = initialXml;
|
||||||
xmlDom = Blockly.Xml.textToDom(xml);
|
var xmlDom = Blockly.Xml.textToDom(xml);
|
||||||
Blockly.Xml.clearWorkspaceAndLoadFromXml(xmlDom, workspace);
|
Blockly.Xml.clearWorkspaceAndLoadFromXml(xmlDom, workspace);
|
||||||
// var toolbox = workspace.getToolbox();
|
// var toolbox = workspace.getToolbox();
|
||||||
// workspace.updateToolbox(toolbox.toolboxDef_);
|
// workspace.updateToolbox(toolbox.toolboxDef_);
|
||||||
@@ -136,16 +124,14 @@ BlocklyWindow.propTypes = {
|
|||||||
onChangeWorkspace: PropTypes.func.isRequired,
|
onChangeWorkspace: PropTypes.func.isRequired,
|
||||||
clearStats: PropTypes.func.isRequired,
|
clearStats: PropTypes.func.isRequired,
|
||||||
renderer: PropTypes.string.isRequired,
|
renderer: PropTypes.string.isRequired,
|
||||||
sounds: PropTypes.bool.isRequired,
|
sounds: PropTypes.string.isRequired,
|
||||||
language: PropTypes.string.isRequired,
|
language: PropTypes.string.isRequired,
|
||||||
selectedBoard: PropTypes.string.isRequired,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = (state) => ({
|
||||||
renderer: state.general.renderer,
|
renderer: state.general.renderer,
|
||||||
sounds: state.general.sounds,
|
sounds: state.general.sounds,
|
||||||
language: state.general.language,
|
language: state.general.language,
|
||||||
selectedBoard: state.board.board,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, { onChangeWorkspace, clearStats })(
|
export default connect(mapStateToProps, { onChangeWorkspace, clearStats })(
|
||||||
|
|||||||
@@ -6,11 +6,9 @@ import "./sensebox-telegram";
|
|||||||
import "./sensebox-osem";
|
import "./sensebox-osem";
|
||||||
import "./sensebox-web";
|
import "./sensebox-web";
|
||||||
import "./sensebox-display";
|
import "./sensebox-display";
|
||||||
import "./sensebox-motors";
|
|
||||||
import "./sensebox-lora";
|
import "./sensebox-lora";
|
||||||
import "./sensebox-led";
|
import "./sensebox-led";
|
||||||
import "./sensebox-rtc";
|
import "./sensebox-rtc";
|
||||||
import "./sensebox-ntp";
|
|
||||||
import "./sensebox-ble";
|
import "./sensebox-ble";
|
||||||
import "./sensebox-sd";
|
import "./sensebox-sd";
|
||||||
import "./mqtt";
|
import "./mqtt";
|
||||||
|
|||||||
@@ -45,11 +45,15 @@ Blockly.Blocks['sensebox_rgb_led'] = {
|
|||||||
|
|
||||||
Blockly.Blocks['sensebox_ws2818_led_init'] = {
|
Blockly.Blocks['sensebox_ws2818_led_init'] = {
|
||||||
init: function () {
|
init: function () {
|
||||||
|
|
||||||
|
var dropdownOptions = [[Blockly.Msg.senseBox_ultrasonic_port_A, '1'],
|
||||||
|
[Blockly.Msg.senseBox_ultrasonic_port_B, '3'], [Blockly.Msg.senseBox_ultrasonic_port_C, '5']];
|
||||||
|
|
||||||
this.setColour(getColour().sensebox);
|
this.setColour(getColour().sensebox);
|
||||||
this.appendDummyInput()
|
this.appendDummyInput()
|
||||||
.appendField(Blockly.Msg.senseBox_ws2818_rgb_led_init)
|
.appendField(Blockly.Msg.senseBox_ws2818_rgb_led_init)
|
||||||
.appendField("Port:")
|
.appendField("Port:")
|
||||||
.appendField(new Blockly.FieldDropdown(selectedBoard().digitalPinsRGB), "Port")
|
.appendField(new Blockly.FieldDropdown(dropdownOptions), "Port")
|
||||||
this.appendValueInput("BRIGHTNESS", "brightness")
|
this.appendValueInput("BRIGHTNESS", "brightness")
|
||||||
.appendField((Blockly.Msg.senseBox_ws2818_rgb_led_brightness));
|
.appendField((Blockly.Msg.senseBox_ws2818_rgb_led_brightness));
|
||||||
this.appendValueInput("NUMBER", "number")
|
this.appendValueInput("NUMBER", "number")
|
||||||
@@ -62,11 +66,15 @@ Blockly.Blocks['sensebox_ws2818_led_init'] = {
|
|||||||
|
|
||||||
Blockly.Blocks['sensebox_ws2818_led'] = {
|
Blockly.Blocks['sensebox_ws2818_led'] = {
|
||||||
init: function () {
|
init: function () {
|
||||||
|
|
||||||
|
var dropdownOptions = [[Blockly.Msg.senseBox_ultrasonic_port_A, '1'],
|
||||||
|
[Blockly.Msg.senseBox_ultrasonic_port_B, '3'], [Blockly.Msg.senseBox_ultrasonic_port_C, '5']];
|
||||||
|
|
||||||
this.setColour(getColour().sensebox);
|
this.setColour(getColour().sensebox);
|
||||||
this.appendDummyInput()
|
this.appendDummyInput()
|
||||||
.appendField(Blockly.Msg.senseBox_ws2818_rgb_led)
|
.appendField(Blockly.Msg.senseBox_ws2818_rgb_led)
|
||||||
.appendField("Port:")
|
.appendField("Port:")
|
||||||
.appendField(new Blockly.FieldDropdown(selectedBoard().digitalPinsRGB), "Port")
|
.appendField(new Blockly.FieldDropdown(dropdownOptions), "Port")
|
||||||
this.appendValueInput("POSITION", "position")
|
this.appendValueInput("POSITION", "position")
|
||||||
.appendField((Blockly.Msg.senseBox_ws2818_rgb_led_position));
|
.appendField((Blockly.Msg.senseBox_ws2818_rgb_led_position));
|
||||||
this.appendValueInput("COLOR", 'Number')
|
this.appendValueInput("COLOR", 'Number')
|
||||||
|
|||||||
@@ -1,144 +0,0 @@
|
|||||||
import * as Blockly from "blockly/core";
|
|
||||||
import { getColour } from "../helpers/colour";
|
|
||||||
import { selectedBoard } from "../helpers/board";
|
|
||||||
import { FieldSlider } from "@blockly/field-slider";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Servo Motor
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
Blockly.Blocks["sensebox_motors_beginServoMotor"] = {
|
|
||||||
init: function () {
|
|
||||||
this.appendDummyInput()
|
|
||||||
.appendField(Blockly.Msg.sensebox_motors_beginServoMotor);
|
|
||||||
this.appendDummyInput()
|
|
||||||
.appendField(Blockly.Msg.sensebox_motors_beginServoMotor_pin)
|
|
||||||
.appendField(new Blockly.FieldDropdown(selectedBoard().digitalPins), "pin")
|
|
||||||
.setAlign(Blockly.ALIGN_RIGHT);
|
|
||||||
this.setPreviousStatement(true, null);
|
|
||||||
this.setNextStatement(true, null);
|
|
||||||
this.setColour(getColour().motors);
|
|
||||||
this.setTooltip(Blockly.Msg.sensebox_motors_beginServoMotor_tooltip);
|
|
||||||
this.setHelpUrl(Blockly.Msg.sensebox_motors_beginServoMotor_helpurl);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Blockly.Blocks["sensebox_motors_moveServoMotor"] = {
|
|
||||||
init: function () {
|
|
||||||
this.appendDummyInput()
|
|
||||||
.appendField(Blockly.Msg.sensebox_motors_moveServoMotor);
|
|
||||||
this.appendDummyInput()
|
|
||||||
.appendField(Blockly.Msg.sensebox_motors_moveServoMotor_pin)
|
|
||||||
.appendField(new Blockly.FieldDropdown(selectedBoard().digitalPins), "pin")
|
|
||||||
.setAlign(Blockly.ALIGN_RIGHT);
|
|
||||||
this.appendValueInput("degrees", "Number")
|
|
||||||
.appendField(Blockly.Msg.sensebox_motors_moveServoMotor_degrees)
|
|
||||||
.setAlign(Blockly.ALIGN_RIGHT);
|
|
||||||
this.setPreviousStatement(true, null);
|
|
||||||
this.setNextStatement(true, null);
|
|
||||||
this.setColour(getColour().motors);
|
|
||||||
this.setTooltip(Blockly.Msg.sensebox_motors_moveServoMotor_tooltip);
|
|
||||||
this.setHelpUrl(Blockly.Msg.sensebox_motors_moveServoMotor_helpurl);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* I2C Motor Board
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
Blockly.Blocks["sensebox_motors_I2CMotorBoard_begin"] = {
|
|
||||||
init: function () {
|
|
||||||
this.appendDummyInput()
|
|
||||||
.appendField(Blockly.Msg.sensebox_motors_I2CMotorBoard_begin);
|
|
||||||
this.setPreviousStatement(true, null);
|
|
||||||
this.setNextStatement(true, null);
|
|
||||||
this.setColour(getColour().motors);
|
|
||||||
this.setTooltip(Blockly.Msg.sensebox_motors_I2CMotorBoard_begin_tooltip);
|
|
||||||
this.setHelpUrl(Blockly.Msg.sensebox_motors_I2CMotorBoard_begin_helpurl);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Blockly.Blocks["sensebox_motors_I2CMotorBoard_moveDCMotor"] = {
|
|
||||||
init: function () {
|
|
||||||
var dropdownOptions = [[Blockly.Msg.sensebox_motors_I2CMotorBoard_moveDCMotor_left, '1'],
|
|
||||||
[Blockly.Msg.sensebox_motors_I2CMotorBoard_moveDCMotor_right, '2']];
|
|
||||||
|
|
||||||
this.appendDummyInput()
|
|
||||||
.appendField(Blockly.Msg.sensebox_motors_I2CMotorBoard_moveDCMotor)
|
|
||||||
.appendField(new Blockly.FieldDropdown(dropdownOptions), "motor")
|
|
||||||
.appendField(Blockly.Msg.sensebox_motors_I2CMotorBoard_moveDCMotor_motor);
|
|
||||||
this.appendValueInput("speed", "Number")
|
|
||||||
.appendField(Blockly.Msg.sensebox_motors_I2CMotorBoard_moveDCMotor_speed)
|
|
||||||
.setAlign(Blockly.ALIGN_RIGHT);
|
|
||||||
this.setPreviousStatement(true, null);
|
|
||||||
this.setNextStatement(true, null);
|
|
||||||
this.setColour(getColour().motors);
|
|
||||||
this.setTooltip(Blockly.Msg.sensebox_motors_I2CMotorBoard_moveDCMotor_tooltip);
|
|
||||||
this.setHelpUrl(Blockly.Msg.sensebox_motors_I2CMotorBoard_moveDCMotor_helpurl);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Blockly.Blocks["sensebox_motors_I2CMotorBoard_stopDCMotor"] = {
|
|
||||||
init: function () {
|
|
||||||
var dropdownOptions = [[Blockly.Msg.sensebox_motors_I2CMotorBoard_stopDCMotor_left, '1'],
|
|
||||||
[Blockly.Msg.sensebox_motors_I2CMotorBoard_stopDCMotor_right, '2']];
|
|
||||||
|
|
||||||
this.appendDummyInput()
|
|
||||||
.appendField(Blockly.Msg.sensebox_motors_I2CMotorBoard_stopDCMotor)
|
|
||||||
.appendField(new Blockly.FieldDropdown(dropdownOptions), "motor")
|
|
||||||
.appendField(Blockly.Msg.sensebox_motors_I2CMotorBoard_stopDCMotor_motor)
|
|
||||||
this.setPreviousStatement(true, null);
|
|
||||||
this.setNextStatement(true, null);
|
|
||||||
this.setColour(getColour().motors);
|
|
||||||
this.setTooltip(Blockly.Msg.sensebox_motors_I2CMotorBoard_stopDCMotor_tooltip);
|
|
||||||
this.setHelpUrl(Blockly.Msg.sensebox_motors_I2CMotorBoard_stopDCMotor_helpurl);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stepper Motor
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
Blockly.Blocks["sensebox_motors_beginStepperMotor"] = {
|
|
||||||
init: function () {
|
|
||||||
this.appendDummyInput()
|
|
||||||
.appendField(Blockly.Msg.sensebox_motors_beginStepperMotor);
|
|
||||||
this.appendDummyInput()
|
|
||||||
.appendField(Blockly.Msg.sensebox_motors_beginStepperMotor_pins);
|
|
||||||
this.appendDummyInput()
|
|
||||||
.setAlign(Blockly.ALIGN_RIGHT)
|
|
||||||
.appendField(new Blockly.FieldDropdown(selectedBoard().digitalPins), "in1")
|
|
||||||
.appendField(new Blockly.FieldDropdown(selectedBoard().digitalPins), "in2")
|
|
||||||
.appendField(new Blockly.FieldDropdown(selectedBoard().digitalPins), "in3")
|
|
||||||
.appendField(new Blockly.FieldDropdown(selectedBoard().digitalPins), "in4");
|
|
||||||
this.setFieldValue("1", "in1");
|
|
||||||
this.setFieldValue("2", "in2");
|
|
||||||
this.setFieldValue("3", "in3");
|
|
||||||
this.setFieldValue("4", "in4");
|
|
||||||
this.appendDummyInput()
|
|
||||||
.appendField(Blockly.Msg.sensebox_motors_beginStepperMotor_rpm)
|
|
||||||
.appendField(new FieldSlider(3, 1, 3), "rpm");
|
|
||||||
this.setPreviousStatement(true, null);
|
|
||||||
this.setNextStatement(true, null);
|
|
||||||
this.setColour(getColour().motors);
|
|
||||||
this.setTooltip(Blockly.Msg.sensebox_motors_beginStepperMotor_tooltip);
|
|
||||||
this.setHelpUrl(Blockly.Msg.sensebox_motors_beginStepperMotor_helpurl);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Blockly.Blocks["sensebox_motors_moveStepperMotor"] = {
|
|
||||||
init: function () {
|
|
||||||
this.appendDummyInput()
|
|
||||||
.appendField(Blockly.Msg.sensebox_motors_moveStepperMotor);
|
|
||||||
this.appendValueInput("steps", "Number")
|
|
||||||
.setAlign(Blockly.ALIGN_RIGHT)
|
|
||||||
.appendField(Blockly.Msg.sensebox_motors_moveStepperMotor_step);
|
|
||||||
this.setPreviousStatement(true, null);
|
|
||||||
this.setNextStatement(true, null);
|
|
||||||
this.setColour(getColour().motors);
|
|
||||||
this.setTooltip(Blockly.Msg.sensebox_motors_moveStepperMotor_tooltip);
|
|
||||||
this.setHelpUrl(Blockly.Msg.sensebox_motors_moveStepperMotor_helpurl);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
import * as Blockly from "blockly";
|
|
||||||
import { getColour } from "../helpers/colour";
|
|
||||||
import * as Types from "../helpers/types";
|
|
||||||
|
|
||||||
Blockly.Blocks["sensebox_ntp_init"] = {
|
|
||||||
init: function () {
|
|
||||||
this.setHelpUrl(Blockly.Msg.sensebox_ntp_helpurl);
|
|
||||||
this.setColour(getColour().time);
|
|
||||||
this.appendDummyInput().appendField(Blockly.Msg.sensebox_ntp_init);
|
|
||||||
this.setPreviousStatement(true);
|
|
||||||
this.setNextStatement(true);
|
|
||||||
this.setTooltip(Blockly.Msg.sensebox_ntp_tooltip);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Blockly.Blocks["sensebox_ntp_get"] = {
|
|
||||||
init: function () {
|
|
||||||
this.setHelpUrl(Blockly.Msg.sensebox_ntp_get_helpurl);
|
|
||||||
this.setColour(getColour().time);
|
|
||||||
this.appendDummyInput()
|
|
||||||
.appendField(Blockly.Msg.sensebox_ntp_get)
|
|
||||||
.appendField(
|
|
||||||
new Blockly.FieldDropdown([
|
|
||||||
[Blockly.Msg.sensebox_ntp_epochTime, "getEpochTime"],
|
|
||||||
[Blockly.Msg.sensebox_ntp_formattedTimeStamp, "getFormattedTime"],
|
|
||||||
]),
|
|
||||||
"dropdown"
|
|
||||||
);
|
|
||||||
this.setOutput(true, Types.LARGE_NUMBER.typeName);
|
|
||||||
this.setTooltip(Blockly.Msg.sensebox_rtc_get_tooltip);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Blockly.Blocks["sensebox_ntp_get_timestamp"] = {
|
|
||||||
init: function () {
|
|
||||||
this.setHelpUrl(Blockly.Msg.sensebox_rtc_helpurl);
|
|
||||||
this.setColour(getColour().time);
|
|
||||||
this.appendDummyInput().appendField(Blockly.Msg.sensebox_rtc_get_timestamp);
|
|
||||||
this.setOutput(true);
|
|
||||||
this.setTooltip(Blockly.Msg.sensebox_rtc_get_timestamp_tooltip);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -19,7 +19,6 @@ Blockly.Blocks["sensebox_osem_connection"] = {
|
|||||||
this.setColour(getColour().sensebox);
|
this.setColour(getColour().sensebox);
|
||||||
this.appendDummyInput()
|
this.appendDummyInput()
|
||||||
.appendField(Blockly.Msg.senseBox_osem_connection)
|
.appendField(Blockly.Msg.senseBox_osem_connection)
|
||||||
.appendField( new Blockly.FieldDropdown([[Blockly.Msg.senseBox_osem_host, "opensensemap.org"], [Blockly.Msg.senseBox_osem_host_testing, "testing.opensensemap.org"]]), "HOST")
|
|
||||||
.appendField("SSL")
|
.appendField("SSL")
|
||||||
.appendField(new Blockly.FieldCheckbox(ssl), "SSL");
|
.appendField(new Blockly.FieldCheckbox(ssl), "SSL");
|
||||||
this.appendDummyInput()
|
this.appendDummyInput()
|
||||||
@@ -54,10 +53,6 @@ Blockly.Blocks["sensebox_osem_connection"] = {
|
|||||||
.setAlign(Blockly.ALIGN_LEFT)
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
.appendField(Blockly.Msg.senseBox_osem_access_token)
|
.appendField(Blockly.Msg.senseBox_osem_access_token)
|
||||||
.appendField(new Blockly.FieldTextInput("access_token"), "access_token");
|
.appendField(new Blockly.FieldTextInput("access_token"), "access_token");
|
||||||
this.appendDummyInput()
|
|
||||||
.setAlign(Blockly.ALIGN_LEFT)
|
|
||||||
.appendField(Blockly.Msg.senseBox_osem_xallowtoken)
|
|
||||||
.appendField(new Blockly.FieldTextInput("ratelimit-token"), "ratelimit-token");
|
|
||||||
this.appendStatementInput("DO")
|
this.appendStatementInput("DO")
|
||||||
.appendField(Blockly.Msg.senseBox_sensor)
|
.appendField(Blockly.Msg.senseBox_sensor)
|
||||||
.setCheck(null);
|
.setCheck(null);
|
||||||
|
|||||||
@@ -76,67 +76,3 @@ Blockly.Blocks["sensebox_rtc_get_timestamp"] = {
|
|||||||
this.setTooltip(Blockly.Msg.sensebox_rtc_get_timestamp_tooltip);
|
this.setTooltip(Blockly.Msg.sensebox_rtc_get_timestamp_tooltip);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal RTC
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
Blockly.Blocks["sensebox_internal_rtc_init"] = {
|
|
||||||
init: function () {
|
|
||||||
this.setHelpUrl(Blockly.Msg.sensebox_internal_rtc_helpurl);
|
|
||||||
this.setColour(getColour().time);
|
|
||||||
this.appendDummyInput().appendField(Blockly.Msg.sensebox_internal_rtc_init);
|
|
||||||
this.setPreviousStatement(true);
|
|
||||||
this.setNextStatement(true);
|
|
||||||
this.setTooltip(Blockly.Msg.sensebox_internal_rtc_init_tooltip);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Blockly.Blocks["sensebox_internal_rtc_set"] = {
|
|
||||||
init: function () {
|
|
||||||
this.setHelpUrl(Blockly.Msg.sensebox_rtc_helpurl);
|
|
||||||
this.setColour(getColour().time);
|
|
||||||
this.appendValueInput("time").appendField(
|
|
||||||
Blockly.Msg.sensebox_internal_rtc_set
|
|
||||||
);
|
|
||||||
this.setPreviousStatement(true);
|
|
||||||
this.setNextStatement(true);
|
|
||||||
this.setTooltip(Blockly.Msg.sensebox_internal_rtc_set_tooltip);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Blockly.Blocks["sensebox_internal_rtc_get"] = {
|
|
||||||
init: function () {
|
|
||||||
this.setHelpUrl(Blockly.Msg.sensebox_rtc_helpurl);
|
|
||||||
this.setColour(getColour().time);
|
|
||||||
this.appendDummyInput()
|
|
||||||
.appendField(Blockly.Msg.sensebox_internal_rtc_get)
|
|
||||||
.appendField(
|
|
||||||
new Blockly.FieldDropdown([
|
|
||||||
[Blockly.Msg.sensebox_internal_rtc_epoch, "Epoch"],
|
|
||||||
[Blockly.Msg.sensebox_internal_rtc_year, "Year"],
|
|
||||||
[Blockly.Msg.sensebox_internal_rtc_month, "Month"],
|
|
||||||
[Blockly.Msg.sensebox_internal_rtc_day, "Day"],
|
|
||||||
[Blockly.Msg.sensebox_internal_rtc_hour, "Hours"],
|
|
||||||
[Blockly.Msg.sensebox_internal_rtc_minutes, "Minutes"],
|
|
||||||
[Blockly.Msg.sensebox_internal_rtc_seconds, "Seconds"],
|
|
||||||
]),
|
|
||||||
"dropdown"
|
|
||||||
);
|
|
||||||
this.setOutput(true, Types.LARGE_NUMBER.typeName);
|
|
||||||
this.setTooltip(Blockly.Msg.sensebox_internal_rtc_get_tooltip);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Blockly.Blocks["sensebox_internal_rtc_get_timestamp"] = {
|
|
||||||
init: function () {
|
|
||||||
this.setHelpUrl(Blockly.Msg.sensebox_internal_rtc_helpurl);
|
|
||||||
this.setColour(getColour().time);
|
|
||||||
this.appendDummyInput().appendField(
|
|
||||||
Blockly.Msg.sensebox_internal_rtc_get_timestamp
|
|
||||||
);
|
|
||||||
this.setOutput(true);
|
|
||||||
this.setTooltip(Blockly.Msg.sensebox_internal_rtc_get_timestamp_tooltip);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -114,8 +114,10 @@ Blockly.Blocks["sensebox_sensor_sds011"] = {
|
|||||||
)
|
)
|
||||||
.appendField(Blockly.Msg.senseBox_sds011_dimension)
|
.appendField(Blockly.Msg.senseBox_sds011_dimension)
|
||||||
.appendField(
|
.appendField(
|
||||||
new Blockly.FieldDropdown(
|
new Blockly.FieldDropdown([
|
||||||
selectedBoard().serialSensors),
|
[Blockly.Msg.senseBox_sds011_serial1, "Serial1"],
|
||||||
|
[Blockly.Msg.senseBox_sds011_serial2, "Serial2"],
|
||||||
|
]),
|
||||||
"SERIAL"
|
"SERIAL"
|
||||||
);
|
);
|
||||||
this.setOutput(true, Types.DECIMAL.typeName);
|
this.setOutput(true, Types.DECIMAL.typeName);
|
||||||
@@ -186,7 +188,7 @@ Blockly.Blocks["sensebox_sensor_bme680_bsec"] = {
|
|||||||
var dropdownOptions = [
|
var dropdownOptions = [
|
||||||
[Blockly.Msg.senseBox_temp, "temperature"],
|
[Blockly.Msg.senseBox_temp, "temperature"],
|
||||||
[Blockly.Msg.senseBox_hum, "humidity"],
|
[Blockly.Msg.senseBox_hum, "humidity"],
|
||||||
[Blockly.Msg.senseBox_bme_pressure, "pressure"],
|
[Blockly.Msg.senseBox_pressure, "pressure"],
|
||||||
[Blockly.Msg.senseBox_bme_iaq, "IAQ"],
|
[Blockly.Msg.senseBox_bme_iaq, "IAQ"],
|
||||||
[Blockly.Msg.senseBox_bme_iaq_accuracy, "IAQAccuracy"],
|
[Blockly.Msg.senseBox_bme_iaq_accuracy, "IAQAccuracy"],
|
||||||
[Blockly.Msg.senseBox_bme_co2, "CO2"],
|
[Blockly.Msg.senseBox_bme_co2, "CO2"],
|
||||||
@@ -512,6 +514,40 @@ Blockly.Blocks["sensebox_soundsensor_dfrobot"] = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rainsensor hydreon rg-15
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Blocks["sensebox_rainsensor_hydreon_rg15"] = {
|
||||||
|
init: function () {
|
||||||
|
var dropdownOptionsPorts = [
|
||||||
|
[Blockly.Msg.sensebox_rainsensor_hydreon_rg15_serial1, "Serial1"],
|
||||||
|
[Blockly.Msg.sensebox_rainsensor_hydreon_rg15_serial2, "Serial2"],
|
||||||
|
];
|
||||||
|
var dropdownOptionsValues = [
|
||||||
|
[Blockly.Msg.sensebox_rainsensor_hydreon_rg15_acc, "getAccumulation"],
|
||||||
|
[Blockly.Msg.sensebox_rainsensor_hydreon_rg15_totalAcc, "getTotalAccumulation"],
|
||||||
|
[Blockly.Msg.sensebox_rainsensor_hydreon_rg15_eventAcc, "getEventAccumulation"],
|
||||||
|
[Blockly.Msg.sensebox_rainsensor_hydreon_rg15_rainInt, "getRainfallIntensity"],
|
||||||
|
];
|
||||||
|
this.setColour(getColour().sensebox);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(Blockly.Msg.sensebox_rainsensor_hydreon_rg15);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(Blockly.Msg.sensebox_rainsensor_hydreon_rg15_port)
|
||||||
|
.appendField(new Blockly.FieldDropdown(dropdownOptionsPorts), "SERIAL");
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(Blockly.Msg.sensebox_rainsensor_hydreon_rg15_value)
|
||||||
|
.appendField(new Blockly.FieldDropdown(dropdownOptionsValues), "VALUE");
|
||||||
|
this.setOutput(true, Types.DECIMAL.typeName);
|
||||||
|
this.setTooltip(Blockly.Msg.sensebox_rainsensor_hydreon_rg15_tooltip);
|
||||||
|
this.setHelpUrl(Blockly.Msg.sensebox_rainsensor_hydreon_rg15_helpurl);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Infineon DPS310 Pressure Sensor
|
* Infineon DPS310 Pressure Sensor
|
||||||
*
|
*
|
||||||
@@ -562,31 +598,3 @@ Blockly.Blocks["sensebox_sensor_dps310"] = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Sensirion SPS30 Fine Particular Matter Sensor
|
|
||||||
* added 02.12.2022
|
|
||||||
*/
|
|
||||||
|
|
||||||
Blockly.Blocks["sensebox_sensor_sps30"] = {
|
|
||||||
init: function () {
|
|
||||||
this.appendDummyInput().appendField(Blockly.Msg.senseBox_sps30);
|
|
||||||
this.appendDummyInput()
|
|
||||||
.setAlign(Blockly.ALIGN_LEFT)
|
|
||||||
.appendField(Blockly.Msg.senseBox_value)
|
|
||||||
.appendField(
|
|
||||||
new Blockly.FieldDropdown([
|
|
||||||
[Blockly.Msg.senseBox_sps30_1p0, "1p0"],
|
|
||||||
[Blockly.Msg.senseBox_sps30_2p5, "2p5"],
|
|
||||||
[Blockly.Msg.senseBox_sps30_4p0, "4p0"],
|
|
||||||
[Blockly.Msg.senseBox_sps30_10p0, "10p0"],
|
|
||||||
]),
|
|
||||||
"value"
|
|
||||||
)
|
|
||||||
.appendField(Blockly.Msg.senseBox_sps30_dimension);
|
|
||||||
this.setOutput(true, Types.DECIMAL.typeName);
|
|
||||||
this.setColour(getColour().sensebox);
|
|
||||||
this.setTooltip(Blockly.Msg.senseBox_sps30_tooltip);
|
|
||||||
this.setHelpUrl(Blockly.Msg.senseBox_sps30_helpurl);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -148,7 +148,53 @@ Blockly["Arduino"].init = function (workspace) {
|
|||||||
// Blockly.Names.DEVELOPER_VARIABLE_TYPE));
|
// Blockly.Names.DEVELOPER_VARIABLE_TYPE));
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
const doubleVariables = workspace.getVariablesOfType("Number");
|
||||||
|
let i = 0;
|
||||||
|
let variableCode = "";
|
||||||
|
for (i = 0; i < doubleVariables.length; i += 1) {
|
||||||
|
variableCode +=
|
||||||
|
"double " +
|
||||||
|
Blockly["Arduino"].nameDB_.getName(
|
||||||
|
doubleVariables[i].getId(),
|
||||||
|
Blockly.Variables.NAME_TYPE
|
||||||
|
) +
|
||||||
|
" = 0; \n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
const stringVariables = workspace.getVariablesOfType("String");
|
||||||
|
for (i = 0; i < stringVariables.length; i += 1) {
|
||||||
|
variableCode +=
|
||||||
|
"String " +
|
||||||
|
Blockly["Arduino"].nameDB_.getName(
|
||||||
|
stringVariables[i].getId(),
|
||||||
|
Blockly.Variables.NAME_TYPE
|
||||||
|
) +
|
||||||
|
' = ""; \n\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
const booleanVariables = workspace.getVariablesOfType("Boolean");
|
||||||
|
for (i = 0; i < booleanVariables.length; i += 1) {
|
||||||
|
variableCode +=
|
||||||
|
"boolean " +
|
||||||
|
Blockly["Arduino"].nameDB_.getDistinctName(
|
||||||
|
booleanVariables[i].getId(),
|
||||||
|
Blockly.Variables.NAME_TYPE
|
||||||
|
) +
|
||||||
|
" = false; \n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
const colourVariables = workspace.getVariablesOfType("Colour");
|
||||||
|
for (i = 0; i < colourVariables.length; i += 1) {
|
||||||
|
variableCode +=
|
||||||
|
"RGB " +
|
||||||
|
Blockly["Arduino"].nameDB_.getName(
|
||||||
|
colourVariables[i].getId(),
|
||||||
|
Blockly.Variables.NAME_TYPE
|
||||||
|
) +
|
||||||
|
" = {0, 0, 0}; \n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
Blockly["Arduino"].variablesInitCode_ = variableCode;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,12 +5,10 @@ import "./sensebox-telegram";
|
|||||||
import "./sensebox-osem";
|
import "./sensebox-osem";
|
||||||
import "./sensebox-web";
|
import "./sensebox-web";
|
||||||
import "./sensebox-display";
|
import "./sensebox-display";
|
||||||
import "./sensebox-motors";
|
|
||||||
import "./sensebox-lora";
|
import "./sensebox-lora";
|
||||||
import "./sensebox-led";
|
import "./sensebox-led";
|
||||||
import "./sensebox";
|
import "./sensebox";
|
||||||
import "./sensebox-rtc";
|
import "./sensebox-rtc";
|
||||||
import "./sensebox-ntp";
|
|
||||||
import "./sensebox-ble";
|
import "./sensebox-ble";
|
||||||
import "./sensebox-sd";
|
import "./sensebox-sd";
|
||||||
import "./mqtt";
|
import "./mqtt";
|
||||||
|
|||||||
@@ -275,15 +275,10 @@ Blockly.Arduino["math_change"] = function (block) {
|
|||||||
"DELTA",
|
"DELTA",
|
||||||
Blockly.Arduino.ORDER_ADDITIVE
|
Blockly.Arduino.ORDER_ADDITIVE
|
||||||
) || "0";
|
) || "0";
|
||||||
var id = block.getFieldValue("VAR")
|
var varName = Blockly.Arduino.nameDB_.getName(
|
||||||
const varName = Blockly.Variables.getVariable(
|
block.getFieldValue("VAR"),
|
||||||
Blockly.getMainWorkspace(),
|
Blockly.Variables.NAME_TYPE
|
||||||
id
|
);
|
||||||
).name;
|
|
||||||
// var varName = Blockly.Arduino.nameDB_.getName(
|
|
||||||
// block.getFieldValue("VAR"),
|
|
||||||
// Blockly.Variables.NAME_TYPE
|
|
||||||
// );
|
|
||||||
return varName + " += " + argument0 + ";\n";
|
return varName + " += " + argument0 + ";\n";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ Blockly.Arduino.sensebox_phyphox_graph = function () {
|
|||||||
Blockly.Arduino.sensebox_phyphox_experiment_send = function () {
|
Blockly.Arduino.sensebox_phyphox_experiment_send = function () {
|
||||||
var branch = Blockly.Arduino.statementToCode(this, "sendValues");
|
var branch = Blockly.Arduino.statementToCode(this, "sendValues");
|
||||||
var blocks = this.getDescendants();
|
var blocks = this.getDescendants();
|
||||||
|
console.log(blocks);
|
||||||
var count = 0;
|
var count = 0;
|
||||||
if (blocks !== undefined) {
|
if (blocks !== undefined) {
|
||||||
for (var i = 0; i < blocks.length; i++) {
|
for (var i = 0; i < blocks.length; i++) {
|
||||||
@@ -114,6 +115,7 @@ Blockly.Arduino.sensebox_phyphox_experiment_send = function () {
|
|||||||
var string = "";
|
var string = "";
|
||||||
|
|
||||||
for (var j = 1; j <= count; j++) {
|
for (var j = 1; j <= count; j++) {
|
||||||
|
console.log("append");
|
||||||
if (string === "") {
|
if (string === "") {
|
||||||
string += `channel${j}`;
|
string += `channel${j}`;
|
||||||
} else if (string !== "") {
|
} else if (string !== "") {
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
import * as Blockly from "blockly/core";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Servo Motor
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
Blockly.Arduino.sensebox_motors_beginServoMotor = function () {
|
|
||||||
var pin = this.getFieldValue("pin");
|
|
||||||
Blockly.Arduino.libraries_["library_senseBoxIO"] = "#include <senseBoxIO.h>";
|
|
||||||
Blockly.Arduino.libraries_["include_servo_motor"] = "#include <Servo.h>";
|
|
||||||
Blockly.Arduino.definitions_[`define_servo_motor_${pin}`] = `Servo servo_motor_${pin}; // servo Motor`;
|
|
||||||
Blockly.Arduino.setupCode_[`setup_servo_motor_${pin}`] = `servo_motor_${pin}.attach(${pin}); // attach servo motor to pin ${pin}`;
|
|
||||||
var code = "";
|
|
||||||
return code;
|
|
||||||
};
|
|
||||||
|
|
||||||
Blockly.Arduino.sensebox_motors_moveServoMotor = function () {
|
|
||||||
var pin = this.getFieldValue("pin");
|
|
||||||
var degrees = Blockly.Arduino.valueToCode(this, 'degrees', Blockly.Arduino.ORDER_ATOMIC) || "90";
|
|
||||||
var code = `servo_motor_${pin}.write(${degrees}); // move servo motor to ${degrees} degrees\n`;
|
|
||||||
return code;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* I2C Motor Board
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
Blockly.Arduino.sensebox_motors_I2CMotorBoard_begin = function () {
|
|
||||||
Blockly.Arduino.libraries_["library_senseBoxIO"] = "#include <senseBoxIO.h>";
|
|
||||||
Blockly.Arduino.libraries_["include_i2c_motor_board"] = "#include <Grove_I2C_Motor_Driver.h>";
|
|
||||||
Blockly.Arduino.definitions_["define_i2c_motor_board"] = `
|
|
||||||
#define I2C_MOTOR_BOARD_ADDRESS 0x0f // default I2C address of I2C Motor Board`;
|
|
||||||
Blockly.Arduino.setupCode_["setup_i2c_motor_board"] = `
|
|
||||||
Motor.begin(I2C_MOTOR_BOARD_ADDRESS); // Initialize I2C Motor Board`;
|
|
||||||
var code = "";
|
|
||||||
return code;
|
|
||||||
};
|
|
||||||
|
|
||||||
Blockly.Arduino.sensebox_motors_I2CMotorBoard_moveDCMotor = function () {
|
|
||||||
var motor = this.getFieldValue("motor");
|
|
||||||
var speed = Blockly.Arduino.valueToCode(this, 'speed', Blockly.Arduino.ORDER_ATOMIC) || "50";
|
|
||||||
var code = `Motor.speed(MOTOR${motor}, ${speed}); // set speed of motor\n`;
|
|
||||||
return code;
|
|
||||||
};
|
|
||||||
|
|
||||||
Blockly.Arduino.sensebox_motors_I2CMotorBoard_stopDCMotor = function () {
|
|
||||||
var motor = this.getFieldValue("motor");
|
|
||||||
var code = `Motor.stop(MOTOR${motor}); // stop motor\n`;
|
|
||||||
return code;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stepper Motor
|
|
||||||
*/
|
|
||||||
Blockly.Arduino.sensebox_motors_beginStepperMotor = function () {
|
|
||||||
var in1 = this.getFieldValue("in1");
|
|
||||||
var in2 = this.getFieldValue("in2");
|
|
||||||
var in3 = this.getFieldValue("in3");
|
|
||||||
var in4 = this.getFieldValue("in4");
|
|
||||||
var rpm = this.getFieldValue("rpm");
|
|
||||||
Blockly.Arduino.libraries_["library_senseBoxIO"] = "#include <senseBoxIO.h>";
|
|
||||||
Blockly.Arduino.libraries_["include_stepper_motor"] = "#include <Stepper.h>";
|
|
||||||
Blockly.Arduino.definitions_["define_stepper_motor"] = `
|
|
||||||
Stepper stepper_motor(2048, ${in1}, ${in2}, ${in3}, ${in4}); // stepper Motor with 2048 steps per rotation`;
|
|
||||||
Blockly.Arduino.setupCode_["setup_stepper_motor"] =
|
|
||||||
`stepper_motor.setSpeed(${rpm}); // speed in rotations per minute`;
|
|
||||||
var code = "";
|
|
||||||
return code;
|
|
||||||
};
|
|
||||||
|
|
||||||
Blockly.Arduino.sensebox_motors_moveStepperMotor = function () {
|
|
||||||
var steps = Blockly.Arduino.valueToCode(this, 'steps', Blockly.Arduino.ORDER_ATOMIC) || '2048';
|
|
||||||
var code = `stepper_motor.step(${steps}); // 2048 steps correspond to one rotation\n`;
|
|
||||||
return code;
|
|
||||||
};
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import Blockly from "blockly";
|
|
||||||
|
|
||||||
Blockly.Arduino.sensebox_ntp_init = function () {
|
|
||||||
Blockly.Arduino.libraries_["WiFiUdp"] = `#include <WiFiUdp.h>`;
|
|
||||||
Blockly.Arduino.libraries_["NTPClient"] = `#include <NTPClient.h>`;
|
|
||||||
Blockly.Arduino.definitions_["WiFiUDP"] = `WiFiUDP ntpUDP;`;
|
|
||||||
Blockly.Arduino.definitions_["NTPClient"] = `NTPClient timeClient(ntpUDP);`;
|
|
||||||
Blockly.Arduino.libraries_["library_senseBoxIO"] = "#include <senseBoxIO.h>";
|
|
||||||
Blockly.Arduino.setupCode_["timeclient.begin"] = `timeClient.begin();`;
|
|
||||||
Blockly.Arduino.setupCode_["timeclient.update"] = `timeClient.update();`;
|
|
||||||
var code = ``;
|
|
||||||
return code;
|
|
||||||
};
|
|
||||||
|
|
||||||
Blockly.Arduino.sensebox_ntp_get = function () {
|
|
||||||
var format = this.getFieldValue("dropdown");
|
|
||||||
var code = `timeClient.${format}()`;
|
|
||||||
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
|
||||||
};
|
|
||||||
@@ -30,8 +30,6 @@ Blockly.Arduino.sensebox_osem_connection = function (Block) {
|
|||||||
var box_id = this.getFieldValue("BoxID");
|
var box_id = this.getFieldValue("BoxID");
|
||||||
var branch = Blockly.Arduino.statementToCode(Block, "DO");
|
var branch = Blockly.Arduino.statementToCode(Block, "DO");
|
||||||
var access_token = this.getFieldValue("access_token");
|
var access_token = this.getFieldValue("access_token");
|
||||||
var host = this.getFieldValue("HOST");
|
|
||||||
var ratelimit_token = this.getFieldValue("ratelimit-token");
|
|
||||||
var blocks = this.getDescendants();
|
var blocks = this.getDescendants();
|
||||||
var type = this.getFieldValue("type");
|
var type = this.getFieldValue("type");
|
||||||
var ssl = this.getFieldValue("SSL");
|
var ssl = this.getFieldValue("SSL");
|
||||||
@@ -52,7 +50,7 @@ Blockly.Arduino.sensebox_osem_connection = function (Block) {
|
|||||||
Blockly.Arduino.definitions_["SenseBoxID"] =
|
Blockly.Arduino.definitions_["SenseBoxID"] =
|
||||||
'const char SENSEBOX_ID [] PROGMEM = "' + box_id + '";';
|
'const char SENSEBOX_ID [] PROGMEM = "' + box_id + '";';
|
||||||
Blockly.Arduino.definitions_["host"] =
|
Blockly.Arduino.definitions_["host"] =
|
||||||
`const char server [] PROGMEM ="ingress.${host}";`;
|
'const char server [] PROGMEM ="ingress.opensensemap.org";';
|
||||||
if (wifi === true) {
|
if (wifi === true) {
|
||||||
if (ssl === "TRUE") {
|
if (ssl === "TRUE") {
|
||||||
Blockly.Arduino.libraries_["library_bearSSL"] =
|
Blockly.Arduino.libraries_["library_bearSSL"] =
|
||||||
@@ -156,7 +154,7 @@ ${
|
|||||||
if (connected == true) {
|
if (connected == true) {
|
||||||
// construct the HTTP POST request:
|
// construct the HTTP POST request:
|
||||||
sprintf_P(buffer,
|
sprintf_P(buffer,
|
||||||
PSTR("POST /boxes/%s/data HTTP/1.1\\nAuthorization: ${access_token}\\nX-Allow-Token: ${ratelimit_token}\\nHost: %s\\nContent-Type: "
|
PSTR("POST /boxes/%s/data HTTP/1.1\\nAuthorization: ${access_token}\\nHost: %s\\nContent-Type: "
|
||||||
"text/csv\\nConnection: close\\nContent-Length: %i\\n\\n"),
|
"text/csv\\nConnection: close\\nContent-Length: %i\\n\\n"),
|
||||||
SENSEBOX_ID, server, num_measurements * lengthMultiplikator);
|
SENSEBOX_ID, server, num_measurements * lengthMultiplikator);
|
||||||
// send the HTTP POST request:
|
// send the HTTP POST request:
|
||||||
@@ -255,7 +253,7 @@ ${
|
|||||||
if (connected == true) {
|
if (connected == true) {
|
||||||
// construct the HTTP POST request:
|
// construct the HTTP POST request:
|
||||||
sprintf_P(buffer,
|
sprintf_P(buffer,
|
||||||
PSTR("POST /boxes/%s/data HTTP/1.1\\nAuthorization: ${access_token}\\nX-Allow-Token: ${ratelimit_token}\\nHost: %s\\nContent-Type: "
|
PSTR("POST /boxes/%s/data HTTP/1.1\\nAuthorization: ${access_token}\\nHost: %s\\nContent-Type: "
|
||||||
"text/csv\\nConnection: close\\nContent-Length: %i\\n\\n"),
|
"text/csv\\nConnection: close\\nContent-Length: %i\\n\\n"),
|
||||||
SENSEBOX_ID, server, num_measurements * lengthMultiplikator);
|
SENSEBOX_ID, server, num_measurements * lengthMultiplikator);
|
||||||
// send the HTTP POST request:
|
// send the HTTP POST request:
|
||||||
|
|||||||
@@ -94,46 +94,3 @@ uint8_t sec, min, hour, day, month;
|
|||||||
var code = `getTimeStamp()`;
|
var code = `getTimeStamp()`;
|
||||||
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
||||||
};
|
};
|
||||||
|
|
||||||
Blockly.Arduino.sensebox_internal_rtc_init = function () {
|
|
||||||
Blockly.Arduino.libraries_["RTClib"] = `#include <RTCZero.h>`;
|
|
||||||
Blockly.Arduino.definitions_["RTC"] = `RTCZero rtc;`;
|
|
||||||
Blockly.Arduino.libraries_["library_senseBoxIO"] = "#include <senseBoxIO.h>";
|
|
||||||
Blockly.Arduino.setupCode_["rtc.begin"] = `rtc.begin();`;
|
|
||||||
return "";
|
|
||||||
};
|
|
||||||
|
|
||||||
Blockly.Arduino.sensebox_internal_rtc_set = function () {
|
|
||||||
var branch =
|
|
||||||
Blockly.Arduino.valueToCode(this, "time", Blockly.Arduino.ORDER_ATOMIC) ||
|
|
||||||
"0";
|
|
||||||
Blockly.Arduino.setupCode_["rtc.setEpoch"] = `rtc.setEpoch(${branch});`;
|
|
||||||
var code = ``;
|
|
||||||
return code;
|
|
||||||
};
|
|
||||||
|
|
||||||
Blockly.Arduino.sensebox_internal_rtc_get = function () {
|
|
||||||
var dropdown = this.getFieldValue("dropdown");
|
|
||||||
var code = `rtc.get${dropdown}()`;
|
|
||||||
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
|
||||||
};
|
|
||||||
|
|
||||||
Blockly.Arduino.sensebox_internal_rtc_get_timestamp = function () {
|
|
||||||
Blockly.Arduino.variables_["rtc_timestamp"] = `char timestamp[20];`;
|
|
||||||
Blockly.Arduino.codeFunctions_["getTimeStamp"] = `
|
|
||||||
char* getTimeStamp() {
|
|
||||||
uint8_t sec, min, hour, day, month;
|
|
||||||
uint16_t year;
|
|
||||||
sec = rtc.getSeconds();
|
|
||||||
min = rtc.getMinutes();
|
|
||||||
hour = rtc.getHours();
|
|
||||||
day = rtc.getDay();
|
|
||||||
month = rtc.getMonth();
|
|
||||||
year = rtc.getYear();
|
|
||||||
sprintf(timestamp, "%02d-%02d-%02dT%02d:%02d:%02dZ", year, month, day, hour, min, sec);
|
|
||||||
return timestamp;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
var code = `getTimeStamp()`;
|
|
||||||
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -203,5 +203,6 @@ Blockly.Arduino.sensebox_sd_save_for_osem = function (block) {
|
|||||||
Blockly.Arduino.definitions_["SENSOR_ID" + id + ""] =
|
Blockly.Arduino.definitions_["SENSOR_ID" + id + ""] =
|
||||||
"const char SENSOR_ID" + id + '[] PROGMEM = "' + sensor_id + '";';
|
"const char SENSOR_ID" + id + '[] PROGMEM = "' + sensor_id + '";';
|
||||||
code += "addMeasurement(SENSOR_ID" + id + "," + sensor_value + ");\n";
|
code += "addMeasurement(SENSOR_ID" + id + "," + sensor_value + ");\n";
|
||||||
|
console.log(code);
|
||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -429,13 +429,11 @@ Blockly.Arduino.sensebox_scd30 = function () {
|
|||||||
"#include <SparkFun_SCD30_Arduino_Library.h> // http://librarymanager/All#SparkFun_SCD30_Arduino_Library";
|
"#include <SparkFun_SCD30_Arduino_Library.h> // http://librarymanager/All#SparkFun_SCD30_Arduino_Library";
|
||||||
Blockly.Arduino.definitions_["SCD30"] = "SCD30 airSensor;";
|
Blockly.Arduino.definitions_["SCD30"] = "SCD30 airSensor;";
|
||||||
Blockly.Arduino.setupCode_["init_scd30"] = ` Wire.begin();
|
Blockly.Arduino.setupCode_["init_scd30"] = ` Wire.begin();
|
||||||
if (airSensor.begin() == false)
|
if (airSensor.begin() == false)
|
||||||
{
|
{
|
||||||
while (1)
|
while (1)
|
||||||
;
|
;
|
||||||
}`;
|
}`;
|
||||||
Blockly.Arduino.setupCode_["scd30_staleData"] =
|
|
||||||
"airSensor.useStaleData(true);";
|
|
||||||
var code = "";
|
var code = "";
|
||||||
switch (dropdown) {
|
switch (dropdown) {
|
||||||
case "temperature":
|
case "temperature":
|
||||||
@@ -656,6 +654,23 @@ float getSoundValue(){
|
|||||||
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rainsensor hydreon rg-15
|
||||||
|
*/
|
||||||
|
|
||||||
|
Blockly.Arduino.sensebox_rainsensor_hydreon_rg15 = function () {
|
||||||
|
var port = this.getFieldValue("SERIAL");
|
||||||
|
var value = this.getFieldValue("VALUE");
|
||||||
|
Blockly.Arduino.libraries_["library_senseBoxIO"] = "#include <senseBoxIO.h>";
|
||||||
|
Blockly.Arduino.libraries_["library_rainsensor_rg15"] = "#include <hydreon.h>";
|
||||||
|
Blockly.Arduino.definitions_["def_rainsensor_rg15_" + port] = "HYDREON rainsensor_" + port + "(" + port + ");";
|
||||||
|
Blockly.Arduino.setupCode_["setup_rainsensor_rg15_" + port] = "rainsensor_" + port + ".begin();";
|
||||||
|
Blockly.Arduino.loopCodeOnce_["loop_rainsensor_rg15_" + port] = "rainsensor_" + port + ".readAllData();"
|
||||||
|
|
||||||
|
var code = "rainsensor_" + port + "." + value + "()";
|
||||||
|
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Infineon DPS310 Pressure Sensor
|
* Infineon DPS310 Pressure Sensor
|
||||||
*
|
*
|
||||||
@@ -694,57 +709,3 @@ Blockly.Arduino.sensebox_sensor_dps310 = function () {
|
|||||||
}
|
}
|
||||||
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Sensirion SPS30 Fine Particlar Matter
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
Blockly.Arduino.sensebox_sensor_sps30 = function () {
|
|
||||||
var dropdown_name = this.getFieldValue("value");
|
|
||||||
Blockly.Arduino.libraries_["library_senseBoxIO"] = "#include <senseBoxIO.h>";
|
|
||||||
Blockly.Arduino.libraries_[
|
|
||||||
"sps30"
|
|
||||||
] = `#include <sps30.h> // http://librarymanager/All#`;
|
|
||||||
Blockly.Arduino.variables_["sps30_measurement"] =
|
|
||||||
"struct sps30_measurement m;";
|
|
||||||
Blockly.Arduino.variables_["sps30_auto_clean_days"] =
|
|
||||||
"uint32_t auto_clean_days = 4;";
|
|
||||||
Blockly.Arduino.variables_["sps30_interval_intervalsps"] =
|
|
||||||
"const long intervalsps = 1000;";
|
|
||||||
Blockly.Arduino.variables_["sps30_time_startsps"] =
|
|
||||||
"unsigned long time_startsps = 0;";
|
|
||||||
Blockly.Arduino.variables_["sps30_time_actualsps"] =
|
|
||||||
"unsigned long time_actualsps = 0;";
|
|
||||||
Blockly.Arduino.codeFunctions_["sps30_getData"] = `
|
|
||||||
void getSPS30Data(){
|
|
||||||
|
|
||||||
uint16_t data_ready;
|
|
||||||
int16_t ret;
|
|
||||||
|
|
||||||
do {
|
|
||||||
ret = sps30_read_data_ready(&data_ready);
|
|
||||||
if (ret < 0) {
|
|
||||||
} else if (!data_ready) {}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
delay(100); /* retry in 100ms */
|
|
||||||
} while (1);
|
|
||||||
ret = sps30_read_measurement(&m);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
Blockly.Arduino.setupCode_["sps30_begin"] = "sensirion_i2c_init();";
|
|
||||||
Blockly.Arduino.setupCode_["sps30_setFanCleaningInterval"] =
|
|
||||||
"sps30_set_fan_auto_cleaning_interval_days(auto_clean_days);";
|
|
||||||
Blockly.Arduino.setupCode_["sps30_startMeasurement"] =
|
|
||||||
"sps30_start_measurement();";
|
|
||||||
Blockly.Arduino.loopCodeOnce_["getSPS30Data();"] = `
|
|
||||||
time_startsps = millis();
|
|
||||||
if (time_startsps > time_actualsps + intervalsps) {
|
|
||||||
time_actualsps = millis();
|
|
||||||
getSPS30Data();
|
|
||||||
}`;
|
|
||||||
var code = `m.mc_${dropdown_name}`;
|
|
||||||
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,12 +1,4 @@
|
|||||||
import Blockly from "blockly";
|
import Blockly from "blockly";
|
||||||
//import store from "../../../store";
|
|
||||||
|
|
||||||
// preperations for the esp board
|
|
||||||
// var selectedBoard = store.getState().board.board;
|
|
||||||
// store.subscribe(() => {
|
|
||||||
// selectedBoard = store.getState().board.board;
|
|
||||||
// });
|
|
||||||
|
|
||||||
|
|
||||||
/* Wifi connection and openSenseMap Blocks*/
|
/* Wifi connection and openSenseMap Blocks*/
|
||||||
Blockly.Arduino.sensebox_wifi = function (block) {
|
Blockly.Arduino.sensebox_wifi = function (block) {
|
||||||
@@ -118,5 +110,3 @@ Blockly.Arduino.sensebox_ethernetIp = function () {
|
|||||||
var code = "Ethernet.localIP()";
|
var code = "Ethernet.localIP()";
|
||||||
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
return [code, Blockly.Arduino.ORDER_ATOMIC];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,17 +2,10 @@ import Blockly from "blockly";
|
|||||||
|
|
||||||
const setVariableFunction = function (defaultValue) {
|
const setVariableFunction = function (defaultValue) {
|
||||||
return function (block) {
|
return function (block) {
|
||||||
var id = block.getFieldValue("VAR");
|
const variableName = Blockly["Arduino"].nameDB_.getName(
|
||||||
|
block.getFieldValue("VAR"),
|
||||||
const variableName = Blockly.Variables.getVariable(
|
Blockly.Variables.NAME_TYPE
|
||||||
Blockly.getMainWorkspace(),
|
);
|
||||||
id
|
|
||||||
).name;
|
|
||||||
|
|
||||||
// const variableName = Blockly["Arduino"].nameDB_.getName(
|
|
||||||
// id,
|
|
||||||
// Blockly.Variables.NAME_TYPE
|
|
||||||
// );
|
|
||||||
const variableValue = Blockly["Arduino"].valueToCode(
|
const variableValue = Blockly["Arduino"].valueToCode(
|
||||||
block,
|
block,
|
||||||
"VALUE",
|
"VALUE",
|
||||||
@@ -24,32 +17,42 @@ const setVariableFunction = function (defaultValue) {
|
|||||||
.getAllVariables();
|
.getAllVariables();
|
||||||
const myVar = allVars.filter((v) => v.name === variableName)[0];
|
const myVar = allVars.filter((v) => v.name === variableName)[0];
|
||||||
var code = "";
|
var code = "";
|
||||||
if (myVar !== undefined) {
|
|
||||||
|
switch (myVar.type) {
|
||||||
|
default:
|
||||||
Blockly.Arduino.variables_[variableName + myVar.type] =
|
Blockly.Arduino.variables_[variableName + myVar.type] =
|
||||||
myVar.type + " " + myVar.name + ";\n";
|
myVar.type + " " + myVar.name + ";\n";
|
||||||
code = variableName + " = " + (variableValue || defaultValue) + ";\n";
|
code = variableName + " = " + (variableValue || defaultValue) + ";\n";
|
||||||
|
break;
|
||||||
|
case "Array":
|
||||||
|
var arrayType;
|
||||||
|
var number;
|
||||||
|
|
||||||
|
if (this.getChildren().length > 0) {
|
||||||
|
if (this.getChildren()[0].type === "lists_create_empty") {
|
||||||
|
arrayType = this.getChildren()[0].getFieldValue("type");
|
||||||
|
number = Blockly.Arduino.valueToCode(
|
||||||
|
this.getChildren()[0],
|
||||||
|
"NUMBER",
|
||||||
|
Blockly["Arduino"].ORDER_ATOMIC
|
||||||
|
);
|
||||||
|
Blockly.Arduino.variables_[
|
||||||
|
myVar + myVar.type
|
||||||
|
] = `${arrayType} ${myVar.name} [${number}];\n`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const getVariableFunction = function (block) {
|
const getVariableFunction = function (block) {
|
||||||
var id = block.getFieldValue("VAR");
|
const variableName = Blockly["Arduino"].nameDB_.getName(
|
||||||
|
block.getFieldValue("VAR"),
|
||||||
const variableName = Blockly.Variables.getVariable(
|
Blockly.Variables.NAME_TYPE
|
||||||
Blockly.getMainWorkspace(),
|
);
|
||||||
id
|
var code = variableName;
|
||||||
).name;
|
|
||||||
|
|
||||||
const allVars = Blockly.getMainWorkspace()
|
|
||||||
.getVariableMap()
|
|
||||||
.getAllVariables();
|
|
||||||
const myVar = allVars.filter((v) => v.name === variableName)[0];
|
|
||||||
// const variableName = Blockly["Arduino"].nameDB_.getName(
|
|
||||||
// block.getFieldValue("VAR"),
|
|
||||||
// Blockly.Variables.NAME_TYPE
|
|
||||||
// );
|
|
||||||
var code = myVar.name;
|
|
||||||
return [code, Blockly["Arduino"].ORDER_ATOMIC];
|
return [code, Blockly["Arduino"].ORDER_ATOMIC];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -23,11 +23,6 @@ const sensebox_mcu = {
|
|||||||
["C5", "5"],
|
["C5", "5"],
|
||||||
["C6", "6"],
|
["C6", "6"],
|
||||||
],
|
],
|
||||||
digitalPinsRGB: [
|
|
||||||
["A", "1"],
|
|
||||||
["B", "3"],
|
|
||||||
["C", "5"],
|
|
||||||
],
|
|
||||||
digitalPinsButton: [
|
digitalPinsButton: [
|
||||||
["on Board", "0"],
|
["on Board", "0"],
|
||||||
["A1", "1"],
|
["A1", "1"],
|
||||||
@@ -46,13 +41,9 @@ const sensebox_mcu = {
|
|||||||
["C6", "6"],
|
["C6", "6"],
|
||||||
],
|
],
|
||||||
serial: [
|
serial: [
|
||||||
["SerialUSB", "SerialUSB"],
|
["serial", "SerialUSB"],
|
||||||
["Serial1", "Serial1"],
|
["serial_1", "Serial1"],
|
||||||
["Serial2", "Serial2"],
|
["serial_2", "Serial2"],
|
||||||
],
|
|
||||||
serialSensors: [
|
|
||||||
["Serial1", "Serial1"],
|
|
||||||
["Serial2", "Serial2"],
|
|
||||||
],
|
],
|
||||||
serialPins: {
|
serialPins: {
|
||||||
SerialUSB: [
|
SerialUSB: [
|
||||||
@@ -135,127 +126,6 @@ const sensebox_mcu = {
|
|||||||
parseKey: "_*_",
|
parseKey: "_*_",
|
||||||
};
|
};
|
||||||
|
|
||||||
//senseBox MCU mini
|
|
||||||
const sensebox_mini = {
|
|
||||||
description: "senseBox Mini",
|
|
||||||
compilerFlag: "arduino:samd",
|
|
||||||
digitalPins: [
|
|
||||||
["IO1", "1"],
|
|
||||||
["IO2", "2"],
|
|
||||||
],
|
|
||||||
digitalPinsLED: [
|
|
||||||
["BUILTIN_1", "7"],
|
|
||||||
["BUILTIN_2", "8"],
|
|
||||||
["IO1", "1"],
|
|
||||||
["IO2", "2"],
|
|
||||||
],
|
|
||||||
digitalPinsRGB: [
|
|
||||||
["on Board", "6"],
|
|
||||||
["IO1", "1"],
|
|
||||||
["IO2", "2"],
|
|
||||||
],
|
|
||||||
digitalPinsButton: [
|
|
||||||
["on Board", "0"],
|
|
||||||
["IO1", "1"],
|
|
||||||
["IO2", "2"],
|
|
||||||
|
|
||||||
],
|
|
||||||
pwmPins: [
|
|
||||||
["IO1", "1"],
|
|
||||||
["IO2", "2"],
|
|
||||||
],
|
|
||||||
serial: [
|
|
||||||
["SerialUSB", "SerialUSB"],
|
|
||||||
["Serial1", "Serial1"],
|
|
||||||
],
|
|
||||||
serialSensors: [
|
|
||||||
["Serial1", "Serial1"],
|
|
||||||
],
|
|
||||||
serialPins: {
|
|
||||||
SerialUSB: [
|
|
||||||
["RX", ""],
|
|
||||||
["TX", ""],
|
|
||||||
],
|
|
||||||
Serial1: [
|
|
||||||
["RX", "11"],
|
|
||||||
["TX", "10"],
|
|
||||||
],
|
|
||||||
Serial2: [
|
|
||||||
["RX", "13"],
|
|
||||||
["TX", "12"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
serialSpeed: [
|
|
||||||
["300", "300"],
|
|
||||||
["600", "600"],
|
|
||||||
["1200", "1200"],
|
|
||||||
["2400", "2400"],
|
|
||||||
["4800", "4800"],
|
|
||||||
["9600", "9600"],
|
|
||||||
["14400", "14400"],
|
|
||||||
["19200", "19200"],
|
|
||||||
["28800", "28800"],
|
|
||||||
["31250", "31250"],
|
|
||||||
["38400", "38400"],
|
|
||||||
["57600", "57600"],
|
|
||||||
["115200", "115200"],
|
|
||||||
],
|
|
||||||
spi: [["SPI", "SPI"]],
|
|
||||||
spiPins: {
|
|
||||||
SPI: [
|
|
||||||
["MOSI", "19"],
|
|
||||||
["MISO", "21"],
|
|
||||||
["SCK", "20"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
spiClockDivide: [
|
|
||||||
["2 (8MHz)", "SPI_CLOCK_DIV2"],
|
|
||||||
["4 (4MHz)", "SPI_CLOCK_DIV4"],
|
|
||||||
["8 (2MHz)", "SPI_CLOCK_DIV8"],
|
|
||||||
["16 (1MHz)", "SPI_CLOCK_DIV16"],
|
|
||||||
["32 (500KHz)", "SPI_CLOCK_DIV32"],
|
|
||||||
["64 (250KHz)", "SPI_CLOCK_DIV64"],
|
|
||||||
["128 (125KHz)", "SPI_CLOCK_DIV128"],
|
|
||||||
],
|
|
||||||
i2c: [["I2C", "Wire"]],
|
|
||||||
i2cPins: {
|
|
||||||
Wire: [
|
|
||||||
["SDA", "17"],
|
|
||||||
["SCL", "16"],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
i2cSpeed: [
|
|
||||||
["100kHz", "100000L"],
|
|
||||||
["400kHz", "400000L"],
|
|
||||||
],
|
|
||||||
builtinLed: [
|
|
||||||
["BUILTIN_1", "7"],
|
|
||||||
["BUILTIN_2", "8"],
|
|
||||||
],
|
|
||||||
interrupt: [
|
|
||||||
["interrupt1", "1"],
|
|
||||||
["interrupt2", "2"],
|
|
||||||
],
|
|
||||||
analogPins: [
|
|
||||||
["A1", "A1"],
|
|
||||||
["A2", "A2"],
|
|
||||||
],
|
|
||||||
serial_baud_rate: 9600,
|
|
||||||
parseKey: "_*_",
|
|
||||||
};
|
|
||||||
|
|
||||||
var board = sensebox_mcu
|
|
||||||
|
|
||||||
export const setBoard = (selectedBoard) => {
|
|
||||||
if (selectedBoard === "mini"){
|
|
||||||
board = sensebox_mini
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
board = sensebox_mcu
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export const selectedBoard = () => {
|
export const selectedBoard = () => {
|
||||||
return board;
|
return sensebox_mcu;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ const colours = {
|
|||||||
serial: 230,
|
serial: 230,
|
||||||
webserver: 40,
|
webserver: 40,
|
||||||
phyphox: 25,
|
phyphox: 25,
|
||||||
motors: 190,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getColour = () => {
|
export const getColour = () => {
|
||||||
|
|||||||
@@ -21,8 +21,8 @@
|
|||||||
* @author samelh@google.com (Sam El-Husseini)
|
* @author samelh@google.com (Sam El-Husseini)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import BlocklyComponent from "./BlocklyComponent";
|
import BlocklyComponent from './BlocklyComponent';
|
||||||
|
|
||||||
export default BlocklyComponent;
|
export default BlocklyComponent;
|
||||||
|
|
||||||
@@ -56,16 +56,4 @@ const Shadow = (p) => {
|
|||||||
return React.createElement("shadow", props, children);
|
return React.createElement("shadow", props, children);
|
||||||
};
|
};
|
||||||
|
|
||||||
const Sep = (p) => {
|
export { Block, Category, Value, Field, Shadow }
|
||||||
const { children, ...props } = p;
|
|
||||||
props.is = "blockly";
|
|
||||||
return React.createElement("sep", props, children);
|
|
||||||
};
|
|
||||||
|
|
||||||
const Label = (p) => {
|
|
||||||
const { children, ...props } = p;
|
|
||||||
props.is = "blockly";
|
|
||||||
return React.createElement("label", props, children);
|
|
||||||
};
|
|
||||||
|
|
||||||
export { Block, Category, Value, Field, Shadow, Sep, Label };
|
|
||||||
@@ -7,12 +7,10 @@ import { LOOPS } from "./de/loops";
|
|||||||
import { MATH } from "./de/math";
|
import { MATH } from "./de/math";
|
||||||
import { MQTT } from "./de/mqtt";
|
import { MQTT } from "./de/mqtt";
|
||||||
import { DISPLAY } from "./de/sensebox-display";
|
import { DISPLAY } from "./de/sensebox-display";
|
||||||
import { MOTORS } from "./de/sensebox-motors";
|
|
||||||
import { LED } from "./de/sensebox-led";
|
import { LED } from "./de/sensebox-led";
|
||||||
import { LORA } from "./de/sensebox-lora";
|
import { LORA } from "./de/sensebox-lora";
|
||||||
import { OSEM } from "./de/sensebox-osem";
|
import { OSEM } from "./de/sensebox-osem";
|
||||||
import { RTC } from "./de/sensebox-rtc";
|
import { RTC } from "./de/sensebox-rtc";
|
||||||
import { NTP } from "./de/sensebox-ntp";
|
|
||||||
import { SD } from "./de/sensebox-sd";
|
import { SD } from "./de/sensebox-sd";
|
||||||
import { SENSORS } from "./de/sensebox-sensors";
|
import { SENSORS } from "./de/sensebox-sensors";
|
||||||
import { SENSEBOX } from "./de/sensebox";
|
import { SENSEBOX } from "./de/sensebox";
|
||||||
@@ -36,12 +34,10 @@ export const De = {
|
|||||||
...MATH,
|
...MATH,
|
||||||
...MQTT,
|
...MQTT,
|
||||||
...DISPLAY,
|
...DISPLAY,
|
||||||
...MOTORS,
|
|
||||||
...LED,
|
...LED,
|
||||||
...LORA,
|
...LORA,
|
||||||
...OSEM,
|
...OSEM,
|
||||||
...RTC,
|
...RTC,
|
||||||
...NTP,
|
|
||||||
...SD,
|
...SD,
|
||||||
...SENSORS,
|
...SENSORS,
|
||||||
...SENSEBOX,
|
...SENSEBOX,
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
export const MOTORS = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Motors
|
|
||||||
*/
|
|
||||||
|
|
||||||
sensebox_motors_beginServoMotor: "Initialisiere Servomotor",
|
|
||||||
sensebox_motors_beginServoMotor_pin: "Pin:",
|
|
||||||
sensebox_motors_beginServoMotor_tooltip: "Verbinde einen digitalen Pin mit dem orangen Kabel des Servomotrors. Verbinde zusätzlich GND mit GND (schwarzes und braunes Kabel) und 5V mit 5V (rotes Kabel).",
|
|
||||||
sensebox_motors_beginServoMotor_helpurl: "https://de.wikipedia.org/wiki/Servomotor",
|
|
||||||
|
|
||||||
sensebox_motors_moveServoMotor: "Bewege Servomotor",
|
|
||||||
sensebox_motors_moveServoMotor_pin: "Pin:",
|
|
||||||
sensebox_motors_moveServoMotor_degrees: "Winkel in Grad:",
|
|
||||||
sensebox_motors_moveServoMotor_tooltip: "Der Servomotor kann zwischen 0 und 180 Grad bewegt werden.",
|
|
||||||
sensebox_motors_moveServoMotor_helpurl: "https://de.wikipedia.org/wiki/Servomotor",
|
|
||||||
|
|
||||||
sensebox_motors_I2CMotorBoard_begin: "Initialize I2C Motor Board",
|
|
||||||
sensebox_motors_I2CMotorBoard_begin_tooltip: "Connect the I2C Moztor Board with the two DC Motors to one of the five I2C-Ports. Use this Block inside the setup()-function.",
|
|
||||||
sensebox_motors_I2CMotorBoard_begin_helpurl: "TODO",
|
|
||||||
|
|
||||||
sensebox_motors_I2CMotorBoard_moveDCMotor: "Move",
|
|
||||||
sensebox_motors_I2CMotorBoard_moveDCMotor_left: "left",
|
|
||||||
sensebox_motors_I2CMotorBoard_moveDCMotor_right: "right",
|
|
||||||
sensebox_motors_I2CMotorBoard_moveDCMotor_motor: "DC Motor at I2C Motor Board",
|
|
||||||
sensebox_motors_I2CMotorBoard_moveDCMotor_speed: "Speed:",
|
|
||||||
sensebox_motors_I2CMotorBoard_moveDCMotor_tooltip: "You can set the Speed between -100 and 100.",
|
|
||||||
sensebox_motors_I2CMotorBoard_moveDCMotor_helpurl: "TODO",
|
|
||||||
|
|
||||||
sensebox_motors_I2CMotorBoard_stopDCMotor: "Stop ",
|
|
||||||
sensebox_motors_I2CMotorBoard_stopDCMotor_left: "left",
|
|
||||||
sensebox_motors_I2CMotorBoard_stopDCMotor_right: "right",
|
|
||||||
sensebox_motors_I2CMotorBoard_stopDCMotor_motor: "DC Motor at I2C Motor Board",
|
|
||||||
sensebox_motors_I2CMotorBoard_stopDCMotor_tooltip: "TODO",
|
|
||||||
sensebox_motors_I2CMotorBoard_stopDCMotor_helpurl: "TODO",
|
|
||||||
|
|
||||||
sensebox_motors_beginStepperMotor: "Initialize Stepper Motor (28BYJ-48)",
|
|
||||||
sensebox_motors_beginStepperMotor_rpm: "Rotations per Minute:",
|
|
||||||
sensebox_motors_beginStepperMotor_pins: "Input Pins (IN1-IN4):",
|
|
||||||
sensebox_motors_beginStepperMotor_tooltip: "Connect four of the the digital pins in the right order to the inputs IN1-IN4 on the stepper motor board. Connect a GND pin (black wire) to the minus pin and a 5V pin (red wire) to the plus pin on the board. Also connect the stepper motor to this Board. Use this Block inside the setup()-function.",
|
|
||||||
sensebox_motors_beginStepperMotor_helpurl: "TODO",
|
|
||||||
|
|
||||||
sensebox_motors_moveStepperMotor: "Move Stepper Motor (28BYJ-48)",
|
|
||||||
sensebox_motors_moveStepperMotor_step: "Steps:",
|
|
||||||
sensebox_motors_moveStepperMotor_tooltip: "Move stepper motor. 2048 steps equal a full rotation.",
|
|
||||||
sensebox_motors_moveStepperMotor_helpurl: "TODO",
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
export const NTP = {
|
|
||||||
sensebox_ntp_init: "Initialisiere NTP",
|
|
||||||
sensebox_ntp_init_tooltip: "Initialisiere den NTP Server.",
|
|
||||||
sensebox_ntp_get: "Hole Zeit von NTP Server: ",
|
|
||||||
sensebox_ntp_get_timestamp_tooltip:
|
|
||||||
"Gibt dir einen in ISO 8601 formatierten Zeitstempel zurück. Bsp: 2021-12-24T18:21Z",
|
|
||||||
sensebox_ntp_get_tooltip:
|
|
||||||
"Gibt dir den ausgewählten Wert zurück. Unix Zeit entspricht der Anzahl der Sekunden seit dem 1.1.1970",
|
|
||||||
sensebox_ntp_epochTime: "Unix Zeit",
|
|
||||||
sensebox_ntp_formattedTimeStamp: "Zeitstempel (hh:mm:ss)",
|
|
||||||
};
|
|
||||||
@@ -10,12 +10,11 @@ export const OSEM = {
|
|||||||
senseBox_send_to_osem: "Sende Messwert an die openSenseMap",
|
senseBox_send_to_osem: "Sende Messwert an die openSenseMap",
|
||||||
senseBox_osem_connection: "Verbinde mit openSenseMap:",
|
senseBox_osem_connection: "Verbinde mit openSenseMap:",
|
||||||
senseBox_osem_host: "opensensemap.org",
|
senseBox_osem_host: "opensensemap.org",
|
||||||
senseBox_osem_host_testing: "testing.opensensemap.org",
|
senseBox_osem_host_workshop: "workshop.opensensemap.org",
|
||||||
senseBox_osem_exposure: "Typ",
|
senseBox_osem_exposure: "Typ",
|
||||||
senseBox_osem_stationary: "Stationär",
|
senseBox_osem_stationary: "Stationär",
|
||||||
senseBox_osem_mobile: "Mobil",
|
senseBox_osem_mobile: "Mobil",
|
||||||
senseBox_osem_access_token: "API Schlüssel",
|
senseBox_osem_access_token: "API Schlüssel",
|
||||||
senseBox_osem_xallowtoken: "X-ALLOW-TOKEN",
|
|
||||||
senseBox_send_mobile_to_osem:
|
senseBox_send_mobile_to_osem:
|
||||||
"Sende Messwert und Standort an die openSenseMap",
|
"Sende Messwert und Standort an die openSenseMap",
|
||||||
senseBox_send_mobile_to_osem_tip:
|
senseBox_send_mobile_to_osem_tip:
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
export const RTC = {
|
export const RTC = {
|
||||||
sensebox_rtc_init: "Initialisiere externe RTC",
|
sensebox_rtc_init: "Initialisiere RTC",
|
||||||
sensebox_rtc_init_tooltip:
|
sensebox_rtc_init_tooltip:
|
||||||
"Initialisiere die RTC. Schließe diese an einen der 5 I2C/Wire Anschlüsse an und lege die Batterie ein. Bevor du die Uhrzeit auslesen kannst muss diese zunächst einmal gesetzt werden. Dieser Schritt muss normalerweise nur einmalig durchgeführt werden.",
|
"Initialisiere die RTC. Schließe diese an einen der 5 I2C/Wire Anschlüsse an und lege die Batterie ein. Bevor du die Uhrzeit auslesen kannst muss diese zunächst einmal gesetzt werden. Dieser Schritt muss normalerweise nur einmalig durchgeführt werden.",
|
||||||
sensebox_rtc_set: "Setze Uhrzeit/Datum der externen RTC",
|
sensebox_rtc_set: "Setze Uhrzeit/Datum der RTC",
|
||||||
sensebox_rtc_set_tooltip:
|
sensebox_rtc_set_tooltip:
|
||||||
"Stellt die Uhrzeit der RTC ein. Beachte, dass du diesen Block im Setup ausführst.",
|
"Stellt die Uhrzeit der RTC ein. Beachte, dass du diesen Block im Setup ausführst.",
|
||||||
sensebox_rtc_get_timestamp: "Zeitstempel externe RTC (RFC 3339)",
|
sensebox_rtc_get_timestamp: "Zeitstempel (RFC 3339)",
|
||||||
sensebox_rtc_get_timestamp_tooltip:
|
sensebox_rtc_get_timestamp_tooltip:
|
||||||
"Gibt dir einen in ISO 8601 formatierten Zeitstempel zurück. Bsp: 2021-12-24T18:21Z",
|
"Gibt dir einen in ISO 8601 formatierten Zeitstempel zurück. Bsp: 2021-12-24T18:21Z",
|
||||||
sensebox_rtc_get: "Wert (externe RTC): ",
|
sensebox_rtc_get: "Wert: ",
|
||||||
sensebox_rtc_get_tooltip: "Gibt dir den ausgewählten Wert zurück.",
|
sensebox_rtc_get_tooltip: "Gibt dir den ausgewählten Wert zurück.",
|
||||||
sensebox_rtc_second: "Sekunden",
|
sensebox_rtc_second: "Sekunden",
|
||||||
sensebox_rtc_minutes: "Minuten",
|
sensebox_rtc_minutes: "Minuten",
|
||||||
@@ -16,22 +16,4 @@ export const RTC = {
|
|||||||
sensebox_rtc_day: "Tag",
|
sensebox_rtc_day: "Tag",
|
||||||
sensebox_rtc_month: "Monat",
|
sensebox_rtc_month: "Monat",
|
||||||
sensebox_rtc_year: "Jahr",
|
sensebox_rtc_year: "Jahr",
|
||||||
sensebox_internal_rtc_init: "Initialisiere interne RTC",
|
|
||||||
sensebox_internal_rtc_init_tooltip:
|
|
||||||
"Initialisieren der internen RTC. Diese RTC ist nicht batteriegepuffert und wird bei jedem Einschaltvorgang zurückgesetzt",
|
|
||||||
sensebox_internal_rtc_set: "Setze interne RTC Zeit/Datum (Unix Time)",
|
|
||||||
sensebox_internal_rtc_set_tooltip:
|
|
||||||
"Setzt die Zeit der internen RTC. Führe den Block einmalig im Setup aus und setzte die Uhrzeit über die Unix Zeit.",
|
|
||||||
sensebox_internal_rtc_get: "Wert (interne RTC): ",
|
|
||||||
sensebox_internal_rtc_get_timestamp: "Zeitstempel interne RTC (RFC 3339)",
|
|
||||||
sensebox_internal_rtc_get_timestamp_tooltip:
|
|
||||||
"Returns a timestamp formatted in ISO 8601. Ex: 2021-12-24T18:21Z",
|
|
||||||
sensebox_internal_rtc_get_tooltip: "Gibt den ausgewählten Wert zurück",
|
|
||||||
sensebox_internal_rtc_epoch: "Unix Zeit",
|
|
||||||
sensebox_internal_rtc_year: "Jahr",
|
|
||||||
sensebox_internal_rtc_month: "Monat",
|
|
||||||
sensebox_internal_rtc_day: "Tag",
|
|
||||||
sensebox_internal_rtc_hour: "Stunde",
|
|
||||||
sensebox_internal_rtc_minutes: "Minute",
|
|
||||||
sensebox_internal_rtc_seconds: "Sekunde",
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -132,15 +132,29 @@ Wenn die maximale Distanz überschritten wird, wird ein Wert von **O** ausgegebe
|
|||||||
"Schließe den Sensor an einen der 3 **digital/analog Ports** an. Der Sensor gibt dir den Messwert in dB mit einer Nachkommastelle",
|
"Schließe den Sensor an einen der 3 **digital/analog Ports** an. Der Sensor gibt dir den Messwert in dB mit einer Nachkommastelle",
|
||||||
senseBox_soundsensor_dfrobot_helpurl:
|
senseBox_soundsensor_dfrobot_helpurl:
|
||||||
"https://docs.sensebox.de/hardware/sensoren-lautstaerke/",
|
"https://docs.sensebox.de/hardware/sensoren-lautstaerke/",
|
||||||
|
|
||||||
|
/*
|
||||||
|
* rainsensor hydreon rg-15
|
||||||
|
*/
|
||||||
|
sensebox_rainsensor_hydreon_rg15: "Regensensor (RG-15)",
|
||||||
|
sensebox_rainsensor_hydreon_rg15_port: "Serieller Port:",
|
||||||
|
sensebox_rainsensor_hydreon_rg15_serial1: "Serial1",
|
||||||
|
sensebox_rainsensor_hydreon_rg15_serial2: "Serial2",
|
||||||
|
sensebox_rainsensor_hydreon_rg15_value: "Messwert:",
|
||||||
|
sensebox_rainsensor_hydreon_rg15_totalAcc: "gesamter Niederschlag in mm",
|
||||||
|
sensebox_rainsensor_hydreon_rg15_rainInt: "Niederschlagsintensität in mm/h",
|
||||||
|
sensebox_rainsensor_hydreon_rg15_eventAcc: "Niederschlag pro Event in mm",
|
||||||
|
sensebox_rainsensor_hydreon_rg15_acc: "Niederschlag seit letzter Messung in mm",
|
||||||
|
sensebox_rainsensor_hydreon_rg15_tooltip: "Regensensor (RG-15) an einen der Seriellen Ports anschließen.",
|
||||||
|
sensebox_rainsensor_hydreon_rg15_helpurl: "https://rainsensors.com/products/rg-15/",
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BME680
|
* BME680
|
||||||
*/
|
*/
|
||||||
|
|
||||||
senseBox_bme680: "Umweltsensor (BME680)",
|
senseBox_bme680: "Umweltsensor (BME680)",
|
||||||
senseBox_bme_iaq: "Innenraumluftqualität (IAQ)",
|
senseBox_bme_iaq: "Innenraumluftqualität (IAQ)",
|
||||||
senseBox_bme_iaq_accuracy: "Kalibrierungswert",
|
senseBox_bme_iaq_accuracy: "Kalibrierungswert",
|
||||||
senseBox_bme_co2: "CO2 Äquivalent",
|
senseBox_bme_co2: "CO2 Äquivalent",
|
||||||
senseBox_bme_pressure: "Luftdruck in Pa",
|
|
||||||
senseBox_bme_breatheVocEquivalent: "Atemluft VOC Äquivalent",
|
senseBox_bme_breatheVocEquivalent: "Atemluft VOC Äquivalent",
|
||||||
senseBox_bme_tooltip: `Schließe den Umweltsensor an einen der 5 **I2C-Anschlüsse** an. **Beachte:** Der Sensor benöigt eine gewisse Zeit zum kalibrieren.
|
senseBox_bme_tooltip: `Schließe den Umweltsensor an einen der 5 **I2C-Anschlüsse** an. **Beachte:** Der Sensor benöigt eine gewisse Zeit zum kalibrieren.
|
||||||
Den Status der Kalibrierung kann über den Kalibrierungswert abgelesen werden. Er ist entweder 0, 1, 2 oder 3 und sagt folgendes aus:
|
Den Status der Kalibrierung kann über den Kalibrierungswert abgelesen werden. Er ist entweder 0, 1, 2 oder 3 und sagt folgendes aus:
|
||||||
@@ -176,7 +190,7 @@ Die Messwerte für Temperatur, Luftfeuchtigkeit und Luftdruck können direkt ver
|
|||||||
* Feinstaubsensor (SDS011)
|
* Feinstaubsensor (SDS011)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
senseBox_sds011: "Feinstaubsensor SDS011",
|
senseBox_sds011: "Feinstaubsensor",
|
||||||
senseBox_sds011_dimension: "in µg/m³ an",
|
senseBox_sds011_dimension: "in µg/m³ an",
|
||||||
senseBox_sds011_pm25: "PM2.5",
|
senseBox_sds011_pm25: "PM2.5",
|
||||||
senseBox_sds011_pm10: "PM10",
|
senseBox_sds011_pm10: "PM10",
|
||||||
@@ -201,23 +215,4 @@ Die Messwerte für Temperatur, Luftfeuchtigkeit und Luftdruck können direkt ver
|
|||||||
- "wurde gedrückt": Mit diesem Modus kannst du abfragen ob der Block gedrückt wurde. Erst wenn der Knopf gedrückt und wieder losgelassen wurde erhältst du TRUE zurück
|
- "wurde gedrückt": Mit diesem Modus kannst du abfragen ob der Block gedrückt wurde. Erst wenn der Knopf gedrückt und wieder losgelassen wurde erhältst du TRUE zurück
|
||||||
- "als Schalter": Wenn du diesen Block verwendest kannst du den Knopf wie ein Lichtschalter verwenden. Der Status wird gespeichert bis der Button erneut gedrückt wird`,
|
- "als Schalter": Wenn du diesen Block verwendest kannst du den Knopf wie ein Lichtschalter verwenden. Der Status wird gespeichert bis der Button erneut gedrückt wird`,
|
||||||
senseBox_button_helpurl: "",
|
senseBox_button_helpurl: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Feinstaubsensor Sensirion SPS30
|
|
||||||
*/
|
|
||||||
|
|
||||||
senseBox_sps30: "Feinstaubsensor Sensirion SPS30",
|
|
||||||
senseBox_sps30_dimension: "in µg/m³",
|
|
||||||
senseBox_sps30_1p0: "PM1.0",
|
|
||||||
senseBox_sps30_2p5: "PM2.5",
|
|
||||||
senseBox_sps30_4p0: "PM4.0",
|
|
||||||
senseBox_sps30_10p0: "PM10",
|
|
||||||
senseBox_sps30_tooltip:"Dieser Block gibt dir den Messwert des Sensirion SPS30 Feinstaubsensor. Schließe den Feinstaubsensor an einen der 5 **I2C** Anschlüssen an. Im Dropdown Menü zwischen PM1.0, PM2.5, PM4.0 und PM10 auswählen. Der Messwert wird dir als **Kommazahl** in µg/m3",
|
|
||||||
senseBox_sps30_helpurl:
|
|
||||||
"https://docs.sensebox.de/hardware/sensoren-feinstaub/",
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -8,15 +8,10 @@ export const UI = {
|
|||||||
toolbox_math: "Mathematik",
|
toolbox_math: "Mathematik",
|
||||||
toolbox_io: "Eingang/Ausgang",
|
toolbox_io: "Eingang/Ausgang",
|
||||||
toolbox_time: "Zeit",
|
toolbox_time: "Zeit",
|
||||||
toolbox_rtc: "RTC",
|
|
||||||
toolbox_ntp: "NTP",
|
|
||||||
toolbox_functions: "Funktionen",
|
toolbox_functions: "Funktionen",
|
||||||
toolbox_variables: "Variablen",
|
toolbox_variables: "Variablen",
|
||||||
toolbox_serial: "Seriell",
|
toolbox_serial: "Seriell",
|
||||||
toolbox_advanced: "Erweitert",
|
toolbox_advanced: "Erweitert",
|
||||||
toolbox_motors: "Motoren",
|
|
||||||
toolbox_label_externalRTC: "Externe RTC",
|
|
||||||
toolbox_label_internalRTC: "Interne RTC",
|
|
||||||
variable_NUMBER: "Zahl (int)",
|
variable_NUMBER: "Zahl (int)",
|
||||||
variable_SHORT_NUMBER: "char",
|
variable_SHORT_NUMBER: "char",
|
||||||
variable_LONG: "große Zahl (long)",
|
variable_LONG: "große Zahl (long)",
|
||||||
@@ -146,7 +141,6 @@ export const UI = {
|
|||||||
|
|
||||||
button_cancel: "Abbrechen",
|
button_cancel: "Abbrechen",
|
||||||
button_close: "Schließen",
|
button_close: "Schließen",
|
||||||
button_save: "Speichern",
|
|
||||||
button_accept: "Bestätigen",
|
button_accept: "Bestätigen",
|
||||||
button_compile: "Kompilieren",
|
button_compile: "Kompilieren",
|
||||||
button_create_variableCreate: "Erstelle Variable",
|
button_create_variableCreate: "Erstelle Variable",
|
||||||
@@ -187,8 +181,7 @@ export const UI = {
|
|||||||
settings_sounds: "Töne",
|
settings_sounds: "Töne",
|
||||||
settings_sounds_text:
|
settings_sounds_text:
|
||||||
"Aktiviere oder Deaktiviere Töne beim hinzufügen und löschen von Blöcken. Standardmäßig deaktiviert",
|
"Aktiviere oder Deaktiviere Töne beim hinzufügen und löschen von Blöcken. Standardmäßig deaktiviert",
|
||||||
settings_board: "Board",
|
|
||||||
settings_board_text: "Wähle dein verwendetes Board aus",
|
|
||||||
/**
|
/**
|
||||||
* 404
|
* 404
|
||||||
*/
|
*/
|
||||||
@@ -235,12 +228,6 @@ export const UI = {
|
|||||||
builder_requirements_head: "Voraussetzungen",
|
builder_requirements_head: "Voraussetzungen",
|
||||||
builder_requirements_order:
|
builder_requirements_order:
|
||||||
"Beachte, dass die Reihenfolge des Anhakens maßgebend ist.",
|
"Beachte, dass die Reihenfolge des Anhakens maßgebend ist.",
|
||||||
builder_difficulty: "Schwierigkeitsgrad",
|
|
||||||
builder_public_head: "Tutorial veröffentlichen",
|
|
||||||
builder_public_label: "Tutorial für alle Nutzer:innen veröffentlichen",
|
|
||||||
builder_review_head: "Tutorial veröffentlichen",
|
|
||||||
builder_review_text:
|
|
||||||
"Du kannst dein Tutorial direkt über den Link mit anderen Personen teilen. Wenn du dein Tutorial für alle Nutzer:innen in der Überischt veröffenltichen wollen kannst du es hier aktivieren. Ein Administrator wird dein Tutorial ansehen und anschließend freischalten.",
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Login
|
* Login
|
||||||
@@ -254,7 +241,7 @@ export const UI = {
|
|||||||
/**
|
/**
|
||||||
* Navbar
|
* Navbar
|
||||||
*/
|
*/
|
||||||
navbar_blockly: "Blockly",
|
|
||||||
navbar_tutorials: "Tutorials",
|
navbar_tutorials: "Tutorials",
|
||||||
navbar_tutorialbuilder: "Tutorial erstellen",
|
navbar_tutorialbuilder: "Tutorial erstellen",
|
||||||
navbar_gallery: "Galerie",
|
navbar_gallery: "Galerie",
|
||||||
@@ -295,26 +282,4 @@ export const UI = {
|
|||||||
drawer_ideerror_head: "Hoppla da ist was schief gegangen.",
|
drawer_ideerror_head: "Hoppla da ist was schief gegangen.",
|
||||||
drawer_ideerror_text:
|
drawer_ideerror_text:
|
||||||
"Beim kompilieren ist ein Fehler aufgetreten, überprüfe deine Blöcke.",
|
"Beim kompilieren ist ein Fehler aufgetreten, überprüfe deine Blöcke.",
|
||||||
|
|
||||||
/**
|
|
||||||
* Code Editor
|
|
||||||
* */
|
|
||||||
codeeditor_libraries_head: "Installierte Arduino Libraries",
|
|
||||||
codeeditor_libraries_text:
|
|
||||||
"Für die Dokumentation sehen Sie sich die installierten Bibliotheken und deren Beispiele an",
|
|
||||||
codeeditor_save_code: "Code herunterladen",
|
|
||||||
codeeditor_open_code: "Code öffnen",
|
|
||||||
codeeditor_reset_code: "Code zurücksetzen",
|
|
||||||
codeeditor_blockly_code: "Lade Blockly Code",
|
|
||||||
codeeditor_compile_progress:
|
|
||||||
"Dein Code wird nun kompiliert und anschließend auf deinen Computer heruntergeladen",
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Device Selction
|
|
||||||
* */
|
|
||||||
deviceselection_head: "Welches Board benutzt du?",
|
|
||||||
deviceselection_keep_selection:
|
|
||||||
"Speichere meine Auswahl fürs nächste Mal (Du kannst das Board später in den Einstellungen wechseln)",
|
|
||||||
deviceselection_footnote: "Hier kommst du zur alten Blockly Version für den ",
|
|
||||||
deviceselection_footnote_02: "oder die",
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,12 +8,10 @@ import { MATH } from "./en/math";
|
|||||||
import { MQTT } from "./en/mqtt";
|
import { MQTT } from "./en/mqtt";
|
||||||
import { SENSEBOX } from "./en/sensebox";
|
import { SENSEBOX } from "./en/sensebox";
|
||||||
import { DISPLAY } from "./en/sensebox-display";
|
import { DISPLAY } from "./en/sensebox-display";
|
||||||
import { MOTORS } from "./en/sensebox-motors";
|
|
||||||
import { LED } from "./en/sensebox-led";
|
import { LED } from "./en/sensebox-led";
|
||||||
import { LORA } from "./en/sensebox-lora";
|
import { LORA } from "./en/sensebox-lora";
|
||||||
import { OSEM } from "./en/sensebox-osem";
|
import { OSEM } from "./en/sensebox-osem";
|
||||||
import { RTC } from "./en/sensebox-rtc";
|
import { RTC } from "./en/sensebox-rtc";
|
||||||
import { NTP } from "./en/sensebox-ntp";
|
|
||||||
import { SD } from "./en/sensebox-sd";
|
import { SD } from "./en/sensebox-sd";
|
||||||
import { SENSORS } from "./en/sensebox-sensors";
|
import { SENSORS } from "./en/sensebox-sensors";
|
||||||
import { TELEGRAM } from "./en/sensebox-telegram";
|
import { TELEGRAM } from "./en/sensebox-telegram";
|
||||||
@@ -36,12 +34,10 @@ export const En = {
|
|||||||
...MATH,
|
...MATH,
|
||||||
...MQTT,
|
...MQTT,
|
||||||
...DISPLAY,
|
...DISPLAY,
|
||||||
...MOTORS,
|
|
||||||
...LED,
|
...LED,
|
||||||
...LORA,
|
...LORA,
|
||||||
...OSEM,
|
...OSEM,
|
||||||
...RTC,
|
...RTC,
|
||||||
...NTP,
|
|
||||||
...SD,
|
...SD,
|
||||||
...SENSORS,
|
...SENSORS,
|
||||||
...SENSEBOX,
|
...SENSEBOX,
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
export const MOTORS = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Motors
|
|
||||||
*/
|
|
||||||
|
|
||||||
sensebox_motors_beginServoMotor: "Initialize Servo Motor",
|
|
||||||
sensebox_motors_beginServoMotor_pin: "Pin:",
|
|
||||||
sensebox_motors_beginServoMotor_tooltip: "Connect one of the the digital pins to the orange wire of the Servo Motor. Also Connect GND to GND (black and brown wire) and 5V to 5V (red wire).",
|
|
||||||
sensebox_motors_beginServoMotor_helpurl: "https://en.wikipedia.org/wiki/Servomotor",
|
|
||||||
|
|
||||||
sensebox_motors_moveServoMotor: "Move Servo Motor",
|
|
||||||
sensebox_motors_moveServoMotor_pin: "Pin:",
|
|
||||||
sensebox_motors_moveServoMotor_degrees: "Degrees:",
|
|
||||||
sensebox_motors_moveServoMotor_tooltip: "The Servo Motor can be moved to a spezific angle between 0 and 180 degrees.",
|
|
||||||
sensebox_motors_moveServoMotor_helpurl: "https://en.wikipedia.org/wiki/Servomotor",
|
|
||||||
|
|
||||||
sensebox_motors_I2CMotorBoard_begin: "Initialize I2C Motor Board",
|
|
||||||
sensebox_motors_I2CMotorBoard_begin_tooltip: "Connect the I2C Moztor Board with the two DC Motors to one of the five I2C-Ports. Use this Block inside the setup()-function.",
|
|
||||||
sensebox_motors_I2CMotorBoard_begin_helpurl: "TODO",
|
|
||||||
|
|
||||||
sensebox_motors_I2CMotorBoard_moveDCMotor: "Move",
|
|
||||||
sensebox_motors_I2CMotorBoard_moveDCMotor_left: "left",
|
|
||||||
sensebox_motors_I2CMotorBoard_moveDCMotor_right: "right",
|
|
||||||
sensebox_motors_I2CMotorBoard_moveDCMotor_motor: "DC Motor at I2C Motor Board",
|
|
||||||
sensebox_motors_I2CMotorBoard_moveDCMotor_speed: "Speed:",
|
|
||||||
sensebox_motors_I2CMotorBoard_moveDCMotor_tooltip: "You can set the Speed between -100 and 100.",
|
|
||||||
sensebox_motors_I2CMotorBoard_moveDCMotor_helpurl: "TODO",
|
|
||||||
|
|
||||||
sensebox_motors_I2CMotorBoard_stopDCMotor: "Stop ",
|
|
||||||
sensebox_motors_I2CMotorBoard_stopDCMotor_left: "left",
|
|
||||||
sensebox_motors_I2CMotorBoard_stopDCMotor_right: "right",
|
|
||||||
sensebox_motors_I2CMotorBoard_stopDCMotor_motor: "DC Motor at I2C Motor Board",
|
|
||||||
sensebox_motors_I2CMotorBoard_stopDCMotor_tooltip: "TODO",
|
|
||||||
sensebox_motors_I2CMotorBoard_stopDCMotor_helpurl: "TODO",
|
|
||||||
|
|
||||||
sensebox_motors_beginStepperMotor: "Initialize Stepper Motor (28BYJ-48)",
|
|
||||||
sensebox_motors_beginStepperMotor_rpm: "Rotations per Minute:",
|
|
||||||
sensebox_motors_beginStepperMotor_pins: "Input Pins (IN1-IN4):",
|
|
||||||
sensebox_motors_beginStepperMotor_tooltip: "Connect four of the the digital pins in the right order to the inputs IN1-IN4 on the stepper motor board. Connect a GND pin (black wire) to the minus pin and a 5V pin (red wire) to the plus pin on the board. Also connect the stepper motor to this Board. Use this Block inside the setup()-function.",
|
|
||||||
sensebox_motors_beginStepperMotor_helpurl: "TODO",
|
|
||||||
|
|
||||||
sensebox_motors_moveStepperMotor: "Move Stepper Motor (28BYJ-48)",
|
|
||||||
sensebox_motors_moveStepperMotor_step: "Steps:",
|
|
||||||
sensebox_motors_moveStepperMotor_tooltip: "Move stepper motor. 2048 steps equal a full rotation.",
|
|
||||||
sensebox_motors_moveStepperMotor_helpurl: "TODO",
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
export const NTP = {
|
|
||||||
sensebox_ntp_init: "Initialise NTP",
|
|
||||||
sensebox_ntp_init_tooltip:
|
|
||||||
"Initialisiere die RTC. Schließe diese an einen der 5 I2C/Wire Anschlüsse an und lege die Batterie ein. Bevor du die Uhrzeit auslesen kannst muss diese zunächst einmal gesetzt werden. Dieser Schritt muss normalerweise nur einmalig durchgeführt werden.",
|
|
||||||
sensebox_ntp_get: "Get time from NTP Server: ",
|
|
||||||
sensebox_ntp_get_tooltip:
|
|
||||||
"Gibt dir den ausgewählten Wert zurück. Unix Zeit entspricht der Anzahl der Sekunden seit dem 1.1.1970",
|
|
||||||
sensebox_ntp_epochTime: "Unix time",
|
|
||||||
sensebox_ntp_formattedTimeStamp: "Timestamp (hh:mm:ss)",
|
|
||||||
};
|
|
||||||
@@ -11,12 +11,11 @@ export const OSEM = {
|
|||||||
senseBox_send_to_osem: "Send measurement to openSenseMap",
|
senseBox_send_to_osem: "Send measurement to openSenseMap",
|
||||||
senseBox_osem_connection: "Connect to openSenseMap",
|
senseBox_osem_connection: "Connect to openSenseMap",
|
||||||
senseBox_osem_host: "opensensemap.org",
|
senseBox_osem_host: "opensensemap.org",
|
||||||
senseBox_osem_host_testing: "testing.opensensemap.org",
|
senseBox_osem_host_workshop: "workshop.opensensemap.org",
|
||||||
senseBox_osem_exposure: "Type",
|
senseBox_osem_exposure: "Type",
|
||||||
senseBox_osem_stationary: "Stationary",
|
senseBox_osem_stationary: "Stationary",
|
||||||
senseBox_osem_mobile: "Mobile",
|
senseBox_osem_mobile: "Mobile",
|
||||||
senseBox_osem_access_token: "API Key",
|
senseBox_osem_access_token: "API Key",
|
||||||
senseBox_osem_xallowtoken: "X-ALLOW-TOKEN",
|
|
||||||
senseBox_send_mobile_to_osem: "Send measurement and location to openSenseMap",
|
senseBox_send_mobile_to_osem: "Send measurement and location to openSenseMap",
|
||||||
senseBox_send_mobile_to_osem_tip: "Send Value and Location to openSenseMap",
|
senseBox_send_mobile_to_osem_tip: "Send Value and Location to openSenseMap",
|
||||||
senseBox_osem_restart: "Restart device if disconnected?",
|
senseBox_osem_restart: "Restart device if disconnected?",
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
export const RTC = {
|
export const RTC = {
|
||||||
sensebox_rtc_init: "Initialise external RTC",
|
sensebox_rtc_init: "Initialise RTC",
|
||||||
sensebox_rtc_init_tooltip:
|
sensebox_rtc_init_tooltip:
|
||||||
"Initialise the RTC. Connect it to one of the 5 I2C/Wire connections and insert the battery. Before you can read out the time, it must first be set. This step usually only needs to be done once.",
|
"Initialise the RTC. Connect it to one of the 5 I2C/Wire connections and insert the battery. Before you can read out the time, it must first be set. This step usually only needs to be done once.",
|
||||||
sensebox_rtc_set: "Set RTC time/date:",
|
sensebox_rtc_set: "Set RTC time/date:",
|
||||||
sensebox_rtc_set_tooltip:
|
sensebox_rtc_set_tooltip:
|
||||||
"Sets the time of the RTC. Note that you execute this block in the setup.",
|
"Sets the time of the RTC. Note that you execute this block in the setup.",
|
||||||
sensebox_rtc_get_timestamp: "Timestamp external RTC (RFC 3339)",
|
sensebox_rtc_get_timestamp: "Get timestamp",
|
||||||
sensebox_rtc_get_timestamp_tooltip:
|
sensebox_rtc_get_timestamp_tooltip:
|
||||||
"Returns a timestamp formatted in ISO 8601. Ex: 2021-12-24T18:21Z",
|
"Returns a timestamp formatted in ISO 8601. Ex: 2021-12-24T18:21Z",
|
||||||
sensebox_rtc_get_tooltip: "Returns the selected value",
|
sensebox_rtc_get_tooltip: "Returns the selected value",
|
||||||
@@ -17,22 +17,4 @@ export const RTC = {
|
|||||||
sensebox_rtc_day: "day",
|
sensebox_rtc_day: "day",
|
||||||
sensebox_rtc_month: "month",
|
sensebox_rtc_month: "month",
|
||||||
sensebox_rtc_year: "year",
|
sensebox_rtc_year: "year",
|
||||||
sensebox_internal_rtc_init: "Initialise internal RTC",
|
|
||||||
sensebox_internal_rtc_init_tooltip:
|
|
||||||
"Initialise the internal RTC. This RTC is not battery backed and will be reset on every power cycle.",
|
|
||||||
sensebox_internal_rtc_set: "Set internal RTC time/date:",
|
|
||||||
sensebox_internal_rtc_set_tooltip:
|
|
||||||
"Sets the time of the internal RTC. Note that you execute this block in the setup.",
|
|
||||||
sensebox_internal_rtc_get: "Get: ",
|
|
||||||
sensebox_internal_rtc_get_timestamp: "Timestamp internal RTC (RFC 3339)",
|
|
||||||
sensebox_internal_rtc_get_timestamp_tooltip:
|
|
||||||
"Returns a timestamp formatted in ISO 8601. Ex: 2021-12-24T18:21Z",
|
|
||||||
sensebox_internal_rtc_get_tooltip: "Returns the selected value",
|
|
||||||
sensebox_internal_rtc_epoch: "Unix Time",
|
|
||||||
sensebox_internal_rtc_year: "year",
|
|
||||||
sensebox_internal_rtc_month: "month",
|
|
||||||
sensebox_internal_rtc_day: "day",
|
|
||||||
sensebox_internal_rtc_hour: "hour",
|
|
||||||
sensebox_internal_rtc_minutes: "minutes",
|
|
||||||
sensebox_internal_rtc_seconds: "seconds",
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -134,6 +134,21 @@ If the max distance is reached the a value of **O** will be returned`,
|
|||||||
senseBox_soundsensor_dfrobot_helpurl:
|
senseBox_soundsensor_dfrobot_helpurl:
|
||||||
"https://en.docs.sensebox.de/hardware/sensoren-lautstaerke/",
|
"https://en.docs.sensebox.de/hardware/sensoren-lautstaerke/",
|
||||||
|
|
||||||
|
/*
|
||||||
|
* rainsensor hydreon rg-15
|
||||||
|
*/
|
||||||
|
sensebox_rainsensor_hydreon_rg15: "Rainsensor (RG-15)",
|
||||||
|
sensebox_rainsensor_hydreon_rg15_port: "Serial Port:",
|
||||||
|
sensebox_rainsensor_hydreon_rg15_serial1: "Serial1",
|
||||||
|
sensebox_rainsensor_hydreon_rg15_serial2: "Serial2",
|
||||||
|
sensebox_rainsensor_hydreon_rg15_value: "value:",
|
||||||
|
sensebox_rainsensor_hydreon_rg15_totalAcc: "total Accumulation in mm",
|
||||||
|
sensebox_rainsensor_hydreon_rg15_rainInt: "Rainfall Intensity in mm/h",
|
||||||
|
sensebox_rainsensor_hydreon_rg15_eventAcc: "Accumulation per Event in mm",
|
||||||
|
sensebox_rainsensor_hydreon_rg15_acc: "Accumulation since last loop in mm",
|
||||||
|
sensebox_rainsensor_hydreon_rg15_tooltip: "Connect Rainsensor (RG-15) to one of the Serial ports.",
|
||||||
|
sensebox_rainsensor_hydreon_rg15_helpurl: "https://rainsensors.com/products/rg-15/",
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BME680
|
* BME680
|
||||||
*/
|
*/
|
||||||
@@ -141,7 +156,6 @@ If the max distance is reached the a value of **O** will be returned`,
|
|||||||
senseBox_bme680: "Environmental sensor (BME680)",
|
senseBox_bme680: "Environmental sensor (BME680)",
|
||||||
senseBox_bme_iaq: "Indoor Air Quality (IAQ)",
|
senseBox_bme_iaq: "Indoor Air Quality (IAQ)",
|
||||||
senseBox_bme_iaq_accuracy: "Calibration Value",
|
senseBox_bme_iaq_accuracy: "Calibration Value",
|
||||||
senseBox_bme_pressure: "Airpressure in Pa",
|
|
||||||
senseBox_bme_co2: "CO2 Equivalent",
|
senseBox_bme_co2: "CO2 Equivalent",
|
||||||
senseBox_bme_breatheVocEquivalent: "Breathe VOC Equivalent",
|
senseBox_bme_breatheVocEquivalent: "Breathe VOC Equivalent",
|
||||||
senseBox_bme_tooltip: `Connect the environmental sensor to one of the 5 **I2C ports**. **Note:** The sensor needs some time to calibrate.
|
senseBox_bme_tooltip: `Connect the environmental sensor to one of the 5 **I2C ports**. **Note:** The sensor needs some time to calibrate.
|
||||||
@@ -206,23 +220,4 @@ The measured values for temperature, humidity and air pressure can be used direc
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
senseBox_watertemperature: "Water Temperature",
|
senseBox_watertemperature: "Water Temperature",
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Feinstaubsensor Sensirion SPS30
|
|
||||||
*/
|
|
||||||
|
|
||||||
senseBox_sps30: "Particulate Matter Sensor (Sensirion SPS30)",
|
|
||||||
senseBox_sps30_dimension: "in µg/m³",
|
|
||||||
senseBox_sps30_1p0: "PM1.0",
|
|
||||||
senseBox_sps30_2p5: "PM2.5",
|
|
||||||
senseBox_sps30_4p0: "PM4.0",
|
|
||||||
senseBox_sps30_10p0: "PM10",
|
|
||||||
senseBox_sps30_tooltip:
|
|
||||||
"This block gives you the measured value of the Sensirion SPS30 fine dust sensor. Connect the fine dust sensor to one of the 5 **I2C** connectors. Select between PM1.0, PM2.5, PM4.0 and PM10 in the dropdown menu. The measured value will be displayed as **decimal** in µg/m3",
|
|
||||||
senseBox_sps30_helpurl:
|
|
||||||
"https://docs.sensebox.de/hardware/sensoren-feinstaub/",
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,15 +8,10 @@ export const UI = {
|
|||||||
toolbox_math: "Math",
|
toolbox_math: "Math",
|
||||||
toolbox_io: "Input/Output",
|
toolbox_io: "Input/Output",
|
||||||
toolbox_time: "Time",
|
toolbox_time: "Time",
|
||||||
toolbox_rtc: "RTC",
|
|
||||||
toolbox_ntp: "NTP",
|
|
||||||
toolbox_functions: "Functions",
|
toolbox_functions: "Functions",
|
||||||
toolbox_variables: "Variables",
|
toolbox_variables: "Variables",
|
||||||
toolbox_serial: "Serial",
|
toolbox_serial: "Serial",
|
||||||
toolbox_advanced: "Erweitert",
|
toolbox_advanced: "Erweitert",
|
||||||
toolbox_motors: "Motors",
|
|
||||||
toolbox_label_externalRTC: "External RTC",
|
|
||||||
toolbox_label_internalRTC: "Internal RTC",
|
|
||||||
variable_NUMBER: "Number (int)",
|
variable_NUMBER: "Number (int)",
|
||||||
variable_SHORT_NUMBER: "char",
|
variable_SHORT_NUMBER: "char",
|
||||||
variable_LONG: " Zahl (long)",
|
variable_LONG: " Zahl (long)",
|
||||||
@@ -181,8 +176,6 @@ export const UI = {
|
|||||||
settings_sounds: "Sound",
|
settings_sounds: "Sound",
|
||||||
settings_sounds_text:
|
settings_sounds_text:
|
||||||
"Enable or disable sounds when adding and deleting blocks. Disabled by default",
|
"Enable or disable sounds when adding and deleting blocks. Disabled by default",
|
||||||
settings_board: "Board",
|
|
||||||
settings_board_text: "Choose your board",
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 404
|
* 404
|
||||||
@@ -229,12 +222,6 @@ export const UI = {
|
|||||||
builder_requirements_head: "Requirements.",
|
builder_requirements_head: "Requirements.",
|
||||||
builder_requirements_order:
|
builder_requirements_order:
|
||||||
"Note that the order of ticking is authoritative.",
|
"Note that the order of ticking is authoritative.",
|
||||||
builder_difficulty: "Difficulty level",
|
|
||||||
builder_public_head: "Publish tutorial",
|
|
||||||
builder_public_label: "Publish tutorial for all users",
|
|
||||||
builder_review_head: "Publish tutorial",
|
|
||||||
builder_review_text:
|
|
||||||
"You can share your tutorial with other people directly from the link. If you want to publish your tutorial for all users in the overview you can activate it here. An administrator will view your tutorial and then activate it.",
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Login
|
* Login
|
||||||
@@ -250,7 +237,7 @@ export const UI = {
|
|||||||
/**
|
/**
|
||||||
* Navbar
|
* Navbar
|
||||||
*/
|
*/
|
||||||
navbar_blockly: "Blockly",
|
|
||||||
navbar_tutorials: "Tutorials",
|
navbar_tutorials: "Tutorials",
|
||||||
navbar_tutorialbuilder: "Create tutorial",
|
navbar_tutorialbuilder: "Create tutorial",
|
||||||
navbar_gallery: "Gallery",
|
navbar_gallery: "Gallery",
|
||||||
@@ -290,27 +277,4 @@ export const UI = {
|
|||||||
*/
|
*/
|
||||||
drawer_ideerror_head: "Oops something went wrong",
|
drawer_ideerror_head: "Oops something went wrong",
|
||||||
drawer_ideerror_text: "An error occurred while compiling, check your blocks",
|
drawer_ideerror_text: "An error occurred while compiling, check your blocks",
|
||||||
|
|
||||||
/**
|
|
||||||
* Code Editor
|
|
||||||
* */
|
|
||||||
codeeditor_libraries_head: "Installed Arduino Libraries",
|
|
||||||
codeeditor_libraries_text:
|
|
||||||
"For documentation, view the installed libraries and their examples",
|
|
||||||
codeeditor_save_code: "Download code",
|
|
||||||
codeeditor_open_code: "Open code",
|
|
||||||
codeeditor_reset_code: "Reset code",
|
|
||||||
codeeditor_blockly_code: "Load blockly code",
|
|
||||||
codeeditor_compile_progress:
|
|
||||||
"Your code will now be compiled and then downloaded to your computer",
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Device Selction
|
|
||||||
* */
|
|
||||||
deviceselection_head: "Which board are you using?",
|
|
||||||
deviceselection_keep_selection:
|
|
||||||
"Save my choice (You can change the board later in the settings)",
|
|
||||||
deviceselection_footnote:
|
|
||||||
"Here you can access the old blockly Version for the",
|
|
||||||
deviceselection_footnote_02: "or the",
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Block, Value, Field, Shadow, Category, Sep, Label } from "../";
|
import { Block, Value, Field, Shadow, Category } from "../";
|
||||||
import { getColour } from "../helpers/colour";
|
import { getColour } from "../helpers/colour";
|
||||||
import "@blockly/block-plus-minus";
|
import "@blockly/block-plus-minus";
|
||||||
import { TypedVariableModal } from "@blockly/plugin-typed-variable-modal";
|
import { TypedVariableModal } from "@blockly/plugin-typed-variable-modal";
|
||||||
@@ -21,8 +21,11 @@ class Toolbox extends React.Component {
|
|||||||
[`${Blockly.Msg.variable_LONG}`, "long"],
|
[`${Blockly.Msg.variable_LONG}`, "long"],
|
||||||
[`${Blockly.Msg.variable_DECIMAL}`, "float"],
|
[`${Blockly.Msg.variable_DECIMAL}`, "float"],
|
||||||
[`${Blockly.Msg.variables_TEXT}`, "String"],
|
[`${Blockly.Msg.variables_TEXT}`, "String"],
|
||||||
|
[`${Blockly.Msg.variables_ARRAY}`, "Array"],
|
||||||
[`${Blockly.Msg.variables_CHARACTER}`, "char"],
|
[`${Blockly.Msg.variables_CHARACTER}`, "char"],
|
||||||
[`${Blockly.Msg.variables_BOOLEAN}`, "boolean"],
|
[`${Blockly.Msg.variables_BOOLEAN}`, "boolean"],
|
||||||
|
[`${Blockly.Msg.variables_NULL}`, "void"],
|
||||||
|
[`${Blockly.Msg.variables_UNDEF}`, "undefined"],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
typedVarModal.init();
|
typedVarModal.init();
|
||||||
@@ -61,7 +64,6 @@ class Toolbox extends React.Component {
|
|||||||
<Block type="sensebox_sensor_uv_light" />
|
<Block type="sensebox_sensor_uv_light" />
|
||||||
<Block type="sensebox_sensor_bmx055_accelerometer" />
|
<Block type="sensebox_sensor_bmx055_accelerometer" />
|
||||||
<Block type="sensebox_sensor_sds011" />
|
<Block type="sensebox_sensor_sds011" />
|
||||||
<Block type="sensebox_sensor_sps30" />
|
|
||||||
<Block type="sensebox_sensor_pressure" />
|
<Block type="sensebox_sensor_pressure" />
|
||||||
<Block type="sensebox_sensor_dps310" />
|
<Block type="sensebox_sensor_dps310" />
|
||||||
<Block type="sensebox_sensor_bme680_bsec" />
|
<Block type="sensebox_sensor_bme680_bsec" />
|
||||||
@@ -74,6 +76,7 @@ class Toolbox extends React.Component {
|
|||||||
<Block type="sensebox_sensor_watertemperature" />
|
<Block type="sensebox_sensor_watertemperature" />
|
||||||
{/* <Block type="sensebox_windspeed" /> */}
|
{/* <Block type="sensebox_windspeed" /> */}
|
||||||
<Block type="sensebox_soundsensor_dfrobot" />
|
<Block type="sensebox_soundsensor_dfrobot" />
|
||||||
|
<Block type="sensebox_rainsensor_hydreon_rg15" />
|
||||||
<Block type="sensebox_multiplexer_init">
|
<Block type="sensebox_multiplexer_init">
|
||||||
<Value name="nrChannels">
|
<Value name="nrChannels">
|
||||||
<Block type="math_number">
|
<Block type="math_number">
|
||||||
@@ -296,7 +299,6 @@ class Toolbox extends React.Component {
|
|||||||
</Value>
|
</Value>
|
||||||
</Block>
|
</Block>
|
||||||
</Category>
|
</Category>
|
||||||
|
|
||||||
{/* <Category name="Telegram" colour={getColour().sensebox}>
|
{/* <Category name="Telegram" colour={getColour().sensebox}>
|
||||||
<Block type="sensebox_telegram" />
|
<Block type="sensebox_telegram" />
|
||||||
<Block type="sensebox_telegram_do" />
|
<Block type="sensebox_telegram_do" />
|
||||||
@@ -503,12 +505,6 @@ class Toolbox extends React.Component {
|
|||||||
<Block type="time_micros"></Block>
|
<Block type="time_micros"></Block>
|
||||||
<Block type="infinite_loop"></Block>
|
<Block type="infinite_loop"></Block>
|
||||||
<Block type="sensebox_interval_timer"></Block>
|
<Block type="sensebox_interval_timer"></Block>
|
||||||
<Category
|
|
||||||
id="time"
|
|
||||||
name={Blockly.Msg.toolbox_rtc}
|
|
||||||
colour={getColour().time}
|
|
||||||
>
|
|
||||||
<Label text={Blockly.Msg.toolbox_label_externalRTC}></Label>
|
|
||||||
<Block type="sensebox_rtc_init"></Block>
|
<Block type="sensebox_rtc_init"></Block>
|
||||||
<Block type="sensebox_rtc_set">
|
<Block type="sensebox_rtc_set">
|
||||||
<Value name="second">
|
<Value name="second">
|
||||||
@@ -545,21 +541,6 @@ class Toolbox extends React.Component {
|
|||||||
{/* <Block type="sensebox_rtc_set_ntp"></Block> */}
|
{/* <Block type="sensebox_rtc_set_ntp"></Block> */}
|
||||||
<Block type="sensebox_rtc_get"></Block>
|
<Block type="sensebox_rtc_get"></Block>
|
||||||
<Block type="sensebox_rtc_get_timestamp"></Block>
|
<Block type="sensebox_rtc_get_timestamp"></Block>
|
||||||
<Sep gap="40"></Sep>
|
|
||||||
<Label text={Blockly.Msg.toolbox_label_internalRTC}></Label>
|
|
||||||
<Block type="sensebox_internal_rtc_init"></Block>
|
|
||||||
<Block type="sensebox_internal_rtc_set"></Block>
|
|
||||||
<Block type="sensebox_internal_rtc_get"></Block>
|
|
||||||
<Block type="sensebox_internal_rtc_get_timestamp"></Block>
|
|
||||||
</Category>
|
|
||||||
<Category
|
|
||||||
id="timeUTP"
|
|
||||||
name={Blockly.Msg.toolbox_ntp}
|
|
||||||
colour={getColour().time}
|
|
||||||
>
|
|
||||||
<Block type="sensebox_ntp_init"></Block>
|
|
||||||
<Block type="sensebox_ntp_get"></Block>
|
|
||||||
</Category>
|
|
||||||
</Category>
|
</Category>
|
||||||
<Category
|
<Category
|
||||||
id="math"
|
id="math"
|
||||||
@@ -665,36 +646,6 @@ class Toolbox extends React.Component {
|
|||||||
</Value>
|
</Value>
|
||||||
</Block>
|
</Block>
|
||||||
</Category>
|
</Category>
|
||||||
<Category
|
|
||||||
name={Blockly.Msg.toolbox_motors}
|
|
||||||
colour={getColour().motors}
|
|
||||||
>
|
|
||||||
<Block type="sensebox_motors_beginServoMotor" />
|
|
||||||
<Block type="sensebox_motors_moveServoMotor">
|
|
||||||
<Value name="degrees">
|
|
||||||
<Block type="math_number">
|
|
||||||
<Field name="NUM">90</Field>
|
|
||||||
</Block>
|
|
||||||
</Value>
|
|
||||||
</Block>
|
|
||||||
{/* <Block type="sensebox_motors_I2CMotorBoard_begin" />
|
|
||||||
<Block type="sensebox_motors_I2CMotorBoard_moveDCMotor">
|
|
||||||
<Value name="speed">
|
|
||||||
<Block type="math_number">
|
|
||||||
<Field name="NUM">100</Field>
|
|
||||||
</Block>
|
|
||||||
</Value>
|
|
||||||
</Block>
|
|
||||||
<Block type="sensebox_motors_I2CMotorBoard_stopDCMotor" />
|
|
||||||
<Block type="sensebox_motors_beginStepperMotor" />
|
|
||||||
<Block type="sensebox_motors_moveStepperMotor">
|
|
||||||
<Value name="steps">
|
|
||||||
<Block type="math_number">
|
|
||||||
<Field name="NUM">2048</Field>
|
|
||||||
</Block>
|
|
||||||
</Value>
|
|
||||||
</Block> */}
|
|
||||||
</Category>
|
|
||||||
<Category name="Watchdog" colour={getColour().io}>
|
<Category name="Watchdog" colour={getColour().io}>
|
||||||
<Block type="watchdog_enable"></Block>
|
<Block type="watchdog_enable"></Block>
|
||||||
<Block type="watchdog_reset"></Block>
|
<Block type="watchdog_reset"></Block>
|
||||||
|
|||||||
@@ -1,279 +0,0 @@
|
|||||||
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 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) => {
|
|
||||||
if (data.code === "Internal Server Error") {
|
|
||||||
setProgress(false);
|
|
||||||
setOpen(true);
|
|
||||||
setError(data.message);
|
|
||||||
}
|
|
||||||
setProgress(false);
|
|
||||||
const result = data.data.id;
|
|
||||||
//setId(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 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} md={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={
|
|
||||||
localStorage.getItem("ArduinoCode")
|
|
||||||
? localStorage.getItem("ArduinoCode")
|
|
||||||
: `#include <senseBoxIO.h> //needs to be always included
|
|
||||||
|
|
||||||
void setup () {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
|
|
||||||
}`
|
|
||||||
}
|
|
||||||
value={fileContent}
|
|
||||||
onMount={(editor, monaco) => {
|
|
||||||
editorRef.current = editor;
|
|
||||||
saveValue();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
<Grid item lg={4} md={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()}
|
|
||||||
>
|
|
||||||
{Blockly.Msg.codeeditor_save_code}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
style={{ padding: "1rem", margin: "1rem" }}
|
|
||||||
variant="contained"
|
|
||||||
color="primary"
|
|
||||||
onClick={() => openIno()}
|
|
||||||
>
|
|
||||||
{Blockly.Msg.codeeditor_open_code}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
style={{ padding: "1rem", margin: "1rem" }}
|
|
||||||
variant="contained"
|
|
||||||
color="primary"
|
|
||||||
onClick={() => setResetDialog(true)}
|
|
||||||
>
|
|
||||||
{Blockly.Msg.codeeditor_reset_code}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
style={{ padding: "1rem", margin: "1rem" }}
|
|
||||||
variant="contained"
|
|
||||||
color="primary"
|
|
||||||
onClick={() => getBlocklyCode()}
|
|
||||||
>
|
|
||||||
{Blockly.Msg.codeeditor_blockly_code}
|
|
||||||
</Button>
|
|
||||||
<Sidebar />
|
|
||||||
<Dialog
|
|
||||||
style={{ zIndex: 9999999 }}
|
|
||||||
fullWidth
|
|
||||||
maxWidth={"sm"}
|
|
||||||
open={progress}
|
|
||||||
title={"Code wird kompiliert"}
|
|
||||||
content={""}
|
|
||||||
>
|
|
||||||
<div>{Blockly.Msg.codeeditor_compile_progress}</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);
|
|
||||||
@@ -1,331 +0,0 @@
|
|||||||
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) => {
|
|
||||||
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="xs" />
|
|
||||||
</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)
|
|
||||||
);
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
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;
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
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);
|
|
||||||
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;
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import Blockly from "blockly";
|
|
||||||
import { useSelector } from "react-redux";
|
|
||||||
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 SerialMonitor from "./SerialMonitor.js";
|
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
const Sidebar = () => {
|
|
||||||
//const [examples, setExamples] = React.useState([]);
|
|
||||||
const user = useSelector((state) => state.auth.user);
|
|
||||||
// useEffect(() => {
|
|
||||||
// axios
|
|
||||||
// .get("https://coelho.opensensemap.org/items/blocklysamples")
|
|
||||||
// .then((res) => {
|
|
||||||
// setExamples(res.data.data);
|
|
||||||
// });
|
|
||||||
// }, []);
|
|
||||||
const monaco = useMonaco();
|
|
||||||
const loadCode = (code) => {
|
|
||||||
monaco.editor.getModels()[0].setValue(code);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getOsemScript = (id) => {
|
|
||||||
axios
|
|
||||||
.get(`https://api.opensensemap.org/boxes/${id}/script/`)
|
|
||||||
.then((res) => {
|
|
||||||
loadCode(res.data);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
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"
|
|
||||||
key={i}
|
|
||||||
onClick={() => loadCode(object.code)}
|
|
||||||
>
|
|
||||||
{object.name}
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Typography>
|
|
||||||
</AccordionDetails>
|
|
||||||
</Accordion> */}
|
|
||||||
{user ? (
|
|
||||||
<Accordion>
|
|
||||||
<AccordionSummary
|
|
||||||
expandIcon={""}
|
|
||||||
aria-controls="panel1a-content"
|
|
||||||
id="panel1a-header"
|
|
||||||
>
|
|
||||||
<Typography>Deine openSenseMap Codes</Typography>
|
|
||||||
</AccordionSummary>
|
|
||||||
<AccordionDetails>
|
|
||||||
<Typography>
|
|
||||||
{user.boxes.map((box, i) => {
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
style={{ padding: "1rem", margin: "1rem" }}
|
|
||||||
variant="contained"
|
|
||||||
color="primary"
|
|
||||||
key={i}
|
|
||||||
onClick={() => getOsemScript(box._id)}
|
|
||||||
>
|
|
||||||
{box.name}
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Typography>
|
|
||||||
</AccordionDetails>
|
|
||||||
</Accordion>
|
|
||||||
) : null}
|
|
||||||
<Accordion>
|
|
||||||
<AccordionSummary
|
|
||||||
expandIcon={""}
|
|
||||||
aria-controls="panel2a-content"
|
|
||||||
id="panel2a-header"
|
|
||||||
>
|
|
||||||
<Typography>{Blockly.Msg.codeeditor_libraries_head}</Typography>
|
|
||||||
</AccordionSummary>
|
|
||||||
<AccordionDetails
|
|
||||||
style={{ padding: 0, height: "60vH", backgroundColor: "white" }}
|
|
||||||
>
|
|
||||||
<Typography
|
|
||||||
style={{ overflow: "auto", width: "100%", padding: "1rem" }}
|
|
||||||
>
|
|
||||||
<p>{Blockly.Msg.codeeditor_libraries_text}</p>
|
|
||||||
{LibraryVersions().map((object, i) => {
|
|
||||||
return (
|
|
||||||
<p>
|
|
||||||
<a href={object.link} target="_blank" rel="noreferrer">
|
|
||||||
{object.library} {object.version}
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Typography>
|
|
||||||
</AccordionDetails>
|
|
||||||
</Accordion>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Sidebar;
|
|
||||||
+61
-104
@@ -1,25 +1,30 @@
|
|||||||
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: {},
|
||||||
@@ -29,15 +34,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: {},
|
||||||
@@ -49,60 +54,40 @@ 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() {
|
||||||
this.setState({ componentHeight: this.myDiv.current.offsetHeight + "px" });
|
Prism.highlightAll();
|
||||||
|
this.setState({ componentHeight: this.myDiv.current.offsetHeight + 'px' });
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate(props, state) {
|
||||||
// if (this.props.arduino !== prevProps.arduino) {
|
if (this.myDiv.current && this.myDiv.current.offsetHeight + 'px' !== this.state.componentHeight) {
|
||||||
// this.setState({ changed: true });
|
this.setState({ componentHeight: this.myDiv.current.offsetHeight + 'px' });
|
||||||
|
|
||||||
// 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 }}
|
||||||
@@ -110,32 +95,15 @@ class CodeViewer extends Component {
|
|||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
>
|
>
|
||||||
<AccordionSummary>
|
<AccordionSummary>
|
||||||
<b style={{ fontSize: "20px", marginRight: "5px", width: "35px" }}>
|
<b style={{ fontSize: '20px', marginRight: '5px', width: '35px' }}>{curlyBrackets}</b>
|
||||||
{curlyBrackets}
|
<div style={{ margin: 'auto 5px 2px 0px' }}>{Blockly.Msg.codeviewer_arduino}</div>
|
||||||
</b>
|
|
||||||
<div style={{ margin: "auto 5px 2px 0px" }}>
|
|
||||||
{Blockly.Msg.codeviewer_arduino}
|
|
||||||
</div>
|
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails
|
<AccordionDetails style={{ padding: 0, height: `calc(${this.state.componentHeight} - 50px - 50px)`, backgroundColor: 'white' }}>
|
||||||
style={{
|
<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' }}>
|
||||||
padding: 0,
|
<code className="language-clike">
|
||||||
height: `calc(${this.state.componentHeight} - 50px - 50px)`,
|
{this.props.arduino}
|
||||||
backgroundColor: "white",
|
</code>
|
||||||
}}
|
</pre>
|
||||||
>
|
|
||||||
<MonacoEditor
|
|
||||||
height="80vh"
|
|
||||||
defaultLanguage="cpp"
|
|
||||||
value={this.props.arduino}
|
|
||||||
// modified={this.props.arduino}
|
|
||||||
// original={this.state.code}
|
|
||||||
options={{
|
|
||||||
readOnly: true,
|
|
||||||
|
|
||||||
fontSize: "16px",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
<Accordion
|
<Accordion
|
||||||
@@ -145,43 +113,32 @@ class CodeViewer extends Component {
|
|||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
>
|
>
|
||||||
<AccordionSummary>
|
<AccordionSummary>
|
||||||
<b style={{ fontSize: "20px", marginRight: "5px", width: "35px" }}>
|
<b style={{ fontSize: '20px', marginRight: '5px', width: '35px' }}>{unequal}</b>
|
||||||
{unequal}
|
<div style={{ margin: 'auto 5px 2px 0px' }}>{Blockly.Msg.codeviewer_xml}</div>
|
||||||
</b>
|
|
||||||
<div style={{ margin: "auto 5px 2px 0px" }}>
|
|
||||||
{Blockly.Msg.codeviewer_xml}
|
|
||||||
</div>
|
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails
|
<AccordionDetails style={{ padding: 0, height: `calc(${this.state.componentHeight} - 50px - 50px)`, backgroundColor: 'white' }}>
|
||||||
style={{
|
<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' }}>
|
||||||
padding: 0,
|
<code className="language-xml">
|
||||||
height: `calc(${this.state.componentHeight} - 50px - 50px)`,
|
{`${this.props.xml}`}
|
||||||
backgroundColor: "white",
|
</code>
|
||||||
}}
|
</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));
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import Navbar from './Navbar';
|
|||||||
import Footer from './Footer';
|
import Footer from './Footer';
|
||||||
import Routes from './Route/Routes';
|
import Routes from './Route/Routes';
|
||||||
import Cookies from './Cookies';
|
import Cookies from './Cookies';
|
||||||
import { setBoard } from './Blockly/helpers/board';
|
|
||||||
|
|
||||||
class Content extends Component {
|
class Content extends Component {
|
||||||
|
|
||||||
@@ -20,7 +19,6 @@ class Content extends Component {
|
|||||||
} else if (this.props.language === 'en_US') {
|
} else if (this.props.language === 'en_US') {
|
||||||
Blockly.setLocale(En);
|
Blockly.setLocale(En);
|
||||||
}
|
}
|
||||||
setBoard(this.props.board)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(props) {
|
componentDidUpdate(props) {
|
||||||
@@ -31,7 +29,6 @@ class Content extends Component {
|
|||||||
Blockly.setLocale(En);
|
Blockly.setLocale(En);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setBoard(this.props.board)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -51,8 +48,7 @@ Content.propTypes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
language: state.general.language,
|
language: state.general.language
|
||||||
board: state.board.board
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(Content);
|
export default connect(mapStateToProps, null)(Content);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class Cookies extends Component {
|
|||||||
return (
|
return (
|
||||||
<CookieConsent
|
<CookieConsent
|
||||||
location="bottom"
|
location="bottom"
|
||||||
buttonText="Okay!"
|
buttonText="Okay!!"
|
||||||
cookieName="cookieConsent"
|
cookieName="cookieConsent"
|
||||||
style={{ background: "#2B373B" }}
|
style={{ background: "#2B373B" }}
|
||||||
buttonStyle={{ background: "white", color: "#4EAF47", fontSize: "1rem" }}
|
buttonStyle={{ background: "white", color: "#4EAF47", fontSize: "1rem" }}
|
||||||
|
|||||||
@@ -1,162 +0,0 @@
|
|||||||
import React, { Component } from "react";
|
|
||||||
import PropTypes from "prop-types";
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import Dialog from "./Dialog";
|
|
||||||
|
|
||||||
import { withStyles } from "@material-ui/core/styles";
|
|
||||||
import Checkbox from "@material-ui/core/Checkbox";
|
|
||||||
import FormControlLabel from "@material-ui/core/FormControlLabel";
|
|
||||||
import * as Blockly from "blockly";
|
|
||||||
import { IconButton, Grid, Avatar, Typography } from "@material-ui/core";
|
|
||||||
import { setBoard } from "../actions/boardAction";
|
|
||||||
|
|
||||||
const styles = (theme) => ({
|
|
||||||
link: {
|
|
||||||
color: theme.palette.primary.main,
|
|
||||||
textDecoration: "none",
|
|
||||||
"&:hover": {
|
|
||||||
color: theme.palette.primary.main,
|
|
||||||
textDecoration: `underline`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
fontSize: "0.9rem",
|
|
||||||
color: "grey",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
class DeviceSeclection extends Component {
|
|
||||||
constructor(props) {
|
|
||||||
var previousPageWasAnotherDomain = props.pageVisits === 0;
|
|
||||||
var userWantToKeepBoard = window.localStorage.getItem("board")
|
|
||||||
? true
|
|
||||||
: false;
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
open: userWantToKeepBoard
|
|
||||||
? !userWantToKeepBoard
|
|
||||||
: previousPageWasAnotherDomain,
|
|
||||||
selectedBoard : "",
|
|
||||||
saveSettings: false,
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleDialog = () => {
|
|
||||||
this.setState({ open: !this.state });
|
|
||||||
if(this.state.saveSettings){
|
|
||||||
window.localStorage.setItem("board", this.state.selectedBoard)
|
|
||||||
}
|
|
||||||
this.props.setBoard(this.state.selectedBoard)
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
onChange = (e) => {
|
|
||||||
if (e.target.checked) {
|
|
||||||
this.setState({ saveSettings: true});
|
|
||||||
} else {
|
|
||||||
this.setState({ saveSettings: false});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onclick = (e, value) => {
|
|
||||||
console.log(e, value)
|
|
||||||
this.setState({selectedBoard: value})
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Dialog
|
|
||||||
style={{ zIndex: 9999999 }}
|
|
||||||
fullWidth
|
|
||||||
maxWidth={"xl"}
|
|
||||||
open={this.state.open}
|
|
||||||
title={Blockly.Msg.deviceselection_head}
|
|
||||||
content={""}
|
|
||||||
onClick={this.toggleDialog}
|
|
||||||
button={Blockly.Msg.button_accept}
|
|
||||||
disabled={this.state.selectedBoard===""}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<Grid container spacing={2} style={{ textAlign : "center" }}>
|
|
||||||
<Grid item xs={6}>
|
|
||||||
<IconButton onClick={(e) => this.onclick(e, "mcu")}>
|
|
||||||
<Avatar
|
|
||||||
alt="Sensebox MCU"
|
|
||||||
src="/media/hardware/senseboxmcu.png"
|
|
||||||
style={{
|
|
||||||
border: this.state.selectedBoard === "mcu" ? 'medium solid DeepSkyBlue': "0.1px solid lightgray",
|
|
||||||
width:"20vw",
|
|
||||||
height: "20vw"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</IconButton>
|
|
||||||
<p>senseBox MCU</p>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
{/* <Grid item xs={4}>
|
|
||||||
<IconButton onClick={(e) => this.onclick(e, "esp")}>
|
|
||||||
<Avatar
|
|
||||||
alt="Sensebox ESP"
|
|
||||||
src="/media/hardware/senseboxmcu.png"
|
|
||||||
style={{
|
|
||||||
border: this.state.selectedBoard == "esp" ? 'medium solid DeepSkyBlue': "0.1px solid lightgray",
|
|
||||||
width:"20vw",
|
|
||||||
height: "20vw"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</IconButton>
|
|
||||||
<p>Sensebox ESP</p>
|
|
||||||
</Grid> */}
|
|
||||||
<Grid item xs={6}>
|
|
||||||
<IconButton onClick={(e) => this.onclick(e, "mini")}>
|
|
||||||
<Avatar
|
|
||||||
alt="Sensebox Mini"
|
|
||||||
src="/media/hardware/senseboxmcumini.png"
|
|
||||||
style={{
|
|
||||||
border: this.state.selectedBoard === "mini" ? 'medium solid DeepSkyBlue': "0.1px solid lightgray",
|
|
||||||
width:"20vw",
|
|
||||||
height: "20vw"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</IconButton>
|
|
||||||
<p>senseBox MCU:mini</p>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</div>
|
|
||||||
<FormControlLabel
|
|
||||||
style={{ marginTop: "20px" }}
|
|
||||||
classes={{ label: this.props.classes.label }}
|
|
||||||
control={
|
|
||||||
<Checkbox
|
|
||||||
size={"small"}
|
|
||||||
value={true}
|
|
||||||
checked={this.state.checked}
|
|
||||||
onChange={(e) => this.onChange(e)}
|
|
||||||
name="dialog"
|
|
||||||
color="primary"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label={Blockly.Msg.deviceselection_keep_selection}
|
|
||||||
/>
|
|
||||||
<Typography variant="body1" >
|
|
||||||
{Blockly.Msg.deviceselection_footnote} <a href="https://sensebox.github.io/blockly/">Arduino UNO</a> {Blockly.Msg.deviceselection_footnote_02} <a href="https://sensebox-blockly.netlify.app/ardublockly/?board=sensebox-mcu">senseBox MCU</a>
|
|
||||||
</Typography>
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DeviceSeclection.propTypes = {
|
|
||||||
pageVisits: PropTypes.number.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
|
||||||
pageVisits: state.general.pageVisits,
|
|
||||||
selectedBoard: state.board.board
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(
|
|
||||||
mapStateToProps,
|
|
||||||
{setBoard}
|
|
||||||
)(withStyles(styles, { withTheme: true })(DeviceSeclection));
|
|
||||||
@@ -24,7 +24,7 @@ class Dialog extends Component {
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
{this.props.actions ? this.props.actions :
|
{this.props.actions ? this.props.actions :
|
||||||
<Button onClick={this.props.onClick} disabled={this.props.disabled} color="primary">
|
<Button onClick={this.props.onClick} color="primary">
|
||||||
{this.props.button}
|
{this.props.button}
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
|
|||||||
+124
-45
@@ -1,36 +1,39 @@
|
|||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
import Breadcrumbs from "./Breadcrumbs";
|
import Breadcrumbs from './Breadcrumbs';
|
||||||
|
|
||||||
import { withRouter } from "react-router-dom";
|
import { withRouter } from 'react-router-dom';
|
||||||
|
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from '@material-ui/core/Button';
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from '@material-ui/core/Typography';
|
||||||
import * as Blockly from "blockly";
|
import * as Blockly from 'blockly'
|
||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from 'react-markdown';
|
||||||
import Container from "@material-ui/core/Container";
|
import Container from '@material-ui/core/Container';
|
||||||
import ExpansionPanel from "@material-ui/core/ExpansionPanel";
|
import ExpansionPanel from '@material-ui/core/ExpansionPanel';
|
||||||
import ExpansionPanelSummary from "@material-ui/core/ExpansionPanelSummary";
|
import ExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary';
|
||||||
import ExpansionPanelDetails from "@material-ui/core/ExpansionPanelDetails";
|
import ExpansionPanelDetails from '@material-ui/core/ExpansionPanelDetails';
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { faChevronDown } from "@fortawesome/free-solid-svg-icons";
|
import { faChevronDown } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FaqQuestions } from "../data/faq";
|
import { FaqQuestions } from '../data/faq'
|
||||||
|
|
||||||
|
|
||||||
class Faq extends Component {
|
class Faq extends Component {
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
panel: "",
|
panel: '',
|
||||||
expanded: false,
|
expanded: false
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
handleChange = (panel) => {
|
handleChange = (panel) => {
|
||||||
this.setState({ panel: this.state.panel === panel ? "" : panel });
|
this.setState({ panel: this.state.panel === panel ? '' : panel });
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
// Ensure that Blockly.setLocale is adopted in the component.
|
// Ensure that Blockly.setLocale is adopted in the component.
|
||||||
// Otherwise, the text will not be displayed until the next update of the component.
|
// Otherwise, the text will not be displayed until the next update of the component.
|
||||||
|
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0)
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,63 +41,139 @@ class Faq extends Component {
|
|||||||
const { panel } = this.state;
|
const { panel } = this.state;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Breadcrumbs
|
<Breadcrumbs content={[{ link: this.props.location.pathname, title: 'FAQ' }]} />
|
||||||
content={[{ link: this.props.location.pathname, title: "FAQ" }]}
|
|
||||||
/>
|
|
||||||
<Container fixed>
|
<Container fixed>
|
||||||
<div style={{ margin: "0px 24px 0px 24px" }}>
|
<div style={{ margin: '0px 24px 0px 24px' }}>
|
||||||
<h1>FAQ</h1>
|
<h1>FAQ</h1>
|
||||||
{FaqQuestions().map((object, i) => {
|
{FaqQuestions().map((object, i) => {
|
||||||
return (
|
return (
|
||||||
<ExpansionPanel
|
<ExpansionPanel expanded={panel === `panel${i}`} onChange={() => this.handleChange(`panel${i}`)}>
|
||||||
expanded={panel === `panel${i}`}
|
|
||||||
onChange={() => this.handleChange(`panel${i}`)}
|
|
||||||
>
|
|
||||||
<ExpansionPanelSummary
|
<ExpansionPanelSummary
|
||||||
expandIcon={<FontAwesomeIcon icon={faChevronDown} />}
|
expandIcon={
|
||||||
|
<FontAwesomeIcon icon={faChevronDown} />
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Typography variant="h6">{object.question}</Typography>
|
<Typography variant="h6">{object.question}</Typography>
|
||||||
</ExpansionPanelSummary>
|
</ExpansionPanelSummary>
|
||||||
<ExpansionPanelDetails>
|
<ExpansionPanelDetails>
|
||||||
<Typography>
|
<Typography>
|
||||||
<ReactMarkdown
|
<ReactMarkdown className="news" allowDangerousHtml="true" children={object.answer}>
|
||||||
className="news"
|
</ReactMarkdown>
|
||||||
allowDangerousHtml="true"
|
|
||||||
children={object.answer}
|
|
||||||
></ReactMarkdown>
|
|
||||||
</Typography>
|
</Typography>
|
||||||
</ExpansionPanelDetails>
|
</ExpansionPanelDetails>
|
||||||
</ExpansionPanel>
|
</ExpansionPanel>
|
||||||
);
|
)
|
||||||
})}
|
})}
|
||||||
{this.props.button ? (
|
{
|
||||||
|
this.props.button ?
|
||||||
<Button
|
<Button
|
||||||
style={{ marginTop: "20px" }}
|
style={{ marginTop: '20px' }}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={() => {
|
onClick={() => { this.props.history.push(this.props.button.link) }}
|
||||||
this.props.history.push(this.props.button.link);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{this.props.button.title}
|
{this.props.button.title}
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
:
|
||||||
<Button
|
<Button
|
||||||
style={{ marginTop: "20px" }}
|
style={{ marginTop: '20px' }}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={() => {
|
onClick={() => { this.props.history.push('/') }}
|
||||||
this.props.history.push("/");
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{Blockly.Msg.button_back}
|
{Blockly.Msg.button_back}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
}
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</Container>
|
||||||
</div>
|
</div >
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withRouter(Faq);
|
export default withRouter(Faq);
|
||||||
|
/*
|
||||||
|
<ExpansionPanel expanded={panel === 'panel1'} onChange={() => this.handleChange('panel1')}>
|
||||||
|
<ExpansionPanelSummary
|
||||||
|
expandIcon={
|
||||||
|
<FontAwesomeIcon icon={faChevronDown} />
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Typography variant="h6">{Blockly.Msg.faq_q1_question}</Typography>
|
||||||
|
</ExpansionPanelSummary>
|
||||||
|
<ExpansionPanelDetails>
|
||||||
|
<Typography>
|
||||||
|
<ReactMarkdown className="news" allowDangerousHtml="true" children={Blockly.Msg.faq_q1_answer}>
|
||||||
|
</ReactMarkdown>
|
||||||
|
</Typography>
|
||||||
|
</ExpansionPanelDetails>
|
||||||
|
</ExpansionPanel>
|
||||||
|
<ExpansionPanel expanded={panel === 'panel2'} onChange={() => this.handleChange('panel2')}>
|
||||||
|
<ExpansionPanelSummary
|
||||||
|
expandIcon={
|
||||||
|
<FontAwesomeIcon icon={faChevronDown} />
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Typography>Frage 2</Typography>
|
||||||
|
</ExpansionPanelSummary>
|
||||||
|
<ExpansionPanelDetails>
|
||||||
|
<Typography>
|
||||||
|
Donec placerat, lectus sed mattis semper, neque lectus feugiat lectus, varius pulvinar
|
||||||
|
diam eros in elit. Pellentesque convallis laoreet laoreet.
|
||||||
|
</Typography>
|
||||||
|
</ExpansionPanelDetails>
|
||||||
|
</ExpansionPanel>
|
||||||
|
<ExpansionPanel expanded={panel === 'panel3'} onChange={() => this.handleChange('panel3')}>
|
||||||
|
<ExpansionPanelSummary
|
||||||
|
expandIcon={
|
||||||
|
<FontAwesomeIcon icon={faChevronDown} />
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Typography>Frage 3</Typography>
|
||||||
|
</ExpansionPanelSummary>
|
||||||
|
<ExpansionPanelDetails>
|
||||||
|
<Typography>
|
||||||
|
Nunc vitae orci ultricies, auctor nunc in, volutpat nisl. Integer sit amet egestas eros,
|
||||||
|
vitae egestas augue. Duis vel est augue.
|
||||||
|
</Typography>
|
||||||
|
</ExpansionPanelDetails>
|
||||||
|
</ExpansionPanel>
|
||||||
|
<ExpansionPanel expanded={panel === 'panel4'} onChange={() => this.handleChange('panel4')}>
|
||||||
|
<ExpansionPanelSummary
|
||||||
|
expandIcon={
|
||||||
|
<FontAwesomeIcon icon={faChevronDown} />
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Typography>Frage 4</Typography>
|
||||||
|
</ExpansionPanelSummary>
|
||||||
|
<ExpansionPanelDetails>
|
||||||
|
<Typography>
|
||||||
|
Nunc vitae orci ultricies, auctor nunc in, volutpat nisl. Integer sit amet egestas eros,
|
||||||
|
vitae egestas augue. Duis vel est augue.
|
||||||
|
</Typography>
|
||||||
|
</ExpansionPanelDetails>
|
||||||
|
</ExpansionPanel>
|
||||||
|
*/
|
||||||
|
|
||||||
|
// {{
|
||||||
|
// this.props.button ?
|
||||||
|
// <Button
|
||||||
|
// style={{ marginTop: '20px' }}
|
||||||
|
// variant="contained"
|
||||||
|
// color="primary"
|
||||||
|
// onClick={() => { this.props.history.push(this.props.button.link) }}
|
||||||
|
// >
|
||||||
|
// {this.props.button.title}
|
||||||
|
// </Button>
|
||||||
|
// :
|
||||||
|
// <Button
|
||||||
|
// style={{ marginTop: '20px' }}
|
||||||
|
// variant="contained"
|
||||||
|
// color="primary"
|
||||||
|
// onClick={() => { this.props.history.push('/') }}
|
||||||
|
// >
|
||||||
|
// {Blockly.Msg.button_back}
|
||||||
|
// </Button>
|
||||||
|
// }}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+6
-14
@@ -11,8 +11,7 @@ import WorkspaceFunc from "./Workspace/WorkspaceFunc";
|
|||||||
import BlocklyWindow from "./Blockly/BlocklyWindow";
|
import BlocklyWindow from "./Blockly/BlocklyWindow";
|
||||||
import CodeViewer from "./CodeViewer";
|
import CodeViewer from "./CodeViewer";
|
||||||
import TrashcanButtons from "./Workspace/TrashcanButtons";
|
import TrashcanButtons from "./Workspace/TrashcanButtons";
|
||||||
// import HintTutorialExists from "./Tutorial/HintTutorialExists";
|
import HintTutorialExists from "./Tutorial/HintTutorialExists";
|
||||||
import DeviceSelection from "./DeviceSelection";
|
|
||||||
|
|
||||||
import Grid from "@material-ui/core/Grid";
|
import Grid from "@material-ui/core/Grid";
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
import IconButton from "@material-ui/core/IconButton";
|
||||||
@@ -23,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,
|
||||||
@@ -55,11 +54,11 @@ class Home extends Component {
|
|||||||
key: "",
|
key: "",
|
||||||
message: "",
|
message: "",
|
||||||
open: true,
|
open: true,
|
||||||
initialXml: localStorage.getItem("autoSaveXML"),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
console.log(this.props.platform);
|
||||||
if (this.props.platform === true) {
|
if (this.props.platform === true) {
|
||||||
this.setState({ codeOn: false });
|
this.setState({ codeOn: false });
|
||||||
}
|
}
|
||||||
@@ -120,12 +119,10 @@ 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}
|
||||||
@@ -164,7 +161,6 @@ 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 ? (
|
||||||
@@ -173,10 +169,7 @@ class Home extends Component {
|
|||||||
initialXml={this.props.project.xml}
|
initialXml={this.props.project.xml}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<BlocklyWindow
|
<BlocklyWindow blocklyCSS={{ height: "80vH" }} />
|
||||||
blocklyCSS={{ height: "80vH" }}
|
|
||||||
initialXml={this.state.initialXml}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -187,8 +180,7 @@ class Home extends Component {
|
|||||||
</Grid>
|
</Grid>
|
||||||
) : null}
|
) : null}
|
||||||
</Grid>
|
</Grid>
|
||||||
<DeviceSelection />
|
<HintTutorialExists />
|
||||||
{/* <HintTutorialExists /> */}
|
|
||||||
{this.props.platform ? (
|
{this.props.platform ? (
|
||||||
<Dialog
|
<Dialog
|
||||||
style={{ zIndex: 9999999 }}
|
style={{ zIndex: 9999999 }}
|
||||||
@@ -224,7 +216,7 @@ Home.propTypes = {
|
|||||||
workspaceName: PropTypes.func.isRequired,
|
workspaceName: PropTypes.func.isRequired,
|
||||||
message: PropTypes.object.isRequired,
|
message: PropTypes.object.isRequired,
|
||||||
statistics: PropTypes.bool.isRequired,
|
statistics: PropTypes.bool.isRequired,
|
||||||
platform: PropTypes.bool.isRequired,
|
platform: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = (state) => ({
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ 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,
|
||||||
@@ -35,8 +34,6 @@ import {
|
|||||||
faChalkboardTeacher,
|
faChalkboardTeacher,
|
||||||
faTools,
|
faTools,
|
||||||
faLightbulb,
|
faLightbulb,
|
||||||
faCode,
|
|
||||||
faPuzzlePiece,
|
|
||||||
} 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";
|
||||||
@@ -214,11 +211,6 @@ class Navbar extends Component {
|
|||||||
</div>
|
</div>
|
||||||
<List>
|
<List>
|
||||||
{[
|
{[
|
||||||
{
|
|
||||||
text: Blockly.Msg.navbar_blockly,
|
|
||||||
icon: faPuzzlePiece,
|
|
||||||
link: "/",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
text: Blockly.Msg.navbar_tutorials,
|
text: Blockly.Msg.navbar_tutorials,
|
||||||
icon: faChalkboardTeacher,
|
icon: faChalkboardTeacher,
|
||||||
@@ -244,11 +236,6 @@ class Navbar extends Component {
|
|||||||
link: "/project",
|
link: "/project",
|
||||||
restriction: this.props.isAuthenticated,
|
restriction: this.props.isAuthenticated,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
text: "Code Editor",
|
|
||||||
icon: faCode,
|
|
||||||
link: "/codeeditor",
|
|
||||||
},
|
|
||||||
].map((item, index) => {
|
].map((item, index) => {
|
||||||
if (
|
if (
|
||||||
item.restriction ||
|
item.restriction ||
|
||||||
@@ -266,13 +253,7 @@ class Navbar extends Component {
|
|||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<FontAwesomeIcon icon={item.icon} />
|
<FontAwesomeIcon icon={item.icon} />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
{item.text === "Code Editor" ? (
|
|
||||||
<Badge badgeContent={"Experimental"} color="primary">
|
|
||||||
<ListItemText primary={item.text} />
|
<ListItemText primary={item.text} />
|
||||||
</Badge>
|
|
||||||
) : (
|
|
||||||
<ListItemText primary={item.text} />
|
|
||||||
)}
|
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
@@ -365,9 +346,9 @@ class Navbar extends Component {
|
|||||||
Navbar.propTypes = {
|
Navbar.propTypes = {
|
||||||
tutorialIsLoading: PropTypes.bool.isRequired,
|
tutorialIsLoading: PropTypes.bool.isRequired,
|
||||||
projectIsLoading: PropTypes.bool.isRequired,
|
projectIsLoading: PropTypes.bool.isRequired,
|
||||||
isAuthenticated: PropTypes.bool,
|
isAuthenticated: PropTypes.bool.isRequired,
|
||||||
user: PropTypes.object,
|
user: PropTypes.object,
|
||||||
tutorial: PropTypes.object,
|
tutorial: PropTypes.object.isRequired,
|
||||||
activeStep: PropTypes.number.isRequired,
|
activeStep: PropTypes.number.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,41 +1,44 @@
|
|||||||
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 { Route, Redirect, withRouter } from 'react-router-dom';
|
||||||
|
|
||||||
import { Route, Redirect, withRouter } from "react-router-dom";
|
|
||||||
|
|
||||||
class PrivateRoute extends Component {
|
class PrivateRoute extends Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return !this.props.progress ? (
|
return (
|
||||||
|
!this.props.progress ?
|
||||||
<Route
|
<Route
|
||||||
{...this.props.exact}
|
{...this.props.exact}
|
||||||
render={({ location }) =>
|
render={({ location }) =>
|
||||||
this.props.isAuthenticated
|
this.props.isAuthenticated ? (
|
||||||
? this.props.children
|
this.props.children
|
||||||
: (() => {
|
) : (()=>{
|
||||||
return (
|
return (
|
||||||
<Redirect
|
<Redirect
|
||||||
to={{
|
to={{
|
||||||
pathname: "/user/login",
|
pathname: "/user/login",
|
||||||
state: { from: location },
|
state: { from: location }
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
)
|
||||||
})()
|
})()
|
||||||
}
|
}
|
||||||
/>
|
/> : null
|
||||||
) : null;
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PrivateRoute.propTypes = {
|
PrivateRoute.propTypes = {
|
||||||
isAuthenticated: PropTypes.bool,
|
isAuthenticated: PropTypes.bool.isRequired,
|
||||||
progress: PropTypes.bool.isRequired,
|
progress: PropTypes.bool.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = state => ({
|
||||||
isAuthenticated: state.auth.isAuthenticated,
|
isAuthenticated: state.auth.isAuthenticated,
|
||||||
progress: state.auth.progress,
|
progress: state.auth.progress
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(withRouter(PrivateRoute));
|
export default connect(mapStateToProps, null)(withRouter(PrivateRoute));
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
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 { visitPage, setPlatform } from "../../actions/generalActions";
|
import { visitPage } from "../../actions/generalActions";
|
||||||
|
|
||||||
import { Route, Switch, withRouter } from "react-router-dom";
|
import { Route, Switch, withRouter } from "react-router-dom";
|
||||||
|
|
||||||
@@ -24,27 +24,8 @@ 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 {
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
const { location } = this.props;
|
|
||||||
const query = new URLSearchParams(location.search, [location.search]);
|
|
||||||
const mode = query.get('mode');
|
|
||||||
|
|
||||||
if (!this.props.platform && mode) {
|
|
||||||
switch (mode.toLowerCase()) {
|
|
||||||
case 'tablet':
|
|
||||||
this.props.setPlatform(true);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
this.props.visitPage();
|
this.props.visitPage();
|
||||||
}
|
}
|
||||||
@@ -66,9 +47,6 @@ 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 />
|
||||||
@@ -122,13 +100,7 @@ class Routes extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Home.propTypes = {
|
Home.propTypes = {
|
||||||
visitPage: PropTypes.func,
|
visitPage: PropTypes.func.isRequired,
|
||||||
platform: PropTypes.bool.isRequired,
|
|
||||||
setPlatform: PropTypes.func.isRequired
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
export default connect(null, { visitPage })(withRouter(Routes));
|
||||||
platform: state.general.platform,
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, { visitPage, setPlatform })(withRouter(Routes));
|
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
import React, { Component } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { setBoard } from '../../actions/boardAction';
|
|
||||||
|
|
||||||
import * as Blockly from 'blockly/core';
|
|
||||||
|
|
||||||
import InputLabel from '@material-ui/core/InputLabel';
|
|
||||||
import MenuItem from '@material-ui/core/MenuItem';
|
|
||||||
import FormControl from '@material-ui/core/FormControl';
|
|
||||||
import Select from '@material-ui/core/Select';
|
|
||||||
import Typography from '@material-ui/core/Typography';
|
|
||||||
import FormHelperText from '@material-ui/core/FormHelperText';
|
|
||||||
|
|
||||||
class DeviceSelector extends Component {
|
|
||||||
|
|
||||||
componentDidMount(){
|
|
||||||
// Ensure that Blockly.setLocale is adopted in the component.
|
|
||||||
// Otherwise, the text will not be displayed until the next update of the component.
|
|
||||||
this.forceUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
render(){
|
|
||||||
return(
|
|
||||||
<div>
|
|
||||||
<Typography style={{fontWeight: 'bold'}}>{Blockly.Msg.settings_board}</Typography>
|
|
||||||
<FormHelperText style={{color: 'black', lineHeight: 1.3, marginBottom: '8px'}}>{Blockly.Msg.settings_board_text}</FormHelperText>
|
|
||||||
<FormControl>
|
|
||||||
<InputLabel id="demo-simple-select-label">{Blockly.Msg.settings_board}</InputLabel>
|
|
||||||
<Select
|
|
||||||
labelId="demo-simple-select-label"
|
|
||||||
id="demo-simple-select"
|
|
||||||
value={this.props.selectedBoard}
|
|
||||||
onChange={(e) => this.props.setBoard(e.target.value)}
|
|
||||||
>
|
|
||||||
<MenuItem value="mcu">senseBox MCU</MenuItem>
|
|
||||||
<MenuItem value="mini">senseBox MCU mini</MenuItem>
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DeviceSelector.propTypes = {
|
|
||||||
setBoard: PropTypes.func.isRequired,
|
|
||||||
selectedBoard: PropTypes.string.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
|
||||||
selectedBoard: state.board.board
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, { setBoard })(DeviceSelector);
|
|
||||||
@@ -12,7 +12,6 @@ import RenderSelector from "./RenderSelector";
|
|||||||
import StatsSelector from "./StatsSelector";
|
import StatsSelector from "./StatsSelector";
|
||||||
import OtaSelector from "./OtaSelector";
|
import OtaSelector from "./OtaSelector";
|
||||||
import SoundsSelector from "./SoundsSelector";
|
import SoundsSelector from "./SoundsSelector";
|
||||||
import DeviceSelector from "./DeviceSelector";
|
|
||||||
|
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@material-ui/core/Button";
|
||||||
import Paper from "@material-ui/core/Paper";
|
import Paper from "@material-ui/core/Paper";
|
||||||
@@ -53,9 +52,6 @@ class Settings extends Component {
|
|||||||
<Paper style={{ margin: "10px 0px", padding: "10px" }}>
|
<Paper style={{ margin: "10px 0px", padding: "10px" }}>
|
||||||
<SoundsSelector />
|
<SoundsSelector />
|
||||||
</Paper>
|
</Paper>
|
||||||
<Paper style={{ margin: "10px 0px", padding: "10px" }}>
|
|
||||||
<DeviceSelector />
|
|
||||||
</Paper>
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
style={{ marginTop: "10px" }}
|
style={{ marginTop: "10px" }}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class SoundsSelector extends Component {
|
|||||||
SoundsSelector.propTypes = {
|
SoundsSelector.propTypes = {
|
||||||
setSounds: PropTypes.func.isRequired,
|
setSounds: PropTypes.func.isRequired,
|
||||||
language: PropTypes.string.isRequired,
|
language: PropTypes.string.isRequired,
|
||||||
sounds: PropTypes.bool.isRequired,
|
sounds: PropTypes.string.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = (state) => ({
|
||||||
|
|||||||
@@ -1,55 +1,47 @@
|
|||||||
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 withWidth from "@material-ui/core/withWidth";
|
import withWidth from '@material-ui/core/withWidth';
|
||||||
|
|
||||||
import { Card } from "@material-ui/core";
|
import { Card } from '@material-ui/core';
|
||||||
import * as Blockly from "blockly";
|
import * as Blockly from 'blockly'
|
||||||
import CardContent from "@material-ui/core/CardContent";
|
import CardContent from '@material-ui/core/CardContent';
|
||||||
|
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from '@material-ui/core/Typography';
|
||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from 'react-markdown';
|
||||||
|
|
||||||
class TooltipViewer extends Component {
|
class TooltipViewer extends Component {
|
||||||
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card className="tooltipViewer" style={{ height: '100%', margin: '1vH 0 0 0', maxHeight: '19vH', overflow: 'auto' }} ref={this.myDiv}>
|
||||||
className="tooltipViewer"
|
|
||||||
style={{
|
|
||||||
height: "100%",
|
|
||||||
margin: "1vH 0 0 0",
|
|
||||||
maxHeight: "19vH",
|
|
||||||
overflow: "auto",
|
|
||||||
}}
|
|
||||||
ref={this.myDiv}
|
|
||||||
>
|
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<Typography variant="h5" component="h2">
|
<Typography variant="h5" component="h2">
|
||||||
{Blockly.Msg.tooltip_viewer}
|
{Blockly.Msg.tooltip_viewer}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
<Typography variant="body2" component="p">
|
||||||
|
<ReactMarkdown linkTarget="_blank">{this.props.tooltip}</ReactMarkdown>
|
||||||
|
|
||||||
<ReactMarkdown linkTarget="_blank">
|
{this.props.helpurl !== '' ? <ReactMarkdown>{`${Blockly.Msg.tooltip_moreInformation} [${Blockly.Msg.labels_here}](${this.props.helpurl})`}</ReactMarkdown> : null}
|
||||||
{this.props.tooltip}
|
|
||||||
</ReactMarkdown>
|
|
||||||
|
|
||||||
{this.props.helpurl !== "" ? (
|
</Typography>
|
||||||
<ReactMarkdown>{`${Blockly.Msg.tooltip_moreInformation} [${Blockly.Msg.labels_here}](${this.props.helpurl})`}</ReactMarkdown>
|
|
||||||
) : null}
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
TooltipViewer.propTypes = {
|
TooltipViewer.propTypes = {
|
||||||
tooltip: PropTypes.string.isRequired,
|
tooltip: PropTypes.string.isRequired,
|
||||||
helpurl: PropTypes.string.isRequired,
|
helpurl: PropTypes.string.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = state => ({
|
||||||
tooltip: state.workspace.code.tooltip,
|
tooltip: state.workspace.code.tooltip,
|
||||||
helpurl: state.workspace.code.helpurl,
|
helpurl: state.workspace.code.helpurl
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(withWidth()(TooltipViewer));
|
export default connect(mapStateToProps, null)(withWidth()(TooltipViewer));
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { connect } from "react-redux";
|
|||||||
import { workspaceName } from "../../actions/workspaceActions";
|
import { workspaceName } from "../../actions/workspaceActions";
|
||||||
|
|
||||||
import BlocklyWindow from "../Blockly/BlocklyWindow";
|
import BlocklyWindow from "../Blockly/BlocklyWindow";
|
||||||
|
import CodeViewer from "../CodeViewer";
|
||||||
import WorkspaceFunc from "../Workspace/WorkspaceFunc";
|
import WorkspaceFunc from "../Workspace/WorkspaceFunc";
|
||||||
|
|
||||||
import withWidth, { isWidthDown } from "@material-ui/core/withWidth";
|
import withWidth, { isWidthDown } from "@material-ui/core/withWidth";
|
||||||
@@ -12,46 +13,8 @@ import Card from "@material-ui/core/Card";
|
|||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { initialXml } from "../Blockly/initialXml";
|
import { initialXml } from "../Blockly/initialXml";
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
|
||||||
import CodeViewer from "../CodeViewer";
|
|
||||||
import TooltipViewer from "../TooltipViewer";
|
|
||||||
import Tooltip from "@material-ui/core/Tooltip";
|
|
||||||
import ReactMarkdown from "react-markdown";
|
|
||||||
import { faCode } from "@fortawesome/free-solid-svg-icons";
|
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
||||||
import { withStyles } from "@material-ui/core/styles";
|
|
||||||
import remarkGfm from "remark-gfm";
|
|
||||||
import remarkGemoji from "remark-gemoji";
|
|
||||||
|
|
||||||
const styles = (theme) => ({
|
|
||||||
codeOn: {
|
|
||||||
backgroundColor: theme.palette.primary.main,
|
|
||||||
color: theme.palette.primary.contrastText,
|
|
||||||
"&:hover": {
|
|
||||||
backgroundColor: theme.palette.primary.contrastText,
|
|
||||||
color: theme.palette.primary.main,
|
|
||||||
border: `1px solid ${theme.palette.secondary.main}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
codeOff: {
|
|
||||||
backgroundColor: theme.palette.primary.contrastText,
|
|
||||||
color: theme.palette.primary.main,
|
|
||||||
border: `1px solid ${theme.palette.secondary.main}`,
|
|
||||||
"&:hover": {
|
|
||||||
backgroundColor: theme.palette.primary.main,
|
|
||||||
color: theme.palette.primary.contrastText,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
class Assessment extends Component {
|
class Assessment extends Component {
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
codeOn: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.workspaceName(this.props.name);
|
this.props.workspaceName(this.props.name);
|
||||||
}
|
}
|
||||||
@@ -62,10 +25,6 @@ class Assessment extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange = () => {
|
|
||||||
this.setState({ codeOn: !this.state.codeOn });
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var tutorialId = this.props.tutorial._id;
|
var tutorialId = this.props.tutorial._id;
|
||||||
var currentTask = this.props.step;
|
var currentTask = this.props.step;
|
||||||
@@ -76,98 +35,63 @@ class Assessment extends Component {
|
|||||||
(task) => task._id === currentTask._id
|
(task) => task._id === currentTask._id
|
||||||
);
|
);
|
||||||
var statusTask = status.tasks[taskIndex];
|
var statusTask = status.tasks[taskIndex];
|
||||||
console.log(statusTask);
|
|
||||||
return (
|
return (
|
||||||
<div className="assessmentDiv" style={{ width: "100%" }}>
|
<div className="assessmentDiv" style={{ width: "100%" }}>
|
||||||
|
<Typography
|
||||||
|
variant="h4"
|
||||||
|
style={{
|
||||||
|
float: "left",
|
||||||
|
marginBottom: "5px",
|
||||||
|
height: "40px",
|
||||||
|
display: "table",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{currentTask.headline}
|
||||||
|
</Typography>
|
||||||
<div style={{ float: "right", height: "40px" }}>
|
<div style={{ float: "right", height: "40px" }}>
|
||||||
<WorkspaceFunc assessment />
|
<WorkspaceFunc assessment />
|
||||||
</div>
|
</div>
|
||||||
<Grid container spacing={2} style={{ marginBottom: "5px" }}>
|
<Grid container spacing={2} style={{ marginBottom: "5px" }}>
|
||||||
<Grid
|
<Grid item xs={12} md={6} lg={8}>
|
||||||
item
|
|
||||||
xs={12}
|
|
||||||
md={this.state.codeOn ? 6 : 9}
|
|
||||||
lg={this.state.codeOn ? 6 : 9}
|
|
||||||
style={{ position: "relative" }}
|
|
||||||
>
|
|
||||||
<Tooltip
|
|
||||||
title={
|
|
||||||
this.state.codeOn
|
|
||||||
? Blockly.Msg.tooltip_hide_code
|
|
||||||
: Blockly.Msg.tooltip_show_code
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<IconButton
|
|
||||||
className={`showCode ${
|
|
||||||
this.state.codeOn
|
|
||||||
? this.props.classes.codeOn
|
|
||||||
: this.props.classes.codeOff
|
|
||||||
}`}
|
|
||||||
style={{
|
|
||||||
width: "40px",
|
|
||||||
height: "40px",
|
|
||||||
position: "absolute",
|
|
||||||
top: 6,
|
|
||||||
right: 8,
|
|
||||||
zIndex: 21,
|
|
||||||
}}
|
|
||||||
onClick={() => this.onChange()}
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon icon={faCode} size="xs" />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
<BlocklyWindow
|
<BlocklyWindow
|
||||||
initialXml={initialXml}
|
initialXml={initialXml}
|
||||||
blockDisabled
|
blockDisabled
|
||||||
blocklyCSS={{ height: "65vH" }}
|
blocklyCSS={{ height: "65vH" }}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
{this.state.codeOn ? (
|
|
||||||
<Grid item xs={12} md={4} lg={3}>
|
|
||||||
<CodeViewer />
|
|
||||||
</Grid>
|
|
||||||
) : null}
|
|
||||||
<Grid
|
<Grid
|
||||||
item
|
item
|
||||||
xs={12}
|
xs={12}
|
||||||
md={3}
|
md={6}
|
||||||
lg={3}
|
lg={4}
|
||||||
style={{
|
style={
|
||||||
position: "relative",
|
isWidthDown("sm", this.props.width)
|
||||||
// isWidthDown("sm", this.props.width)
|
? { height: "max-content" }
|
||||||
// ? { height: "max-content" }
|
: {}
|
||||||
// : {}
|
}
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Card
|
<Card
|
||||||
style={{
|
style={{
|
||||||
height: "calc(44vH - 35px)",
|
height: "calc(50% - 30px)",
|
||||||
padding: "10px",
|
padding: "10px",
|
||||||
marginBottom: "10px",
|
marginBottom: "10px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography>
|
<Typography variant="h5">
|
||||||
<ReactMarkdown remarkPlugins={[remarkGfm, remarkGemoji]}>
|
{Blockly.Msg.tutorials_assessment_task}
|
||||||
{currentTask.text}
|
|
||||||
</ReactMarkdown>
|
|
||||||
</Typography>
|
</Typography>
|
||||||
|
<Typography>{currentTask.text}</Typography>
|
||||||
</Card>
|
</Card>
|
||||||
{/* <Card
|
|
||||||
style={{
|
|
||||||
height: "20vH",
|
|
||||||
padding: "10px",
|
|
||||||
marginBottom: "10px",
|
|
||||||
}}
|
|
||||||
> */}
|
|
||||||
<TooltipViewer />
|
|
||||||
{/* </Card> */}
|
|
||||||
<div
|
<div
|
||||||
style={
|
style={
|
||||||
isWidthDown("sm", this.props.width)
|
isWidthDown("sm", this.props.width)
|
||||||
? { height: "500px" }
|
? { height: "500px" }
|
||||||
: { height: "50%" }
|
: { height: "50%" }
|
||||||
}
|
}
|
||||||
></div>
|
>
|
||||||
|
<CodeViewer />
|
||||||
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</div>
|
</div>
|
||||||
@@ -189,5 +113,5 @@ const mapStateToProps = (state) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, { workspaceName })(
|
export default connect(mapStateToProps, { workspaceName })(
|
||||||
withWidth()(withStyles(styles, { withTheme: true })(Assessment))
|
withWidth()(Assessment)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,57 +1,53 @@
|
|||||||
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 {
|
import { changeContent, deleteProperty, setError, deleteError } from '../../../actions/tutorialBuilderActions';
|
||||||
changeContent,
|
|
||||||
deleteProperty,
|
|
||||||
setError,
|
|
||||||
deleteError,
|
|
||||||
} from "../../../actions/tutorialBuilderActions";
|
|
||||||
|
|
||||||
import moment from "moment";
|
import moment from 'moment';
|
||||||
import localization from "moment/locale/de";
|
import localization from 'moment/locale/de';
|
||||||
import * as Blockly from "blockly/core";
|
import * as Blockly from 'blockly/core';
|
||||||
|
|
||||||
import { initialXml } from "../../Blockly//initialXml.js";
|
import { initialXml } from '../../Blockly//initialXml.js';
|
||||||
import BlocklyWindow from "../../Blockly/BlocklyWindow";
|
import BlocklyWindow from '../../Blockly/BlocklyWindow';
|
||||||
|
|
||||||
import { withStyles } from "@material-ui/core/styles";
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import Switch from "@material-ui/core/Switch";
|
import Switch from '@material-ui/core/Switch';
|
||||||
import FormControlLabel from "@material-ui/core/FormControlLabel";
|
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
||||||
import FormHelperText from "@material-ui/core/FormHelperText";
|
import FormHelperText from '@material-ui/core/FormHelperText';
|
||||||
import FormLabel from "@material-ui/core/FormLabel";
|
import FormLabel from '@material-ui/core/FormLabel';
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from '@material-ui/core/Button';
|
||||||
import Grid from "@material-ui/core/Grid";
|
import Grid from '@material-ui/core/Grid';
|
||||||
|
|
||||||
const styles = (theme) => ({
|
const styles = (theme) => ({
|
||||||
errorColor: {
|
errorColor: {
|
||||||
color: theme.palette.error.dark,
|
color: theme.palette.error.dark
|
||||||
},
|
},
|
||||||
errorBorder: {
|
errorBorder: {
|
||||||
border: `1px solid ${theme.palette.error.dark}`,
|
border: `1px solid ${theme.palette.error.dark}`
|
||||||
},
|
},
|
||||||
errorButton: {
|
errorButton: {
|
||||||
marginTop: "5px",
|
marginTop: '5px',
|
||||||
height: "40px",
|
height: '40px',
|
||||||
backgroundColor: theme.palette.error.dark,
|
backgroundColor: theme.palette.error.dark,
|
||||||
"&:hover": {
|
'&:hover': {
|
||||||
backgroundColor: theme.palette.error.dark,
|
backgroundColor: theme.palette.error.dark
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
class BlocklyExample extends Component {
|
class BlocklyExample extends Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
checked: props.task ? props.task : props.value ? true : false,
|
checked: props.task ? props.task : props.value ? true : false,
|
||||||
input: null,
|
input: null,
|
||||||
disabled: false,
|
disabled: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
moment.updateLocale("de", localization);
|
moment.updateLocale('de', localization);
|
||||||
this.isError();
|
this.isError();
|
||||||
// if(this.props.task){
|
// if(this.props.task){
|
||||||
// this.props.setError(this.props.index, 'xml');
|
// this.props.setError(this.props.index, 'xml');
|
||||||
@@ -60,14 +56,7 @@ class BlocklyExample extends Component {
|
|||||||
|
|
||||||
componentDidUpdate(props, state) {
|
componentDidUpdate(props, state) {
|
||||||
if (props.task !== this.props.task || props.value !== this.props.value) {
|
if (props.task !== this.props.task || props.value !== this.props.value) {
|
||||||
this.setState(
|
this.setState({ checked: this.props.task ? this.props.task : this.props.value ? true : false },
|
||||||
{
|
|
||||||
checked: this.props.task
|
|
||||||
? this.props.task
|
|
||||||
: this.props.value
|
|
||||||
? true
|
|
||||||
: false,
|
|
||||||
},
|
|
||||||
() => this.isError()
|
() => this.isError()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -88,11 +77,12 @@ class BlocklyExample extends Component {
|
|||||||
// check if value is valid xml;
|
// check if value is valid xml;
|
||||||
try {
|
try {
|
||||||
Blockly.Xml.textToDom(xml);
|
Blockly.Xml.textToDom(xml);
|
||||||
this.props.deleteError(this.props.index, "xml");
|
this.props.deleteError(this.props.index, 'xml');
|
||||||
} catch (err) {
|
}
|
||||||
|
catch (err) {
|
||||||
xml = initialXml;
|
xml = initialXml;
|
||||||
// not valid xml, throw error in redux store
|
// not valid xml, throw error in redux store
|
||||||
this.props.setError(this.props.index, "xml");
|
this.props.setError(this.props.index, 'xml');
|
||||||
}
|
}
|
||||||
if (!this.props.task) {
|
if (!this.props.task) {
|
||||||
// instruction can also display only one block, which does not necessarily
|
// instruction can also display only one block, which does not necessarily
|
||||||
@@ -100,38 +90,31 @@ class BlocklyExample extends Component {
|
|||||||
xml = xml.replace('deletable="false"', 'deletable="true"');
|
xml = xml.replace('deletable="false"', 'deletable="true"');
|
||||||
}
|
}
|
||||||
this.setState({ xml: xml });
|
this.setState({ xml: xml });
|
||||||
} else {
|
|
||||||
this.props.deleteError(this.props.index, "xml");
|
|
||||||
}
|
}
|
||||||
};
|
else {
|
||||||
|
this.props.deleteError(this.props.index, 'xml');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onChange = (value) => {
|
onChange = (value) => {
|
||||||
var oldValue = this.state.checked;
|
var oldValue = this.state.checked;
|
||||||
this.setState({ checked: value });
|
this.setState({ checked: value });
|
||||||
if (oldValue !== value && !value) {
|
if (oldValue !== value && !value) {
|
||||||
this.props.deleteError(this.props.index, "xml");
|
this.props.deleteError(this.props.index, 'xml');
|
||||||
this.props.deleteProperty(this.props.index, "xml");
|
this.props.deleteProperty(this.props.index, 'xml');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
setXml = () => {
|
setXml = () => {
|
||||||
var xml = this.props.xml;
|
var xml = this.props.xml;
|
||||||
this.props.changeContent(xml, this.props.index, "xml");
|
this.props.changeContent(xml, this.props.index, 'xml');
|
||||||
this.setState({ input: moment(Date.now()).format("LTS") });
|
this.setState({ input: moment(Date.now()).format('LTS') });
|
||||||
};
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div
|
<div style={{ marginBottom: '10px', padding: '18.5px 14px', borderRadius: '25px', border: '1px solid lightgrey', width: 'calc(100% - 28px)' }}>
|
||||||
style={{
|
{!this.props.task ?
|
||||||
marginBottom: "10px",
|
|
||||||
padding: "18.5px 14px",
|
|
||||||
borderRadius: "25px",
|
|
||||||
border: "1px solid lightgrey",
|
|
||||||
width: "calc(100% - 28px)",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{!this.props.task ? (
|
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
labelPlacement="end"
|
labelPlacement="end"
|
||||||
label={"Blockly Beispiel"}
|
label={"Blockly Beispiel"}
|
||||||
@@ -143,77 +126,45 @@ class BlocklyExample extends Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
) : (
|
: <FormLabel style={{ color: 'black' }}>{Blockly.Msg.builder_solution}</FormLabel>}
|
||||||
<FormLabel style={{ color: "black" }}>
|
{this.state.checked ? !this.props.value || this.props.error ?
|
||||||
{Blockly.Msg.builder_solution}
|
<FormHelperText style={{ lineHeight: 'initial' }} className={this.props.classes.errorColor}>{`Reiche deine Blöcke ein, indem du auf den '${this.props.task ? Blockly.Msg.builder_solution_submit : Blockly.Msg.builder_example_submit}'-Button klickst.`}</FormHelperText>
|
||||||
</FormLabel>
|
: this.state.input ? <FormHelperText style={{ lineHeight: 'initial' }}>Die letzte Einreichung erfolgte um {this.state.input} Uhr.</FormHelperText> : null
|
||||||
)}
|
: null}
|
||||||
{this.state.checked ? (
|
{this.state.checked && !this.props.task ?
|
||||||
!this.props.value || this.props.error ? (
|
<FormHelperText style={{ lineHeight: 'initial' }}>{Blockly.Msg.builder_comment}</FormHelperText>
|
||||||
<FormHelperText
|
: null}
|
||||||
style={{ lineHeight: "initial" }}
|
|
||||||
className={this.props.classes.errorColor}
|
|
||||||
>{`Reiche deine Blöcke ein, indem du auf den '${
|
|
||||||
this.props.task
|
|
||||||
? Blockly.Msg.builder_solution_submit
|
|
||||||
: Blockly.Msg.builder_example_submit
|
|
||||||
}'-Button klickst.`}</FormHelperText>
|
|
||||||
) : this.state.input ? (
|
|
||||||
<FormHelperText style={{ lineHeight: "initial" }}>
|
|
||||||
Die letzte Einreichung erfolgte um {this.state.input} Uhr.
|
|
||||||
</FormHelperText>
|
|
||||||
) : null
|
|
||||||
) : null}
|
|
||||||
{this.state.checked && !this.props.task ? (
|
|
||||||
<FormHelperText style={{ lineHeight: "initial" }}>
|
|
||||||
{Blockly.Msg.builder_comment}
|
|
||||||
</FormHelperText>
|
|
||||||
) : null}
|
|
||||||
{/* ensure that the correct xml-file is displayed in the workspace */}
|
{/* ensure that the correct xml-file is displayed in the workspace */}
|
||||||
{this.state.checked && this.state.xml
|
{this.state.checked && this.state.xml ? (() => {
|
||||||
? (() => {
|
|
||||||
return (
|
return (
|
||||||
<div style={{ marginTop: "10px" }}>
|
<div style={{ marginTop: '10px' }}>
|
||||||
<Grid
|
<Grid container className={!this.props.value || this.props.error ? this.props.classes.errorBorder : null}>
|
||||||
container
|
|
||||||
className={
|
|
||||||
!this.props.value || this.props.error
|
|
||||||
? this.props.classes.errorBorder
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<BlocklyWindow
|
<BlocklyWindow
|
||||||
blockDisabled={this.props.task}
|
blockDisabled={this.props.task}
|
||||||
trashcan={false}
|
trashcan={false}
|
||||||
initialXml={this.state.xml}
|
initialXml={this.state.xml}
|
||||||
blocklyCSS={{ height: "500px" }}
|
blocklyCSS={{ height: '500px' }}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Button
|
<Button
|
||||||
className={
|
className={!this.props.value || this.props.error ? this.props.classes.errorButton : null}
|
||||||
!this.props.value || this.props.error
|
style={{ marginTop: '5px', height: '40px' }}
|
||||||
? this.props.classes.errorButton
|
variant='contained'
|
||||||
: null
|
color='primary'
|
||||||
}
|
|
||||||
style={{ marginTop: "5px", height: "40px" }}
|
|
||||||
variant="contained"
|
|
||||||
color="primary"
|
|
||||||
disabled={this.state.disabled}
|
disabled={this.state.disabled}
|
||||||
onClick={() => this.setXml()}
|
onClick={() => this.setXml()}
|
||||||
>
|
>
|
||||||
{this.props.task
|
{this.props.task ? Blockly.Msg.builder_solution_submit : Blockly.Msg.builder_example_submit}
|
||||||
? Blockly.Msg.builder_solution_submit
|
|
||||||
: Blockly.Msg.builder_example_submit}
|
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
})()
|
})()
|
||||||
: null}
|
: null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
BlocklyExample.propTypes = {
|
BlocklyExample.propTypes = {
|
||||||
@@ -221,16 +172,12 @@ BlocklyExample.propTypes = {
|
|||||||
deleteProperty: PropTypes.func.isRequired,
|
deleteProperty: PropTypes.func.isRequired,
|
||||||
setError: PropTypes.func.isRequired,
|
setError: PropTypes.func.isRequired,
|
||||||
deleteError: PropTypes.func.isRequired,
|
deleteError: PropTypes.func.isRequired,
|
||||||
xml: PropTypes.string.isRequired,
|
xml: PropTypes.string.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = state => ({
|
||||||
xml: state.workspace.code.xml,
|
xml: state.workspace.code.xml
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, {
|
|
||||||
changeContent,
|
export default connect(mapStateToProps, { changeContent, deleteProperty, setError, deleteError })(withStyles(styles, { withTheme: true })(BlocklyExample));
|
||||||
deleteProperty,
|
|
||||||
setError,
|
|
||||||
deleteError,
|
|
||||||
})(withStyles(styles, { withTheme: true })(BlocklyExample));
|
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ import {
|
|||||||
resetTutorial as resetTutorialBuilder,
|
resetTutorial as resetTutorialBuilder,
|
||||||
} from "../../../actions/tutorialBuilderActions";
|
} from "../../../actions/tutorialBuilderActions";
|
||||||
import {
|
import {
|
||||||
getAllTutorials,
|
|
||||||
getUserTutorials,
|
|
||||||
getTutorials,
|
getTutorials,
|
||||||
resetTutorial,
|
resetTutorial,
|
||||||
deleteTutorial,
|
deleteTutorial,
|
||||||
@@ -21,17 +19,12 @@ import { clearMessages } from "../../../actions/messageActions";
|
|||||||
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { withRouter } from "react-router-dom";
|
import { withRouter } from "react-router-dom";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
||||||
import { faEyeSlash, faUserCheck } from "@fortawesome/free-solid-svg-icons";
|
|
||||||
|
|
||||||
import Breadcrumbs from "../../Breadcrumbs";
|
import Breadcrumbs from "../../Breadcrumbs";
|
||||||
import Textfield from "./Textfield";
|
import Textfield from "./Textfield";
|
||||||
import Difficulty from "./Difficulty";
|
|
||||||
import Step from "./Step";
|
import Step from "./Step";
|
||||||
import Dialog from "../../Dialog";
|
import Dialog from "../../Dialog";
|
||||||
import Snackbar from "../../Snackbar";
|
import Snackbar from "../../Snackbar";
|
||||||
import Public from "./Public";
|
|
||||||
import Review from "./Review";
|
|
||||||
|
|
||||||
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";
|
||||||
@@ -73,8 +66,6 @@ class Builder extends Component {
|
|||||||
tutorial: "new",
|
tutorial: "new",
|
||||||
open: false,
|
open: false,
|
||||||
title: "",
|
title: "",
|
||||||
public: false,
|
|
||||||
difficulty: "",
|
|
||||||
content: "",
|
content: "",
|
||||||
string: false,
|
string: false,
|
||||||
snackbar: false,
|
snackbar: false,
|
||||||
@@ -89,11 +80,7 @@ class Builder extends Component {
|
|||||||
// retrieve tutorials only if a potential user is loaded - authentication
|
// retrieve tutorials only if a potential user is loaded - authentication
|
||||||
// is finished (success or failed)
|
// is finished (success or failed)
|
||||||
if (!this.props.authProgress) {
|
if (!this.props.authProgress) {
|
||||||
if (this.props.user.role === "admin") {
|
this.props.getTutorials();
|
||||||
this.props.getAllTutorials();
|
|
||||||
} else {
|
|
||||||
this.props.getUserTutorials();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,12 +89,8 @@ class Builder extends Component {
|
|||||||
props.authProgress !== this.props.authProgress &&
|
props.authProgress !== this.props.authProgress &&
|
||||||
!this.props.authProgress
|
!this.props.authProgress
|
||||||
) {
|
) {
|
||||||
if (this.props.user.role === "admin") {
|
|
||||||
// authentication is completed
|
// authentication is completed
|
||||||
this.props.getAllTutorials();
|
this.props.getTutorials();
|
||||||
} else {
|
|
||||||
this.props.getUserTutorials();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (props.message !== this.props.message) {
|
if (props.message !== this.props.message) {
|
||||||
if (this.props.message.id === "GET_TUTORIALS_FAIL") {
|
if (this.props.message.id === "GET_TUTORIALS_FAIL") {
|
||||||
@@ -275,9 +258,6 @@ class Builder extends Component {
|
|||||||
var steps = this.props.steps;
|
var steps = this.props.steps;
|
||||||
var newTutorial = new FormData();
|
var newTutorial = new FormData();
|
||||||
newTutorial.append("title", this.props.title);
|
newTutorial.append("title", this.props.title);
|
||||||
newTutorial.append("difficulty", this.props.difficulty);
|
|
||||||
newTutorial.append("public", this.props.public);
|
|
||||||
newTutorial.append("review", this.props.review);
|
|
||||||
steps.forEach((step, i) => {
|
steps.forEach((step, i) => {
|
||||||
if (step._id) {
|
if (step._id) {
|
||||||
newTutorial.append(`steps[${i}][_id]`, step._id);
|
newTutorial.append(`steps[${i}][_id]`, step._id);
|
||||||
@@ -303,6 +283,21 @@ class Builder extends Component {
|
|||||||
// optional
|
// optional
|
||||||
newTutorial.append(`steps[${i}][xml]`, step.xml);
|
newTutorial.append(`steps[${i}][xml]`, step.xml);
|
||||||
}
|
}
|
||||||
|
if (step.media) {
|
||||||
|
// optional
|
||||||
|
if (step.media.youtube) {
|
||||||
|
newTutorial.append(
|
||||||
|
`steps[${i}][media][youtube]`,
|
||||||
|
step.media.youtube
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (step.media.picture) {
|
||||||
|
newTutorial.append(
|
||||||
|
`steps[${i}][media][picture]`,
|
||||||
|
step.media.picture
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return newTutorial;
|
return newTutorial;
|
||||||
}
|
}
|
||||||
@@ -375,19 +370,9 @@ class Builder extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.props.user.role === "admin") {
|
var filteredTutorials = this.props.tutorials.filter(
|
||||||
var filteredTutorials = this.props.tutorials;
|
|
||||||
} else {
|
|
||||||
filteredTutorials = this.props.tutorials.filter(
|
|
||||||
(tutorial) => tutorial.creator === this.props.user.email
|
(tutorial) => tutorial.creator === this.props.user.email
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
// } else {
|
|
||||||
// filteredTutorials = this.props.userTutorials.filter(
|
|
||||||
// (tutorial) => tutorial.creator === this.props.user.email
|
|
||||||
// );
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Breadcrumbs
|
<Breadcrumbs
|
||||||
@@ -477,24 +462,7 @@ class Builder extends Component {
|
|||||||
label="Tutorial"
|
label="Tutorial"
|
||||||
>
|
>
|
||||||
{filteredTutorials.map((tutorial) => (
|
{filteredTutorials.map((tutorial) => (
|
||||||
<MenuItem value={tutorial._id}>
|
|
||||||
{tutorial.title}{" "}
|
|
||||||
{tutorial.review && tutorial.public === false ? (
|
|
||||||
<div>
|
|
||||||
<FontAwesomeIcon icon={faUserCheck} />
|
|
||||||
<FontAwesomeIcon icon={faEyeSlash} />
|
|
||||||
</div>
|
|
||||||
) : tutorial.public === false ? (
|
|
||||||
<FontAwesomeIcon icon={faEyeSlash} />
|
|
||||||
) : null}
|
|
||||||
</MenuItem>
|
|
||||||
/* ) : tutorial.public === false ? (
|
|
||||||
<MenuItem value={tutorial._id}>
|
|
||||||
{tutorial.title} <FontAwesomeIcon icon={faEyeSlash} />
|
|
||||||
</MenuItem>
|
|
||||||
) : (
|
|
||||||
<MenuItem value={tutorial._id}>{tutorial.title}</MenuItem>
|
<MenuItem value={tutorial._id}>{tutorial.title}</MenuItem>
|
||||||
)} */
|
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
@@ -519,45 +487,6 @@ class Builder extends Component {
|
|||||||
label={"Titel"}
|
label={"Titel"}
|
||||||
error={this.props.error.title}
|
error={this.props.error.title}
|
||||||
/>
|
/>
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
borderRadius: "25px",
|
|
||||||
border: "1px solid lightgrey",
|
|
||||||
padding: "10px 14px 10px 10px",
|
|
||||||
marginBottom: "20px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Difficulty
|
|
||||||
value={this.props.difficulty}
|
|
||||||
property={"difficulty"}
|
|
||||||
label={"difficulty"}
|
|
||||||
error={this.props.error.difficulty}
|
|
||||||
/>
|
|
||||||
<Divider
|
|
||||||
variant="fullWidth"
|
|
||||||
style={{ margin: "30px 0 10px 0" }}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Review
|
|
||||||
value={this.props.review}
|
|
||||||
property={"review"}
|
|
||||||
label={"review"}
|
|
||||||
error={this.props.error.review}
|
|
||||||
/>
|
|
||||||
<Divider
|
|
||||||
variant="fullWidth"
|
|
||||||
style={{ margin: "30px 0 10px 0" }}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{this.props.user.blocklyRole === "admin" ? (
|
|
||||||
<Public
|
|
||||||
value={this.props.public}
|
|
||||||
property={"public"}
|
|
||||||
label={"public"}
|
|
||||||
error={this.props.error.public}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{this.props.steps.map((step, i) => (
|
{this.props.steps.map((step, i) => (
|
||||||
<Step step={step} index={i} key={i} />
|
<Step step={step} index={i} key={i} />
|
||||||
@@ -690,8 +619,6 @@ class Builder extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Builder.propTypes = {
|
Builder.propTypes = {
|
||||||
getAllTutorials: PropTypes.func.isRequired,
|
|
||||||
getUserTutorials: PropTypes.func.isRequired,
|
|
||||||
getTutorials: PropTypes.func.isRequired,
|
getTutorials: PropTypes.func.isRequired,
|
||||||
resetTutorial: PropTypes.func.isRequired,
|
resetTutorial: PropTypes.func.isRequired,
|
||||||
clearMessages: PropTypes.func.isRequired,
|
clearMessages: PropTypes.func.isRequired,
|
||||||
@@ -704,9 +631,6 @@ Builder.propTypes = {
|
|||||||
resetTutorialBuilder: PropTypes.func.isRequired,
|
resetTutorialBuilder: PropTypes.func.isRequired,
|
||||||
tutorialProgress: PropTypes.func.isRequired,
|
tutorialProgress: PropTypes.func.isRequired,
|
||||||
title: PropTypes.string.isRequired,
|
title: PropTypes.string.isRequired,
|
||||||
difficulty: PropTypes.number.isRequired,
|
|
||||||
public: PropTypes.bool.isRequired,
|
|
||||||
review: PropTypes.bool.isRequired,
|
|
||||||
id: PropTypes.string.isRequired,
|
id: PropTypes.string.isRequired,
|
||||||
steps: PropTypes.array.isRequired,
|
steps: PropTypes.array.isRequired,
|
||||||
change: PropTypes.number.isRequired,
|
change: PropTypes.number.isRequired,
|
||||||
@@ -721,16 +645,12 @@ Builder.propTypes = {
|
|||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = (state) => ({
|
||||||
title: state.builder.title,
|
title: state.builder.title,
|
||||||
difficulty: state.builder.difficulty,
|
|
||||||
review: state.builder.review,
|
|
||||||
public: state.builder.public,
|
|
||||||
id: state.builder.id,
|
id: state.builder.id,
|
||||||
steps: state.builder.steps,
|
steps: state.builder.steps,
|
||||||
change: state.builder.change,
|
change: state.builder.change,
|
||||||
error: state.builder.error,
|
error: state.builder.error,
|
||||||
json: state.builder.json,
|
json: state.builder.json,
|
||||||
isProgress: state.builder.progress,
|
isProgress: state.builder.progress,
|
||||||
userTutorials: state.tutorial.userTutorials,
|
|
||||||
tutorials: state.tutorial.tutorials,
|
tutorials: state.tutorial.tutorials,
|
||||||
message: state.message,
|
message: state.message,
|
||||||
user: state.auth.user,
|
user: state.auth.user,
|
||||||
@@ -745,8 +665,6 @@ export default connect(mapStateToProps, {
|
|||||||
tutorialId,
|
tutorialId,
|
||||||
resetTutorialBuilder,
|
resetTutorialBuilder,
|
||||||
getTutorials,
|
getTutorials,
|
||||||
getUserTutorials,
|
|
||||||
getAllTutorials,
|
|
||||||
resetTutorial,
|
resetTutorial,
|
||||||
tutorialProgress,
|
tutorialProgress,
|
||||||
clearMessages,
|
clearMessages,
|
||||||
|
|||||||
@@ -1,99 +0,0 @@
|
|||||||
import React, { Component } from "react";
|
|
||||||
import PropTypes from "prop-types";
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import {
|
|
||||||
tutorialDifficulty,
|
|
||||||
jsonString,
|
|
||||||
changeContent,
|
|
||||||
setError,
|
|
||||||
deleteError,
|
|
||||||
} from "../../../actions/tutorialBuilderActions";
|
|
||||||
|
|
||||||
import { withStyles } from "@material-ui/core/styles";
|
|
||||||
import ReactStars from "react-rating-stars-component";
|
|
||||||
import * as Blockly from "blockly";
|
|
||||||
import FormGroup from "@material-ui/core/FormGroup";
|
|
||||||
import FormControlLabel from "@material-ui/core/FormControlLabel";
|
|
||||||
import FormControl from "@material-ui/core/FormControl";
|
|
||||||
import FormLabel from "@material-ui/core/FormLabel";
|
|
||||||
|
|
||||||
const styles = (theme) => ({
|
|
||||||
multiline: {
|
|
||||||
padding: "18.5px 14px 18.5px 24px",
|
|
||||||
},
|
|
||||||
errorColor: {
|
|
||||||
color: `${theme.palette.error.dark} !important`,
|
|
||||||
},
|
|
||||||
errorColorShrink: {
|
|
||||||
color: `rgba(0, 0, 0, 0.54) !important`,
|
|
||||||
},
|
|
||||||
errorBorder: {
|
|
||||||
borderColor: `${theme.palette.error.dark} !important`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
class Difficulty extends Component {
|
|
||||||
ratingChanged = (newRating) => {
|
|
||||||
this.handleChange(newRating);
|
|
||||||
};
|
|
||||||
|
|
||||||
handleChange = (e) => {
|
|
||||||
var value = e;
|
|
||||||
if (this.props.property === "difficulty") {
|
|
||||||
this.props.tutorialDifficulty(value);
|
|
||||||
} else if (this.props.property === "json") {
|
|
||||||
this.props.jsonString(value);
|
|
||||||
} else {
|
|
||||||
this.props.changeContent(
|
|
||||||
value,
|
|
||||||
this.props.index,
|
|
||||||
this.props.property,
|
|
||||||
this.props.property2
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<FormControl component="fieldset">
|
|
||||||
<FormLabel component="legend">
|
|
||||||
{Blockly.Msg.builder_difficulty}
|
|
||||||
</FormLabel>
|
|
||||||
<FormGroup aria-label="position" row>
|
|
||||||
<FormControlLabel
|
|
||||||
value="Tutorial veröffentlichen"
|
|
||||||
control={
|
|
||||||
<ReactStars
|
|
||||||
count={5}
|
|
||||||
onChange={this.handleChange}
|
|
||||||
value={this.props.value}
|
|
||||||
size={30}
|
|
||||||
isHalf={true}
|
|
||||||
emptyIcon={<i className="fa fa-star"></i>}
|
|
||||||
halfIcon={<i className="fa fa-star-half-alt"></i>}
|
|
||||||
fullIcon={<i className="fa fa-star"></i>}
|
|
||||||
activeColor="#ffd700"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label="Schwierigkeitsgrad"
|
|
||||||
labelPlacement="start"
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
</FormControl>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Difficulty.propTypes = {
|
|
||||||
tutorialDifficulty: PropTypes.func.isRequired,
|
|
||||||
jsonString: PropTypes.func.isRequired,
|
|
||||||
changeContent: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(null, {
|
|
||||||
tutorialDifficulty,
|
|
||||||
jsonString,
|
|
||||||
changeContent,
|
|
||||||
setError,
|
|
||||||
deleteError,
|
|
||||||
})(withStyles(styles, { withTheme: true })(Difficulty));
|
|
||||||
@@ -1,159 +1,107 @@
|
|||||||
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 {
|
import { changeContent, setError, deleteError } from '../../../actions/tutorialBuilderActions';
|
||||||
changeContent,
|
|
||||||
setError,
|
|
||||||
deleteError,
|
|
||||||
} from "../../../actions/tutorialBuilderActions";
|
|
||||||
|
|
||||||
import hardware from "../../../data/hardware.json";
|
import hardware from '../../../data/hardware.json';
|
||||||
|
|
||||||
import { withStyles } from "@material-ui/core/styles";
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import withWidth, { isWidthDown } from "@material-ui/core/withWidth";
|
import withWidth, { isWidthDown } from '@material-ui/core/withWidth';
|
||||||
import ImageList from "@material-ui/core/ImageList";
|
import GridList from '@material-ui/core/GridList';
|
||||||
import ImageListItem from "@material-ui/core/ImageListItem";
|
import GridListTile from '@material-ui/core/GridListTile';
|
||||||
import ImageListItemBar from "@material-ui/core/ImageListItemBar";
|
import GridListTileBar from '@material-ui/core/GridListTileBar';
|
||||||
import FormHelperText from "@material-ui/core/FormHelperText";
|
import FormHelperText from '@material-ui/core/FormHelperText';
|
||||||
import FormLabel from "@material-ui/core/FormLabel";
|
import FormLabel from '@material-ui/core/FormLabel';
|
||||||
import * as Blockly from "blockly";
|
import * as Blockly from 'blockly'
|
||||||
|
|
||||||
const styles = (theme) => ({
|
|
||||||
multiImageListItem: {
|
const styles = theme => ({
|
||||||
|
multiGridListTile: {
|
||||||
background: theme.palette.primary.main,
|
background: theme.palette.primary.main,
|
||||||
opacity: 0.9,
|
opacity: 0.9,
|
||||||
height: "30px",
|
height: '30px'
|
||||||
},
|
},
|
||||||
multiImageListItemTitle: {
|
multiGridListTileTitle: {
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary
|
||||||
},
|
},
|
||||||
border: {
|
border: {
|
||||||
cursor: "pointer",
|
cursor: 'pointer',
|
||||||
"&:hover": {
|
'&:hover': {
|
||||||
width: "calc(100% - 4px)",
|
width: 'calc(100% - 4px)',
|
||||||
height: "calc(100% - 4px)",
|
height: 'calc(100% - 4px)',
|
||||||
border: `2px solid ${theme.palette.primary.main}`,
|
border: `2px solid ${theme.palette.primary.main}`
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
active: {
|
active: {
|
||||||
cursor: "pointer",
|
cursor: 'pointer',
|
||||||
width: "calc(100% - 4px)",
|
width: 'calc(100% - 4px)',
|
||||||
height: "calc(100% - 4px)",
|
height: 'calc(100% - 4px)',
|
||||||
border: `2px solid ${theme.palette.primary.main}`,
|
border: `2px solid ${theme.palette.primary.main}`
|
||||||
},
|
},
|
||||||
errorColor: {
|
errorColor: {
|
||||||
color: theme.palette.error.dark,
|
color: theme.palette.error.dark,
|
||||||
lineHeight: "initial",
|
lineHeight: 'initial',
|
||||||
marginBottom: "10px",
|
marginBottom: '10px'
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
class Requirements extends Component {
|
class Requirements extends Component {
|
||||||
|
|
||||||
onChange = (hardware) => {
|
onChange = (hardware) => {
|
||||||
var hardwareArray = this.props.value;
|
var hardwareArray = this.props.value;
|
||||||
if (hardwareArray.filter((value) => value === hardware).length > 0) {
|
if (hardwareArray.filter(value => value === hardware).length > 0) {
|
||||||
hardwareArray = hardwareArray.filter((value) => value !== hardware);
|
hardwareArray = hardwareArray.filter(value => value !== hardware);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
hardwareArray.push(hardware);
|
hardwareArray.push(hardware);
|
||||||
if (this.props.error) {
|
if (this.props.error) {
|
||||||
this.props.deleteError(this.props.index, "hardware");
|
this.props.deleteError(this.props.index, 'hardware');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.props.changeContent(hardwareArray, this.props.index, "hardware");
|
this.props.changeContent(hardwareArray, this.props.index, 'hardware');
|
||||||
if (hardwareArray.length === 0) {
|
if (hardwareArray.length === 0) {
|
||||||
this.props.setError(this.props.index, "hardware");
|
this.props.setError(this.props.index, 'hardware');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var cols = isWidthDown("md", this.props.width)
|
var cols = isWidthDown('md', this.props.width) ? isWidthDown('sm', this.props.width) ? isWidthDown('xs', this.props.width) ? 2 : 3 : 4 : 6;
|
||||||
? isWidthDown("sm", this.props.width)
|
|
||||||
? isWidthDown("xs", this.props.width)
|
|
||||||
? 2
|
|
||||||
: 3
|
|
||||||
: 4
|
|
||||||
: 6;
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div style={{ marginBottom: '10px', padding: '18.5px 14px', borderRadius: '25px', border: '1px solid lightgrey', width: 'calc(100% - 28px)' }}>
|
||||||
style={{
|
<FormLabel style={{ color: 'black' }}>Hardware</FormLabel>
|
||||||
marginBottom: "10px",
|
<FormHelperText style={this.props.error ? { lineHeight: 'initial', marginTop: '5px' } : { marginTop: '5px', lineHeight: 'initial', marginBottom: '10px' }}>{Blockly.Msg.builder_hardware_order}</FormHelperText>
|
||||||
padding: "18.5px 14px",
|
{this.props.error ? <FormHelperText className={this.props.classes.errorColor}>{Blockly.Msg.builder_hardware_helper}</FormHelperText> : null}
|
||||||
borderRadius: "25px",
|
<GridList cellHeight={100} cols={cols} spacing={10}>
|
||||||
border: "1px solid lightgrey",
|
|
||||||
width: "calc(100% - 28px)",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FormLabel style={{ color: "black" }}>Hardware</FormLabel>
|
|
||||||
<FormHelperText
|
|
||||||
style={
|
|
||||||
this.props.error
|
|
||||||
? { lineHeight: "initial", marginTop: "5px" }
|
|
||||||
: {
|
|
||||||
marginTop: "5px",
|
|
||||||
lineHeight: "initial",
|
|
||||||
marginBottom: "10px",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{Blockly.Msg.builder_hardware_order}
|
|
||||||
</FormHelperText>
|
|
||||||
{this.props.error ? (
|
|
||||||
<FormHelperText className={this.props.classes.errorColor}>
|
|
||||||
{Blockly.Msg.builder_hardware_helper}
|
|
||||||
</FormHelperText>
|
|
||||||
) : null}
|
|
||||||
<ImageList rowHeight={100} cols={cols} gap={10}>
|
|
||||||
{hardware.map((picture, i) => (
|
{hardware.map((picture, i) => (
|
||||||
<ImageListItem
|
<GridListTile key={i} onClick={() => this.onChange(picture.id)} classes={{ tile: this.props.value.filter(value => value === picture.id).length > 0 ? this.props.classes.active : this.props.classes.border }}>
|
||||||
key={i}
|
<div style={{ margin: 'auto', width: 'max-content' }}>
|
||||||
onClick={() => this.onChange(picture.id)}
|
<img src={`/media/hardware/${picture.src}`} alt={picture.name} height={100} />
|
||||||
classes={{
|
|
||||||
item:
|
|
||||||
this.props.value.filter((value) => value === picture.id)
|
|
||||||
.length > 0
|
|
||||||
? this.props.classes.active
|
|
||||||
: this.props.classes.border,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div style={{ margin: "auto", width: "max-content" }}>
|
|
||||||
<img
|
|
||||||
src={`/media/hardware/${picture.src}`}
|
|
||||||
alt={picture.name}
|
|
||||||
height={100}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<ImageListItemBar
|
<GridListTileBar
|
||||||
classes={{ root: this.props.classes.multiImageListItem }}
|
classes={{ root: this.props.classes.multiGridListTile }}
|
||||||
title={
|
title={
|
||||||
<div
|
<div style={{ overflow: 'hidden', textOverflow: 'ellipsis' }} className={this.props.classes.multiGridListTileTitle}>
|
||||||
style={{ overflow: "hidden", textOverflow: "ellipsis" }}
|
|
||||||
className={this.props.classes.multiImageListItemTitle}
|
|
||||||
>
|
|
||||||
{picture.name}
|
{picture.name}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</ImageListItem>
|
</GridListTile>
|
||||||
))}
|
))}
|
||||||
</ImageList>
|
</GridList>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Requirements.propTypes = {
|
Requirements.propTypes = {
|
||||||
changeContent: PropTypes.func.isRequired,
|
changeContent: PropTypes.func.isRequired,
|
||||||
setError: PropTypes.func.isRequired,
|
setError: PropTypes.func.isRequired,
|
||||||
deleteError: PropTypes.func.isRequired,
|
deleteError: PropTypes.func.isRequired,
|
||||||
change: PropTypes.number.isRequired,
|
change: PropTypes.number.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = state => ({
|
||||||
change: state.builder.change,
|
change: state.builder.change
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, {
|
export default connect(mapStateToProps, { changeContent, setError, deleteError })(withStyles(styles, { withTheme: true })(withWidth()(Requirements)));
|
||||||
changeContent,
|
|
||||||
setError,
|
|
||||||
deleteError,
|
|
||||||
})(withStyles(styles, { withTheme: true })(withWidth()(Requirements)));
|
|
||||||
|
|||||||
@@ -1,80 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import {
|
|
||||||
tutorialTitle,
|
|
||||||
jsonString,
|
|
||||||
changeContent,
|
|
||||||
setError,
|
|
||||||
deleteError,
|
|
||||||
} from "../../../actions/tutorialBuilderActions";
|
|
||||||
|
|
||||||
import FormControl from "@material-ui/core/FormControl";
|
|
||||||
import MarkdownIt from "markdown-it";
|
|
||||||
import Editor from "react-markdown-editor-lite";
|
|
||||||
import "react-markdown-editor-lite/lib/index.css";
|
|
||||||
|
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
const mdParser = new MarkdownIt(/* Markdown-it options */);
|
|
||||||
|
|
||||||
const MarkdownEditor = (props) => {
|
|
||||||
const [value, setValue] = React.useState(props.value);
|
|
||||||
|
|
||||||
const mdEditor = React.useRef(null);
|
|
||||||
|
|
||||||
function handleChange({ html, text }) {
|
|
||||||
setValue(text);
|
|
||||||
var value = text;
|
|
||||||
props.changeContent(value, props.index, props.property, props.property2);
|
|
||||||
if (value.replace(/\s/g, "") === "") {
|
|
||||||
props.setError(props.index, props.property);
|
|
||||||
} else {
|
|
||||||
props.deleteError(props.index, props.property);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function uploadImage(files) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append("files", files);
|
|
||||||
axios({
|
|
||||||
method: "post",
|
|
||||||
url: `${process.env.REACT_APP_BLOCKLY_API}/upload/uploadImage`,
|
|
||||||
data: formData,
|
|
||||||
headers: { "Content-Type": "multipart/form-data" },
|
|
||||||
})
|
|
||||||
.then((res) => {
|
|
||||||
resolve(
|
|
||||||
`${process.env.REACT_APP_BLOCKLY_API}/upload/` + res.data.filename
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
reject(new Error("error"));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FormControl variant="outlined" fullWidth style={{ marginBottom: "10px" }}>
|
|
||||||
<Editor
|
|
||||||
ref={mdEditor}
|
|
||||||
style={{ height: "500px" }}
|
|
||||||
renderHTML={(text) => mdParser.render(text)}
|
|
||||||
onChange={handleChange}
|
|
||||||
value={value}
|
|
||||||
id={props.property}
|
|
||||||
label={props.label}
|
|
||||||
property={props.property}
|
|
||||||
onImageUpload={uploadImage}
|
|
||||||
/>
|
|
||||||
</FormControl>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(null, {
|
|
||||||
tutorialTitle,
|
|
||||||
jsonString,
|
|
||||||
changeContent,
|
|
||||||
setError,
|
|
||||||
deleteError,
|
|
||||||
})(MarkdownEditor);
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
import React, { Component } from "react";
|
|
||||||
import PropTypes from "prop-types";
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import {
|
|
||||||
tutorialPublic,
|
|
||||||
jsonString,
|
|
||||||
changeContent,
|
|
||||||
setError,
|
|
||||||
deleteError,
|
|
||||||
} from "../../../actions/tutorialBuilderActions";
|
|
||||||
|
|
||||||
import { withStyles } from "@material-ui/core/styles";
|
|
||||||
|
|
||||||
import * as Blockly from "blockly";
|
|
||||||
import Checkbox from "@material-ui/core/Checkbox";
|
|
||||||
import FormGroup from "@material-ui/core/FormGroup";
|
|
||||||
import FormControlLabel from "@material-ui/core/FormControlLabel";
|
|
||||||
import FormControl from "@material-ui/core/FormControl";
|
|
||||||
import FormLabel from "@material-ui/core/FormLabel";
|
|
||||||
|
|
||||||
const styles = (theme) => ({
|
|
||||||
multiline: {
|
|
||||||
padding: "18.5px 14px 18.5px 24px",
|
|
||||||
},
|
|
||||||
errorColor: {
|
|
||||||
color: `${theme.palette.error.dark} !important`,
|
|
||||||
},
|
|
||||||
errorColorShrink: {
|
|
||||||
color: `rgba(0, 0, 0, 0.54) !important`,
|
|
||||||
},
|
|
||||||
errorBorder: {
|
|
||||||
borderColor: `${theme.palette.error.dark} !important`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
class Public extends Component {
|
|
||||||
handleChange = (e) => {
|
|
||||||
var value = e.target.checked;
|
|
||||||
if (this.props.property === "public") {
|
|
||||||
this.props.tutorialPublic(value);
|
|
||||||
} else if (this.props.property === "json") {
|
|
||||||
this.props.jsonString(value);
|
|
||||||
} else {
|
|
||||||
this.props.changeContent(
|
|
||||||
value,
|
|
||||||
this.props.index,
|
|
||||||
this.props.property,
|
|
||||||
this.props.property2
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<FormControl component="fieldset">
|
|
||||||
<FormLabel component="legend">
|
|
||||||
{Blockly.Msg.builder_public_head}
|
|
||||||
</FormLabel>
|
|
||||||
<FormGroup aria-label="position" row>
|
|
||||||
<FormControlLabel
|
|
||||||
value="Tutorial veröffentlichen"
|
|
||||||
control={
|
|
||||||
<Checkbox
|
|
||||||
checked={this.props.value}
|
|
||||||
onChange={this.handleChange}
|
|
||||||
color="primary"
|
|
||||||
name="checkedA"
|
|
||||||
inputProps={{ "aria-label": "secondary checkbox" }}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label={Blockly.Msg.builder_public_label}
|
|
||||||
labelPlacement="start"
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
</FormControl>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Public.propTypes = {
|
|
||||||
tutorialPublic: PropTypes.func.isRequired,
|
|
||||||
jsonString: PropTypes.func.isRequired,
|
|
||||||
changeContent: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(null, {
|
|
||||||
tutorialPublic,
|
|
||||||
jsonString,
|
|
||||||
changeContent,
|
|
||||||
setError,
|
|
||||||
deleteError,
|
|
||||||
})(withStyles(styles, { withTheme: true })(Public));
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
import React, { Component } from "react";
|
|
||||||
import PropTypes from "prop-types";
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import {
|
|
||||||
tutorialReview,
|
|
||||||
jsonString,
|
|
||||||
changeContent,
|
|
||||||
setError,
|
|
||||||
deleteError,
|
|
||||||
} from "../../../actions/tutorialBuilderActions";
|
|
||||||
|
|
||||||
import { withStyles } from "@material-ui/core/styles";
|
|
||||||
|
|
||||||
import * as Blockly from "blockly";
|
|
||||||
import Checkbox from "@material-ui/core/Checkbox";
|
|
||||||
import FormGroup from "@material-ui/core/FormGroup";
|
|
||||||
import FormControlLabel from "@material-ui/core/FormControlLabel";
|
|
||||||
import FormControl from "@material-ui/core/FormControl";
|
|
||||||
import FormLabel from "@material-ui/core/FormLabel";
|
|
||||||
|
|
||||||
const styles = (theme) => ({
|
|
||||||
multiline: {
|
|
||||||
padding: "18.5px 14px 18.5px 24px",
|
|
||||||
},
|
|
||||||
errorColor: {
|
|
||||||
color: `${theme.palette.error.dark} !important`,
|
|
||||||
},
|
|
||||||
errorColorShrink: {
|
|
||||||
color: `rgba(0, 0, 0, 0.54) !important`,
|
|
||||||
},
|
|
||||||
errorBorder: {
|
|
||||||
borderColor: `${theme.palette.error.dark} !important`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
class Review extends Component {
|
|
||||||
handleChange = (e) => {
|
|
||||||
var value = e.target.checked;
|
|
||||||
if (this.props.property === "review") {
|
|
||||||
this.props.tutorialReview(value);
|
|
||||||
} else if (this.props.property === "json") {
|
|
||||||
this.props.jsonString(value);
|
|
||||||
} else {
|
|
||||||
this.props.changeContent(
|
|
||||||
value,
|
|
||||||
this.props.index,
|
|
||||||
this.props.property,
|
|
||||||
this.props.property2
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<FormControl component="fieldset">
|
|
||||||
<FormLabel component="legend">
|
|
||||||
{Blockly.Msg.builder_review_head}
|
|
||||||
</FormLabel>
|
|
||||||
{Blockly.Msg.builder_review_text}
|
|
||||||
<FormGroup aria-label="position" row>
|
|
||||||
<FormControlLabel
|
|
||||||
value="Tutorial veröffentlichen"
|
|
||||||
control={
|
|
||||||
<Checkbox
|
|
||||||
checked={this.props.value}
|
|
||||||
onChange={this.handleChange}
|
|
||||||
color="primary"
|
|
||||||
name="checkedA"
|
|
||||||
inputProps={{ "aria-label": "secondary checkbox" }}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label="Ich möchte mein Tutorial öffentlich machen"
|
|
||||||
labelPlacement="start"
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
</FormControl>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Review.propTypes = {
|
|
||||||
tutorialReview: PropTypes.func.isRequired,
|
|
||||||
jsonString: PropTypes.func.isRequired,
|
|
||||||
changeContent: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(null, {
|
|
||||||
tutorialReview,
|
|
||||||
jsonString,
|
|
||||||
changeContent,
|
|
||||||
setError,
|
|
||||||
deleteError,
|
|
||||||
})(withStyles(styles, { withTheme: true })(Review));
|
|
||||||
@@ -1,194 +1,118 @@
|
|||||||
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 {
|
import { addStep, removeStep, changeStepIndex } from '../../../actions/tutorialBuilderActions';
|
||||||
addStep,
|
|
||||||
removeStep,
|
|
||||||
changeStepIndex,
|
|
||||||
} from "../../../actions/tutorialBuilderActions";
|
|
||||||
|
|
||||||
import clsx from "clsx";
|
import clsx from 'clsx';
|
||||||
|
|
||||||
import Textfield from "./Textfield";
|
import Textfield from './Textfield';
|
||||||
import StepType from "./StepType";
|
import StepType from './StepType';
|
||||||
import BlocklyExample from "./BlocklyExample";
|
import BlocklyExample from './BlocklyExample';
|
||||||
import Requirements from "./Requirements";
|
import Requirements from './Requirements';
|
||||||
import Hardware from "./Hardware";
|
import Hardware from './Hardware';
|
||||||
|
import Media from './Media';
|
||||||
|
|
||||||
import { withStyles } from "@material-ui/core/styles";
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from '@material-ui/core/Typography';
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
import IconButton from '@material-ui/core/IconButton';
|
||||||
import Tooltip from "@material-ui/core/Tooltip";
|
import Tooltip from '@material-ui/core/Tooltip';
|
||||||
|
|
||||||
import {
|
import { faPlus, faAngleDoubleUp, faAngleDoubleDown, faTrash } from "@fortawesome/free-solid-svg-icons";
|
||||||
faPlus,
|
|
||||||
faAngleDoubleUp,
|
|
||||||
faAngleDoubleDown,
|
|
||||||
faTrash,
|
|
||||||
} from "@fortawesome/free-solid-svg-icons";
|
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
|
||||||
import MarkdownEditor from "./MarkdownEditor";
|
|
||||||
|
|
||||||
const styles = (theme) => ({
|
const styles = (theme) => ({
|
||||||
button: {
|
button: {
|
||||||
backgroundColor: theme.palette.primary.main,
|
backgroundColor: theme.palette.primary.main,
|
||||||
color: theme.palette.primary.contrastText,
|
color: theme.palette.primary.contrastText,
|
||||||
width: "40px",
|
width: '40px',
|
||||||
height: "40px",
|
height: '40px',
|
||||||
"&:hover": {
|
'&:hover': {
|
||||||
backgroundColor: theme.palette.primary.main,
|
backgroundColor: theme.palette.primary.main,
|
||||||
color: theme.palette.primary.contrastText,
|
color: theme.palette.primary.contrastText,
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
delete: {
|
delete: {
|
||||||
backgroundColor: theme.palette.error.dark,
|
backgroundColor: theme.palette.error.dark,
|
||||||
color: theme.palette.error.contrastText,
|
color: theme.palette.error.contrastText,
|
||||||
"&:hover": {
|
'&:hover': {
|
||||||
backgroundColor: theme.palette.error.dark,
|
backgroundColor: theme.palette.error.dark,
|
||||||
color: theme.palette.error.contrastText,
|
color: theme.palette.error.contrastText,
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
class Step extends Component {
|
class Step extends Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var index = this.props.index;
|
var index = this.props.index;
|
||||||
var steps = this.props.steps;
|
var steps = this.props.steps;
|
||||||
return (
|
return (
|
||||||
<div
|
<div style={{borderRadius: '25px', border: '1px solid lightgrey', padding: '10px 14px 10px 10px', marginBottom: '20px'}}>
|
||||||
style={{
|
<Typography variant='h6' style={{marginBottom: '10px', marginLeft: '4px'}}>Schritt {index+1}</Typography>
|
||||||
borderRadius: "25px",
|
<div style={{display: 'flex', position: 'relative'}}>
|
||||||
border: "1px solid lightgrey",
|
<div style={{width: '40px', marginRight: '10px', position: 'absolute', left: '4px', bottom: '10px'}}>
|
||||||
padding: "10px 14px 10px 10px",
|
<Tooltip title='Schritt hinzufügen' arrow>
|
||||||
marginBottom: "20px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography
|
|
||||||
variant="h6"
|
|
||||||
style={{ marginBottom: "10px", marginLeft: "4px" }}
|
|
||||||
>
|
|
||||||
Schritt {index + 1}
|
|
||||||
</Typography>
|
|
||||||
<div style={{ display: "flex", position: "relative" }}>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
width: "40px",
|
|
||||||
marginRight: "10px",
|
|
||||||
position: "absolute",
|
|
||||||
left: "4px",
|
|
||||||
bottom: "10px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Tooltip title="Schritt hinzufügen" arrow>
|
|
||||||
<IconButton
|
<IconButton
|
||||||
className={this.props.classes.button}
|
className={this.props.classes.button}
|
||||||
style={index === 0 ? {} : { marginBottom: "5px" }}
|
style={index === 0 ? {} : {marginBottom: '5px'}}
|
||||||
onClick={() => this.props.addStep(index + 1)}
|
onClick={() => this.props.addStep(index+1)}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faPlus} size="xs" />
|
<FontAwesomeIcon icon={faPlus} size="xs"/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
{index !== 0 ? (
|
{index !== 0 ?
|
||||||
<div>
|
<div>
|
||||||
<Tooltip
|
<Tooltip title={`Schritt ${index+1} nach oben schieben`} arrow>
|
||||||
title={`Schritt ${index + 1} nach oben schieben`}
|
|
||||||
arrow
|
|
||||||
>
|
|
||||||
<IconButton
|
<IconButton
|
||||||
disabled={index < 2}
|
disabled={index < 2}
|
||||||
className={this.props.classes.button}
|
className={this.props.classes.button}
|
||||||
style={{ marginBottom: "5px" }}
|
style={{marginBottom: '5px'}}
|
||||||
onClick={() => this.props.changeStepIndex(index, index - 1)}
|
onClick={() => this.props.changeStepIndex(index, index-1)}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faAngleDoubleUp} size="xs" />
|
<FontAwesomeIcon icon={faAngleDoubleUp} size="xs"/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip
|
<Tooltip title={`Schritt ${index+1} nach unten schieben`} arrow>
|
||||||
title={`Schritt ${index + 1} nach unten schieben`}
|
|
||||||
arrow
|
|
||||||
>
|
|
||||||
<IconButton
|
<IconButton
|
||||||
disabled={index === steps.length - 1}
|
disabled={index === steps.length-1}
|
||||||
className={this.props.classes.button}
|
className={this.props.classes.button}
|
||||||
style={{ marginBottom: "5px" }}
|
style={{marginBottom: '5px'}}
|
||||||
onClick={() => this.props.changeStepIndex(index, index + 1)}
|
onClick={() => this.props.changeStepIndex(index, index+1)}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faAngleDoubleDown} size="xs" />
|
<FontAwesomeIcon icon={faAngleDoubleDown} size="xs"/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title={`Schritt ${index + 1} löschen`} arrow>
|
<Tooltip title={`Schritt ${index+1} löschen`} arrow>
|
||||||
<IconButton
|
<IconButton
|
||||||
disabled={index === 0}
|
disabled={index === 0}
|
||||||
className={clsx(
|
className={clsx(this.props.classes.button, this.props.classes.delete)}
|
||||||
this.props.classes.button,
|
|
||||||
this.props.classes.delete
|
|
||||||
)}
|
|
||||||
onClick={() => this.props.removeStep(index)}
|
onClick={() => this.props.removeStep(index)}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faTrash} size="xs" />
|
<FontAwesomeIcon icon={faTrash} size="xs"/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
: null}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ width: "100%", marginLeft: "54px" }}>
|
<div style={{width: '100%', marginLeft: '54px'}}>
|
||||||
<StepType value={this.props.step.type} index={index} />
|
<StepType value={this.props.step.type} index={index} />
|
||||||
<Textfield
|
<Textfield value={this.props.step.headline} property={'headline'} label={'Überschrift'} index={index} error={this.props.error.steps[index].headline} errorText={`Gib eine Überschrift für die ${this.props.step.type === 'task' ? 'Aufgabe' : 'Anleitung'} ein.`} />
|
||||||
value={this.props.step.headline}
|
<Textfield value={this.props.step.text} property={'text'} label={this.props.step.type === 'task' ? 'Aufgabenstellung' : 'Instruktionen'} index={index} multiline error={this.props.error.steps[index].text} errorText={`Gib Instruktionen für die ${this.props.step.type === 'task' ? 'Aufgabe' : 'Anleitung'} ein.`}/>
|
||||||
property={"headline"}
|
{index === 0 ?
|
||||||
label={"Überschrift"}
|
|
||||||
index={index}
|
|
||||||
error={this.props.error.steps[index].headline}
|
|
||||||
errorText={`Gib eine Überschrift für die ${
|
|
||||||
this.props.step.type === "task" ? "Aufgabe" : "Anleitung"
|
|
||||||
} ein.`}
|
|
||||||
/>
|
|
||||||
<MarkdownEditor
|
|
||||||
value={this.props.step.text}
|
|
||||||
property={"text"}
|
|
||||||
label={
|
|
||||||
this.props.step.type === "task"
|
|
||||||
? "Aufgabenstellung"
|
|
||||||
: "Instruktionen"
|
|
||||||
}
|
|
||||||
index={index}
|
|
||||||
multiline
|
|
||||||
error={this.props.error.steps[index].text}
|
|
||||||
errorText={`Gib Instruktionen für die ${
|
|
||||||
this.props.step.type === "task" ? "Aufgabe" : "Anleitung"
|
|
||||||
} ein.`}
|
|
||||||
/>
|
|
||||||
{index === 0 ? (
|
|
||||||
<div>
|
<div>
|
||||||
<Requirements
|
<Requirements value={this.props.step.requirements ? this.props.step.requirements : []} index={index}/>
|
||||||
value={
|
<Hardware value={this.props.step.hardware ? this.props.step.hardware : []} index={index} error={this.props.error.steps[index].hardware}/>
|
||||||
this.props.step.requirements
|
|
||||||
? this.props.step.requirements
|
|
||||||
: []
|
|
||||||
}
|
|
||||||
index={index}
|
|
||||||
/>
|
|
||||||
<Hardware
|
|
||||||
value={
|
|
||||||
this.props.step.hardware ? this.props.step.hardware : []
|
|
||||||
}
|
|
||||||
index={index}
|
|
||||||
error={this.props.error.steps[index].hardware}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
: null}
|
||||||
<BlocklyExample
|
{this.props.step.type === 'instruction' ?
|
||||||
value={this.props.step.xml}
|
<Media value={this.props.step.media} picture={this.props.step.media && this.props.step.media.picture} youtube={this.props.step.media && this.props.step.media.youtube} url={this.props.step.url} index={index} error={this.props.error.steps[index].media} />
|
||||||
index={index}
|
: null}
|
||||||
task={this.props.step.type === "task"}
|
<BlocklyExample value={this.props.step.xml} index={index} task={this.props.step.type === 'task'} error={this.props.error.steps[index].xml ? true : false}/>
|
||||||
error={this.props.error.steps[index].xml ? true : false}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Step.propTypes = {
|
Step.propTypes = {
|
||||||
@@ -200,14 +124,10 @@ Step.propTypes = {
|
|||||||
error: PropTypes.object.isRequired,
|
error: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = state => ({
|
||||||
steps: state.builder.steps,
|
steps: state.builder.steps,
|
||||||
change: state.builder.change,
|
change: state.builder.change,
|
||||||
error: state.builder.error,
|
error: state.builder.error
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, {
|
export default connect(mapStateToProps, { addStep, removeStep, changeStepIndex })(withStyles(styles, {withTheme: true})(Step));
|
||||||
addStep,
|
|
||||||
removeStep,
|
|
||||||
changeStepIndex,
|
|
||||||
})(withStyles(styles, { withTheme: true })(Step));
|
|
||||||
|
|||||||
@@ -31,6 +31,14 @@ const styles = (theme) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
class Textfield extends Component {
|
class Textfield extends Component {
|
||||||
|
componentDidMount() {
|
||||||
|
if (this.props.error) {
|
||||||
|
if (this.props.property !== "media") {
|
||||||
|
this.props.deleteError(this.props.index, this.props.property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleChange = (e) => {
|
handleChange = (e) => {
|
||||||
var value = e.target.value;
|
var value = e.target.value;
|
||||||
if (this.props.property === "title") {
|
if (this.props.property === "title") {
|
||||||
|
|||||||
@@ -1,45 +1,47 @@
|
|||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
import Dialog from "../Dialog";
|
import Dialog from '../Dialog';
|
||||||
|
|
||||||
import hardware from "../../data/hardware.json";
|
import hardware from '../../data/hardware.json';
|
||||||
|
|
||||||
import { withStyles } from "@material-ui/core/styles";
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import withWidth, { isWidthDown } from "@material-ui/core/withWidth";
|
import withWidth, { isWidthDown } from '@material-ui/core/withWidth';
|
||||||
import Link from "@material-ui/core/Link";
|
import Link from '@material-ui/core/Link';
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from '@material-ui/core/Typography';
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
import IconButton from '@material-ui/core/IconButton';
|
||||||
import ImageList from "@material-ui/core/ImageList";
|
import GridList from '@material-ui/core/GridList';
|
||||||
import ImageListItem from "@material-ui/core/ImageListItem";
|
import GridListTile from '@material-ui/core/GridListTile';
|
||||||
import ImageListItemBar from "@material-ui/core/ImageListItemBar";
|
import GridListTileBar from '@material-ui/core/GridListTileBar';
|
||||||
|
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { faExpandAlt } from "@fortawesome/free-solid-svg-icons";
|
import { faExpandAlt } from "@fortawesome/free-solid-svg-icons";
|
||||||
import * as Blockly from "blockly";
|
import * as Blockly from 'blockly'
|
||||||
const styles = (theme) => ({
|
const styles = theme => ({
|
||||||
expand: {
|
expand: {
|
||||||
"&:hover": {
|
'&:hover': {
|
||||||
color: theme.palette.primary.main,
|
color: theme.palette.primary.main,
|
||||||
},
|
},
|
||||||
"&:active": {
|
'&:active': {
|
||||||
color: theme.palette.primary.main,
|
color: theme.palette.primary.main,
|
||||||
},
|
},
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary
|
||||||
},
|
},
|
||||||
multiImageListItem: {
|
multiGridListTile: {
|
||||||
background: theme.palette.primary.main,
|
background: theme.palette.primary.main,
|
||||||
opacity: 0.9,
|
opacity: 0.9,
|
||||||
height: "30px",
|
height: '30px'
|
||||||
},
|
|
||||||
multiImageListItemTitle: {
|
|
||||||
color: theme.palette.text.primary,
|
|
||||||
},
|
},
|
||||||
|
multiGridListTileTitle: {
|
||||||
|
color: theme.palette.text.primary
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
class Hardware extends Component {
|
class Hardware extends Component {
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
open: false,
|
open: false,
|
||||||
hardwareInfo: {},
|
hardwareInfo: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleClickOpen = (hardwareInfo) => {
|
handleClickOpen = (hardwareInfo) => {
|
||||||
@@ -51,57 +53,36 @@ class Hardware extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var cols = isWidthDown("md", this.props.width)
|
var cols = isWidthDown('md', this.props.width) ? isWidthDown('sm', this.props.width) ? isWidthDown('xs', this.props.width) ? 2 : 3 : 4 : 6;
|
||||||
? isWidthDown("sm", this.props.width)
|
|
||||||
? isWidthDown("xs", this.props.width)
|
|
||||||
? 2
|
|
||||||
: 3
|
|
||||||
: 4
|
|
||||||
: 6;
|
|
||||||
return (
|
return (
|
||||||
<div style={{ marginTop: "10px", marginBottom: "5px" }}>
|
<div style={{ marginTop: '10px', marginBottom: '5px' }}>
|
||||||
<Typography>{Blockly.Msg.tutorials_hardware_head}</Typography>
|
<Typography>{Blockly.Msg.tutorials_hardware_head}</Typography>
|
||||||
|
|
||||||
<ImageList rowHeight={100} cols={cols} gap={10}>
|
<GridList cellHeight={100} cols={cols} spacing={10}>
|
||||||
{this.props.picture.map((picture, i) => {
|
{this.props.picture.map((picture, i) => {
|
||||||
var hardwareInfo = hardware.filter(
|
var hardwareInfo = hardware.filter(hardware => hardware.id === picture)[0];
|
||||||
(hardware) => hardware.id === picture
|
|
||||||
)[0];
|
|
||||||
return (
|
return (
|
||||||
<ImageListItem key={i}>
|
<GridListTile key={i}>
|
||||||
<div style={{ margin: "auto", width: "max-content" }}>
|
<div style={{ margin: 'auto', width: 'max-content' }}>
|
||||||
<img
|
<img src={`/media/hardware/${hardwareInfo.src}`} alt={hardwareInfo.name} height={100} style={{ cursor: 'pointer' }} onClick={() => this.handleClickOpen(hardwareInfo)} />
|
||||||
src={`/media/hardware/${hardwareInfo.src}`}
|
|
||||||
alt={hardwareInfo.name}
|
|
||||||
height={100}
|
|
||||||
style={{ cursor: "pointer" }}
|
|
||||||
onClick={() => this.handleClickOpen(hardwareInfo)}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<ImageListItemBar
|
<GridListTileBar
|
||||||
classes={{ root: this.props.classes.multiImageListItem }}
|
classes={{ root: this.props.classes.multiGridListTile }}
|
||||||
title={
|
title={
|
||||||
<div
|
<div style={{ overflow: 'hidden', textOverflow: 'ellipsis' }} className={this.props.classes.multiGridListTileTitle}>
|
||||||
style={{ overflow: "hidden", textOverflow: "ellipsis" }}
|
|
||||||
className={this.props.classes.multiImageListItemTitle}
|
|
||||||
>
|
|
||||||
{hardwareInfo.name}
|
{hardwareInfo.name}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
actionIcon={
|
actionIcon={
|
||||||
<IconButton
|
<IconButton className={this.props.classes.expand} aria-label='Vollbild' onClick={() => this.handleClickOpen(hardwareInfo)}>
|
||||||
className={this.props.classes.expand}
|
|
||||||
aria-label="Vollbild"
|
|
||||||
onClick={() => this.handleClickOpen(hardwareInfo)}
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon icon={faExpandAlt} size="xs" />
|
<FontAwesomeIcon icon={faExpandAlt} size="xs" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</ImageListItem>
|
</GridListTile>
|
||||||
);
|
)
|
||||||
})}
|
})}
|
||||||
</ImageList>
|
</GridList>
|
||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
style={{ zIndex: 1500 }}
|
style={{ zIndex: 1500 }}
|
||||||
@@ -113,26 +94,14 @@ class Hardware extends Component {
|
|||||||
button={Blockly.Msg.button_close}
|
button={Blockly.Msg.button_close}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<img
|
<img src={`/media/hardware/${this.state.hardwareInfo.src}`} width="100%" alt={this.state.hardwareInfo.name} />
|
||||||
src={`/media/hardware/${this.state.hardwareInfo.src}`}
|
{Blockly.Msg.tutorials_hardware_moreInformation} <Link rel="noreferrer" target="_blank" href={this.state.hardwareInfo.url} color="primary">{Blockly.Msg.tutorials_hardware_here}</Link>.
|
||||||
width="100%"
|
|
||||||
alt={this.state.hardwareInfo.name}
|
|
||||||
/>
|
|
||||||
{Blockly.Msg.tutorials_hardware_moreInformation}{" "}
|
|
||||||
<Link
|
|
||||||
rel="noreferrer"
|
|
||||||
target="_blank"
|
|
||||||
href={this.state.hardwareInfo.url}
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
{Blockly.Msg.tutorials_hardware_here}
|
|
||||||
</Link>
|
|
||||||
.
|
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withWidth()(withStyles(styles, { withTheme: true })(Hardware));
|
export default withWidth()(withStyles(styles, { withTheme: true })(Hardware));
|
||||||
|
|||||||
@@ -1,79 +1,75 @@
|
|||||||
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 Dialog from "../Dialog";
|
import Dialog from '../Dialog';
|
||||||
|
|
||||||
import { withStyles } from "@material-ui/core/styles";
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import Checkbox from "@material-ui/core/Checkbox";
|
import Checkbox from '@material-ui/core/Checkbox';
|
||||||
import FormControlLabel from "@material-ui/core/FormControlLabel";
|
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
||||||
import * as Blockly from "blockly";
|
import * as Blockly from 'blockly'
|
||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from 'react-markdown';
|
||||||
|
|
||||||
const styles = (theme) => ({
|
const styles = (theme) => ({
|
||||||
link: {
|
link: {
|
||||||
color: theme.palette.primary.main,
|
color: theme.palette.primary.main,
|
||||||
textDecoration: "none",
|
textDecoration: 'none',
|
||||||
"&:hover": {
|
'&:hover': {
|
||||||
color: theme.palette.primary.main,
|
color: theme.palette.primary.main,
|
||||||
textDecoration: `underline`,
|
textDecoration: `underline`
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
fontSize: "0.9rem",
|
fontSize: '0.9rem',
|
||||||
color: "grey",
|
color: 'grey'
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
class HintTutorialExists extends Component {
|
class HintTutorialExists extends Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
var previousPageWasAnotherDomain = props.pageVisits === 0;
|
var previousPageWasAnotherDomain = props.pageVisits === 0;
|
||||||
var userDoNotWantToSeeNews = window.localStorage.getItem("news")
|
var userDoNotWantToSeeNews = window.localStorage.getItem('news') ? true : false;
|
||||||
? true
|
|
||||||
: false;
|
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
open: userDoNotWantToSeeNews
|
open: userDoNotWantToSeeNews ? !userDoNotWantToSeeNews : previousPageWasAnotherDomain
|
||||||
? !userDoNotWantToSeeNews
|
|
||||||
: previousPageWasAnotherDomain,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleDialog = () => {
|
toggleDialog = () => {
|
||||||
this.setState({ open: !this.state });
|
this.setState({ open: !this.state });
|
||||||
};
|
}
|
||||||
|
|
||||||
onChange = (e) => {
|
onChange = (e) => {
|
||||||
if (e.target.checked) {
|
if (e.target.checked) {
|
||||||
window.localStorage.setItem("news", e.target.checked);
|
window.localStorage.setItem('news', e.target.checked);
|
||||||
} else {
|
}
|
||||||
window.localStorage.removeItem("news");
|
else {
|
||||||
|
window.localStorage.removeItem('news');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
style={{ zIndex: 9999999 }}
|
style={{ zIndex: 9999999 }}
|
||||||
fullWidth
|
fullWidth
|
||||||
maxWidth={"sm"}
|
maxWidth={'sm'}
|
||||||
open={this.state.open}
|
open={this.state.open}
|
||||||
title={Blockly.Msg.messages_newblockly_head}
|
title={Blockly.Msg.messages_newblockly_head}
|
||||||
content={""}
|
content={''}
|
||||||
onClose={this.toggleDialog}
|
onClose={this.toggleDialog}
|
||||||
onClick={this.toggleDialog}
|
onClick={this.toggleDialog}
|
||||||
button={Blockly.Msg.button_close}
|
button={Blockly.Msg.button_close}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<ReactMarkdown linkTarget="_blank">
|
<ReactMarkdown linkTarget="_blank">{Blockly.Msg.messages_newblockly_text}</ReactMarkdown>
|
||||||
{Blockly.Msg.messages_newblockly_text}
|
|
||||||
</ReactMarkdown>
|
|
||||||
</div>
|
</div>
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
style={{ marginTop: "20px" }}
|
style={{ marginTop: '20px' }}
|
||||||
classes={{ label: this.props.classes.label }}
|
classes={{ label: this.props.classes.label }}
|
||||||
control={
|
control={
|
||||||
<Checkbox
|
<Checkbox
|
||||||
size={"small"}
|
size={'small'}
|
||||||
value={true}
|
value={true}
|
||||||
checked={this.state.checked}
|
checked={this.state.checked}
|
||||||
onChange={(e) => this.onChange(e)}
|
onChange={(e) => this.onChange(e)}
|
||||||
@@ -85,18 +81,15 @@ class HintTutorialExists extends Component {
|
|||||||
/>
|
/>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
HintTutorialExists.propTypes = {
|
HintTutorialExists.propTypes = {
|
||||||
pageVisits: PropTypes.number.isRequired,
|
pageVisits: PropTypes.number.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = state => ({
|
||||||
pageVisits: state.general.pageVisits,
|
pageVisits: state.general.pageVisits
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(
|
export default connect(mapStateToProps, null)(withStyles(styles, { withTheme: true })(HintTutorialExists));
|
||||||
mapStateToProps,
|
|
||||||
null
|
|
||||||
)(withStyles(styles, { withTheme: true })(HintTutorialExists));
|
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ import BlocklyWindow from "../Blockly/BlocklyWindow";
|
|||||||
import Grid from "@material-ui/core/Grid";
|
import Grid from "@material-ui/core/Grid";
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from "react-markdown";
|
||||||
import remarkGfm from "remark-gfm";
|
|
||||||
import remarkGemoji from "remark-gemoji";
|
|
||||||
|
|
||||||
class Instruction extends Component {
|
class Instruction extends Component {
|
||||||
render() {
|
render() {
|
||||||
@@ -17,13 +15,14 @@ class Instruction extends Component {
|
|||||||
var areRequirements = step.requirements && step.requirements.length > 0;
|
var areRequirements = step.requirements && step.requirements.length > 0;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
<Typography variant="h4" style={{ marginBottom: "5px" }}>
|
||||||
|
{step.headline}
|
||||||
|
</Typography>
|
||||||
<Typography style={isHardware ? {} : { marginBottom: "5px" }}>
|
<Typography style={isHardware ? {} : { marginBottom: "5px" }}>
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
className={"tutorial"}
|
className={"tutorial"}
|
||||||
linkTarget={"_blank"}
|
linkTarget={"_blank"}
|
||||||
skipHtml={false}
|
skipHtml={false}
|
||||||
allowDangerousHtml={true}
|
|
||||||
remarkPlugins={[remarkGfm, remarkGemoji]}
|
|
||||||
>
|
>
|
||||||
{step.text}
|
{step.text}
|
||||||
</ReactMarkdown>
|
</ReactMarkdown>
|
||||||
|
|||||||
@@ -1,233 +1,124 @@
|
|||||||
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 clsx from "clsx";
|
import clsx from 'clsx';
|
||||||
import { withRouter, Link } from "react-router-dom";
|
import { withRouter, Link } from 'react-router-dom';
|
||||||
import { alpha } from "@material-ui/core/styles";
|
|
||||||
import { withStyles } from "@material-ui/core/styles";
|
import { fade } from '@material-ui/core/styles/colorManipulator';
|
||||||
import Typography from "@material-ui/core/Typography";
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import List from "@material-ui/core/List";
|
import Typography from '@material-ui/core/Typography';
|
||||||
import Tooltip from "@material-ui/core/Tooltip";
|
import List from '@material-ui/core/List';
|
||||||
|
import Tooltip from '@material-ui/core/Tooltip';
|
||||||
|
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { faCheck, faTimes } from "@fortawesome/free-solid-svg-icons";
|
import { faCheck, faTimes } from "@fortawesome/free-solid-svg-icons";
|
||||||
import * as Blockly from "blockly";
|
import * as Blockly from 'blockly'
|
||||||
|
|
||||||
const styles = (theme) => ({
|
const styles = theme => ({
|
||||||
outerDiv: {
|
outerDiv: {
|
||||||
width: "50px",
|
width: '50px',
|
||||||
height: "50px",
|
height: '50px',
|
||||||
position: "absolute",
|
position: 'absolute',
|
||||||
color: alpha(theme.palette.secondary.main, 0.6),
|
color: fade(theme.palette.secondary.main, 0.6)
|
||||||
},
|
},
|
||||||
outerDivError: {
|
outerDivError: {
|
||||||
stroke: alpha(theme.palette.error.dark, 0.6),
|
stroke: fade(theme.palette.error.dark, 0.6),
|
||||||
color: alpha(theme.palette.error.dark, 0.6),
|
color: fade(theme.palette.error.dark, 0.6)
|
||||||
},
|
},
|
||||||
outerDivSuccess: {
|
outerDivSuccess: {
|
||||||
stroke: alpha(theme.palette.primary.main, 0.6),
|
stroke: fade(theme.palette.primary.main, 0.6),
|
||||||
color: alpha(theme.palette.primary.main, 0.6),
|
color: fade(theme.palette.primary.main, 0.6)
|
||||||
},
|
},
|
||||||
outerDivOther: {
|
outerDivOther: {
|
||||||
stroke: alpha(theme.palette.secondary.main, 0.6),
|
stroke: fade(theme.palette.secondary.main, 0.6)
|
||||||
},
|
},
|
||||||
innerDiv: {
|
innerDiv: {
|
||||||
width: "inherit",
|
width: 'inherit',
|
||||||
height: "inherit",
|
height: 'inherit',
|
||||||
display: "table-cell",
|
display: 'table-cell',
|
||||||
verticalAlign: "middle",
|
verticalAlign: 'middle',
|
||||||
textAlign: "center",
|
textAlign: 'center'
|
||||||
},
|
},
|
||||||
link: {
|
link: {
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
position: "relative",
|
position: 'relative',
|
||||||
height: "50px",
|
height: '50px',
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
margin: "5px 0 5px 10px",
|
margin: '5px 0 5px 10px',
|
||||||
textDecoration: "none",
|
textDecoration: 'none'
|
||||||
},
|
},
|
||||||
hoverLink: {
|
hoverLink: {
|
||||||
"&:hover": {
|
'&:hover': {
|
||||||
background: alpha(theme.palette.secondary.main, 0.5),
|
background: fade(theme.palette.secondary.main, 0.5),
|
||||||
borderRadius: "0 25px 25px 0 ",
|
borderRadius: '0 25px 25px 0 '
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
class Requirement extends Component {
|
class Requirement extends Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var requirements = this.props.requirements;
|
var requirements = this.props.requirements;
|
||||||
var tutorialIds = requirements.map((requirement) => requirement._id);
|
var tutorialIds = requirements.map(requirement => requirement._id);
|
||||||
return (
|
return (
|
||||||
<div style={{ marginTop: "20px", marginBottom: "5px" }}>
|
<div style={{ marginTop: '20px', marginBottom: '5px' }}>
|
||||||
<Typography>{Blockly.Msg.tutorials_requirements}</Typography>
|
<Typography>{Blockly.Msg.tutorials_requirements}</Typography>
|
||||||
<List component="div">
|
<List component="div">
|
||||||
{tutorialIds.map((tutorialId, i) => {
|
{tutorialIds.map((tutorialId, i) => {
|
||||||
var title = requirements[i].title;
|
var title = requirements[i].title
|
||||||
var status = this.props.status.filter(
|
var status = this.props.status.filter(status => status._id === tutorialId)[0];
|
||||||
(status) => status._id === tutorialId
|
|
||||||
)[0];
|
|
||||||
var tasks = status.tasks;
|
var tasks = status.tasks;
|
||||||
var error =
|
var error = status.tasks.filter(task => task.type === 'error').length > 0;
|
||||||
status.tasks.filter((task) => task.type === "error").length > 0;
|
var success = status.tasks.filter(task => task.type === 'success').length / tasks.length
|
||||||
var success =
|
var tutorialStatus = success === 1 ? 'Success' : error ? 'Error' : 'Other';
|
||||||
status.tasks.filter((task) => task.type === "success").length /
|
|
||||||
tasks.length;
|
|
||||||
var tutorialStatus =
|
|
||||||
success === 1 ? "Success" : error ? "Error" : "Other";
|
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link to={`/tutorial/${tutorialId}`} className={this.props.classes.link} key={i}>
|
||||||
target={"_blank"}
|
<Tooltip style={{ height: '50px', width: '50px', position: 'absolute', background: 'white', zIndex: 1, borderRadius: '25px' }} title={error ? `Mind. eine Aufgabe im Tutorial wurde nicht richtig gelöst.` : success === 1 ? `Das Tutorial wurde bereits erfolgreich abgeschlossen.` : `Das Tutorial ist zu ${success * 100}% abgeschlossen.`} arrow>
|
||||||
to={`/tutorial/${tutorialId}`}
|
|
||||||
className={this.props.classes.link}
|
|
||||||
key={i}
|
|
||||||
>
|
|
||||||
<Tooltip
|
|
||||||
style={{
|
|
||||||
height: "50px",
|
|
||||||
width: "50px",
|
|
||||||
position: "absolute",
|
|
||||||
background: "white",
|
|
||||||
zIndex: 1,
|
|
||||||
borderRadius: "25px",
|
|
||||||
}}
|
|
||||||
title={
|
|
||||||
error
|
|
||||||
? `Mind. eine Aufgabe im Tutorial wurde nicht richtig gelöst.`
|
|
||||||
: success === 1
|
|
||||||
? `Das Tutorial wurde bereits erfolgreich abgeschlossen.`
|
|
||||||
: `Das Tutorial ist zu ${success * 100}% abgeschlossen.`
|
|
||||||
}
|
|
||||||
arrow
|
|
||||||
>
|
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div className={clsx(this.props.classes.outerDiv)} style={{ width: '50px', height: '50px', border: 0 }}>
|
||||||
className={clsx(this.props.classes.outerDiv)}
|
<svg style={{ width: '100%', height: '100%' }}>
|
||||||
style={{ width: "50px", height: "50px", border: 0 }}
|
{error || success === 1 ?
|
||||||
>
|
<circle className={error ? this.props.classes.outerDivError : this.props.classes.outerDivSuccess} r="22.5" cx="50%" cy="50%" fill="none" strokeWidth="5"></circle>
|
||||||
<svg style={{ width: "100%", height: "100%" }}>
|
: <circle className={this.props.classes.outerDivOther} r="22.5" cx="50%" cy="50%" fill="none" strokeWidth="5"></circle>}
|
||||||
{error || success === 1 ? (
|
{success < 1 && !error ?
|
||||||
<circle
|
<circle className={this.props.classes.outerDivSuccess} style={{ transform: 'rotate(-90deg)', transformOrigin: "50% 50%" }} r="22.5" cx="50%" cy="50%" fill="none" strokeWidth="5" strokeDashoffset={`${(22.5 * 2 * Math.PI) * (1 - success)}`} strokeDasharray={`${(22.5 * 2 * Math.PI)}`}>
|
||||||
className={
|
</circle>
|
||||||
error
|
: null}
|
||||||
? this.props.classes.outerDivError
|
|
||||||
: this.props.classes.outerDivSuccess
|
|
||||||
}
|
|
||||||
r="22.5"
|
|
||||||
cx="50%"
|
|
||||||
cy="50%"
|
|
||||||
fill="none"
|
|
||||||
strokeWidth="5"
|
|
||||||
></circle>
|
|
||||||
) : (
|
|
||||||
<circle
|
|
||||||
className={this.props.classes.outerDivOther}
|
|
||||||
r="22.5"
|
|
||||||
cx="50%"
|
|
||||||
cy="50%"
|
|
||||||
fill="none"
|
|
||||||
strokeWidth="5"
|
|
||||||
></circle>
|
|
||||||
)}
|
|
||||||
{success < 1 && !error ? (
|
|
||||||
<circle
|
|
||||||
className={this.props.classes.outerDivSuccess}
|
|
||||||
style={{
|
|
||||||
transform: "rotate(-90deg)",
|
|
||||||
transformOrigin: "50% 50%",
|
|
||||||
}}
|
|
||||||
r="22.5"
|
|
||||||
cx="50%"
|
|
||||||
cy="50%"
|
|
||||||
fill="none"
|
|
||||||
strokeWidth="5"
|
|
||||||
strokeDashoffset={`${
|
|
||||||
22.5 * 2 * Math.PI * (1 - success)
|
|
||||||
}`}
|
|
||||||
strokeDasharray={`${22.5 * 2 * Math.PI}`}
|
|
||||||
></circle>
|
|
||||||
) : null}
|
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className={clsx(this.props.classes.outerDiv, tutorialStatus === 'Error' ? this.props.classes.outerDivError : tutorialStatus === 'Success' ? this.props.classes.outerDivSuccess : null)}>
|
||||||
className={clsx(
|
|
||||||
this.props.classes.outerDiv,
|
|
||||||
tutorialStatus === "Error"
|
|
||||||
? this.props.classes.outerDivError
|
|
||||||
: tutorialStatus === "Success"
|
|
||||||
? this.props.classes.outerDivSuccess
|
|
||||||
: null
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className={this.props.classes.innerDiv}>
|
<div className={this.props.classes.innerDiv}>
|
||||||
{error || success === 1 ? (
|
{error || success === 1 ?
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon icon={tutorialStatus === 'Success' ? faCheck : faTimes} />
|
||||||
icon={
|
: <Typography variant='h7' className={success > 0 ? this.props.classes.outerDivSuccess : {}}>{Math.round(success * 100)}%</Typography>
|
||||||
tutorialStatus === "Success" ? faCheck : faTimes
|
|
||||||
}
|
}
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Typography
|
|
||||||
variant="h7"
|
|
||||||
className={
|
|
||||||
success > 0
|
|
||||||
? this.props.classes.outerDivSuccess
|
|
||||||
: {}
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{Math.round(success * 100)}%
|
|
||||||
</Typography>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<div
|
<div style={{ height: '50px', width: 'calc(100% - 25px)', transform: 'translate(25px)' }} className={this.props.classes.hoverLink}>
|
||||||
style={{
|
<Typography style={{ margin: 0, position: 'absolute', top: '50%', transform: 'translate(45px, -50%)', maxHeight: '50px', overflow: 'hidden', maxWidth: 'calc(100% - 45px)', textOverflow: 'ellipsis', whiteSpace: 'pre-line', overflowWrap: 'anywhere' }}>{title}</Typography>
|
||||||
height: "50px",
|
|
||||||
width: "calc(100% - 25px)",
|
|
||||||
transform: "translate(25px)",
|
|
||||||
}}
|
|
||||||
className={this.props.classes.hoverLink}
|
|
||||||
>
|
|
||||||
<Typography
|
|
||||||
style={{
|
|
||||||
margin: 0,
|
|
||||||
position: "absolute",
|
|
||||||
top: "50%",
|
|
||||||
transform: "translate(45px, -50%)",
|
|
||||||
maxHeight: "50px",
|
|
||||||
overflow: "hidden",
|
|
||||||
maxWidth: "calc(100% - 45px)",
|
|
||||||
textOverflow: "ellipsis",
|
|
||||||
whiteSpace: "pre-line",
|
|
||||||
overflowWrap: "anywhere",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{title}
|
|
||||||
</Typography>
|
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
);
|
)
|
||||||
})}
|
}
|
||||||
|
)}
|
||||||
</List>
|
</List>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Requirement.propTypes = {
|
Requirement.propTypes = {
|
||||||
status: PropTypes.array.isRequired,
|
status: PropTypes.array.isRequired,
|
||||||
change: PropTypes.number.isRequired,
|
change: PropTypes.number.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = state => ({
|
||||||
change: state.tutorial.change,
|
change: state.tutorial.change,
|
||||||
status: state.tutorial.status,
|
status: state.tutorial.status,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(
|
export default connect(mapStateToProps, null)(withStyles(styles, { withTheme: true })(withRouter(Requirement)));
|
||||||
mapStateToProps,
|
|
||||||
null
|
|
||||||
)(withStyles(styles, { withTheme: true })(withRouter(Requirement)));
|
|
||||||
|
|||||||
@@ -1,49 +1,51 @@
|
|||||||
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 { tutorialCheck, tutorialStep } from "../../actions/tutorialActions";
|
import { tutorialCheck, tutorialStep } from '../../actions/tutorialActions';
|
||||||
|
|
||||||
import { withRouter } from "react-router-dom";
|
import { withRouter } from 'react-router-dom';
|
||||||
|
|
||||||
import Compile from "../Workspace/Compile";
|
import Compile from '../Workspace/Compile';
|
||||||
import Dialog from "../Dialog";
|
import Dialog from '../Dialog';
|
||||||
|
|
||||||
import { checkXml } from "../../helpers/compareXml";
|
import { checkXml } from '../../helpers/compareXml';
|
||||||
|
|
||||||
import { withStyles } from "@material-ui/core/styles";
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
import IconButton from '@material-ui/core/IconButton';
|
||||||
import Tooltip from "@material-ui/core/Tooltip";
|
import Tooltip from '@material-ui/core/Tooltip';
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from '@material-ui/core/Button';
|
||||||
|
|
||||||
import { faClipboardCheck } from "@fortawesome/free-solid-svg-icons";
|
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";
|
import * as Blockly from 'blockly'
|
||||||
|
|
||||||
const styles = (theme) => ({
|
const styles = (theme) => ({
|
||||||
compile: {
|
compile: {
|
||||||
backgroundColor: theme.palette.button.compile,
|
backgroundColor: theme.palette.button.compile,
|
||||||
color: theme.palette.primary.contrastText,
|
color: theme.palette.primary.contrastText,
|
||||||
"&:hover": {
|
'&:hover': {
|
||||||
backgroundColor: theme.palette.button.compile,
|
backgroundColor: theme.palette.button.compile,
|
||||||
color: theme.palette.primary.contrastText,
|
color: theme.palette.primary.contrastText,
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
class SolutionCheck extends Component {
|
class SolutionCheck extends Component {
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
open: false,
|
open: false,
|
||||||
msg: "",
|
msg: ''
|
||||||
};
|
}
|
||||||
|
|
||||||
toggleDialog = () => {
|
toggleDialog = () => {
|
||||||
if (this.state.open) {
|
if (this.state.open) {
|
||||||
this.setState({ open: false, msg: "" });
|
this.setState({ open: false, msg: '' });
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
this.setState({ open: !this.state });
|
this.setState({ open: !this.state });
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
check = () => {
|
check = () => {
|
||||||
const tutorial = this.props.tutorial;
|
const tutorial = this.props.tutorial;
|
||||||
@@ -51,7 +53,7 @@ class SolutionCheck extends Component {
|
|||||||
var msg = checkXml(step.xml, this.props.xml);
|
var msg = checkXml(step.xml, this.props.xml);
|
||||||
this.props.tutorialCheck(msg.type, step);
|
this.props.tutorialCheck(msg.type, step);
|
||||||
this.setState({ msg, open: true });
|
this.setState({ msg, open: true });
|
||||||
};
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const steps = this.props.tutorial.steps;
|
const steps = this.props.tutorial.steps;
|
||||||
@@ -60,74 +62,68 @@ class SolutionCheck extends Component {
|
|||||||
<Tooltip title={Blockly.Msg.tooltip_check_solution} arrow>
|
<Tooltip title={Blockly.Msg.tooltip_check_solution} arrow>
|
||||||
<IconButton
|
<IconButton
|
||||||
className={`solutionCheck ${this.props.classes.compile}`}
|
className={`solutionCheck ${this.props.classes.compile}`}
|
||||||
style={{ width: "40px", height: "40px", marginRight: "5px" }}
|
style={{ width: '40px', height: '40px', marginRight: '5px' }}
|
||||||
onClick={() => this.check()}
|
onClick={() => this.check()}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faClipboardCheck} size="xs" />
|
<FontAwesomeIcon icon={faClipboardCheck} size="l" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
style={{ zIndex: 9999999 }}
|
style={{ zIndex: 9999999 }}
|
||||||
fullWidth
|
fullWidth
|
||||||
maxWidth={"sm"}
|
maxWidth={'sm'}
|
||||||
open={this.state.open}
|
open={this.state.open}
|
||||||
title={this.state.msg.type === "error" ? "Fehler" : "Erfolg"}
|
title={this.state.msg.type === 'error' ? 'Fehler' : 'Erfolg'}
|
||||||
content={this.state.msg.text}
|
content={this.state.msg.text}
|
||||||
onClose={this.toggleDialog}
|
onClose={this.toggleDialog}
|
||||||
onClick={this.toggleDialog}
|
onClick={this.toggleDialog}
|
||||||
button={Blockly.Msg.button_close}
|
button={Blockly.Msg.button_close}
|
||||||
>
|
>
|
||||||
{this.state.msg.type === "success" ? (
|
{this.state.msg.type === 'success' ?
|
||||||
<div style={{ marginTop: "20px", display: "flex" }}>
|
<div style={{ marginTop: '20px', display: 'flex' }}>
|
||||||
<Compile />
|
<Compile />
|
||||||
{this.props.activeStep === steps.length - 1 ? (
|
{this.props.activeStep === steps.length - 1 ?
|
||||||
<Button
|
<Button
|
||||||
style={{ marginLeft: "10px" }}
|
style={{ marginLeft: '10px' }}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={() => {
|
onClick={() => { this.toggleDialog(); this.props.history.push(`/tutorial/`) }}
|
||||||
this.toggleDialog();
|
|
||||||
this.props.history.push(`/tutorial/`);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{Blockly.Msg.button_tutorial_overview}
|
{Blockly.Msg.button_tutorial_overview}
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
:
|
||||||
<Button
|
<Button
|
||||||
style={{ marginLeft: "10px" }}
|
style={{ marginLeft: '10px' }}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={() => {
|
onClick={() => { this.toggleDialog(); this.props.tutorialStep(this.props.activeStep + 1) }}
|
||||||
this.toggleDialog();
|
|
||||||
this.props.tutorialStep(this.props.activeStep + 1);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{Blockly.Msg.button_next}
|
{Blockly.Msg.button_next}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
: null}
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SolutionCheck.propTypes = {
|
SolutionCheck.propTypes = {
|
||||||
tutorialCheck: PropTypes.func.isRequired,
|
tutorialCheck: PropTypes.func.isRequired,
|
||||||
tutorialStep: PropTypes.func.isRequired,
|
tutorialStep: PropTypes.func.isRequired,
|
||||||
activeStep: PropTypes.number.isRequired,
|
activeStep: PropTypes.number.isRequired,
|
||||||
xml: PropTypes.string.isRequired,
|
xml: PropTypes.string.isRequired,
|
||||||
tutorial: PropTypes.object.isRequired,
|
tutorial: PropTypes.object.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = state => ({
|
||||||
activeStep: state.tutorial.activeStep,
|
activeStep: state.tutorial.activeStep,
|
||||||
xml: state.workspace.code.xml,
|
xml: state.workspace.code.xml,
|
||||||
tutorial: state.tutorial.tutorials[0],
|
tutorial: state.tutorial.tutorials[0]
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, { tutorialCheck, tutorialStep })(
|
export default connect(mapStateToProps, { tutorialCheck, tutorialStep })(withStyles(styles, { withTheme: true })(withRouter(SolutionCheck)));
|
||||||
withStyles(styles, { withTheme: true })(withRouter(SolutionCheck))
|
|
||||||
);
|
|
||||||
|
|||||||
@@ -1,183 +1,109 @@
|
|||||||
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 { withRouter } from "react-router-dom";
|
import { withRouter } from 'react-router-dom';
|
||||||
|
|
||||||
import clsx from "clsx";
|
import clsx from 'clsx';
|
||||||
|
|
||||||
// import tutorials from '../../data/tutorials';
|
// import tutorials from '../../data/tutorials';
|
||||||
import { alpha } from "@material-ui/core/styles";
|
|
||||||
|
|
||||||
import { withStyles } from "@material-ui/core/styles";
|
import { fade } from '@material-ui/core/styles/colorManipulator';
|
||||||
import Typography from "@material-ui/core/Typography";
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import Tooltip from "@material-ui/core/Tooltip";
|
import Typography from '@material-ui/core/Typography';
|
||||||
import Button from "@material-ui/core/Button";
|
import Tooltip from '@material-ui/core/Tooltip';
|
||||||
|
import Button from '@material-ui/core/Button';
|
||||||
|
|
||||||
import { faCheck, faTimes } from "@fortawesome/free-solid-svg-icons";
|
import { faCheck, faTimes } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
|
||||||
const styles = (theme) => ({
|
const styles = (theme) => ({
|
||||||
stepper: {
|
stepper: {
|
||||||
width: "calc(100% - 40px)",
|
width: 'calc(100% - 40px)',
|
||||||
height: "40px",
|
height: '40px',
|
||||||
borderRadius: "25px",
|
borderRadius: '25px',
|
||||||
padding: "0 20px",
|
padding: '0 20px',
|
||||||
margin: "20px 0",
|
margin: '20px 0',
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
justifyContent: "space-between",
|
justifyContent: 'space-between'
|
||||||
},
|
},
|
||||||
stepperSuccess: {
|
stepperSuccess: {
|
||||||
backgroundColor: alpha(theme.palette.primary.main, 0.6),
|
backgroundColor: fade(theme.palette.primary.main, 0.6),
|
||||||
},
|
},
|
||||||
stepperError: {
|
stepperError: {
|
||||||
backgroundColor: alpha(theme.palette.error.dark, 0.6),
|
backgroundColor: fade(theme.palette.error.dark, 0.6),
|
||||||
},
|
},
|
||||||
stepperOther: {
|
stepperOther: {
|
||||||
backgroundColor: alpha(theme.palette.secondary.main, 0.6),
|
backgroundColor: fade(theme.palette.secondary.main, 0.6),
|
||||||
},
|
},
|
||||||
color: {
|
color: {
|
||||||
backgroundColor: "transparent ",
|
backgroundColor: 'transparent '
|
||||||
},
|
},
|
||||||
iconDivSuccess: {
|
iconDivSuccess: {
|
||||||
color: theme.palette.primary.main,
|
color: theme.palette.primary.main
|
||||||
},
|
},
|
||||||
iconDivError: {
|
iconDivError: {
|
||||||
color: theme.palette.error.dark,
|
color: theme.palette.error.dark
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
class StepperHorizontal extends Component {
|
class StepperHorizontal extends Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var tutorialId = this.props.tutorial._id;
|
var tutorialId = this.props.tutorial._id;
|
||||||
var status = this.props.status.filter(
|
var status = this.props.status.filter(status => status._id === tutorialId)[0];
|
||||||
(status) => status._id === tutorialId
|
|
||||||
)[0];
|
|
||||||
var tasks = status.tasks;
|
var tasks = status.tasks;
|
||||||
var error = tasks.filter((task) => task.type === "error").length > 0;
|
var error = tasks.filter(task => task.type === 'error').length > 0;
|
||||||
var success =
|
var success = tasks.filter(task => task.type === 'success').length / tasks.length;
|
||||||
tasks.filter((task) => task.type === "success").length / tasks.length;
|
var tutorialStatus = success === 1 ? 'Success' : error ? 'Error' : 'Other';
|
||||||
var tutorialStatus = success === 1 ? "Success" : error ? "Error" : "Other";
|
|
||||||
var title = this.props.tutorial.title;
|
var title = this.props.tutorial.title;
|
||||||
var activeStep = this.props.activeStep;
|
|
||||||
return (
|
return (
|
||||||
<div style={{ position: "relative" }}>
|
<div style={{ position: 'relative' }}>
|
||||||
{error || success > 0 ? (
|
{error || success > 0 ?
|
||||||
<div
|
<div style={{ zIndex: -1, width: error ? 'calc(100% - 40px)' : `calc(${success * 100}% - 40px)`, borderRadius: success === 1 || error ? '25px' : '25px 0 0 25px', position: 'absolute', margin: 0, left: 0 }} className={clsx(this.props.classes.stepper, error ? this.props.classes.stepperError : this.props.classes.stepperSuccess)}>
|
||||||
style={{
|
</div>
|
||||||
zIndex: -1,
|
: null}
|
||||||
width: error
|
{success < 1 && !error ?
|
||||||
? "calc(100% - 40px)"
|
<div style={{ zIndex: -2, width: `calc(${(1 - success) * 100}% - 40px)`, borderRadius: success === 0 ? '25px' : '0px 25px 25px 0', position: 'absolute', margin: 0, right: 0 }} className={clsx(this.props.classes.stepper, this.props.classes.stepperOther)}>
|
||||||
: `calc(${success * 100}% - 40px)`,
|
</div>
|
||||||
borderRadius: success === 1 || error ? "25px" : "25px 0 0 25px",
|
: null}
|
||||||
position: "absolute",
|
|
||||||
margin: 0,
|
|
||||||
left: 0,
|
|
||||||
}}
|
|
||||||
className={clsx(
|
|
||||||
this.props.classes.stepper,
|
|
||||||
error
|
|
||||||
? this.props.classes.stepperError
|
|
||||||
: this.props.classes.stepperSuccess
|
|
||||||
)}
|
|
||||||
></div>
|
|
||||||
) : null}
|
|
||||||
{success < 1 && !error ? (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
zIndex: -2,
|
|
||||||
width: `calc(${(1 - success) * 100}% - 40px)`,
|
|
||||||
borderRadius: success === 0 ? "25px" : "0px 25px 25px 0",
|
|
||||||
position: "absolute",
|
|
||||||
margin: 0,
|
|
||||||
right: 0,
|
|
||||||
}}
|
|
||||||
className={clsx(
|
|
||||||
this.props.classes.stepper,
|
|
||||||
this.props.classes.stepperOther
|
|
||||||
)}
|
|
||||||
></div>
|
|
||||||
) : null}
|
|
||||||
<div className={this.props.classes.stepper}>
|
<div className={this.props.classes.stepper}>
|
||||||
<Button
|
<Button
|
||||||
disabled //={tutorialIndex === 0}
|
disabled//={tutorialIndex === 0}
|
||||||
//onClick={() => { this.props.history.push(`/tutorial/${tutorials[tutorialIndex - 1].id}`) }}
|
//onClick={() => { this.props.history.push(`/tutorial/${tutorials[tutorialIndex - 1].id}`) }}
|
||||||
>
|
>
|
||||||
{"<"}
|
{'<'}
|
||||||
</Button>
|
</Button>
|
||||||
<Tooltip
|
<Tooltip style={{ display: 'flex', width: 'calc(100% - 64px - 64px)', justifyContent: 'center' }} title={title} arrow>
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
width: "calc(100% - 64px - 64px)",
|
|
||||||
justifyContent: "center",
|
|
||||||
}}
|
|
||||||
title={title}
|
|
||||||
arrow
|
|
||||||
>
|
|
||||||
<div>
|
<div>
|
||||||
{tutorialStatus !== "Other" ? (
|
{tutorialStatus !== 'Other' ? <div className={tutorialStatus === 'Success' && success === 1 ? this.props.classes.iconDivSuccess : this.props.classes.iconDivError} style={{ margin: 'auto 10px auto 0' }}><FontAwesomeIcon className={this.props.classes.icon} icon={tutorialStatus === 'Success' ? faCheck : faTimes} /></div> : null}
|
||||||
<div
|
<Typography variant='body2' style={{ fontWeight: 'bold', fontSize: '1.75em', margin: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', color: 'rgba(0, 0, 0, 0.54)' }}>{title}</Typography>
|
||||||
className={
|
|
||||||
tutorialStatus === "Success" && success === 1
|
|
||||||
? this.props.classes.iconDivSuccess
|
|
||||||
: this.props.classes.iconDivError
|
|
||||||
}
|
|
||||||
style={{ margin: "auto 10px auto 0" }}
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className={this.props.classes.icon}
|
|
||||||
icon={tutorialStatus === "Success" ? faCheck : faTimes}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
<Typography
|
|
||||||
variant="body2"
|
|
||||||
style={{
|
|
||||||
fontWeight: "bold",
|
|
||||||
fontSize: "1.75em",
|
|
||||||
margin: 0,
|
|
||||||
overflow: "hidden",
|
|
||||||
textOverflow: "ellipsis",
|
|
||||||
whiteSpace: "nowrap",
|
|
||||||
color: "rgba(0, 0, 0, 0.54)",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{title}
|
|
||||||
{title !== this.props.tutorial.steps[activeStep].headline
|
|
||||||
? ` - ${this.props.tutorial.steps[activeStep].headline}`
|
|
||||||
: null}
|
|
||||||
</Typography>
|
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Button
|
<Button
|
||||||
disabled //={tutorialIndex + 1 === tutorials.length}
|
disabled//={tutorialIndex + 1 === tutorials.length}
|
||||||
//onClick={() => { this.props.history.push(`/tutorial/${tutorials[tutorialIndex + 1].id}`) }}
|
//onClick={() => { this.props.history.push(`/tutorial/${tutorials[tutorialIndex + 1].id}`) }}
|
||||||
>
|
>
|
||||||
{">"}
|
{'>'}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
StepperHorizontal.propTypes = {
|
StepperHorizontal.propTypes = {
|
||||||
status: PropTypes.array.isRequired,
|
status: PropTypes.array.isRequired,
|
||||||
change: PropTypes.number.isRequired,
|
change: PropTypes.number.isRequired,
|
||||||
currentTutorialIndex: PropTypes.number.isRequired,
|
currentTutorialIndex: PropTypes.number.isRequired,
|
||||||
tutorial: PropTypes.object.isRequired,
|
tutorial: PropTypes.object.isRequired
|
||||||
activeStep: PropTypes.number.isRequired,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = state => ({
|
||||||
change: state.tutorial.change,
|
change: state.tutorial.change,
|
||||||
status: state.tutorial.status,
|
status: state.tutorial.status,
|
||||||
currentTutorialIndex: state.tutorial.currentIndex,
|
currentTutorialIndex: state.tutorial.currentIndex,
|
||||||
activeStep: state.tutorial.activeStep,
|
tutorial: state.tutorial.tutorials[0]
|
||||||
tutorial: state.tutorial.tutorials[0],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(
|
export default connect(mapStateToProps, null)(withRouter(withStyles(styles, { withTheme: true })(StepperHorizontal)));
|
||||||
mapStateToProps,
|
|
||||||
null
|
|
||||||
)(withRouter(withStyles(styles, { withTheme: true })(StepperHorizontal)));
|
|
||||||
|
|||||||
@@ -1,35 +1,36 @@
|
|||||||
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 { tutorialStep } from "../../actions/tutorialActions";
|
import { tutorialStep } from '../../actions/tutorialActions';
|
||||||
|
|
||||||
import { withRouter } from "react-router-dom";
|
import { withRouter } from 'react-router-dom';
|
||||||
|
|
||||||
import clsx from "clsx";
|
import clsx from 'clsx';
|
||||||
import { alpha } from "@material-ui/core/styles";
|
|
||||||
import { withStyles } from "@material-ui/core/styles";
|
import { fade } from '@material-ui/core/styles/colorManipulator';
|
||||||
import Stepper from "@material-ui/core/Stepper";
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import Step from "@material-ui/core/Step";
|
import Stepper from '@material-ui/core/Stepper';
|
||||||
import StepLabel from "@material-ui/core/StepLabel";
|
import Step from '@material-ui/core/Step';
|
||||||
import Tooltip from "@material-ui/core/Tooltip";
|
import StepLabel from '@material-ui/core/StepLabel';
|
||||||
|
import Tooltip from '@material-ui/core/Tooltip';
|
||||||
|
|
||||||
const styles = (theme) => ({
|
const styles = (theme) => ({
|
||||||
verticalStepper: {
|
verticalStepper: {
|
||||||
padding: 0,
|
padding: 0,
|
||||||
width: "30px",
|
width: '30px',
|
||||||
},
|
},
|
||||||
stepIcon: {
|
stepIcon: {
|
||||||
borderStyle: `solid`,
|
borderStyle: `solid`,
|
||||||
// borderWidth: '2px',
|
// borderWidth: '2px',
|
||||||
borderRadius: "50%",
|
borderRadius: '50%',
|
||||||
borderColor: theme.palette.secondary.main,
|
borderColor: theme.palette.secondary.main,
|
||||||
width: "12px",
|
width: '12px',
|
||||||
height: "12px",
|
height: '12px',
|
||||||
margin: "0 auto",
|
margin: '0 auto',
|
||||||
},
|
},
|
||||||
stepIconLarge: {
|
stepIconLarge: {
|
||||||
width: "24px",
|
width: '24px',
|
||||||
height: "24px",
|
height: '24px'
|
||||||
},
|
},
|
||||||
stepIconLargeSuccess: {
|
stepIconLargeSuccess: {
|
||||||
borderColor: theme.palette.primary.main,
|
borderColor: theme.palette.primary.main,
|
||||||
@@ -38,27 +39,28 @@ const styles = (theme) => ({
|
|||||||
borderColor: theme.palette.error.dark,
|
borderColor: theme.palette.error.dark,
|
||||||
},
|
},
|
||||||
stepIconActiveOther: {
|
stepIconActiveOther: {
|
||||||
backgroundColor: theme.palette.secondary.main,
|
backgroundColor: theme.palette.secondary.main
|
||||||
},
|
},
|
||||||
stepIconActiveSuccess: {
|
stepIconActiveSuccess: {
|
||||||
backgroundColor: alpha(theme.palette.primary.main, 0.6),
|
backgroundColor: fade(theme.palette.primary.main, 0.6)
|
||||||
},
|
},
|
||||||
stepIconActiveError: {
|
stepIconActiveError: {
|
||||||
backgroundColor: alpha(theme.palette.error.dark, 0.6),
|
backgroundColor: fade(theme.palette.error.dark, 0.6)
|
||||||
},
|
},
|
||||||
connector: {
|
connector: {
|
||||||
height: "10px",
|
height: '10px',
|
||||||
borderLeft: `2px solid black`,
|
borderLeft: `2px solid black`,
|
||||||
margin: "auto",
|
margin: 'auto'
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
class StepperVertical extends Component {
|
class StepperVertical extends Component {
|
||||||
componentDidMount() {
|
|
||||||
|
componentDidMount(){
|
||||||
this.props.tutorialStep(0);
|
this.props.tutorialStep(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(props) {
|
componentDidUpdate(props){
|
||||||
if (props.tutorial._id !== this.props.match.params.tutorialId) {
|
if (props.tutorial._id !== this.props.match.params.tutorialId) {
|
||||||
this.props.tutorialStep(0);
|
this.props.tutorialStep(0);
|
||||||
}
|
}
|
||||||
@@ -67,103 +69,60 @@ class StepperVertical extends Component {
|
|||||||
render() {
|
render() {
|
||||||
var steps = this.props.steps;
|
var steps = this.props.steps;
|
||||||
var activeStep = this.props.activeStep;
|
var activeStep = this.props.activeStep;
|
||||||
var tutorialStatus = this.props.status.filter(
|
var tutorialStatus = this.props.status.filter(status => status._id === this.props.tutorial._id)[0];
|
||||||
(status) => status._id === this.props.tutorial._id
|
|
||||||
)[0];
|
|
||||||
return (
|
return (
|
||||||
<div style={{ marginRight: "10px" }}>
|
<div style={{marginRight: '10px'}}>
|
||||||
<Stepper
|
<Stepper
|
||||||
activeStep={activeStep}
|
activeStep={activeStep}
|
||||||
orientation="vertical"
|
orientation="vertical"
|
||||||
connector={<div className={this.props.classes.connector}></div>}
|
connector={<div className={this.props.classes.connector}></div>}
|
||||||
classes={{ root: this.props.classes.verticalStepper }}
|
classes={{root: this.props.classes.verticalStepper}}
|
||||||
>
|
>
|
||||||
{steps.map((step, i) => {
|
{steps.map((step, i) => {
|
||||||
var tasksIndex = tutorialStatus.tasks.findIndex(
|
var tasksIndex = tutorialStatus.tasks.findIndex(task => task._id === step._id);
|
||||||
(task) => task._id === step._id
|
var taskType = tasksIndex > -1 ? tutorialStatus.tasks[tasksIndex].type : null;
|
||||||
);
|
var taskStatus = taskType === 'success' ? 'Success' : taskType === 'error' ? 'Error' : 'Other';
|
||||||
var taskType =
|
|
||||||
tasksIndex > -1 ? tutorialStatus.tasks[tasksIndex].type : null;
|
|
||||||
var taskStatus =
|
|
||||||
taskType === "success"
|
|
||||||
? "Success"
|
|
||||||
: taskType === "error"
|
|
||||||
? "Error"
|
|
||||||
: "Other";
|
|
||||||
return (
|
return (
|
||||||
<Step key={i}>
|
<Step key={i}>
|
||||||
<Tooltip title={step.headline} placement="right" arrow>
|
<Tooltip title={step.headline} placement='right' arrow >
|
||||||
<div
|
<div style={i === activeStep ? {padding: '5px 0'} : {padding: '5px 0', cursor: 'pointer'}} onClick={i === activeStep ? null : () => { this.props.tutorialStep(i)}}>
|
||||||
style={
|
|
||||||
i === activeStep
|
|
||||||
? { padding: "5px 0" }
|
|
||||||
: { padding: "5px 0", cursor: "pointer" }
|
|
||||||
}
|
|
||||||
onClick={
|
|
||||||
i === activeStep
|
|
||||||
? null
|
|
||||||
: () => {
|
|
||||||
this.props.tutorialStep(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<StepLabel
|
<StepLabel
|
||||||
StepIconComponent={"div"}
|
StepIconComponent={'div'}
|
||||||
classes={{
|
classes={{
|
||||||
root:
|
root: step.type === 'task' ?
|
||||||
step.type === "task"
|
i === activeStep ?
|
||||||
? i === activeStep
|
clsx(this.props.classes.stepIcon, this.props.classes.stepIconLarge, this.props.classes['stepIconLarge'+taskStatus], this.props.classes['stepIconActive'+taskStatus])
|
||||||
? clsx(
|
: clsx(this.props.classes.stepIcon, this.props.classes.stepIconLarge, this.props.classes['stepIconLarge'+taskStatus])
|
||||||
this.props.classes.stepIcon,
|
: i === activeStep ?
|
||||||
this.props.classes.stepIconLarge,
|
clsx(this.props.classes.stepIcon, this.props.classes.stepIconActiveOther)
|
||||||
this.props.classes[
|
: clsx(this.props.classes.stepIcon)
|
||||||
"stepIconLarge" + taskStatus
|
|
||||||
],
|
|
||||||
this.props.classes[
|
|
||||||
"stepIconActive" + taskStatus
|
|
||||||
]
|
|
||||||
)
|
|
||||||
: clsx(
|
|
||||||
this.props.classes.stepIcon,
|
|
||||||
this.props.classes.stepIconLarge,
|
|
||||||
this.props.classes[
|
|
||||||
"stepIconLarge" + taskStatus
|
|
||||||
]
|
|
||||||
)
|
|
||||||
: i === activeStep
|
|
||||||
? clsx(
|
|
||||||
this.props.classes.stepIcon,
|
|
||||||
this.props.classes.stepIconActiveOther
|
|
||||||
)
|
|
||||||
: clsx(this.props.classes.stepIcon),
|
|
||||||
}}
|
}}
|
||||||
></StepLabel>
|
>
|
||||||
|
</StepLabel>
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Step>
|
</Step>
|
||||||
);
|
)})}
|
||||||
})}
|
|
||||||
</Stepper>
|
</Stepper>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
StepperVertical.propTypes = {
|
StepperVertical.propTypes = {
|
||||||
status: PropTypes.array.isRequired,
|
status: PropTypes.array.isRequired,
|
||||||
change: PropTypes.number.isRequired,
|
change: PropTypes.number.isRequired,
|
||||||
activeStep: PropTypes.number.isRequired,
|
activeStep: PropTypes.number.isRequired,
|
||||||
tutorialStep: PropTypes.func.isRequired,
|
tutorialStep: PropTypes.func.isRequired,
|
||||||
tutorial: PropTypes.object.isRequired,
|
tutorial: PropTypes.object.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = state => ({
|
||||||
change: state.tutorial.change,
|
change: state.tutorial.change,
|
||||||
status: state.tutorial.status,
|
status: state.tutorial.status,
|
||||||
activeStep: state.tutorial.activeStep,
|
activeStep: state.tutorial.activeStep,
|
||||||
tutorial: state.tutorial.tutorials[0],
|
tutorial: state.tutorial.tutorials[0]
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, { tutorialStep })(
|
export default connect(mapStateToProps, { tutorialStep })(withRouter(withStyles(styles, {withTheme: true})(StepperVertical)));
|
||||||
withRouter(withStyles(styles, { withTheme: true })(StepperVertical))
|
|
||||||
);
|
|
||||||
|
|||||||
@@ -3,13 +3,9 @@ import PropTypes from "prop-types";
|
|||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import {
|
import {
|
||||||
getTutorials,
|
getTutorials,
|
||||||
getAllTutorials,
|
|
||||||
getUserTutorials,
|
|
||||||
resetTutorial,
|
resetTutorial,
|
||||||
tutorialProgress,
|
tutorialProgress,
|
||||||
} from "../../actions/tutorialActions";
|
} from "../../actions/tutorialActions";
|
||||||
import { progress } from "../../actions/tutorialBuilderActions";
|
|
||||||
|
|
||||||
import { clearMessages } from "../../actions/messageActions";
|
import { clearMessages } from "../../actions/messageActions";
|
||||||
|
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
@@ -17,26 +13,16 @@ import clsx from "clsx";
|
|||||||
import Breadcrumbs from "../Breadcrumbs";
|
import Breadcrumbs from "../Breadcrumbs";
|
||||||
|
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { alpha } from "@material-ui/core/styles";
|
|
||||||
|
import { fade } from "@material-ui/core/styles/colorManipulator";
|
||||||
import { withStyles } from "@material-ui/core/styles";
|
import { withStyles } from "@material-ui/core/styles";
|
||||||
import Grid from "@material-ui/core/Grid";
|
import Grid from "@material-ui/core/Grid";
|
||||||
import Paper from "@material-ui/core/Paper";
|
import Paper from "@material-ui/core/Paper";
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
|
|
||||||
import {
|
import { faCheck, faTimes } from "@fortawesome/free-solid-svg-icons";
|
||||||
faCheck,
|
|
||||||
faTimes,
|
|
||||||
faShareAlt,
|
|
||||||
faEye,
|
|
||||||
faUserCheck,
|
|
||||||
} 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";
|
||||||
import ReactStars from "react-rating-stars-component";
|
|
||||||
import Tooltip from "@material-ui/core/Tooltip";
|
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
|
||||||
import Snackbar from "../Snackbar";
|
|
||||||
import Divider from "@material-ui/core/Divider";
|
|
||||||
|
|
||||||
const styles = (theme) => ({
|
const styles = (theme) => ({
|
||||||
outerDiv: {
|
outerDiv: {
|
||||||
@@ -45,18 +31,18 @@ const styles = (theme) => ({
|
|||||||
bottom: "-30px",
|
bottom: "-30px",
|
||||||
width: "160px",
|
width: "160px",
|
||||||
height: "160px",
|
height: "160px",
|
||||||
color: alpha(theme.palette.secondary.main, 0.6),
|
color: fade(theme.palette.secondary.main, 0.6),
|
||||||
},
|
},
|
||||||
outerDivError: {
|
outerDivError: {
|
||||||
stroke: alpha(theme.palette.error.dark, 0.6),
|
stroke: fade(theme.palette.error.dark, 0.6),
|
||||||
color: alpha(theme.palette.error.dark, 0.6),
|
color: fade(theme.palette.error.dark, 0.6),
|
||||||
},
|
},
|
||||||
outerDivSuccess: {
|
outerDivSuccess: {
|
||||||
stroke: alpha(theme.palette.primary.main, 0.6),
|
stroke: fade(theme.palette.primary.main, 0.6),
|
||||||
color: alpha(theme.palette.primary.main, 0.6),
|
color: fade(theme.palette.primary.main, 0.6),
|
||||||
},
|
},
|
||||||
outerDivOther: {
|
outerDivOther: {
|
||||||
stroke: alpha(theme.palette.secondary.main, 0.6),
|
stroke: fade(theme.palette.secondary.main, 0.6),
|
||||||
},
|
},
|
||||||
innerDiv: {
|
innerDiv: {
|
||||||
width: "inherit",
|
width: "inherit",
|
||||||
@@ -65,85 +51,23 @@ const styles = (theme) => ({
|
|||||||
verticalAlign: "middle",
|
verticalAlign: "middle",
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
},
|
},
|
||||||
button: {
|
|
||||||
backgroundColor: theme.palette.primary.main,
|
|
||||||
color: theme.palette.primary.contrastText,
|
|
||||||
width: "40px",
|
|
||||||
height: "40px",
|
|
||||||
"&:hover": {
|
|
||||||
backgroundColor: theme.palette.primary.main,
|
|
||||||
color: theme.palette.primary.contrastText,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
link: {
|
|
||||||
color: theme.palette.primary.main,
|
|
||||||
textDecoration: "none",
|
|
||||||
"&:hover": {
|
|
||||||
color: theme.palette.primary.main,
|
|
||||||
textDecoration: "underline",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
class TutorialHome extends Component {
|
class TutorialHome extends Component {
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
userTutorials: [],
|
|
||||||
tutorials: [],
|
|
||||||
snackbar: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.tutorialProgress();
|
this.props.tutorialProgress();
|
||||||
// retrieve tutorials only if a potential user is loaded - authentication
|
// retrieve tutorials only if a potential user is loaded - authentication
|
||||||
// is finished (success or failed)
|
// is finished (success or failed)
|
||||||
// if (!this.props.progress) {
|
if (!this.props.progress) {
|
||||||
// if (this.props.user) {
|
|
||||||
// if (this.props.user.blocklyRole === "admin") {
|
|
||||||
// this.props.getAllTutorials();
|
|
||||||
// }
|
|
||||||
// if (this.props.user.blocklyRole === "creator") {
|
|
||||||
// this.props.getUserTutorials();
|
|
||||||
// this.props.getTutorials();
|
|
||||||
// console.log("get user tutorials");
|
|
||||||
// console.log(this.props.userTutorials);
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// this.props.getTutorials();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
if (!this.props.authProgress) {
|
|
||||||
if (this.props.user) {
|
|
||||||
if (this.props.user.role === "admin") {
|
|
||||||
this.props.getAllTutorials();
|
|
||||||
} else {
|
|
||||||
this.props.getUserTutorials();
|
|
||||||
//this.props.getTutorials();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.props.getTutorials();
|
this.props.getTutorials();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(props, state) {
|
componentDidUpdate(props, state) {
|
||||||
if (
|
if (props.progress !== this.props.progress && !this.props.progress) {
|
||||||
props.authProgress !== this.props.authProgress &&
|
|
||||||
!this.props.authProgress
|
|
||||||
)
|
|
||||||
if (this.props.user) {
|
|
||||||
if (this.props.user.role === "admin") {
|
|
||||||
// authentication is completed
|
// authentication is completed
|
||||||
this.props.getAllTutorials();
|
|
||||||
} else {
|
|
||||||
this.props.getUserTutorials();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.props.getTutorials();
|
this.props.getTutorials();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.props.message.id === "GET_TUTORIALS_FAIL") {
|
if (this.props.message.id === "GET_TUTORIALS_FAIL") {
|
||||||
alert(this.props.message.msg);
|
alert(this.props.message.msg);
|
||||||
}
|
}
|
||||||
@@ -157,25 +81,13 @@ class TutorialHome extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var userTutorials = [];
|
|
||||||
const publicTutorials = this.props.tutorials.filter(
|
|
||||||
(tutorial) => tutorial.public === true
|
|
||||||
);
|
|
||||||
if (this.props.user && this.props.user.blocklyRole === "admin") {
|
|
||||||
userTutorials = this.props.tutorials;
|
|
||||||
}
|
|
||||||
if (this.props.user && this.props.user.blocklyRole === "creator") {
|
|
||||||
userTutorials = this.props.tutorials.filter(
|
|
||||||
(tutorial) => tutorial.creator === this.props.user.email
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return this.props.isLoading ? null : (
|
return this.props.isLoading ? null : (
|
||||||
<div>
|
<div>
|
||||||
<Breadcrumbs content={[{ link: "/tutorial", title: "Tutorial" }]} />
|
<Breadcrumbs content={[{ link: "/tutorial", title: "Tutorial" }]} />
|
||||||
|
|
||||||
<h1>{Blockly.Msg.tutorials_home_head}</h1>
|
<h1>{Blockly.Msg.tutorials_home_head}</h1>
|
||||||
<h2>Alle Tutorials</h2>
|
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
{publicTutorials.map((tutorial, i) => {
|
{this.props.tutorials.map((tutorial, i) => {
|
||||||
var status = this.props.status.filter(
|
var status = this.props.status.filter(
|
||||||
(status) => status._id === tutorial._id
|
(status) => status._id === tutorial._id
|
||||||
)[0];
|
)[0];
|
||||||
@@ -187,12 +99,6 @@ class TutorialHome extends Component {
|
|||||||
tasks.length;
|
tasks.length;
|
||||||
var tutorialStatus =
|
var tutorialStatus =
|
||||||
success === 1 ? "Success" : error ? "Error" : "Other";
|
success === 1 ? "Success" : error ? "Error" : "Other";
|
||||||
const firstExample = {
|
|
||||||
size: 30,
|
|
||||||
value: tutorial.difficulty,
|
|
||||||
edit: false,
|
|
||||||
isHalf: true,
|
|
||||||
};
|
|
||||||
return (
|
return (
|
||||||
<Grid item xs={12} sm={6} md={4} xl={3} key={i} style={{}}>
|
<Grid item xs={12} sm={6} md={4} xl={3} key={i} style={{}}>
|
||||||
<Link
|
<Link
|
||||||
@@ -208,7 +114,6 @@ class TutorialHome extends Component {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{tutorial.title}
|
{tutorial.title}
|
||||||
<ReactStars {...firstExample} />
|
|
||||||
<div
|
<div
|
||||||
className={clsx(this.props.classes.outerDiv)}
|
className={clsx(this.props.classes.outerDiv)}
|
||||||
style={{ width: "160px", height: "160px", border: 0 }}
|
style={{ width: "160px", height: "160px", border: 0 }}
|
||||||
@@ -311,119 +216,6 @@ class TutorialHome extends Component {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Grid>
|
</Grid>
|
||||||
{this.props.user ? (
|
|
||||||
<div>
|
|
||||||
<h2>User Tutorials</h2>
|
|
||||||
<Grid container spacing={2}>
|
|
||||||
{userTutorials.map((tutorial, i) => {
|
|
||||||
var status = this.props.status.filter(
|
|
||||||
(status) => status._id === tutorial._id
|
|
||||||
)[0];
|
|
||||||
var tasks = status.tasks;
|
|
||||||
var error =
|
|
||||||
status.tasks.filter((task) => task.type === "error").length >
|
|
||||||
0;
|
|
||||||
var success =
|
|
||||||
status.tasks.filter((task) => task.type === "success")
|
|
||||||
.length / tasks.length;
|
|
||||||
var tutorialStatus =
|
|
||||||
success === 1 ? "Success" : error ? "Error" : "Other";
|
|
||||||
const firstExample = {
|
|
||||||
size: 30,
|
|
||||||
value: tutorial.difficulty,
|
|
||||||
edit: false,
|
|
||||||
isHalf: true,
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<Grid item xs={12} sm={6} md={4} xl={3} key={i} style={{}}>
|
|
||||||
<Paper
|
|
||||||
style={{
|
|
||||||
height: "150",
|
|
||||||
padding: "10px",
|
|
||||||
position: "relative",
|
|
||||||
overflow: "hidden",
|
|
||||||
backgroundColor: tutorial.review
|
|
||||||
? "lightyellow"
|
|
||||||
: "white",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Link
|
|
||||||
to={`/tutorial/${tutorial._id}`}
|
|
||||||
style={{ textDecoration: "none", color: "inherit" }}
|
|
||||||
>
|
|
||||||
{tutorial.title}
|
|
||||||
<ReactStars {...firstExample} />
|
|
||||||
</Link>
|
|
||||||
<Divider
|
|
||||||
style={{
|
|
||||||
marginTop: "10px",
|
|
||||||
marginBottom: "10px",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<p>
|
|
||||||
Creator:{tutorial.creator} <br />
|
|
||||||
<div style={this.props.style}>
|
|
||||||
<Tooltip
|
|
||||||
title={Blockly.Msg.tooltip_share_tutorial}
|
|
||||||
arrow
|
|
||||||
>
|
|
||||||
<IconButton
|
|
||||||
className={`shareTutorial ${this.props.classes.button}`}
|
|
||||||
onClick={() => {
|
|
||||||
navigator.clipboard.writeText(
|
|
||||||
`${window.location.origin}/tutorial/${tutorial._id}`
|
|
||||||
);
|
|
||||||
this.setState({
|
|
||||||
snackbar: true,
|
|
||||||
key: Date.now(),
|
|
||||||
message:
|
|
||||||
Blockly.Msg.messages_copylink_success,
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon icon={faShareAlt} size="xs" />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
<Tooltip
|
|
||||||
title={Blockly.Msg.tooltip_share_tutorial}
|
|
||||||
arrow
|
|
||||||
>
|
|
||||||
<IconButton
|
|
||||||
className={`publicTutorial ${this.props.classes.button}`}
|
|
||||||
disabled={!tutorial.public}
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon icon={faEye} size="xs" />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
{tutorial.review ? (
|
|
||||||
<Tooltip
|
|
||||||
title={Blockly.Msg.tooltip_share_tutorial}
|
|
||||||
arrow
|
|
||||||
>
|
|
||||||
<IconButton
|
|
||||||
className={`publicTutorial ${this.props.classes.button}`}
|
|
||||||
disabled={!tutorial.review}
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon icon={faUserCheck} size="xs" />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
) : null}
|
|
||||||
<Snackbar
|
|
||||||
open={this.state.snackbar}
|
|
||||||
message={Blockly.Msg.messages_copylink_success}
|
|
||||||
type={this.state.type}
|
|
||||||
key={this.state.key}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</p>
|
|
||||||
</Paper>
|
|
||||||
</Grid>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Grid>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -431,8 +223,6 @@ class TutorialHome extends Component {
|
|||||||
|
|
||||||
TutorialHome.propTypes = {
|
TutorialHome.propTypes = {
|
||||||
getTutorials: PropTypes.func.isRequired,
|
getTutorials: PropTypes.func.isRequired,
|
||||||
getAllTutorials: PropTypes.func.isRequired,
|
|
||||||
getUserTutorials: PropTypes.func.isRequired,
|
|
||||||
resetTutorial: PropTypes.func.isRequired,
|
resetTutorial: PropTypes.func.isRequired,
|
||||||
tutorialProgress: PropTypes.func.isRequired,
|
tutorialProgress: PropTypes.func.isRequired,
|
||||||
clearMessages: PropTypes.func.isRequired,
|
clearMessages: PropTypes.func.isRequired,
|
||||||
@@ -442,27 +232,19 @@ TutorialHome.propTypes = {
|
|||||||
isLoading: PropTypes.bool.isRequired,
|
isLoading: PropTypes.bool.isRequired,
|
||||||
message: PropTypes.object.isRequired,
|
message: PropTypes.object.isRequired,
|
||||||
progress: PropTypes.bool.isRequired,
|
progress: PropTypes.bool.isRequired,
|
||||||
user: PropTypes.object.isRequired,
|
|
||||||
authProgress: PropTypes.bool.isRequired,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = (state) => ({
|
||||||
change: state.tutorial.change,
|
change: state.tutorial.change,
|
||||||
status: state.tutorial.status,
|
status: state.tutorial.status,
|
||||||
tutorials: state.tutorial.tutorials,
|
tutorials: state.tutorial.tutorials,
|
||||||
userTutorials: state.tutorial.userTutorials,
|
|
||||||
isLoading: state.tutorial.progress,
|
isLoading: state.tutorial.progress,
|
||||||
message: state.message,
|
message: state.message,
|
||||||
progress: state.auth.progress,
|
progress: state.auth.progress,
|
||||||
user: state.auth.user,
|
|
||||||
authProgress: state.auth.progress,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, {
|
export default connect(mapStateToProps, {
|
||||||
getTutorials,
|
getTutorials,
|
||||||
progress,
|
|
||||||
getUserTutorials,
|
|
||||||
getAllTutorials,
|
|
||||||
resetTutorial,
|
resetTutorial,
|
||||||
clearMessages,
|
clearMessages,
|
||||||
tutorialProgress,
|
tutorialProgress,
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ export class Login extends Component {
|
|||||||
}
|
}
|
||||||
// Check for login error
|
// Check for login error
|
||||||
else if (message.id === "LOGIN_FAIL") {
|
else if (message.id === "LOGIN_FAIL") {
|
||||||
|
console.log("login fail");
|
||||||
this.setState({
|
this.setState({
|
||||||
email: "",
|
email: "",
|
||||||
password: "",
|
password: "",
|
||||||
|
|||||||
@@ -1,71 +0,0 @@
|
|||||||
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() {
|
|
||||||
}
|
|
||||||
|
|
||||||
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,7 +16,10 @@ 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";
|
||||||
|
|
||||||
@@ -68,12 +71,15 @@ 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 = () => {
|
||||||
@@ -89,6 +95,7 @@ class Compile extends Component {
|
|||||||
})
|
})
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
|
console.log(data);
|
||||||
if (data.code === "Internal Server Error") {
|
if (data.code === "Internal Server Error") {
|
||||||
this.setState({
|
this.setState({
|
||||||
progress: false,
|
progress: false,
|
||||||
@@ -189,7 +196,7 @@ class Compile extends Component {
|
|||||||
className={`compileBlocks ${this.props.classes.iconButton}`}
|
className={`compileBlocks ${this.props.classes.iconButton}`}
|
||||||
onClick={() => this.compile()}
|
onClick={() => this.compile()}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faClipboardCheck} size="xs" />
|
<FontAwesomeIcon icon={faClipboardCheck} size="l" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -1,44 +1,47 @@
|
|||||||
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 { 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 IconButton from "@material-ui/core/IconButton";
|
import IconButton from '@material-ui/core/IconButton';
|
||||||
import Tooltip from "@material-ui/core/Tooltip";
|
import Tooltip from '@material-ui/core/Tooltip';
|
||||||
|
|
||||||
import { faCopy } from "@fortawesome/free-solid-svg-icons";
|
import { faCopy } 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 Snackbar from "../Snackbar";
|
import Snackbar from '../Snackbar';
|
||||||
|
|
||||||
|
|
||||||
const styles = (theme) => ({
|
const styles = (theme) => ({
|
||||||
backdrop: {
|
backdrop: {
|
||||||
zIndex: theme.zIndex.drawer + 1,
|
zIndex: theme.zIndex.drawer + 1,
|
||||||
color: "#fff",
|
color: '#fff',
|
||||||
},
|
},
|
||||||
iconButton: {
|
iconButton: {
|
||||||
backgroundColor: theme.palette.primary.main,
|
backgroundColor: theme.palette.primary.main,
|
||||||
color: theme.palette.primary.contrastText,
|
color: theme.palette.primary.contrastText,
|
||||||
width: "40px",
|
width: '40px',
|
||||||
height: "40px",
|
height: '40px',
|
||||||
"&:hover": {
|
'&:hover': {
|
||||||
backgroundColor: theme.palette.primary.main,
|
backgroundColor: theme.palette.primary.main,
|
||||||
color: theme.palette.primary.contrastText,
|
color: theme.palette.primary.contrastText,
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
button: {
|
button: {
|
||||||
backgroundColor: theme.palette.button.copycode,
|
backgroundColor: theme.palette.button.copycode,
|
||||||
color: theme.palette.primary.contrastText,
|
color: theme.palette.primary.contrastText,
|
||||||
"&:hover": {
|
'&:hover': {
|
||||||
backgroundColor: theme.palette.button.copycode,
|
backgroundColor: theme.palette.button.copycode,
|
||||||
color: theme.palette.primary.contrastText,
|
color: theme.palette.primary.contrastText,
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
class CopyCode extends Component {
|
class CopyCode extends Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -46,65 +49,51 @@ class CopyCode extends Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
copyCode = () => {
|
copyCode = () => {
|
||||||
navigator.clipboard.writeText(this.props.arduino);
|
navigator.clipboard.writeText(this.props.arduino)
|
||||||
this.setState({
|
this.setState({ snackbar: true, type: 'success', key: Date.now(), message: Blockly.Msg.messages_copy_code });
|
||||||
snackbar: true,
|
}
|
||||||
type: "success",
|
|
||||||
key: Date.now(),
|
|
||||||
message: Blockly.Msg.messages_copy_code,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div style={{}}>
|
<div style={{}}>
|
||||||
{this.props.iconButton ? (
|
{this.props.iconButton ?
|
||||||
<Tooltip
|
<Tooltip title={Blockly.Msg.tooltip_copy_code} arrow style={{ marginRight: '5px' }}>
|
||||||
title={Blockly.Msg.tooltip_copy_code}
|
|
||||||
arrow
|
|
||||||
style={{ marginRight: "5px" }}
|
|
||||||
>
|
|
||||||
<IconButton
|
<IconButton
|
||||||
className={`copyCode ${this.props.classes.iconButton}`}
|
className={`copyCode ${this.props.classes.iconButton}`}
|
||||||
onClick={() => this.copyCode()}
|
onClick={() => this.copyCode()}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faCopy} size="xs" />
|
<FontAwesomeIcon icon={faCopy} size="l" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
) : (
|
:
|
||||||
<Button
|
<Button style={{ float: 'right', color: 'white' }} variant="contained" className={this.props.classes.button} onClick={() => this.copyCode()}>
|
||||||
style={{ float: "right", color: "white" }}
|
<FontAwesomeIcon icon={faCopy} style={{ marginRight: '5px' }} /> Code kopieren
|
||||||
variant="contained"
|
|
||||||
className={this.props.classes.button}
|
|
||||||
onClick={() => this.copyCode()}
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon icon={faCopy} style={{ marginRight: "5px" }} />{" "}
|
|
||||||
Code kopieren
|
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
}
|
||||||
<Snackbar
|
<Snackbar
|
||||||
open={this.state.snackbar}
|
open={this.state.snackbar}
|
||||||
message={this.state.message}
|
message={this.state.message}
|
||||||
type={this.state.type}
|
type={this.state.type}
|
||||||
key={this.state.key}
|
key={this.state.key}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
|
</div >
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
CopyCode.propTypes = {
|
CopyCode.propTypes = {
|
||||||
arduino: PropTypes.string.isRequired,
|
arduino: PropTypes.string.isRequired,
|
||||||
name: PropTypes.string,
|
name: PropTypes.string,
|
||||||
workspaceName: PropTypes.func.isRequired,
|
workspaceName: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = state => ({
|
||||||
arduino: state.workspace.code.arduino,
|
arduino: state.workspace.code.arduino,
|
||||||
name: state.workspace.name,
|
name: state.workspace.name
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, { workspaceName })(
|
|
||||||
withStyles(styles, { withTheme: true })(CopyCode)
|
export default connect(mapStateToProps, { workspaceName })(withStyles(styles, { withTheme: true })(CopyCode));
|
||||||
);
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user