Compare commits

...
Author SHA1 Message Date
Mario Pesch 2f4538dc89 update ports for senseBox MCU mini 2023-03-30 10:31:05 +02:00
Mario PeschandGitHub d87e47205f Merge pull request #236 from sensebox/development
fix getSelected block
2023-02-14 10:13:57 +01:00
Mario Pesch 7ca5287b86 fix getSelected block 2023-02-14 09:55:17 +01:00
Mario PeschandGitHub 67bac98e65 Merge pull request #199 from sensebox/development
Development
2023-02-13 16:24:20 +01:00
Mario Pesch 2ea773601e fix double var declaration 2023-02-13 16:10:43 +01:00
Mario PeschandGitHub 7969bf2ed7 Merge pull request #235 from sensebox/dev/fix-navbar-visibility
fix navbar visibility
2023-02-12 17:49:29 +01:00
Frederick BruchandGitHub 684417750a Merge branch 'development' into dev/fix-navbar-visibility 2023-02-10 13:59:44 +01:00
fbruc03 df4db30c72 navbar only on root and md breakpoint 2023-02-10 13:56:01 +01:00
Mario PeschandGitHub 2064fa2fb3 Merge pull request #234 from sensebox/dev/fix-gallery
fix gallery
2023-02-10 12:15:55 +01:00
Mario Pesch 98f97d6313 fix gallery 2023-02-10 12:04:10 +01:00
Mario PeschandGitHub ace2237529 Merge pull request #233 from sensebox/dev/update-blockly-v9
Dev/update blockly v9
2023-02-06 17:59:49 +01:00
Mario Pesch 07cd39f364 add account to navbar 2023-02-06 17:56:05 +01:00
Mario Pesch 02de052879 update blockly to v9 2023-02-06 17:55:57 +01:00
Mario PeschandGitHub ade6f3d4bd Merge branch 'master' into development 2023-02-06 15:06:50 +01:00
Mario PeschandGitHub 53d7c77eb5 Merge pull request #229 from sensebox/dev/newNavbarFeatures
add new navbar
2023-02-06 14:53:13 +01:00
fbruc03 426d618769 fix XML on change 2023-02-06 12:57:23 +01:00
Mario PeschandGitHub 69f3bf1db0 Merge pull request #231 from sensebox/fix-bme-dimension
hPa -> Pa
2023-01-13 07:43:15 +01:00
fbruc03 e1b659cda5 menu anchor always on button 2023-01-12 23:30:32 +01:00
fbruc03 2c1594227e style navbar items 2023-01-12 22:30:41 +01:00
Mario Pesch 512839e1f5 hPa -> Pa 2023-01-12 15:17:09 +01:00
Mario PeschandGitHub ec141088cc Merge pull request #230 from sensebox/fix-rtc-hours
Update sensebox-rtc.js
2023-01-12 14:33:38 +01:00
Mario Pesch be51eff3c8 Update sensebox-rtc.js 2023-01-12 14:30:01 +01:00
fbruc03 d05eede14f add new navbar 2023-01-12 12:39:21 +01:00
Mario PeschandGitHub d1b3761349 Merge pull request #228 from sensebox/fix-variable-type
fix variable type in block
2023-01-10 11:51:23 +01:00
Mario Pesch fb9e5c53ff fix variable type in block 2023-01-10 11:43:21 +01:00
Mario PeschandGitHub cfd6fedc6e Merge pull request #227 from sensebox/new-components
add new components
2023-01-06 17:09:18 +01:00
Mario Pesch 126606f4f5 add new components 2023-01-06 17:06:39 +01:00
Mario PeschandGitHub a0bc371bdd Merge pull request #220 from sensebox/dev/migrateMUI
Dev/migrate mUI
2023-01-06 12:59:59 +01:00
Mario PeschandGitHub be8b9ebf32 Merge pull request #217 from sensebox/dev/Tutorial-Builder-Updates
only show public tutorials
2023-01-06 11:29:47 +01:00
Mario PeschandGitHub 133d013081 Merge pull request #223 from sensebox/dev/migrateMUI-fixes
fix stepper size
2023-01-02 12:54:43 +01:00
fbruc03 bf9fe05845 fix isWidthDown 2023-01-02 12:21:18 +01:00
Mario Pesch b9884cc85d fix stepper size 2022-12-16 11:38:59 +01:00
Mario PeschandGitHub cb12aef535 Merge pull request #222 from sensebox/block/add-internalRTC-NTP
Block/add internal rtc ntp
2022-12-14 15:39:18 +01:00
Mario PeschandGitHub 345c15ed77 Merge pull request #221 from sensebox/block/add-sps30
init implementation of sps30 block
2022-12-14 15:35:19 +01:00
Mario Pesch b05b3017e1 remove duplicate variable 2022-12-14 13:59:31 +01:00
Mario Pesch a4641938f0 add block for timestamp from internal rtc 2022-12-14 08:56:55 +01:00
Mario Pesch 9526b154bf add blocks for internal RTC and NTP 2022-12-13 14:44:53 +01:00
Mario Pesch 745f6940ec update tooltip 2022-12-13 09:43:24 +01:00
Mario Pesch 2874620a9f init implementation of sps30 block
closes #218
2022-12-12 10:59:27 +01:00
fbruc03 c463237bd7 undo "isRequired" deletes 2022-12-05 14:12:51 +01:00
fbruc03 ae61d2b11b complete MUI migration 2022-12-05 12:01:51 +01:00
fbruc03 8716649be7 migrateMUI next: Restructure component definitions 2022-12-04 22:05:35 +01:00
fbruc03 d6d2505a4b get rid of most errors on Home page for migration 2022-12-04 21:09:54 +01:00
Mario PeschandGitHub 77b338ffb6 Merge pull request #203 from sensebox/development-featSensorWiki
sensorwiki with tabs and only one request
2022-11-16 12:19:54 +01:00
Mario Pesch 8571f0430f Merge branch 'development-featSensorWiki' of https://github.com/sensebox/React-Ardublockly into development-featSensorWiki 2022-11-16 12:07:44 +01:00
Mario Pesch 1bfe1a26ba change to coming soon... 2022-11-16 12:07:35 +01:00
Mario PeschandGitHub 564dcc4d4a Merge branch 'development' into development-featSensorWiki 2022-11-16 12:04:05 +01:00
Mario PeschandGitHub 50b70b4ee3 Merge pull request #216 from sensebox/development-deviceSelection
Development device selection
2022-11-16 11:56:38 +01:00
Mario PeschandGitHub 00310a49dc Merge pull request #201 from sensebox/development-tutorialSolution
disable solution block length check
2022-11-16 11:48:40 +01:00
fbruc03 ec1eea110c fix baground mcu image 2022-11-16 11:44:16 +01:00
Mario PeschandGitHub 9bf17aed67 Merge pull request #194 from sensebox/feat/mode-query-param
Add mode query parameter for opening from inside Connect App
2022-11-16 09:51:37 +01:00
Mario Pesch b851498fb4 only show public tutorials
closes #206
2022-11-15 18:56:10 +01:00
fbruc03 22d11773e9 save current board in session storage 2022-11-15 16:54:09 +01:00
fbruc03 2de54c0e9b rewrite board check 2022-11-15 16:30:13 +01:00
fbruc03 5974608fd8 add DeviceSelection to CodeEditor,Project+Tutorial 2022-11-15 16:22:29 +01:00
fbruc03 6fcaff9cc3 save board model to localstorage 2022-11-15 16:11:35 +01:00
Mario PeschandGitHub f6e5d086b5 Merge pull request #214 from sensebox/codegenerator/fix-co2-zeros
fix co2 zero issue
2022-11-11 15:13:39 +01:00
Mario Pesch 50ffad0ad2 fix co2 zero issue
closes #170
2022-11-11 15:08:16 +01:00
fbruc03 f95b1b36ca fix faq video 2022-11-11 12:21:13 +01:00
Mario PeschandGitHub 3a6fd07647 Update issue templates 2022-11-11 09:55:38 +01:00
Mario PeschandGitHub 9295d92c65 Merge pull request #205 from sensebox/fix/Serial-for-Sensors
fix Serial Ports for Sensors
2022-11-10 13:34:00 +01:00
Mario Pesch 338a0aada6 fix Serial Ports for Sensors 2022-11-10 12:40:51 +01:00
fbruc03 a31195f71e fix german variable translations 2022-11-09 17:05:51 +01:00
fbruc03 506ddef7e9 solve login snackbar issue 2022-11-09 15:41:26 +01:00
fbruc03 9ac98aa06d change block data to json 2022-11-09 11:20:15 +01:00
fbruc03 a8704316ac sensorwiki with tabs and only one request 2022-11-08 15:59:09 +01:00
fbruc03 c950dbbd86 disable solution block length check 2022-11-07 10:33:45 +01:00
Mario PeschandGitHub e00617ac78 Merge pull request #198 from sensebox/dev/update-deviceSelector
update device Selector
2022-11-04 15:50:40 +01:00
Mario Pesch d61d0cc5c4 update device Selector 2022-11-03 20:04:39 +01:00
Mario PeschandGitHub a528bb7378 Merge pull request #197 from sensebox/fix/variable_db
fix variable db
2022-11-03 13:14:34 +01:00
Mario Pesch 719be33756 fix variable db
closes #192
2022-11-03 13:05:55 +01:00
Mario PeschandGitHub b40a439e16 Merge pull request #196 from sensebox/update-code-editor
bug fix:  translations do not load  on /codeeditor
2022-11-03 10:19:00 +01:00
Mario Pesch d71ca25828 fix formatting 2022-11-03 10:12:45 +01:00
fab-scm 32303494f7 bug fix: translations do not load on /codeeditor 2022-11-02 14:06:26 +01:00
Matthias Pfeil d983677d22 Add mode query parameter for opening from inside Connect App 2022-10-25 10:28:15 +02:00
Mario PeschandGitHub 7cceea84fb Merge pull request #193 from sensebox/fix-getVariable
fix getVariable
2022-10-22 13:57:00 +02:00
Mario Pesch 2865610acb fix getVariable
closes #192
2022-10-22 13:52:46 +02:00
Mario PeschandGitHub 32678c1e62 Merge pull request #191 from sensebox/add-old-blockly
add old link
2022-10-21 11:38:54 +02:00
Mario Pesch d105650e29 add old link 2022-10-21 11:36:04 +02:00
Mario PeschandGitHub 5b43a069f3 Merge pull request #142 from sensebox/development
Development
2022-10-21 11:04:12 +02:00
Mario Pesch d4af1891d2 Delete package-lock.json 2022-10-21 11:01:06 +02:00
Mario Pesch 48be116f5b release ready 2022-10-21 10:55:39 +02:00
Mario Pesch 9cb978b071 fix String variable
closes #186
2022-09-28 11:19:55 +02:00
Mario Pesch eb3a86a379 add blockly to navbar 2022-09-28 11:17:30 +02:00
Mario PeschandGitHub 72b6bf47ef Merge pull request #188 from sensebox/fix-refreshToken
Fix refresh token
2022-09-28 10:54:03 +02:00
Mario PeschandGitHub af6f165cf0 Merge branch 'development' into fix-refreshToken 2022-09-28 10:52:35 +02:00
Mario PeschandGitHub facf4737a1 Merge pull request #187 from sensebox/add-device-selection
dialog for device selection
2022-09-28 10:18:34 +02:00
Mario Pesch 3aa9e715d2 update board definition and translations 2022-09-28 10:17:56 +02:00
fbruc03 02f0e1cf3c remove automatic logout after 15min 2022-09-27 17:16:23 +02:00
Mario Pesch 562a7b53e2 update Board definition 2022-09-27 11:02:38 +02:00
fbruc03 c74f427fd5 update outdated npm packages 2022-09-23 14:26:52 +02:00
Mario Pesch 4565b4e482 add selected Board to settings and solve component rerender 2022-09-23 11:31:44 +02:00
Mario PeschandGitHub 3af994fcc4 Merge pull request #183 from sensebox/qr-code-shorty
Qr code shorty
2022-09-22 16:54:07 +02:00
NJaku01 b212316b0b dialog for device selction 2022-09-21 15:44:56 +02:00
fab-scm 57142dc8a1 link id to 5 digits 2022-08-12 10:28:10 +02:00
Mario PeschandGitHub e73550fc8a Merge pull request #184 from sensebox/add-motors
Add motors
2022-08-10 12:24:52 +02:00
fab-scm 89a5c838bf Download QR Code 2022-08-09 20:55:09 +02:00
Mario Pesch 078bbe0477 update toolbox and change colour 2022-08-03 11:19:59 +02:00
Bjoern Luig 047588842c added german messages and put only servo motor in toolbox 2022-07-30 23:32:22 +02:00
fab-scm e5e0066635 social share buttons added 2022-07-27 13:24:36 +02:00
fab-scm 69de659c11 loading spinner for shorty fetch and qr-code 2022-07-26 13:33:12 +02:00
fab-scm c71a150f38 fetch shortlink 2022-07-25 16:42:45 +02:00
fab-scm b97ce364ce createShortlink function 2022-07-22 13:27:42 +02:00
Mario Pesch 86c709a014 bumb blockly to v8 2022-07-20 13:36:12 +02:00
Mario Pesch 7ab3f91ed8 fix tutorial assessment view 2022-07-18 18:16:02 +02:00
Bjoern de15bcf993 added servo and dc motor blocks 2022-07-14 00:24:37 +02:00
Bjoern dd82781939 added blocks for simple stepper motor 2022-07-05 23:05:54 +02:00
Mario Pesch b6da61fae0 disable redux-devtools 2022-07-05 21:48:07 +02:00
Mario Pesch f28a8c4fe7 Merge branch 'master' into development 2022-07-05 21:42:35 +02:00
Mario PeschandGitHub 3e9d55719b Merge pull request #156 from sensebox/update/tutorial-builder
update tutorial builder
2022-07-05 21:24:43 +02:00
Mario Pesch 2670561a87 remove docs feature 2022-07-05 21:24:21 +02:00
Mario Pesch 6fd66b3c49 [WIP] improved docs 2022-04-06 10:49:37 +02:00
Mario Pesch 652de5a184 fix sidebar 2022-04-05 19:27:40 +02:00
Mario PeschandGitHub 7bd85a4dc2 Merge branch 'development' into update/tutorial-builder 2022-04-05 19:23:39 +02:00
Mario Pesch 49e2090b98 update library list 2022-03-18 11:03:15 +01:00
Mario Pesch 669f0c2ade add translations to codeeditor 2022-03-18 10:38:55 +01:00
Mario Pesch 6097a56129 remove examples from sidebar 2022-03-18 10:38:46 +01:00
Mario Pesch 45b90bfe58 get osem codes if logged in 2022-03-03 10:40:32 +01:00
Mario Pesch 4e8819172b add translations 2022-03-01 15:31:44 +01:00
Mario Pesch a06b52a3ee add remark plugins to assessment 2022-03-01 15:01:00 +01:00
Mario Pesch 8823c09d3f resolve some warnings 2022-03-01 14:56:08 +01:00
Mario Pesch d62a27c2cc fix prop type for sound selector 2022-03-01 11:33:43 +01:00
Mario Pesch ab1a46ab0e replace fade with alpha 2022-03-01 10:25:56 +01:00
Mario Pesch 0414d2043d update tutorial builder
- update tutorial modell
- add difficulty closes #82
- add review system
- make tutorials private by default
- add admin overview
2022-02-28 19:56:19 +01:00
Mario Pesch 39c8fd504f update markdown editor and renderer 2022-02-22 11:18:51 +01:00
Mario Pesch 115e4acc6c fix imageList 2022-02-21 12:26:04 +01:00
Mario PeschandGitHub 8fd9eb01ed Merge pull request #153 from sensebox/markdown_file_upload
file upload with multer
2022-02-18 12:21:00 +01:00
Mario Pesch 8620a452a3 resolve warnings 2022-02-18 12:20:22 +01:00
Mario Pesch a34e0bbb5d fix double ReactMarkdown import 2022-02-18 11:33:07 +01:00
Mario PeschandGitHub b0ab03d95b Merge branch 'development' into markdown_file_upload 2022-02-18 11:26:58 +01:00
Mario Pesch 27c934ae88 update packages 2022-02-18 11:21:14 +01:00
fbruc03 3a8f0c38f6 add markdown 2022-02-18 11:12:55 +01:00
fbruc03 f3f6819f05 bring plugins back 2022-02-18 10:56:42 +01:00
fbruc03 c908aa5b63 file upload with multer 2022-02-17 18:33:31 +01:00
Mario Pesch a2200e565a resolve issues 2022-02-17 11:44:50 +01:00
Mario Pesch 2609e56953 Merge branch 'master' into development 2022-02-17 11:15:24 +01:00
Mario Pesch 1d8e33d189 remove stuff 2022-02-16 09:56:35 +01:00
Mario Pesch b44d858fe6 cleanup code and update some packages 2022-01-31 19:12:34 +01:00
Mario PeschandGitHub 557d66d7d6 Merge pull request #138 from sensebox/change-tutorial-view
Change tutorial view
2022-01-28 15:34:50 +01:00
Mario PeschandGitHub a0dba75c80 Merge branch 'development' into change-tutorial-view 2022-01-28 15:34:09 +01:00
Mario PeschandGitHub 04b15dae0e Merge pull request #133 from sensebox/feat/codeEditor
Feat/code editor
2022-01-28 15:28:59 +01:00
Mario Pesch d74e3d29f6 cleanup code 2022-01-28 15:08:41 +01:00
Mario Pesch 9f7ba27d69 add autosave to blocks
closes #58
2022-01-27 19:14:28 +01:00
Mario Pesch a10e394742 add backpack 2022-01-20 10:31:02 +01:00
Mario Pesch 748c29c260 auto Save Blocks 2022-01-14 08:12:20 +01:00
Mario Pesch f388828c88 improve code reset 2022-01-10 12:21:16 +01:00
Mario Pesch 8616a7d732 get examples from api 2022-01-08 16:43:59 +01:00
Mario Pesch 6af54573d7 Merge branch 'feat/codeEditor' of https://github.com/sensebox/React-Ardublockly into feat/codeEditor 2022-01-06 12:53:11 +01:00
Mario Pesch 0943742b78 add resetCode 2022-01-06 12:53:08 +01:00
Mario PeschandGitHub 3d9a76231b Merge pull request #134 from sensebox/feat/loading-save-icon
Feat/loading-save-icon
2022-01-06 12:52:40 +01:00
Felix ErdmannandGitHub 798bf8ca44 add custom loading save icon 2022-01-06 11:48:25 +00:00
Mario Pesch d682accdbf add autosave and serialmonitor 2022-01-06 10:20:35 +01:00
Mario Pesch 19849d68ab add a new code Editor 2022-01-05 16:24:20 +01:00
Mario Pesch a1dad8205b change tutorial and assessment view 2021-12-21 12:13:31 +01:00
Mario Pesch 85dc4d7fc9 update blockly version 2021-12-21 12:13:13 +01:00
150 changed files with 6537 additions and 46209 deletions
+2
View File
@@ -2,5 +2,7 @@ REACT_APP_COMPILER_URL=https://compiler.sensebox.de
REACT_APP_BOARD=sensebox-mcu
REACT_APP_BLOCKLY_API=https://api.blockly.sensebox.de
GENERATE_SOURCEMAP=false
# in days
REACT_APP_SHARE_LINK_EXPIRES=30
+38
View File
@@ -0,0 +1,38 @@
---
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.
+20
View File
@@ -0,0 +1,20 @@
---
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.
+14
View File
@@ -0,0 +1,14 @@
---
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
View File
@@ -22,4 +22,4 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
package-lock.json
package-lock.json
-44160
View File
File diff suppressed because it is too large Load Diff
+49 -38
View File
@@ -1,45 +1,63 @@
{
"name": "blockly-react",
"version": "0.1.0",
"version": "1.0.0",
"private": true,
"dependencies": {
"@blockly/block-plus-minus": "^2.0.10",
"@blockly/field-grid-dropdown": "^1.0.25",
"@blockly/field-slider": "^2.1.1",
"@blockly/plugin-scroll-options": "^1.0.2",
"@blockly/plugin-typed-variable-modal": "^3.1.26",
"@blockly/zoom-to-fit": "^2.0.7",
"@fortawesome/fontawesome-svg-core": "^1.2.30",
"@fortawesome/free-solid-svg-icons": "^5.14.0",
"@fortawesome/react-fontawesome": "^0.1.11",
"@material-ui/core": "^4.11.0",
"@sentry/react": "^6.0.0",
"@sentry/tracing": "^6.0.0",
"@blockly/block-plus-minus": "^4.0.4",
"@blockly/field-grid-dropdown": "^2.0.4",
"@blockly/field-slider": "4.0.4",
"@blockly/plugin-scroll-options": "^3.0.5",
"@blockly/plugin-typed-variable-modal": "^5.0.6",
"@blockly/workspace-backpack": "^3.0.4",
"@blockly/zoom-to-fit": "^3.0.4",
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
"@fortawesome/fontawesome-svg-core": "^6.2.1",
"@fortawesome/free-solid-svg-icons": "^6.2.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"@monaco-editor/react": "^4.3.1",
"@mui/lab": "^5.0.0-alpha.110",
"@mui/material": "^5.10.16",
"@mui/styles": "^5.10.16",
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^12.1.2",
"@testing-library/user-event": "^7.2.1",
"axios": "^0.22.0",
"blockly": "^6.20210701.0",
"file-saver": "^2.0.2",
"blockly": "^9.2.0",
"file-saver": "^2.0.5",
"markdown-it": "^12.3.2",
"mnemonic-id": "^3.2.7",
"moment": "^2.28.0",
"moment": "^2.29.4",
"prismjs": "^1.27.0",
"qrcode.react": "^3.1.0",
"react": "^17.0.2",
"react-cookie-consent": "^7.0.0",
"react-cookie-consent": "^7.2.1",
"react-dom": "^17.0.2",
"react-markdown": "^5.0.2",
"react-markdown": "^8.0.0",
"react-markdown-editor-lite": "^1.3.3",
"react-mde": "^11.5.0",
"react-redux": "^7.2.4",
"react-router-dom": "^5.2.0",
"react-scripts": "^4.0.3",
"reactour": "^1.18.0",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
"react-rating-stars-component": "^2.2.0",
"react-redux": "^7.2.9",
"react-router-dom": "^5.3.3",
"react-scripts": "^5.0.1",
"react-share": "^4.4.0",
"react-spinners": "^0.13.3",
"reactour": "^1.18.7",
"redux": "^4.2.0",
"redux-thunk": "^2.4.1",
"rehype-raw": "^6.1.1",
"remark-gemoji": "^7.0.1",
"remark-gfm": "^3.0.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": {
"start": "react-scripts start",
"start": "node_modules/react-scripts/bin/react-scripts.js start",
"dev": "set \"REACT_APP_BLOCKLY_API=http://localhost:8080\" && npm start",
"build": "react-scripts build",
"test": "react-scripts test",
@@ -48,16 +66,9 @@
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
"browserslist": [
">0.2%",
"not dead",
"not op_mini all"
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 777 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 728 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

+61 -38
View File
@@ -1,51 +1,74 @@
.wrapper {
min-height: calc(100vh - 60px); /* will cover the 100% of viewport - height of footer (padding-bottom) */
min-height: calc(
100vh - 60px
); /* will cover the 100% of viewport - height of footer (padding-bottom) */
overflow: hidden;
display: block;
position: relative;
padding-bottom: 60px; /* height of your footer + 30px*/
}
.tutorial img{
.tutorial img {
display: flex;
align-items: center;
max-height: 40vH;
max-height: 40vh;
max-width: 100%;
margin: auto;
}
.news img{
display: flex;
align-items: center;
max-height: 40vH;
max-width: 100%;
margin: auto;
}
.tutorial blockquote{
background: #f9f9f9;
border-left: 10px solid#4EAF47;
margin: 1.5em 10px;
padding: 0.5em 10px;
quotes: "\201C""\201D""\2018""\2019";
}
blockquote:before {
color:#4EAF47;
content: open-quote;
font-size: 4em;
line-height: 0.1em;
margin-right: 0.25em;
vertical-align: -0.4em;
}
blockquote p {
display: inline;
}
.overlay {
display: flex;
flex-direction: column;
align-items: center;
}
.news img {
display: flex;
align-items: center;
max-height: 40vh;
max-width: 100%;
margin: auto;
}
.tutorial blockquote {
background: #f9f9f9;
border-left: 10px solid#4EAF47;
margin: 1.5em 10px;
padding: 0.5em 10px;
quotes: "\201C""\201D""\2018""\2019";
}
blockquote:before {
color: #4eaf47;
content: open-quote;
font-size: 4em;
line-height: 0.1em;
margin-right: 0.25em;
vertical-align: -0.4em;
}
blockquote p {
display: inline;
}
.tutorial table,
th,
td {
border: 1px solid #ddd;
}
.tutorial th {
padding-top: 12px;
padding-bottom: 12px;
text-align: left;
border-color: #4eaf47;
color: white;
}
.overlay {
display: flex;
flex-direction: column;
align-items: center;
}
:root {
--url: url('./data/mcu_opacity.png');
}
.blocklySvg {
background-image: var(--url);
background-position: center;
background-repeat: no-repeat;
}
+24 -23
View File
@@ -1,35 +1,34 @@
import React, { Component } from 'react';
import React, { Component } from "react";
import { BrowserRouter as Router } from 'react-router-dom';
import { Router } from "react-router-dom";
import { createBrowserHistory } from "history";
import { Provider } from 'react-redux';
import store from './store';
import { loadUser } from './actions/authActions';
import { Provider } from "react-redux";
import store from "./store";
import { loadUser } from "./actions/authActions";
import './App.css';
import "./App.css";
import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles';
import { ThemeProvider, StyledEngineProvider, createTheme } from "@mui/material/styles";
import Content from './components/Content';
import Content from "./components/Content";
const theme = createMuiTheme({
const theme = createTheme({
palette: {
primary: {
main: '#4EAF47',
contrastText: '#ffffff'
main: "#4EAF47",
contrastText: "#ffffff",
},
secondary: {
main: '#DDDDDD'
main: "#DDDDDD",
},
button: {
compile: '#e27136'
}
}
compile: "#e27136",
},
},
});
class App extends Component {
componentDidMount() {
store.dispatch(loadUser());
}
@@ -37,13 +36,15 @@ class App extends Component {
render() {
const customHistory = createBrowserHistory();
return (
<ThemeProvider theme={theme}>
<Provider store={store}>
<Router history={customHistory}>
<Content />
</Router>
</Provider>
</ThemeProvider>
<StyledEngineProvider injectFirst>
<ThemeProvider theme={theme}>
<Provider store={store}>
<Router history={customHistory}>
<Content />
</Router>
</Provider>
</ThemeProvider>
</StyledEngineProvider>
);
}
}
+46 -59
View File
@@ -63,63 +63,56 @@ export const loadUser = () => (dispatch) => {
});
};
var logoutTimerId;
const timeToLogout = 14.9 * 60 * 1000; // nearly 15 minutes corresponding to the API
// Login user
export const login =
({ email, password }) =>
(dispatch) => {
dispatch({
type: USER_LOADING,
});
// Headers
const config = {
headers: {
"Content-Type": "application/json",
},
};
// Request Body
const body = JSON.stringify({ email, password });
axios
.post(`${process.env.REACT_APP_BLOCKLY_API}/user`, body, config)
.then((res) => {
// Logout automatically if refreshToken "expired"
const logoutTimer = () =>
setTimeout(() => dispatch(logout()), timeToLogout);
logoutTimerId = logoutTimer();
dispatch(setLanguage(res.data.user.language));
dispatch({
type: LOGIN_SUCCESS,
payload: res.data,
});
dispatch({
type: GET_STATUS,
payload: res.data.user.status,
});
dispatch(returnSuccess(res.data.message, res.status, "LOGIN_SUCCESS"));
})
.catch((err) => {
dispatch(
returnErrors(
err.response.data.message,
err.response.status,
"LOGIN_FAIL"
)
);
dispatch({
type: LOGIN_FAIL,
});
var status = [];
if (window.localStorage.getItem("status")) {
status = JSON.parse(window.localStorage.getItem("status"));
}
dispatch({
type: GET_STATUS,
payload: status,
});
(dispatch) => {
dispatch({
type: USER_LOADING,
});
};
// Headers
const config = {
headers: {
"Content-Type": "application/json",
},
};
// Request Body
const body = JSON.stringify({ email, password });
axios
.post(`${process.env.REACT_APP_BLOCKLY_API}/user`, body, config)
.then((res) => {
dispatch(setLanguage(res.data.user.language));
dispatch({
type: LOGIN_SUCCESS,
payload: res.data,
});
dispatch({
type: GET_STATUS,
payload: res.data.user.status,
});
dispatch(returnSuccess(res.data.message, res.status, "LOGIN_SUCCESS"));
})
.catch((err) => {
dispatch(
returnErrors(
err.response.data.message,
err.response.status,
"LOGIN_FAIL"
)
);
dispatch({
type: LOGIN_FAIL,
});
var status = [];
if (window.localStorage.getItem("status")) {
status = JSON.parse(window.localStorage.getItem("status"));
}
dispatch({
type: GET_STATUS,
payload: status,
});
});
};
// Logout User
export const logout = () => (dispatch) => {
@@ -144,7 +137,6 @@ export const logout = () => (dispatch) => {
}
dispatch(setLanguage(locale));
dispatch(returnSuccess(res.data.message, res.status, "LOGOUT_SUCCESS"));
clearTimeout(logoutTimerId);
},
error: (err) => {
dispatch(
@@ -165,7 +157,6 @@ export const logout = () => (dispatch) => {
type: GET_STATUS,
payload: status,
});
clearTimeout(logoutTimerId);
},
};
axios
@@ -222,10 +213,6 @@ export const authInterceptor = () => (dispatch, getState) => {
})
.then((res) => {
if (res.status === 200) {
clearTimeout(logoutTimerId);
const logoutTimer = () =>
setTimeout(() => dispatch(logout()), timeToLogout);
logoutTimerId = logoutTimer();
dispatch({
type: REFRESH_TOKEN_SUCCESS,
payload: res.data,
+15
View File
@@ -0,0 +1,15 @@
import {
BOARD,
} from "./types";
import mini_opacity from "../data/mini_opacity.png"
import mcu_opacity from "../data/mcu_opacity.png"
export const setBoard = (board) => (dispatch) => {
window.sessionStorage.setItem("board", board);
const root = document.querySelector(':root');
root.style.setProperty('--url', `url(${board === "mcu" ? mcu_opacity : mini_opacity})`);
dispatch({
type: BOARD,
payload: board,
});
};
+18
View File
@@ -0,0 +1,18 @@
import axios from 'axios'
const fetchSensorWikiSuccess = sensors => ({
type: 'FETCH_SENSORWIKI_SUCCESS',
payload: { sensors }
})
export const fetchSensors = () => {
return async dispatch => {
try {
let sensors = await axios.get('https://api.sensors.wiki/sensors/all')
dispatch(fetchSensorWikiSuccess(sensors.data))
}
catch(e){
console.log(e)
}
}
}
+71
View File
@@ -84,6 +84,77 @@ 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) => {
if (getState().auth.isAuthenticated) {
// update user account in database - sync with redux store
+28
View File
@@ -4,6 +4,9 @@ import {
BUILDER_CHANGE,
BUILDER_ERROR,
BUILDER_TITLE,
BUILDER_PUBLIC,
BUILDER_DIFFICULTY,
BUILDER_REVIEW,
BUILDER_ID,
BUILDER_ADD_STEP,
BUILDER_DELETE_STEP,
@@ -35,6 +38,30 @@ export const tutorialTitle = (title) => (dispatch) => {
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) => {
dispatch({
type: BUILDER_ADD_STEP,
@@ -320,6 +347,7 @@ export const readJSON = (json) => (dispatch, getState) => {
return object;
});
dispatch(tutorialTitle(json.title));
dispatch(tutorialDifficulty(json.difficulty));
dispatch(tutorialSteps(steps));
dispatch(setSubmitError());
dispatch(progress(false));
+7
View File
@@ -21,6 +21,7 @@ export const NAME = "NAME";
export const TUTORIAL_PROGRESS = "TUTORIAL_PROGRESS";
export const GET_TUTORIAL = "GET_TUTORIAL";
export const GET_TUTORIALS = "GET_TUTORIALS";
export const GET_USERTUTORIALS = "GET_USERTUTORIALS";
export const GET_STATUS = "GET_STATUS";
export const TUTORIAL_SUCCESS = "TUTORIAL_SUCCESS";
export const TUTORIAL_ERROR = "TUTORIAL_ERROR";
@@ -32,6 +33,9 @@ export const JSON_STRING = "JSON_STRING";
export const BUILDER_CHANGE = "BUILDER_CHANGE";
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_ADD_STEP = "BUILDER_ADD_STEP";
export const BUILDER_DELETE_STEP = "BUILDER_DELETE_STEP";
@@ -59,3 +63,6 @@ export const GET_PROJECT = "GET_PROJECT";
export const GET_PROJECTS = "GET_PROJECTS";
export const PROJECT_TYPE = "PROJECT_TYPE";
export const PROJECT_DESCRIPTION = "PROJECT_DESCRIPTION";
//board
export const BOARD = "BOARD";
+7 -1
View File
@@ -16,13 +16,19 @@ export const onChangeCode = () => (dispatch, getState) => {
code.arduino = Blockly.Arduino.workspaceToCode(workspace);
var xmlDom = Blockly.Xml.workspaceToDom(workspace);
code.xml = Blockly.Xml.domToPrettyText(xmlDom);
var selectedBlock = Blockly.selected
var selectedBlock = Blockly.getSelected();
if (selectedBlock !== null) {
code.helpurl = selectedBlock.helpUrl
code.tooltip = selectedBlock.tooltip
if (selectedBlock.data) {
code.data = selectedBlock.data
} else {
code.data = null
}
} else if (selectedBlock === null) {
code.tooltip = Blockly.Msg.tooltip_hint
code.helpurl = ''
code.data = null
}
+13 -18
View File
@@ -1,34 +1,29 @@
import React, { Component } from 'react';
import React, { Component } from "react";
import { withStyles } from '@material-ui/core/styles';
import { fade } from '@material-ui/core/styles/colorManipulator';
import withStyles from '@mui/styles/withStyles';
import { alpha } from "@mui/material/styles";
import Typography from '@material-ui/core/Typography';
import Typography from "@mui/material/Typography";
const styles = (theme) => ({
alert: {
marginBottom: '20px',
marginBottom: "20px",
border: `1px solid ${theme.palette.primary.main}`,
padding: '10px 20px',
borderRadius: '4px',
background: fade(theme.palette.primary.main, 0.3),
color: 'rgb(70,70,70)'
}
padding: "10px 20px",
borderRadius: "4px",
background: alpha(theme.palette.primary.main, 0.3),
color: "rgb(70,70,70)",
},
});
export class Alert extends Component {
render(){
return(
render() {
return (
<div className={this.props.classes.alert}>
<Typography>
{this.props.children}
</Typography>
<Typography>{this.props.children}</Typography>
</div>
);
}
}
export default withStyles(styles, { withTheme: true })(Alert);
+1 -1
View File
@@ -27,7 +27,7 @@ import Blockly from "blockly/core";
import "blockly/blocks";
import Toolbox from "./toolbox/Toolbox";
import { Card } from "@material-ui/core";
import { Card } from "@mui/material";
import {
ScrollOptions,
ScrollBlockDragger,
+19 -3
View File
@@ -12,6 +12,7 @@ import "./generator/index";
import { ZoomToFitControl } from "@blockly/zoom-to-fit";
import { initialXml } from "./initialXml.js";
import { getMaxInstances } from "./helpers/maxInstances";
import { Backpack } from "@blockly/workspace-backpack";
class BlocklyWindow extends Component {
constructor(props) {
@@ -35,12 +36,24 @@ class BlocklyWindow extends Component {
Blockly.svgResize(workspace);
const zoomToFit = new ZoomToFitControl(workspace);
zoomToFit.init();
// Initialize plugin.
const backpack = new Backpack(workspace);
backpack.init();
}
componentDidUpdate(props) {
const workspace = Blockly.getMainWorkspace();
var xml = this.props.initialXml;
if (props.selectedBoard !== this.props.selectedBoard) {
xml = localStorage.getItem("autoSaveXML");
// 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_);
}
// if svg is true, then the update process is done in the BlocklySvg component
if (props.initialXml !== xml && !this.props.svg) {
// guarantees that the current xml-code (this.props.initialXml) is rendered
@@ -50,8 +63,9 @@ class BlocklyWindow extends Component {
}
if (props.language !== this.props.language) {
// change language
xml = localStorage.getItem("autoSaveXML");
if (!xml) xml = initialXml;
var xmlDom = Blockly.Xml.textToDom(xml);
xmlDom = Blockly.Xml.textToDom(xml);
Blockly.Xml.clearWorkspaceAndLoadFromXml(xmlDom, workspace);
// var toolbox = workspace.getToolbox();
// workspace.updateToolbox(toolbox.toolboxDef_);
@@ -124,14 +138,16 @@ BlocklyWindow.propTypes = {
onChangeWorkspace: PropTypes.func.isRequired,
clearStats: PropTypes.func.isRequired,
renderer: PropTypes.string.isRequired,
sounds: PropTypes.string.isRequired,
sounds: PropTypes.bool.isRequired,
language: PropTypes.string.isRequired,
selectedBoard: PropTypes.string.isRequired,
};
const mapStateToProps = (state) => ({
renderer: state.general.renderer,
sounds: state.general.sounds,
language: state.general.language,
selectedBoard: state.board.board,
});
export default connect(mapStateToProps, { onChangeWorkspace, clearStats })(
+2
View File
@@ -6,9 +6,11 @@ import "./sensebox-telegram";
import "./sensebox-osem";
import "./sensebox-web";
import "./sensebox-display";
import "./sensebox-motors";
import "./sensebox-lora";
import "./sensebox-led";
import "./sensebox-rtc";
import "./sensebox-ntp";
import "./sensebox-ble";
import "./sensebox-sd";
import "./mqtt";
+2 -10
View File
@@ -45,15 +45,11 @@ Blockly.Blocks['sensebox_rgb_led'] = {
Blockly.Blocks['sensebox_ws2818_led_init'] = {
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.appendDummyInput()
.appendField(Blockly.Msg.senseBox_ws2818_rgb_led_init)
.appendField("Port:")
.appendField(new Blockly.FieldDropdown(dropdownOptions), "Port")
.appendField(new Blockly.FieldDropdown(selectedBoard().digitalPinsRGB), "Port")
this.appendValueInput("BRIGHTNESS", "brightness")
.appendField((Blockly.Msg.senseBox_ws2818_rgb_led_brightness));
this.appendValueInput("NUMBER", "number")
@@ -66,15 +62,11 @@ Blockly.Blocks['sensebox_ws2818_led_init'] = {
Blockly.Blocks['sensebox_ws2818_led'] = {
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.appendDummyInput()
.appendField(Blockly.Msg.senseBox_ws2818_rgb_led)
.appendField("Port:")
.appendField(new Blockly.FieldDropdown(dropdownOptions), "Port")
.appendField(new Blockly.FieldDropdown(selectedBoard().digitalPinsRGB), "Port")
this.appendValueInput("POSITION", "position")
.appendField((Blockly.Msg.senseBox_ws2818_rgb_led_position));
this.appendValueInput("COLOR", 'Number')
@@ -0,0 +1,144 @@
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);
},
};
@@ -0,0 +1,42 @@
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);
},
};
@@ -76,3 +76,67 @@ Blockly.Blocks["sensebox_rtc_get_timestamp"] = {
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);
},
};
@@ -26,6 +26,7 @@ Blockly.Blocks["sensebox_sensor_temp_hum"] = {
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_temp_hum_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_temp_hum_helpurl);
this.data = {name: "hdc1080", connection: "I2C"};
},
};
@@ -51,6 +52,7 @@ Blockly.Blocks["sensebox_sensor_uv_light"] = {
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_uv_light_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_uv_light_helpurl);
this.data = {name: "veml6070"};
},
};
@@ -91,6 +93,7 @@ Blockly.Blocks["sensebox_sensor_bmx055_accelerometer"] = {
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_bmx055_accelerometer_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_bmx055_helpurl);
this.data = {name: "bmx055"};
},
};
@@ -114,16 +117,15 @@ Blockly.Blocks["sensebox_sensor_sds011"] = {
)
.appendField(Blockly.Msg.senseBox_sds011_dimension)
.appendField(
new Blockly.FieldDropdown([
[Blockly.Msg.senseBox_sds011_serial1, "Serial1"],
[Blockly.Msg.senseBox_sds011_serial2, "Serial2"],
]),
new Blockly.FieldDropdown(
selectedBoard().serialSensors),
"SERIAL"
);
this.setOutput(true, Types.DECIMAL.typeName);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_sds011_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_sds011_helpurl);
this.data = {name: "sds011"};
},
};
@@ -157,6 +159,7 @@ Blockly.Blocks["sensebox_sensor_pressure"] = {
this.setOutput(true, Types.DECIMAL.typeName);
this.setTooltip(Blockly.Msg.senseBox_pressure_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_pressure_helpurl);
this.data = {name: "bmp280"};
this.getField("NAME").setValidator(
function (val) {
this.updateShape_(val === "Altitude");
@@ -188,7 +191,7 @@ Blockly.Blocks["sensebox_sensor_bme680_bsec"] = {
var dropdownOptions = [
[Blockly.Msg.senseBox_temp, "temperature"],
[Blockly.Msg.senseBox_hum, "humidity"],
[Blockly.Msg.senseBox_pressure, "pressure"],
[Blockly.Msg.senseBox_bme_pressure, "pressure"],
[Blockly.Msg.senseBox_bme_iaq, "IAQ"],
[Blockly.Msg.senseBox_bme_iaq_accuracy, "IAQAccuracy"],
[Blockly.Msg.senseBox_bme_co2, "CO2"],
@@ -203,6 +206,7 @@ Blockly.Blocks["sensebox_sensor_bme680_bsec"] = {
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_bme_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_bme680_helpurl);
this.data = {name: "bme680"};
},
};
@@ -214,12 +218,7 @@ Blockly.Blocks["sensebox_sensor_bme680_bsec"] = {
Blockly.Blocks["sensebox_sensor_ultrasonic_ranger"] = {
init: function () {
var dropdownOptions = [
[Blockly.Msg.senseBox_ultrasonic_port_A, "A"],
[Blockly.Msg.senseBox_ultrasonic_port_B, "B"],
[Blockly.Msg.senseBox_ultrasonic_port_C, "C"],
];
var dropdown = new FieldGridDropdown(dropdownOptions, function (option) {
var dropdown = new FieldGridDropdown(selectedBoard().digitalPorts, function (option) {
var input = option === "A" || option === "B" || option === "C";
this.sourceBlock_.updateShape_(input);
});
@@ -247,6 +246,7 @@ Blockly.Blocks["sensebox_sensor_ultrasonic_ranger"] = {
this.setOutput(true, Types.NUMBER.typeName);
this.setTooltip(Blockly.Msg.senseBox_ultrasonic_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_ultrasonic_helpurl);
this.data = {name: "hc-sr04"};
},
/**
* Parse XML to restore the number of pins available.
@@ -384,6 +384,7 @@ Blockly.Blocks["sensebox_scd30"] = {
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_scd_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_scd_helpurl);
this.data = {name: "scd30"};
},
onchange: function (e) {
var dropdown = this.getFieldValue("dropdown");
@@ -427,17 +428,12 @@ Blockly.Blocks["sensebox_gps"] = {
*/
Blockly.Blocks["sensebox_sensor_truebner_smt50"] = {
init: function () {
var dropdownOptions = [
[Blockly.Msg.senseBox_ultrasonic_port_A, "A"],
[Blockly.Msg.senseBox_ultrasonic_port_B, "B"],
[Blockly.Msg.senseBox_ultrasonic_port_C, "C"],
];
init: function () {
this.setColour(getColour().sensebox);
this.appendDummyInput().appendField(Blockly.Msg.senseBox_smt50);
this.appendDummyInput()
.appendField("Port:")
.appendField(new Blockly.FieldDropdown(dropdownOptions), "Port");
.appendField(new Blockly.FieldDropdown(selectedBoard().digitalPorts), "Port");
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_value)
.appendField(
@@ -450,6 +446,7 @@ Blockly.Blocks["sensebox_sensor_truebner_smt50"] = {
this.setOutput(true, Types.NUMBER.typeName);
this.setTooltip(Blockly.Msg.senseBox_smt50_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_smt50_helpurl);
this.data = {name: "smt50"};
},
};
@@ -460,18 +457,15 @@ Blockly.Blocks["sensebox_sensor_truebner_smt50"] = {
Blockly.Blocks["sensebox_sensor_watertemperature"] = {
init: function () {
var dropdownOptions = [
[Blockly.Msg.senseBox_ultrasonic_port_A, "A"],
[Blockly.Msg.senseBox_ultrasonic_port_B, "B"],
[Blockly.Msg.senseBox_ultrasonic_port_C, "C"],
];
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_watertemperature)
.appendField("Port:")
.appendField(new Blockly.FieldDropdown(dropdownOptions), "Port");
.appendField(new Blockly.FieldDropdown(selectedBoard().digitalPorts), "Port");
this.setOutput(true, Types.NUMBER.typeName);
this.setTooltip(Blockly.Msg.senseBox_watertemperature_tip);
this.data = {name: "ds18b20"};
},
};
@@ -498,16 +492,11 @@ Blockly.Blocks['sensebox_windspeed'] = {
Blockly.Blocks["sensebox_soundsensor_dfrobot"] = {
init: function () {
var dropdownOptions = [
[Blockly.Msg.senseBox_ultrasonic_port_A, "A"],
[Blockly.Msg.senseBox_ultrasonic_port_B, "B"],
[Blockly.Msg.senseBox_ultrasonic_port_C, "C"],
];
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_soundsensor_dfrobot)
.appendField("Port:")
.appendField(new Blockly.FieldDropdown(dropdownOptions), "Port");
.appendField(new Blockly.FieldDropdown(selectedBoard().digitalPorts), "Port");
this.setOutput(true, Types.DECIMAL.typeName);
this.setTooltip(Blockly.Msg.senseBox_soundsensor_dfrobot_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_soundsensor_dfrobot_helpurl);
@@ -544,6 +533,7 @@ Blockly.Blocks["sensebox_sensor_dps310"] = {
this.setOutput(true, Types.DECIMAL.typeName);
this.setTooltip(Blockly.Msg.senseBox_sensor_dps310_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_sensor_dps310_helpurl);
this.data = {name: "dps310"};
this.getField("NAME").setValidator(
function (val) {
this.updateShape_(val === "Altitude");
@@ -564,3 +554,31 @@ 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);
},
};
+2 -2
View File
@@ -9,10 +9,10 @@ Blockly.Blocks["variables_set_dynamic"] = {
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.appendValueInput("VALUE")
.appendField("set", "set")
.appendField(Blockly.Msg.variables_set, Blockly.Msg.variables_set)
.appendField("", "type")
.appendField(new Blockly.FieldVariable("VAR"), "VAR")
.appendField("to");
.appendField(Blockly.Msg.variables_to);
},
onchange: function (e) {
let variableID = this.getFieldValue("VAR");
@@ -148,53 +148,7 @@ Blockly["Arduino"].init = function (workspace) {
// 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,10 +5,12 @@ import "./sensebox-telegram";
import "./sensebox-osem";
import "./sensebox-web";
import "./sensebox-display";
import "./sensebox-motors";
import "./sensebox-lora";
import "./sensebox-led";
import "./sensebox";
import "./sensebox-rtc";
import "./sensebox-ntp";
import "./sensebox-ble";
import "./sensebox-sd";
import "./mqtt";
+9 -4
View File
@@ -275,10 +275,15 @@ Blockly.Arduino["math_change"] = function (block) {
"DELTA",
Blockly.Arduino.ORDER_ADDITIVE
) || "0";
var varName = Blockly.Arduino.nameDB_.getName(
block.getFieldValue("VAR"),
Blockly.Variables.NAME_TYPE
);
var id = block.getFieldValue("VAR")
const varName = Blockly.Variables.getVariable(
Blockly.getMainWorkspace(),
id
).name;
// var varName = Blockly.Arduino.nameDB_.getName(
// block.getFieldValue("VAR"),
// Blockly.Variables.NAME_TYPE
// );
return varName + " += " + argument0 + ";\n";
};
@@ -101,7 +101,6 @@ Blockly.Arduino.sensebox_phyphox_graph = function () {
Blockly.Arduino.sensebox_phyphox_experiment_send = function () {
var branch = Blockly.Arduino.statementToCode(this, "sendValues");
var blocks = this.getDescendants();
console.log(blocks);
var count = 0;
if (blocks !== undefined) {
for (var i = 0; i < blocks.length; i++) {
@@ -115,7 +114,6 @@ Blockly.Arduino.sensebox_phyphox_experiment_send = function () {
var string = "";
for (var j = 1; j <= count; j++) {
console.log("append");
if (string === "") {
string += `channel${j}`;
} else if (string !== "") {
@@ -0,0 +1,77 @@
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;
};
@@ -0,0 +1,19 @@
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];
};
@@ -94,3 +94,46 @@ uint8_t sec, min, hour, day, month;
var code = `getTimeStamp()`;
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,6 +203,5 @@ Blockly.Arduino.sensebox_sd_save_for_osem = function (block) {
Blockly.Arduino.definitions_["SENSOR_ID" + id + ""] =
"const char SENSOR_ID" + id + '[] PROGMEM = "' + sensor_id + '";';
code += "addMeasurement(SENSOR_ID" + id + "," + sensor_value + ");\n";
console.log(code);
return code;
};
@@ -429,11 +429,13 @@ Blockly.Arduino.sensebox_scd30 = function () {
"#include <SparkFun_SCD30_Arduino_Library.h> // http://librarymanager/All#SparkFun_SCD30_Arduino_Library";
Blockly.Arduino.definitions_["SCD30"] = "SCD30 airSensor;";
Blockly.Arduino.setupCode_["init_scd30"] = ` Wire.begin();
if (airSensor.begin() == false)
{
while (1)
;
}`;
if (airSensor.begin() == false)
{
while (1)
;
}`;
Blockly.Arduino.setupCode_["scd30_staleData"] =
"airSensor.useStaleData(true);";
var code = "";
switch (dropdown) {
case "temperature":
@@ -692,3 +694,57 @@ Blockly.Arduino.sensebox_sensor_dps310 = function () {
}
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,4 +1,12 @@
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*/
Blockly.Arduino.sensebox_wifi = function (block) {
@@ -110,3 +118,5 @@ Blockly.Arduino.sensebox_ethernetIp = function () {
var code = "Ethernet.localIP()";
return [code, Blockly.Arduino.ORDER_ATOMIC];
};
+31 -34
View File
@@ -2,10 +2,17 @@ import Blockly from "blockly";
const setVariableFunction = function (defaultValue) {
return function (block) {
const variableName = Blockly["Arduino"].nameDB_.getName(
block.getFieldValue("VAR"),
Blockly.Variables.NAME_TYPE
);
var id = block.getFieldValue("VAR");
const variableName = Blockly.Variables.getVariable(
Blockly.getMainWorkspace(),
id
).name;
// const variableName = Blockly["Arduino"].nameDB_.getName(
// id,
// Blockly.Variables.NAME_TYPE
// );
const variableValue = Blockly["Arduino"].valueToCode(
block,
"VALUE",
@@ -17,42 +24,32 @@ const setVariableFunction = function (defaultValue) {
.getAllVariables();
const myVar = allVars.filter((v) => v.name === variableName)[0];
var code = "";
switch (myVar.type) {
default:
Blockly.Arduino.variables_[variableName + myVar.type] =
myVar.type + " " + myVar.name + ";\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;
if (myVar !== undefined) {
Blockly.Arduino.variables_[variableName + myVar.type] =
myVar.type + " " + myVar.name + ";\n";
code = variableName + " = " + (variableValue || defaultValue) + ";\n";
}
return code;
};
};
const getVariableFunction = function (block) {
const variableName = Blockly["Arduino"].nameDB_.getName(
block.getFieldValue("VAR"),
Blockly.Variables.NAME_TYPE
);
var code = variableName;
var id = block.getFieldValue("VAR");
const variableName = Blockly.Variables.getVariable(
Blockly.getMainWorkspace(),
id
).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];
};
+141 -4
View File
@@ -13,6 +13,11 @@ const sensebox_mcu = {
["C5", "5"],
["C6", "6"],
],
digitalPorts: [
["A", "A"],
["B", "B"],
["C", "C"],
],
digitalPinsLED: [
["BUILTIN_1", "7"],
["BUILTIN_2", "8"],
@@ -23,6 +28,11 @@ const sensebox_mcu = {
["C5", "5"],
["C6", "6"],
],
digitalPinsRGB: [
["A", "1"],
["B", "3"],
["C", "5"],
],
digitalPinsButton: [
["on Board", "0"],
["A1", "1"],
@@ -41,9 +51,13 @@ const sensebox_mcu = {
["C6", "6"],
],
serial: [
["serial", "SerialUSB"],
["serial_1", "Serial1"],
["serial_2", "Serial2"],
["SerialUSB", "SerialUSB"],
["Serial1", "Serial1"],
["Serial2", "Serial2"],
],
serialSensors: [
["Serial1", "Serial1"],
["Serial2", "Serial2"],
],
serialPins: {
SerialUSB: [
@@ -126,6 +140,129 @@ const sensebox_mcu = {
parseKey: "_*_",
};
//senseBox MCU mini
const sensebox_mini = {
description: "senseBox Mini",
compilerFlag: "arduino:samd",
digitalPins: [
["IO1", "1"],
["IO2", "2"],
],
digitalPorts: [
["IO1-2", "A"],
],
digitalPinsLED: [
["BUILTIN_1", "7"],
["BUILTIN_2", "8"],
["IO1", "1"],
["IO2", "2"],
],
digitalPinsRGB: [
["on Board", "6"],
["IO1-2", "1"],
],
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 = () => {
return sensebox_mcu;
return board;
};
+1
View File
@@ -14,6 +14,7 @@ const colours = {
serial: 230,
webserver: 40,
phyphox: 25,
motors: 190,
};
export const getColour = () => {
@@ -13,6 +13,8 @@ const maxInstances = {
sensebox_lora_initialize_otaa: 1,
sensebox_lora_initialize_abp: 1,
sensebox_phyphox_init: 1,
sensebox_phyphox_experiment: 1,
sensebox_phyphox_experiment_send: 1,
sensebox_ethernet: 1,
};
+31 -19
View File
@@ -1,6 +1,6 @@
/**
* @license
*
*
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,39 +21,51 @@
* @author samelh@google.com (Sam El-Husseini)
*/
import React from 'react';
import BlocklyComponent from './BlocklyComponent';
import React from "react";
import BlocklyComponent from "./BlocklyComponent";
export default BlocklyComponent;
const Block = (p) => {
const { children, ...props } = p;
props.is = "blockly";
return React.createElement("block", props, children);
const { children, ...props } = p;
props.is = "blockly";
return React.createElement("block", props, children);
};
const Category = (p) => {
const { children, ...props } = p;
props.is = "blockly";
return React.createElement("category", props, children);
const { children, ...props } = p;
props.is = "blockly";
return React.createElement("category", props, children);
};
const Value = (p) => {
const { children, ...props } = p;
props.is = "blockly";
return React.createElement("value", props, children);
const { children, ...props } = p;
props.is = "blockly";
return React.createElement("value", props, children);
};
const Field = (p) => {
const { children, ...props } = p;
props.is = "blockly";
return React.createElement("field", props, children);
const { children, ...props } = p;
props.is = "blockly";
return React.createElement("field", props, children);
};
const Shadow = (p) => {
const { children, ...props } = p;
props.is = "blockly";
return React.createElement("shadow", props, children);
const { children, ...props } = p;
props.is = "blockly";
return React.createElement("shadow", props, children);
};
export { Block, Category, Value, Field, Shadow }
const Sep = (p) => {
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 };
+4
View File
@@ -7,10 +7,12 @@ import { LOOPS } from "./de/loops";
import { MATH } from "./de/math";
import { MQTT } from "./de/mqtt";
import { DISPLAY } from "./de/sensebox-display";
import { MOTORS } from "./de/sensebox-motors";
import { LED } from "./de/sensebox-led";
import { LORA } from "./de/sensebox-lora";
import { OSEM } from "./de/sensebox-osem";
import { RTC } from "./de/sensebox-rtc";
import { NTP } from "./de/sensebox-ntp";
import { SD } from "./de/sensebox-sd";
import { SENSORS } from "./de/sensebox-sensors";
import { SENSEBOX } from "./de/sensebox";
@@ -34,10 +36,12 @@ export const De = {
...MATH,
...MQTT,
...DISPLAY,
...MOTORS,
...LED,
...LORA,
...OSEM,
...RTC,
...NTP,
...SD,
...SENSORS,
...SENSEBOX,
@@ -0,0 +1,48 @@
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",
};
@@ -0,0 +1,11 @@
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)",
};
+22 -4
View File
@@ -1,14 +1,14 @@
export const RTC = {
sensebox_rtc_init: "Initialisiere RTC",
sensebox_rtc_init: "Initialisiere externe RTC",
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.",
sensebox_rtc_set: "Setze Uhrzeit/Datum der RTC",
sensebox_rtc_set: "Setze Uhrzeit/Datum der externen RTC",
sensebox_rtc_set_tooltip:
"Stellt die Uhrzeit der RTC ein. Beachte, dass du diesen Block im Setup ausführst.",
sensebox_rtc_get_timestamp: "Zeitstempel (RFC 3339)",
sensebox_rtc_get_timestamp: "Zeitstempel externe RTC (RFC 3339)",
sensebox_rtc_get_timestamp_tooltip:
"Gibt dir einen in ISO 8601 formatierten Zeitstempel zurück. Bsp: 2021-12-24T18:21Z",
sensebox_rtc_get: "Wert: ",
sensebox_rtc_get: "Wert (externe RTC): ",
sensebox_rtc_get_tooltip: "Gibt dir den ausgewählten Wert zurück.",
sensebox_rtc_second: "Sekunden",
sensebox_rtc_minutes: "Minuten",
@@ -16,4 +16,22 @@ export const RTC = {
sensebox_rtc_day: "Tag",
sensebox_rtc_month: "Monat",
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",
};
@@ -140,6 +140,7 @@ Wenn die maximale Distanz überschritten wird, wird ein Wert von **O** ausgegebe
senseBox_bme_iaq: "Innenraumluftqualität (IAQ)",
senseBox_bme_iaq_accuracy: "Kalibrierungswert",
senseBox_bme_co2: "CO2 Äquivalent",
senseBox_bme_pressure: "Luftdruck in Pa",
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.
Den Status der Kalibrierung kann über den Kalibrierungswert abgelesen werden. Er ist entweder 0, 1, 2 oder 3 und sagt folgendes aus:
@@ -175,7 +176,7 @@ Die Messwerte für Temperatur, Luftfeuchtigkeit und Luftdruck können direkt ver
* Feinstaubsensor (SDS011)
*/
senseBox_sds011: "Feinstaubsensor",
senseBox_sds011: "Feinstaubsensor SDS011",
senseBox_sds011_dimension: "in µg/m³ an",
senseBox_sds011_pm25: "PM2.5",
senseBox_sds011_pm10: "PM10",
@@ -200,4 +201,23 @@ 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
- "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: "",
};
/**
* 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/",
};
+51 -3
View File
@@ -8,20 +8,27 @@ export const UI = {
toolbox_math: "Mathematik",
toolbox_io: "Eingang/Ausgang",
toolbox_time: "Zeit",
toolbox_rtc: "RTC",
toolbox_ntp: "NTP",
toolbox_functions: "Funktionen",
toolbox_variables: "Variablen",
toolbox_serial: "Seriell",
toolbox_advanced: "Erweitert",
toolbox_motors: "Motoren",
toolbox_label_externalRTC: "Externe RTC",
toolbox_label_internalRTC: "Interne RTC",
variable_NUMBER: "Zahl (int)",
variable_SHORT_NUMBER: "char",
variable_LONG: "große Zahl (long)",
variable_DECIMAL: "Kommazahl (float)",
variables_TEXT: "Text (string)",
variables_ARRAY: "Array (array)",
variables_CHARACTER: "char (char)",
variables_CHARACTER: "Buchstabe (char)",
variables_BOOLEAN: "Boolean (boolean)",
variables_NULL: "void (void)",
variables_UNDEF: "undefined",
variables_set: "Schreibe",
variables_to: "",
/**
* Tooltips
@@ -141,6 +148,7 @@ export const UI = {
button_cancel: "Abbrechen",
button_close: "Schließen",
button_save: "Speichern",
button_accept: "Bestätigen",
button_compile: "Kompilieren",
button_create_variableCreate: "Erstelle Variable",
@@ -148,6 +156,7 @@ export const UI = {
button_next: "nächster Schritt",
button_tutorial_overview: "Tutorial Übersicht",
button_login: "Anmelden",
button_createVariable: "Typisierte Variable erstellen",
/**
*
@@ -181,7 +190,8 @@ export const UI = {
settings_sounds: "Töne",
settings_sounds_text:
"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
*/
@@ -228,6 +238,12 @@ export const UI = {
builder_requirements_head: "Voraussetzungen",
builder_requirements_order:
"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
@@ -241,7 +257,7 @@ export const UI = {
/**
* Navbar
*/
navbar_blockly: "Blockly",
navbar_tutorials: "Tutorials",
navbar_tutorialbuilder: "Tutorial erstellen",
navbar_gallery: "Galerie",
@@ -282,4 +298,36 @@ export const UI = {
drawer_ideerror_head: "Hoppla da ist was schief gegangen.",
drawer_ideerror_text:
"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",
/**
* Sensor Markdown Information
*/
sensorinfo_info: "Informationen zum Sensor",
sensorinfo_description: "Beschreibung",
sensorinfo_measurable_phenos: "Messbare Phänomene",
sensorinfo_manufacturer: "Hersteller",
sensorinfo_lifetime: "Lebensdauer",
sensorinfo_explanation: "Diese Informationen wurden aus [sensors.wiki](https://sensors.wiki) entnommen. Für weitere Informationen besuchen Sie den Abschnitt über diesen Sensor "
};
+4
View File
@@ -8,10 +8,12 @@ import { MATH } from "./en/math";
import { MQTT } from "./en/mqtt";
import { SENSEBOX } from "./en/sensebox";
import { DISPLAY } from "./en/sensebox-display";
import { MOTORS } from "./en/sensebox-motors";
import { LED } from "./en/sensebox-led";
import { LORA } from "./en/sensebox-lora";
import { OSEM } from "./en/sensebox-osem";
import { RTC } from "./en/sensebox-rtc";
import { NTP } from "./en/sensebox-ntp";
import { SD } from "./en/sensebox-sd";
import { SENSORS } from "./en/sensebox-sensors";
import { TELEGRAM } from "./en/sensebox-telegram";
@@ -34,10 +36,12 @@ export const En = {
...MATH,
...MQTT,
...DISPLAY,
...MOTORS,
...LED,
...LORA,
...OSEM,
...RTC,
...NTP,
...SD,
...SENSORS,
...SENSEBOX,
@@ -0,0 +1,48 @@
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",
};
@@ -0,0 +1,10 @@
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)",
};
+20 -2
View File
@@ -1,11 +1,11 @@
export const RTC = {
sensebox_rtc_init: "Initialise RTC",
sensebox_rtc_init: "Initialise external RTC",
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.",
sensebox_rtc_set: "Set RTC time/date:",
sensebox_rtc_set_tooltip:
"Sets the time of the RTC. Note that you execute this block in the setup.",
sensebox_rtc_get_timestamp: "Get timestamp",
sensebox_rtc_get_timestamp: "Timestamp external RTC (RFC 3339)",
sensebox_rtc_get_timestamp_tooltip:
"Returns a timestamp formatted in ISO 8601. Ex: 2021-12-24T18:21Z",
sensebox_rtc_get_tooltip: "Returns the selected value",
@@ -17,4 +17,22 @@ export const RTC = {
sensebox_rtc_day: "day",
sensebox_rtc_month: "month",
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",
};
@@ -141,6 +141,7 @@ If the max distance is reached the a value of **O** will be returned`,
senseBox_bme680: "Environmental sensor (BME680)",
senseBox_bme_iaq: "Indoor Air Quality (IAQ)",
senseBox_bme_iaq_accuracy: "Calibration Value",
senseBox_bme_pressure: "Airpressure in Pa",
senseBox_bme_co2: "CO2 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.
@@ -205,4 +206,23 @@ The measured values for temperature, humidity and air pressure can be used direc
*
*/
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/",
};
+53 -3
View File
@@ -8,20 +8,27 @@ export const UI = {
toolbox_math: "Math",
toolbox_io: "Input/Output",
toolbox_time: "Time",
toolbox_rtc: "RTC",
toolbox_ntp: "NTP",
toolbox_functions: "Functions",
toolbox_variables: "Variables",
toolbox_serial: "Serial",
toolbox_advanced: "Erweitert",
toolbox_motors: "Motors",
toolbox_label_externalRTC: "External RTC",
toolbox_label_internalRTC: "Internal RTC",
variable_NUMBER: "Number (int)",
variable_SHORT_NUMBER: "char",
variable_LONG: " Zahl (long)",
variable_LONG: "Big number (long)",
variable_DECIMAL: "Decimal (float)",
variables_TEXT: "Text (string)",
variables_ARRAY: "Array (array)",
variables_CHARACTER: "char (char)",
variables_CHARACTER: "Character (char)",
variables_BOOLEAN: "Boolean (boolean)",
variables_NULL: "void (void)",
variables_UNDEF: "undefined",
variables_set: "set",
variables_to: "to",
/**
* Tooltips
@@ -144,6 +151,7 @@ export const UI = {
button_next: "Next step",
button_tutorial_overview: "Tutorial overview",
button_login: "Login",
button_createVariable: "Create Typed Variable",
/**
*
@@ -176,6 +184,8 @@ export const UI = {
settings_sounds: "Sound",
settings_sounds_text:
"Enable or disable sounds when adding and deleting blocks. Disabled by default",
settings_board: "Board",
settings_board_text: "Choose your board",
/**
* 404
@@ -222,6 +232,12 @@ export const UI = {
builder_requirements_head: "Requirements.",
builder_requirements_order:
"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
@@ -237,7 +253,7 @@ export const UI = {
/**
* Navbar
*/
navbar_blockly: "Blockly",
navbar_tutorials: "Tutorials",
navbar_tutorialbuilder: "Create tutorial",
navbar_gallery: "Gallery",
@@ -277,4 +293,38 @@ export const UI = {
*/
drawer_ideerror_head: "Oops something went wrong",
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 Selection
* */
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",
/**
* Sensor Markdown Information
* */
sensorinfo_info: "Informationen regarding the Sensor",
sensorinfo_description: "Description",
sensorinfo_measurable_phenos: "Measurable Phenomena",
sensorinfo_manufacturer: "Manufacturer",
sensorinfo_lifetime: "Lifetime",
sensorinfo_explanation: "This information was fetched from [sensors.wiki](https://sensors.wiki). For more information visit the section on this sensor ",
};
+92 -43
View File
@@ -1,5 +1,5 @@
import React from "react";
import { Block, Value, Field, Shadow, Category } from "../";
import { Block, Value, Field, Shadow, Category, Sep, Label } from "../";
import { getColour } from "../helpers/colour";
import "@blockly/block-plus-minus";
import { TypedVariableModal } from "@blockly/plugin-typed-variable-modal";
@@ -16,16 +16,12 @@ class Toolbox extends React.Component {
this.props.workspace,
"callbackName",
[
[`${Blockly.Msg.variable_SHORT_NUMBER}`, "char"],
[`${Blockly.Msg.variable_NUMBER}`, "int"],
[`${Blockly.Msg.variable_LONG}`, "long"],
[`${Blockly.Msg.variable_DECIMAL}`, "float"],
[`${Blockly.Msg.variables_TEXT}`, "String"],
[`${Blockly.Msg.variables_ARRAY}`, "Array"],
[`${Blockly.Msg.variables_CHARACTER}`, "char"],
[`${Blockly.Msg.variables_BOOLEAN}`, "boolean"],
[`${Blockly.Msg.variables_NULL}`, "void"],
[`${Blockly.Msg.variables_UNDEF}`, "undefined"],
]
);
typedVarModal.init();
@@ -36,7 +32,7 @@ class Toolbox extends React.Component {
// Add your button and give it a callback name.
const button = document.createElement("button");
button.setAttribute("text", "Create Typed Variable");
button.setAttribute("text", Blockly.Msg.button_createVariable);
button.setAttribute("callbackKey", "callbackName");
xmlList.push(button);
@@ -44,6 +40,7 @@ class Toolbox extends React.Component {
// This gets all the variables that the user creates and adds them to the
// flyout.
const blockList = Blockly.VariablesDynamic.flyoutCategoryBlocks(workspace);
console.log(blockList);
xmlList = xmlList.concat(blockList);
return xmlList;
}
@@ -64,6 +61,7 @@ class Toolbox extends React.Component {
<Block type="sensebox_sensor_uv_light" />
<Block type="sensebox_sensor_bmx055_accelerometer" />
<Block type="sensebox_sensor_sds011" />
<Block type="sensebox_sensor_sps30" />
<Block type="sensebox_sensor_pressure" />
<Block type="sensebox_sensor_dps310" />
<Block type="sensebox_sensor_bme680_bsec" />
@@ -298,6 +296,7 @@ class Toolbox extends React.Component {
</Value>
</Block>
</Category>
{/* <Category name="Telegram" colour={getColour().sensebox}>
<Block type="sensebox_telegram" />
<Block type="sensebox_telegram_do" />
@@ -504,42 +503,63 @@ class Toolbox extends React.Component {
<Block type="time_micros"></Block>
<Block type="infinite_loop"></Block>
<Block type="sensebox_interval_timer"></Block>
<Block type="sensebox_rtc_init"></Block>
<Block type="sensebox_rtc_set">
<Value name="second">
<Block type="math_number">
<Field name="NUM">00</Field>
</Block>
</Value>
<Value name="minutes">
<Block type="math_number">
<Field name="NUM">00</Field>
</Block>
</Value>
<Value name="hour">
<Block type="math_number">
<Field name="NUM">00</Field>
</Block>
</Value>
<Value name="day">
<Block type="math_number">
<Field name="NUM">01</Field>
</Block>
</Value>
<Value name="month">
<Block type="math_number">
<Field name="NUM">01</Field>
</Block>
</Value>
<Value name="year">
<Block type="math_number">
<Field name="NUM">1970</Field>
</Block>
</Value>
</Block>
{/* <Block type="sensebox_rtc_set_ntp"></Block> */}
<Block type="sensebox_rtc_get"></Block>
<Block type="sensebox_rtc_get_timestamp"></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_set">
<Value name="second">
<Block type="math_number">
<Field name="NUM">00</Field>
</Block>
</Value>
<Value name="minutes">
<Block type="math_number">
<Field name="NUM">00</Field>
</Block>
</Value>
<Value name="hour">
<Block type="math_number">
<Field name="NUM">00</Field>
</Block>
</Value>
<Value name="day">
<Block type="math_number">
<Field name="NUM">01</Field>
</Block>
</Value>
<Value name="month">
<Block type="math_number">
<Field name="NUM">01</Field>
</Block>
</Value>
<Value name="year">
<Block type="math_number">
<Field name="NUM">1970</Field>
</Block>
</Value>
</Block>
{/* <Block type="sensebox_rtc_set_ntp"></Block> */}
<Block type="sensebox_rtc_get"></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
id="math"
@@ -613,7 +633,6 @@ class Toolbox extends React.Component {
colour={getColour().procedures}
custom="PROCEDURE"
></Category>
<sep></sep>
<Category name={Blockly.Msg.toolbox_advanced} colour={getColour().io}>
<Category
name={Blockly.Msg.toolbox_serial}
@@ -645,6 +664,36 @@ class Toolbox extends React.Component {
</Value>
</Block>
</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}>
<Block type="watchdog_enable"></Block>
<Block type="watchdog_reset"></Block>
+4 -4
View File
@@ -3,9 +3,9 @@ import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import clsx from 'clsx';
import { withStyles } from '@material-ui/core/styles';
import MaterialUIBreadcrumbs from '@material-ui/core/Breadcrumbs';
import Typography from '@material-ui/core/Typography';
import withStyles from '@mui/styles/withStyles';
import MaterialUIBreadcrumbs from '@mui/material/Breadcrumbs';
import Typography from '@mui/material/Typography';
import { faHome } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
@@ -30,7 +30,7 @@ class Breadcrumbs extends Component {
this.props.content && this.props.content.length > 0 ?
<MaterialUIBreadcrumbs separator="" style={{marginBottom: '20px'}}>
<Link to={'/'} style={{textDecoration: 'none'}}>
<FontAwesomeIcon className={clsx(this.props.classes.home, this.props.classes.hover)} icon={faHome} size="xs"/>
<FontAwesomeIcon className={clsx(this.props.classes.home, this.props.classes.hover)} icon={faHome} size="xs"/>
</Link>
{this.props.content.splice(0, this.props.content.length-1).map((content, i) => (
<Link to={content.link} style={{textDecoration: 'none'}} key={i}>
+281
View File
@@ -0,0 +1,281 @@
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 "@mui/material";
import Blockly from "blockly/core";
import Divider from "@mui/material/Divider";
import { saveAs } from "file-saver";
import Drawer from "@mui/material/Drawer";
import Sidebar from "./Sidebar";
import Dialog from "../Dialog";
import SaveIcon from "./SaveIcon";
import store from "../../store";
import DeviceSelection from "../DeviceSelection";
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>
<DeviceSelection />
<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);
+333
View File
@@ -0,0 +1,333 @@
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 '@mui/styles/withStyles';
import Button from "@mui/material/Button";
import Backdrop from "@mui/material/Backdrop";
import CircularProgress from "@mui/material/CircularProgress";
import IconButton from "@mui/material/IconButton";
import Tooltip from "@mui/material/Tooltip";
import Divider from "@mui/material/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 "@mui/material/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()}
size="large">
<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)
);
+42
View File
@@ -0,0 +1,42 @@
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCircleNotch, faSave } from "@fortawesome/free-solid-svg-icons";
import Tooltip from "@mui/material/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;
@@ -0,0 +1,91 @@
import { useState } from "react";
import Button from "@mui/material/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;
+140
View File
@@ -0,0 +1,140 @@
import React from "react";
import Blockly from "blockly";
import { useSelector } from "react-redux";
import Accordion from "@mui/material/Accordion";
import AccordionSummary from "@mui/material/AccordionSummary";
import AccordionDetails from "@mui/material/AccordionDetails";
import Typography from "@mui/material/Typography";
import { LibraryVersions } from "../../data/versions.js";
import { useMonaco } from "@monaco-editor/react";
import { Button } from "@mui/material";
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;
+105 -60
View File
@@ -1,30 +1,27 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import Prism from "prismjs";
import "prismjs/themes/prism.css";
import "prismjs/plugins/line-numbers/prism-line-numbers";
import "prismjs/plugins/line-numbers/prism-line-numbers.css";
import withWidth from '@material-ui/core/withWidth';
import { withStyles } from '@material-ui/core/styles';
import MuiAccordion from '@material-ui/core/Accordion';
import MuiAccordionSummary from '@material-ui/core/AccordionSummary';
import MuiAccordionDetails from '@material-ui/core/AccordionDetails';
import { Card } from '@material-ui/core';
import * as Blockly from 'blockly'
import withStyles from '@mui/styles/withStyles';
import MuiAccordion from "@mui/material/Accordion";
import MuiAccordionSummary from "@mui/material/AccordionSummary";
import MuiAccordionDetails from "@mui/material/AccordionDetails";
import { Card } from "@mui/material";
import * as Blockly from "blockly";
import { default as MonacoEditor } from "@monaco-editor/react";
// FIXME checkout https://mui.com/components/use-media-query/#migrating-from-withwidth
const withWidth = () => (WrappedComponent) => (props) => <WrappedComponent {...props} width="xs" />;
const Accordion = withStyles((theme) => ({
root: {
border: `1px solid ${theme.palette.secondary.main}`,
boxShadow: 'none',
'&:before': {
display: 'none',
boxShadow: "none",
"&:before": {
display: "none",
},
'&$expanded': {
margin: 'auto',
"&$expanded": {
margin: "auto",
},
},
expanded: {},
@@ -34,15 +31,15 @@ const AccordionSummary = withStyles((theme) => ({
root: {
backgroundColor: theme.palette.secondary.main,
borderBottom: `1px solid white`,
marginBottom: '-1px',
minHeight: '50px',
'&$expanded': {
minHeight: '50px',
marginBottom: "-1px",
minHeight: "50px",
"&$expanded": {
minHeight: "50px",
},
},
content: {
'&$expanded': {
margin: '12px 0',
"&$expanded": {
margin: "12px 0",
},
},
expanded: {},
@@ -54,40 +51,60 @@ const AccordionDetails = withStyles((theme) => ({
},
}))(MuiAccordionDetails);
class CodeViewer extends Component {
constructor(props) {
super(props);
this.state = {
code: this.props.arduino,
changed: false,
expanded: true,
componentHeight: null
componentHeight: null,
};
this.myDiv = React.createRef();
}
componentDidMount() {
Prism.highlightAll();
this.setState({ componentHeight: this.myDiv.current.offsetHeight + 'px' });
this.setState({ componentHeight: this.myDiv.current.offsetHeight + "px" });
}
componentDidUpdate(props, state) {
if (this.myDiv.current && this.myDiv.current.offsetHeight + 'px' !== this.state.componentHeight) {
this.setState({ componentHeight: this.myDiv.current.offsetHeight + 'px' });
componentDidUpdate(prevProps, prevState) {
// if (this.props.arduino !== prevProps.arduino) {
// this.setState({ changed: true });
// console.log(`code changed: ${this.state.changed}`);
// if (this.state.changed && prevState.code !== this.props.arduino) {
// this.setState({ code: this.props.arduino });
// this.setState({ changed: false });
// }
// if (this.state.code !== prevState.code && this.state.changed) {
// this.setState({ changed: false });
// }
// if (this.props.arduino !== this.state.code) {
// this.setState({ changed: true });
// //this.setState({ code: this.props.arduino });
// }
if (
this.myDiv.current &&
this.myDiv.current.offsetHeight + "px" !== this.state.componentHeight
) {
this.setState({
componentHeight: this.myDiv.current.offsetHeight + "px",
});
}
Prism.highlightAll();
}
onChange = () => {
this.setState({ expanded: !this.state.expanded });
}
};
render() {
var curlyBrackets = '{ }';
var unequal = '<>';
var curlyBrackets = "{ }";
var unequal = "<>";
return (
<Card style={{ height: '100%', maxHeight: '60vH' }} ref={this.myDiv}>
<Card style={{ height: "100%", maxHeight: "60vH" }} ref={this.myDiv}>
<Accordion
square={true}
style={{ margin: 0 }}
@@ -95,15 +112,32 @@ class CodeViewer extends Component {
onChange={this.onChange}
>
<AccordionSummary>
<b style={{ fontSize: '20px', marginRight: '5px', width: '35px' }}>{curlyBrackets}</b>
<div style={{ margin: 'auto 5px 2px 0px' }}>{Blockly.Msg.codeviewer_arduino}</div>
<b style={{ fontSize: "20px", marginRight: "5px", width: "35px" }}>
{curlyBrackets}
</b>
<div style={{ margin: "auto 5px 2px 0px" }}>
{Blockly.Msg.codeviewer_arduino}
</div>
</AccordionSummary>
<AccordionDetails style={{ padding: 0, height: `calc(${this.state.componentHeight} - 50px - 50px)`, backgroundColor: 'white' }}>
<pre className="line-numbers" style={{ paddingBottom: 0, width: '100%', overflow: 'auto', scrollbarWidth: 'thin', height: 'calc(100% - 30px)', margin: '15px 0', paddingTop: 0, whiteSpace: 'pre-wrap', backgroundColor: 'white' }}>
<code className="language-clike">
{this.props.arduino}
</code>
</pre>
<AccordionDetails
style={{
padding: 0,
height: `calc(${this.state.componentHeight} - 50px - 50px)`,
backgroundColor: "white",
}}
>
<MonacoEditor
height="80vh"
defaultLanguage="cpp"
value={this.props.arduino}
// modified={this.props.arduino}
// original={this.state.code}
options={{
readOnly: true,
fontSize: "16px",
}}
/>
</AccordionDetails>
</Accordion>
<Accordion
@@ -113,32 +147,43 @@ class CodeViewer extends Component {
onChange={this.onChange}
>
<AccordionSummary>
<b style={{ fontSize: '20px', marginRight: '5px', width: '35px' }}>{unequal}</b>
<div style={{ margin: 'auto 5px 2px 0px' }}>{Blockly.Msg.codeviewer_xml}</div>
<b style={{ fontSize: "20px", marginRight: "5px", width: "35px" }}>
{unequal}
</b>
<div style={{ margin: "auto 5px 2px 0px" }}>
{Blockly.Msg.codeviewer_xml}
</div>
</AccordionSummary>
<AccordionDetails style={{ padding: 0, height: `calc(${this.state.componentHeight} - 50px - 50px)`, backgroundColor: 'white' }}>
<pre className="line-numbers" style={{ paddingBottom: 0, width: '100%', overflow: 'auto', scrollbarWidth: 'thin', height: 'calc(100% - 30px)', margin: '15px 0', paddingTop: 0, whiteSpace: 'pre-wrap', backgroundColor: 'white' }}>
<code className="language-xml">
{`${this.props.xml}`}
</code>
</pre>
<AccordionDetails
style={{
padding: 0,
height: `calc(${this.state.componentHeight} - 50px - 50px)`,
backgroundColor: "white",
}}
>
<MonacoEditor
height="80vh"
defaultLanguage="xml"
value={this.props.xml}
readOnly={true}
/>
</AccordionDetails>
</Accordion>
</Card>
);
};
}
}
CodeViewer.propTypes = {
arduino: PropTypes.string.isRequired,
xml: PropTypes.string.isRequired,
tooltip: PropTypes.string.isRequired
tooltip: PropTypes.string.isRequired,
};
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
arduino: state.workspace.code.arduino,
xml: state.workspace.code.xml,
tooltip: state.workspace.code.tooltip
tooltip: state.workspace.code.tooltip,
});
export default connect(mapStateToProps, null)(withWidth()(CodeViewer));
+5 -1
View File
@@ -10,6 +10,7 @@ import Navbar from './Navbar';
import Footer from './Footer';
import Routes from './Route/Routes';
import Cookies from './Cookies';
import { setBoard } from './Blockly/helpers/board';
class Content extends Component {
@@ -19,6 +20,7 @@ class Content extends Component {
} else if (this.props.language === 'en_US') {
Blockly.setLocale(En);
}
setBoard(this.props.board)
}
componentDidUpdate(props) {
@@ -29,6 +31,7 @@ class Content extends Component {
Blockly.setLocale(En);
}
}
setBoard(this.props.board)
}
render() {
@@ -48,7 +51,8 @@ Content.propTypes = {
};
const mapStateToProps = state => ({
language: state.general.language
language: state.general.language,
board: state.board.board
});
export default connect(mapStateToProps, null)(Content);
+1 -1
View File
@@ -9,7 +9,7 @@ class Cookies extends Component {
return (
<CookieConsent
location="bottom"
buttonText="Okay!!"
buttonText="Okay!"
cookieName="cookieConsent"
style={{ background: "#2B373B" }}
buttonStyle={{ background: "white", color: "#4EAF47", fontSize: "1rem" }}
+133
View File
@@ -0,0 +1,133 @@
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import Dialog from "./Dialog";
import withStyles from '@mui/styles/withStyles';
import * as Blockly from "blockly";
import { IconButton, Grid, Avatar, Typography } from "@mui/material";
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) {
super(props);
this.state = {
open: props.selectedBoard ? false : true,
selectedBoard: "",
saveSettings: false,
};
}
toggleDialog = () => {
this.props.setBoard(this.state.selectedBoard)
};
onChange = (e) => {
if (e.target.checked) {
this.setState({ saveSettings: true });
} else {
this.setState({ saveSettings: false });
}
};
onclick = (e, value) => {
this.setState({ selectedBoard: value })
this.props.setBoard(value)
this.setState({ open: !this.state });
};
render() {
return (
<Dialog
style={{ zIndex: 9999999 }}
fullWidth
maxWidth={"xl"}
open={this.state.open}
title={Blockly.Msg.deviceselection_head}
content={""}
onClick={this.toggleDialog}
disabled={this.state.selectedBoard === ""}
>
<div>
<Grid container spacing={2} style={{ textAlign: "center" }}>
<Grid item xs={6}>
<IconButton onClick={(e) => this.onclick(e, "mcu")} size="large">
<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")} size="large">
<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>
<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));
+6 -6
View File
@@ -1,10 +1,10 @@
import React, { Component } from 'react';
import Button from '@material-ui/core/Button';
import DialogTitle from '@material-ui/core/DialogTitle';
import DialogContent from '@material-ui/core/DialogContent';
import DialogActions from '@material-ui/core/DialogActions';
import MaterialUIDialog from '@material-ui/core/Dialog';
import Button from '@mui/material/Button';
import DialogTitle from '@mui/material/DialogTitle';
import DialogContent from '@mui/material/DialogContent';
import DialogActions from '@mui/material/DialogActions';
import MaterialUIDialog from '@mui/material/Dialog';
class Dialog extends Component {
@@ -24,7 +24,7 @@ class Dialog extends Component {
</DialogContent>
<DialogActions>
{this.props.actions ? this.props.actions :
<Button onClick={this.props.onClick} color="primary">
<Button onClick={this.props.onClick} disabled={this.props.disabled} color="primary">
{this.props.button}
</Button>
}
+88 -165
View File
@@ -1,179 +1,102 @@
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 Typography from '@material-ui/core/Typography';
import * as Blockly from 'blockly'
import ReactMarkdown from 'react-markdown';
import Container from '@material-ui/core/Container';
import ExpansionPanel from '@material-ui/core/ExpansionPanel';
import ExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary';
import ExpansionPanelDetails from '@material-ui/core/ExpansionPanelDetails';
import Button from "@mui/material/Button";
import Typography from "@mui/material/Typography";
import * as Blockly from "blockly";
import ReactMarkdown from "react-markdown";
import rehypeRaw from "rehype-raw";
import Container from "@mui/material/Container";
import Accordion from "@mui/material/Accordion";
import AccordionSummary from "@mui/material/AccordionSummary";
import AccordionDetails from "@mui/material/AccordionDetails";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faChevronDown } from "@fortawesome/free-solid-svg-icons";
import { FaqQuestions } from '../data/faq'
import { FaqQuestions } from "../data/faq";
class Faq extends Component {
state = {
panel: "",
expanded: false,
};
state = {
panel: '',
expanded: false
}
handleChange = (panel) => {
this.setState({ panel: this.state.panel === panel ? "" : panel });
};
componentDidMount() {
// Ensure that Blockly.setLocale is adopted in the component.
// Otherwise, the text will not be displayed until the next update of the component.
handleChange = (panel) => {
this.setState({ panel: this.state.panel === panel ? '' : panel });
};
window.scrollTo(0, 0);
this.forceUpdate();
}
componentDidMount() {
// Ensure that Blockly.setLocale is adopted in the component.
// Otherwise, the text will not be displayed until the next update of the component.
window.scrollTo(0, 0)
this.forceUpdate();
}
render() {
const { panel } = this.state;
return (
<div>
<Breadcrumbs content={[{ link: this.props.location.pathname, title: 'FAQ' }]} />
<Container fixed>
<div style={{ margin: '0px 24px 0px 24px' }}>
<h1>FAQ</h1>
{FaqQuestions().map((object, i) => {
return (
<ExpansionPanel expanded={panel === `panel${i}`} onChange={() => this.handleChange(`panel${i}`)}>
<ExpansionPanelSummary
expandIcon={
<FontAwesomeIcon icon={faChevronDown} />
}
>
<Typography variant="h6">{object.question}</Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<Typography>
<ReactMarkdown className="news" allowDangerousHtml="true" children={object.answer}>
</ReactMarkdown>
</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>
}
</div>
</Container>
</div >
);
};
render() {
const { panel } = this.state;
return (
<div>
<Breadcrumbs
content={[{ link: this.props.location.pathname, title: "FAQ" }]}
/>
<Container fixed>
<div style={{ margin: "0px 24px 0px 24px" }}>
<h1>FAQ</h1>
{FaqQuestions().map((object, i) => {
return (
<Accordion
expanded={panel === `panel${i}`}
onChange={() => this.handleChange(`panel${i}`)}
>
<AccordionSummary
expandIcon={<FontAwesomeIcon icon={faChevronDown} />}
>
<Typography variant="h6">{object.question}</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography>
<ReactMarkdown
className="news"
allowDangerousHtml="true"
children={object.answer}
rehypePlugins={[rehypeRaw]}
></ReactMarkdown>
</Typography>
</AccordionDetails>
</Accordion>
);
})}
{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>
)}
</div>
</Container>
</div>
);
}
}
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>
// }}
+1 -1
View File
@@ -2,7 +2,7 @@ import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import Typography from '@material-ui/core/Typography';
import Typography from '@mui/material/Typography';
class Footer extends Component {
render() {
+20 -12
View File
@@ -11,18 +11,19 @@ import WorkspaceFunc from "./Workspace/WorkspaceFunc";
import BlocklyWindow from "./Blockly/BlocklyWindow";
import CodeViewer from "./CodeViewer";
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 IconButton from "@material-ui/core/IconButton";
import Tooltip from "@material-ui/core/Tooltip";
import { withStyles } from "@material-ui/core/styles";
import Grid from "@mui/material/Grid";
import IconButton from "@mui/material/IconButton";
import Tooltip from "@mui/material/Tooltip";
import withStyles from '@mui/styles/withStyles';
import { faCode } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import TooltipViewer from "./TooltipViewer";
import Dialog from "./Dialog";
// import Autosave from "./Workspace/AutoSave";
const styles = (theme) => ({
codeOn: {
backgroundColor: theme.palette.primary.main,
@@ -54,11 +55,11 @@ class Home extends Component {
key: "",
message: "",
open: true,
initialXml: localStorage.getItem("autoSaveXML"),
};
}
componentDidMount() {
console.log(this.props.platform);
if (this.props.platform === true) {
this.setState({ codeOn: false });
}
@@ -119,10 +120,12 @@ class Home extends Component {
<WorkspaceStats />
</div>
) : null}
<div
className="workspaceFunc"
style={{ float: "right", height: "40px", marginBottom: "20px" }}
>
{/* <Autosave /> */}
<WorkspaceFunc
project={this.props.project}
projectType={this.props.projectType}
@@ -157,10 +160,11 @@ class Home extends Component {
zIndex: 21,
}}
onClick={() => this.onChange()}
>
<FontAwesomeIcon icon={faCode} size="xs" />
size="large">
<FontAwesomeIcon icon={faCode} size="xs" />
</IconButton>
</Tooltip>
<TrashcanButtons />
<div className="blocklyWindow">
{this.props.project ? (
@@ -169,7 +173,10 @@ class Home extends Component {
initialXml={this.props.project.xml}
/>
) : (
<BlocklyWindow blocklyCSS={{ height: "80vH" }} />
<BlocklyWindow
blocklyCSS={{ height: "80vH" }}
initialXml={this.state.initialXml}
/>
)}
</div>
</Grid>
@@ -180,7 +187,8 @@ class Home extends Component {
</Grid>
) : null}
</Grid>
<HintTutorialExists />
<DeviceSelection />
{/* <HintTutorialExists /> */}
{this.props.platform ? (
<Dialog
style={{ zIndex: 9999999 }}
@@ -216,7 +224,7 @@ Home.propTypes = {
workspaceName: PropTypes.func.isRequired,
message: PropTypes.object.isRequired,
statistics: PropTypes.bool.isRequired,
platform: PropTypes.object.isRequired,
platform: PropTypes.bool.isRequired,
};
const mapStateToProps = (state) => ({
+1 -1
View File
@@ -1,6 +1,6 @@
import React, { Component } from "react";
import { withRouter } from "react-router-dom";
import Container from "@material-ui/core/Container";
import Container from "@mui/material/Container";
class Impressum extends Component {
render() {
return (
+4 -4
View File
@@ -5,8 +5,8 @@ import { workspaceChange } from '../actions/workspaceActions';
import * as Blockly from 'blockly/core';
import TextField from '@material-ui/core/TextField';
import Button from '@material-ui/core/Button';
import TextField from '@mui/material/TextField';
import Button from '@mui/material/Button';
class MaxBlocks extends Component {
@@ -28,12 +28,12 @@ class MaxBlocks extends Component {
return (
<div style={{display: 'inline', marginLeft: '10px'}}>
<TextField
variant="standard"
style={{width: '50px', marginRight: '5px'}}
name="max"
type="number"
onChange={this.onChange}
value={this.state.max}
/>
value={this.state.max} />
<Button style={{marginRight: '10px', color: 'white'}} variant="contained" color="primary" onClick={this.setMaxBlocks}>
Maximale Blöcke
</Button>
+280 -70
View File
@@ -8,19 +8,20 @@ import senseboxLogo from "./sensebox_logo.svg";
import { withRouter } from "react-router-dom";
import { withStyles } from "@material-ui/core/styles";
import Drawer from "@material-ui/core/Drawer";
import AppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar";
import List from "@material-ui/core/List";
import Typography from "@material-ui/core/Typography";
import Divider from "@material-ui/core/Divider";
import IconButton from "@material-ui/core/IconButton";
import ListItem from "@material-ui/core/ListItem";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import ListItemText from "@material-ui/core/ListItemText";
import LinearProgress from "@material-ui/core/LinearProgress";
import withStyles from '@mui/styles/withStyles';
import Drawer from "@mui/material/Drawer";
import AppBar from "@mui/material/AppBar";
import Toolbar from "@mui/material/Toolbar";
import List from "@mui/material/List";
import Typography from "@mui/material/Typography";
import Divider from "@mui/material/Divider";
import IconButton from "@mui/material/IconButton";
import ListItem from "@mui/material/ListItem";
import ListItemIcon from "@mui/material/ListItemIcon";
import ListItemText from "@mui/material/ListItemText";
import LinearProgress from "@mui/material/LinearProgress";
import Tour from "reactour";
import { Badge } from "@mui/material";
import { home, assessment } from "./Tour";
import {
faBars,
@@ -34,10 +35,22 @@ import {
faChalkboardTeacher,
faTools,
faLightbulb,
faCode,
faPuzzlePiece,
faUser,
faMicrochip,
faEarthEurope,
faEarthAmericas,
faCaretDown
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import * as Blockly from "blockly";
import Tooltip from "@material-ui/core/Tooltip";
import Tooltip from "@mui/material/Tooltip";
import MenuItem from '@mui/material/MenuItem'
import Menu from '@mui/material/Menu'
import { setLanguage } from "../actions/generalActions";
import { setBoard } from "../actions/boardAction";
import { Button } from "@mui/material";
const styles = (theme) => ({
drawerWidth: {
@@ -57,9 +70,14 @@ const styles = (theme) => ({
class Navbar extends Component {
constructor(props) {
super(props);
this.langRef = React.createRef();
this.mcuRef = React.createRef();
this.state = {
open: false,
isTourOpen: false,
anchorElLang: null,
anchorElBoard: null,
anchorElUser: null
};
}
@@ -77,7 +95,6 @@ class Navbar extends Component {
render() {
var isHome = /^\/(\/.*$|$)/g.test(this.props.location.pathname);
var isTutorial = /^\/tutorial(\/.*$|$)/g.test(this.props.location.pathname);
var isAssessment =
/^\/tutorial\/.{1,}$/g.test(this.props.location.pathname) &&
!this.props.tutorialIsLoading &&
@@ -113,7 +130,7 @@ class Navbar extends Component {
onClick={this.toggleDrawer}
style={{ margin: "0 10px" }}
className="MenuButton"
>
size="large">
<FontAwesomeIcon icon={faBars} />
</IconButton>
<Link to={"/"} style={{ textDecoration: "none", color: "inherit" }}>
@@ -124,55 +141,226 @@ class Navbar extends Component {
<Link to={"/"} style={{ marginLeft: "10px" }}>
<img src={senseboxLogo} alt="senseBox-Logo" width="30" />
</Link>
{isTutorial ? (
<Link
to={"/tutorial"}
style={{
textDecoration: "none",
color: "inherit",
marginLeft: "10px",
<div style={{ margin: "0 0 0 auto", display: "flex", alignItems: 'center', justifyContent: 'center' }}>
{isHome ? (
<div style={{ display: "flex" }}>
<div style={{ padding: "12px" }}>
<Button
style={{ textTransform: 'none', cursor: "pointer", alignItems: "center", alignContent: "center", background: "transparent", color: "inherit", fontWeight: "bold", border: "2px solid white", borderRadius: "25px" }}
ref={this.mcuRef}
onClick={() => {
this.setState({ anchorElBoard: this.mcuRef.current })
}}
startIcon={<FontAwesomeIcon icon={faMicrochip} />}
endIcon={<FontAwesomeIcon icon={faCaretDown} />}
sx={{ display: { xs: "none", sm: "none", md: "flex" } }}
>
{this.props.selectedBoard}
</Button>
<Menu
anchorEl={this.state.anchorElBoard}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
keepMounted
transformOrigin={{
vertical: 'top',
horizontal: 'center',
}}
open={Boolean(this.state.anchorElBoard)}
onClose={() => {
this.setState({ anchorElBoard: null });
}}
>
<MenuItem
value="mcu"
onClick={(event) => {
this.props.setBoard(event.currentTarget.getAttribute("value"));
this.setState({ anchorElBoard: null });
}}
>
mcu
</MenuItem>
<MenuItem
value="mini"
onClick={(event) => {
this.props.setBoard(event.currentTarget.getAttribute("value"));
this.setState({ anchorElBoard: null });
}}
>
mini
</MenuItem>
</Menu>
</div>
<div style={{ padding: "12px" }}>
{
this.props.language === "en_US" ?
(
<Button
style={{ textTransform: 'none', cursor: "pointer", alignItems: "center", alignContent: "center", background: "transparent", color: "inherit", fontWeight: "bold", border: "2px solid white", borderRadius: "25px" }}
ref={this.langRef}
onClick={() => {
this.setState({ anchorElLang: this.langRef.current })
}}
startIcon={<FontAwesomeIcon icon={faEarthAmericas} />}
endIcon={<FontAwesomeIcon icon={faCaretDown} />}
sx={{ display: { xs: "none", sm: "none", md: "flex" } }}
>
English
</Button>
) : (
<Button
style={{ textTransform: 'none', cursor: "pointer", alignItems: "center", alignContent: "center", background: "transparent", color: "inherit", fontWeight: "bold", border: "2px solid white", borderRadius: "25px" }}
ref={this.langRef}
onClick={() => {
this.setState({ anchorElLang: this.langRef.current })
}}
startIcon={<FontAwesomeIcon icon={faEarthEurope} />}
endIcon={<FontAwesomeIcon icon={faCaretDown} />}
sx={{ display: { xs: "none", sm: "none", md: "flex" } }}
>
Deutsch
</Button>
)
}
<Menu
anchorEl={this.state.anchorElLang}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
keepMounted
transformOrigin={{
vertical: 'top',
horizontal: 'center',
}}
open={Boolean(this.state.anchorElLang)}
onClose={() => {
this.setState({ anchorElLang: null });
}}
>
<MenuItem
value="de_DE"
onClick={(event) => {
this.props.setLanguage(event.currentTarget.getAttribute("value"));
this.setState({ anchorElLang: null });
}}
>
Deutsch
</MenuItem>
<MenuItem
value="en_US"
onClick={(event) => {
this.props.setLanguage(event.currentTarget.getAttribute("value"));
this.setState({ anchorElLang: null });
}}
>
English
</MenuItem>
</Menu>
</div>
</div>
) : (null)}
{isHome ? (
<Tooltip title={'Start Tour'} arrow>
<IconButton
color="inherit"
className={`openTour ${this.props.classes.button}`}
onClick={() => {
this.openTour();
}}
size="large">
<FontAwesomeIcon icon={faQuestionCircle} />
</IconButton>
</Tooltip>
) : null}
{isAssessment ? (
<Tooltip title={'Start tour'} arrow>
<IconButton
color="inherit"
className={`openTour ${this.props.classes.button}`}
onClick={() => {
this.openTour();
}}
size="large">
<FontAwesomeIcon icon={faQuestionCircle} />
</IconButton>
</Tooltip>
) : null}
<Tour
steps={isHome ? home() : assessment()}
isOpen={this.state.isTourOpen}
onRequestClose={() => {
this.closeTour();
}}
>
<Typography variant="h6" noWrap>
Tutorial
</Typography>
</Link>
) : null}
{isHome ? (
<Tooltip title={Blockly.Msg.tooltip_start_tour} arrow>
<IconButton
color="inherit"
className={`openTour ${this.props.classes.button}`}
onClick={() => {
this.openTour();
}}
style={{ margin: "0 30px 0 auto" }}
>
<FontAwesomeIcon icon={faQuestionCircle} />
</IconButton>
</Tooltip>
) : null}
{isAssessment ? (
<Tooltip title={Blockly.Msg.tooltip_start_tour} arrow>
<IconButton
color="inherit"
className={`openTour ${this.props.classes.button}`}
onClick={() => {
this.openTour();
}}
style={{ margin: "0 30px 0 auto" }}
>
<FontAwesomeIcon icon={faQuestionCircle} />
</IconButton>
</Tooltip>
) : null}
<Tour
steps={isHome ? home() : assessment()}
isOpen={this.state.isTourOpen}
onRequestClose={() => {
this.closeTour();
}}
/>
/>
{this.props.user ? (
<div>
<IconButton
color="inherit"
onClick={(event) => { this.setState({ anchorElUser: event.target }) }}
style={{ margin: "0 30px 0 0" }}
size="large"
>
<FontAwesomeIcon icon={faUser} />
</IconButton>
<Menu
anchorEl={this.state.anchorElUser}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
keepMounted
transformOrigin={{
vertical: 'top',
horizontal: 'center',
}}
open={Boolean(this.state.anchorElUser)}
onClose={() => { this.setState({ anchorElUser: null }); }}
>
<div className="" style={{ paddingLeft: "16px", paddingRight: "16px", paddingTop: "16px" }}>
<p style={{ fontWeight: "bold", margin: "0px" }}>
{this.props.user.name}
</p>
<p style={{ marginTop: "0px", color: "#696969" }}>
{this.props.user.email}
</p>
</div>
<hr style={{ borderTop: "3px solid #bbb", marginLeft: "5px", marginRight: "5px" }} />
<MenuItem>
<Link to={"/user"} style={{ textDecoration: 'none', color: "black" }}>
{Blockly.Msg.navbar_account}
</Link>
</MenuItem>
<MenuItem>
<Link to={"/settings"} style={{ textDecoration: 'none', color: "black" }}>
{Blockly.Msg.navbar_settings}
</Link>
</MenuItem>
<MenuItem
onClick={() => {
this.props.logout()
}}
>
{Blockly.Msg.navbar_logout}
</MenuItem>
</Menu>
</div>
)
:
(<Link to={"/user/login"} style={{ textDecoration: 'none', color: "white" }}>
<IconButton
color="inherit"
style={{ margin: "0 30px 0 auto" }}
>
<FontAwesomeIcon icon={faUser} />
</IconButton>
</Link>
)
}
</div>
</Toolbar>
</AppBar>
<Drawer
@@ -211,6 +399,11 @@ class Navbar extends Component {
</div>
<List>
{[
{
text: Blockly.Msg.navbar_blockly,
icon: faPuzzlePiece,
link: "/",
},
{
text: Blockly.Msg.navbar_tutorials,
icon: faChalkboardTeacher,
@@ -236,6 +429,11 @@ class Navbar extends Component {
link: "/project",
restriction: this.props.isAuthenticated,
},
{
text: "Code Editor",
icon: faCode,
link: "/codeeditor",
},
].map((item, index) => {
if (
item.restriction ||
@@ -253,7 +451,13 @@ class Navbar extends Component {
<ListItemIcon>
<FontAwesomeIcon icon={item.icon} />
</ListItemIcon>
<ListItemText primary={item.text} />
{item.text === "Code Editor" ? (
<Badge badgeContent={"Experimental"} color="primary" overlap="rectangular">
<ListItemText primary={item.text} />
</Badge>
) : (
<ListItemText primary={item.text} />
)}
</ListItem>
</Link>
);
@@ -310,9 +514,9 @@ class Navbar extends Component {
onClick={
item.function
? () => {
item.function();
this.toggleDrawer();
}
item.function();
this.toggleDrawer();
}
: this.toggleDrawer
}
>
@@ -346,10 +550,14 @@ class Navbar extends Component {
Navbar.propTypes = {
tutorialIsLoading: PropTypes.bool.isRequired,
projectIsLoading: PropTypes.bool.isRequired,
isAuthenticated: PropTypes.bool.isRequired,
isAuthenticated: PropTypes.bool,
user: PropTypes.object,
tutorial: PropTypes.object.isRequired,
tutorial: PropTypes.object,
activeStep: PropTypes.number.isRequired,
setLanguage: PropTypes.func.isRequired,
language: PropTypes.string.isRequired,
setBoard: PropTypes.func.isRequired,
selectedBoard: PropTypes.string.isRequired
};
const mapStateToProps = (state) => ({
@@ -359,8 +567,10 @@ const mapStateToProps = (state) => ({
user: state.auth.user,
tutorial: state.tutorial.tutorials[0],
activeStep: state.tutorial.activeStep,
language: state.general.language,
selectedBoard: state.board.board
});
export default connect(mapStateToProps, { logout })(
export default connect(mapStateToProps, { logout, setLanguage, setBoard })(
withStyles(styles, { withTheme: true })(withRouter(Navbar))
);
+3 -3
View File
@@ -4,11 +4,11 @@ import Breadcrumbs from './Breadcrumbs';
import { withRouter } from 'react-router-dom';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import Button from '@mui/material/Button';
import Typography from '@mui/material/Typography';
import * as Blockly from 'blockly'
import ReactMarkdown from 'react-markdown';
import Container from '@material-ui/core/Container';
import Container from '@mui/material/Container';
const news = `
+2 -2
View File
@@ -4,8 +4,8 @@ import Breadcrumbs from './Breadcrumbs';
import { withRouter } from 'react-router-dom';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import Button from '@mui/material/Button';
import Typography from '@mui/material/Typography';
import * as Blockly from 'blockly'
class NotFound extends Component {
+1 -1
View File
@@ -1,6 +1,6 @@
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import Container from '@material-ui/core/Container';
import Container from '@mui/material/Container';
class Privay extends Component {
render() {
return (
+2 -2
View File
@@ -10,8 +10,8 @@ import { withRouter } from 'react-router-dom';
import Home from '../Home';
import Breadcrumbs from '../Breadcrumbs';
import Backdrop from '@material-ui/core/Backdrop';
import CircularProgress from '@material-ui/core/CircularProgress';
import Backdrop from '@mui/material/Backdrop';
import CircularProgress from '@mui/material/CircularProgress';
class Project extends Component {
+15 -15
View File
@@ -11,13 +11,14 @@ import BlocklyWindow from "../Blockly/BlocklyWindow";
import Snackbar from "../Snackbar";
import WorkspaceFunc from "../Workspace/WorkspaceFunc";
import { withStyles } from "@material-ui/core/styles";
import Grid from "@material-ui/core/Grid";
import Paper from "@material-ui/core/Paper";
import Divider from "@material-ui/core/Divider";
import Typography from "@material-ui/core/Typography";
import Backdrop from "@material-ui/core/Backdrop";
import CircularProgress from "@material-ui/core/CircularProgress";
import withStyles from '@mui/styles/withStyles';
import Grid from "@mui/material/Grid";
import Paper from "@mui/material/Paper";
import Divider from "@mui/material/Divider";
import Typography from "@mui/material/Typography";
import Backdrop from "@mui/material/Backdrop";
import CircularProgress from "@mui/material/CircularProgress";
import DeviceSelection from "../DeviceSelection";
const styles = (theme) => ({
link: {
@@ -60,9 +61,8 @@ class ProjectHome extends Component {
this.setState({
snackbar: true,
key: Date.now(),
message: `Dein angefragtes ${
type === "gallery" ? "Galerie-" : ""
}Projekt konnte nicht gefunden werden.`,
message: `Dein angefragtes ${type === "gallery" ? "Galerie-" : ""
}Projekt konnte nicht gefunden werden.`,
type: "error",
});
}
@@ -108,6 +108,7 @@ class ProjectHome extends Component {
/>
<h1>{data}</h1>
<DeviceSelection />
{this.props.progress ? (
<Backdrop open invisible>
<CircularProgress color="primary" />
@@ -127,9 +128,8 @@ class ProjectHome extends Component {
}}
>
<Link
to={`/${
data === "Projekte" ? "project" : "gallery"
}/${project._id}`}
to={`/${data === "Projekte" ? "project" : "gallery"
}/${project._id}`}
style={{ textDecoration: "none", color: "inherit" }}
>
<h3 style={{ marginTop: 0 }}>{project.title}</h3>
@@ -140,7 +140,7 @@ class ProjectHome extends Component {
svg
blockDisabled
initialXml={project.xml}
/>
/>
<Typography
variant="body2"
style={{
@@ -153,7 +153,7 @@ class ProjectHome extends Component {
</Typography>
</Link>
{this.props.user &&
this.props.user.email === project.creator ? (
this.props.user.email === project.creator ? (
<div>
<Divider
style={{
+23 -26
View File
@@ -1,44 +1,41 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Route, Redirect, withRouter } from 'react-router-dom';
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { Route, Redirect, withRouter } from "react-router-dom";
class PrivateRoute extends Component {
render() {
return (
!this.props.progress ?
return !this.props.progress ? (
<Route
{...this.props.exact}
render={({ location }) =>
this.props.isAuthenticated ? (
this.props.children
) : (()=>{
return (
<Redirect
to={{
pathname: "/user/login",
state: { from: location }
}}
/>
)
})()
this.props.isAuthenticated
? this.props.children
: (() => {
return (
<Redirect
to={{
pathname: "/user/login",
state: { from: location },
}}
/>
);
})()
}
/> : null
);
/>
) : null;
}
}
PrivateRoute.propTypes = {
isAuthenticated: PropTypes.bool.isRequired,
progress: PropTypes.bool.isRequired
isAuthenticated: PropTypes.bool,
progress: PropTypes.bool.isRequired,
};
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
isAuthenticated: state.auth.isAuthenticated,
progress: state.auth.progress
progress: state.auth.progress,
});
export default connect(mapStateToProps, null)(withRouter(PrivateRoute));
+31 -3
View File
@@ -1,7 +1,7 @@
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { visitPage } from "../../actions/generalActions";
import { visitPage, setPlatform } from "../../actions/generalActions";
import { Route, Switch, withRouter } from "react-router-dom";
@@ -24,8 +24,27 @@ import Login from "../User/Login";
import Account from "../User/Account";
import News from "../News";
import Faq from "../Faq";
import CodeEditor from "../CodeEditor/CodeEditor";
class Routes extends Component {
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() {
this.props.visitPage();
}
@@ -47,6 +66,9 @@ class Routes extends Component {
<Route path="/tutorial/:tutorialId" exact>
<Tutorial />
</Route>
<Route path="/CodeEditor" exact>
<CodeEditor />
</Route>
{/* Sharing */}
<PublicRoute path="/share/:shareId" exact>
<Project />
@@ -100,7 +122,13 @@ class Routes extends Component {
}
Home.propTypes = {
visitPage: PropTypes.func.isRequired,
visitPage: PropTypes.func,
platform: PropTypes.bool.isRequired,
setPlatform: PropTypes.func.isRequired
};
export default connect(null, { visitPage })(withRouter(Routes));
const mapStateToProps = (state) => ({
platform: state.general.platform,
});
export default connect(mapStateToProps, { visitPage, setPlatform })(withRouter(Routes));
+77
View File
@@ -0,0 +1,77 @@
import React from "react";
import Box from "@mui/material/Box";
import Tab from "@mui/material/Tab";
import TabContext from "@mui/lab/TabContext";
import TabList from "@mui/lab/TabList";
import TabPanel from "@mui/lab/TabPanel";
import store from "../store";
import ReactMarkdown from "react-markdown";
import * as Blockly from "blockly";
export default function LabTabs() {
const [value, setValue] = React.useState('1');
const handleChange = (event, newValue) => {
setValue(newValue);
};
// get the description in the current language if no lang is give return english or the first one
function filterLanguage(options) {
var lang;
if (window.localStorage.getItem("locale")) {
lang = window.localStorage.getItem("locale").split("_")[0];
}
else {
lang = "en";
}
for (var i = 0; i < options.length; i++) {
if (options[i].languageCode === lang) {
return options[i].text;
}
}
return options[0].text;
}
var currentStore = store.getState();
// ALL SENSOR DATA FROM WIKI
var sensorData = currentStore.sensorwiki;
// NAME OF SELECTED BLOCK
var sensorName = currentStore.workspace.code.data.name;
// SEARCH ALL DATA FOR SELECTED BLOCK NAME
var sensorInfo = sensorData.find(function (element) {
return element.slug === sensorName;
});
if (sensorInfo) {
sensorInfo.markdown = "Coming soon...";
// GET DESCRIPTION OF SELECTED BLOCK
sensorInfo.details = `# ${sensorName.toUpperCase()}
${Blockly.Msg.sensorinfo_explanation} [${sensorName.toUpperCase()}](https://sensors.wiki/sensor/detail/${sensorName})
## ${Blockly.Msg.sensorinfo_description}
${filterLanguage(sensorInfo.description.item)}
## ${Blockly.Msg.sensorinfo_measurable_phenos}
## ${Blockly.Msg.sensorinfo_manufacturer}
${sensorInfo.manufacturer}
## ${Blockly.Msg.sensorinfo_lifetime}
${sensorInfo.lifePeriod}`
}
return (
<Box sx={{ width: '100%', typography: 'body1' }}>
<TabContext value={value}>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
<TabList onChange={handleChange}>
<Tab label="Basic Information" value="1" />
<Tab label="Details" value="2" />
</TabList>
</Box>
<TabPanel value="1">
{sensorInfo ? <ReactMarkdown>{sensorInfo.markdown}</ReactMarkdown> : "No data available"}
</TabPanel>
<TabPanel value="2">
{sensorInfo ? <ReactMarkdown>{sensorInfo.details}</ReactMarkdown> : "No data available"}
</TabPanel>
</TabContext>
</Box>
);
}
+55
View File
@@ -0,0 +1,55 @@
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 '@mui/material/InputLabel';
import MenuItem from '@mui/material/MenuItem';
import FormControl from '@mui/material/FormControl';
import Select from '@mui/material/Select';
import Typography from '@mui/material/Typography';
import FormHelperText from '@mui/material/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 variant="standard">
<InputLabel id="demo-simple-select-label">{Blockly.Msg.settings_board}</InputLabel>
<Select
variant="standard"
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);
+10 -10
View File
@@ -5,12 +5,12 @@ import { setLanguage } from '../../actions/generalActions';
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';
import InputLabel from '@mui/material/InputLabel';
import MenuItem from '@mui/material/MenuItem';
import FormControl from '@mui/material/FormControl';
import Select from '@mui/material/Select';
import Typography from '@mui/material/Typography';
import FormHelperText from '@mui/material/FormHelperText';
class LanguageSelector extends Component {
@@ -25,18 +25,18 @@ class LanguageSelector extends Component {
}
render(){
return(
return (
<div>
<Typography style={{fontWeight: 'bold'}}>{Blockly.Msg.settings_language}</Typography>
<FormHelperText style={{color: 'black', lineHeight: 1.3, marginBottom: '8px'}}>{Blockly.Msg.settings_language_text}</FormHelperText>
<FormControl>
<FormControl variant="standard">
<InputLabel id="demo-simple-select-label">{Blockly.Msg.settings_language}</InputLabel>
<Select
variant="standard"
labelId="demo-simple-select-label"
id="demo-simple-select"
value={this.props.language}
onChange={this.handleChange}
>
onChange={this.handleChange}>
<MenuItem value={'de_DE'}>{Blockly.Msg.settings_language_de}</MenuItem>
<MenuItem value={'en_US'}>{Blockly.Msg.settings_language_en}</MenuItem>
</Select>
+9 -9
View File
@@ -5,12 +5,12 @@ import { setPlatform } from "../../actions/generalActions";
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";
import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
import Select from "@mui/material/Select";
import Typography from "@mui/material/Typography";
import FormHelperText from "@mui/material/FormHelperText";
class OtaSelector extends Component {
componentDidMount() {
@@ -33,16 +33,16 @@ class OtaSelector extends Component {
https://sensebox.de/app
</a>
</FormHelperText>
<FormControl>
<FormControl variant="standard">
<InputLabel id="demo-simple-select-label">
{Blockly.Msg.settings_statistics}
</InputLabel>
<Select
variant="standard"
labelId="demo-simple-select-label"
id="demo-simple-select"
value={this.props.platform}
onChange={(e) => this.props.setPlatform(e.target.value)}
>
onChange={(e) => this.props.setPlatform(e.target.value)}>
<MenuItem value={true}>{Blockly.Msg.settings_ota_on}</MenuItem>
<MenuItem value={false}>{Blockly.Msg.settings_ota_off}</MenuItem>
</Select>
+9 -9
View File
@@ -5,12 +5,12 @@ import { setRenderer } from '../../actions/generalActions';
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';
import InputLabel from '@mui/material/InputLabel';
import MenuItem from '@mui/material/MenuItem';
import FormControl from '@mui/material/FormControl';
import Select from '@mui/material/Select';
import Typography from '@mui/material/Typography';
import FormHelperText from '@mui/material/FormHelperText';
class RenderSelector extends Component {
@@ -26,14 +26,14 @@ class RenderSelector extends Component {
<div>
<Typography style={{fontWeight: 'bold'}}>{Blockly.Msg.settings_renderer}</Typography>
<FormHelperText style={{color: 'black', lineHeight: 1.3, marginBottom: '8px'}}>{Blockly.Msg.settings_renderer_text}</FormHelperText>
<FormControl>
<FormControl variant="standard">
<InputLabel id="demo-simple-select-label">{Blockly.Msg.settings_renderer}</InputLabel>
<Select
variant="standard"
labelId="demo-simple-select-label"
id="demo-simple-select"
value={this.props.renderer}
onChange={(e) => this.props.setRenderer(e.target.value)}
>
onChange={(e) => this.props.setRenderer(e.target.value)}>
<MenuItem value={'geras'}>Geras</MenuItem>
<MenuItem value={'zelos'}>Zelos</MenuItem>
</Select>
+6 -2
View File
@@ -12,9 +12,10 @@ import RenderSelector from "./RenderSelector";
import StatsSelector from "./StatsSelector";
import OtaSelector from "./OtaSelector";
import SoundsSelector from "./SoundsSelector";
import DeviceSelector from "./DeviceSelector";
import Button from "@material-ui/core/Button";
import Paper from "@material-ui/core/Paper";
import Button from "@mui/material/Button";
import Paper from "@mui/material/Paper";
class Settings extends Component {
componentDidMount() {
@@ -52,6 +53,9 @@ class Settings extends Component {
<Paper style={{ margin: "10px 0px", padding: "10px" }}>
<SoundsSelector />
</Paper>
<Paper style={{ margin: "10px 0px", padding: "10px" }}>
<DeviceSelector />
</Paper>
<Button
style={{ marginTop: "10px" }}
+10 -10
View File
@@ -5,12 +5,12 @@ import { setSounds } from "../../actions/generalActions";
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";
import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
import Select from "@mui/material/Select";
import Typography from "@mui/material/Typography";
import FormHelperText from "@mui/material/FormHelperText";
class SoundsSelector extends Component {
componentDidMount() {
@@ -30,16 +30,16 @@ class SoundsSelector extends Component {
>
{Blockly.Msg.settings_sounds_text}
</FormHelperText>
<FormControl>
<FormControl variant="standard">
<InputLabel id="demo-simple-select-label">
{Blockly.Msg.settings_sounds}
</InputLabel>
<Select
variant="standard"
labelId="demo-simple-select-label"
id="demo-simple-select"
value={this.props.sounds}
onChange={(e) => this.props.setSounds(e.target.value)}
>
onChange={(e) => this.props.setSounds(e.target.value)}>
<MenuItem value={false}>{Blockly.Msg.settings_ota_off}</MenuItem>
<MenuItem value={true}>{Blockly.Msg.settings_ota_on}</MenuItem>
</Select>
@@ -52,7 +52,7 @@ class SoundsSelector extends Component {
SoundsSelector.propTypes = {
setSounds: PropTypes.func.isRequired,
language: PropTypes.string.isRequired,
sounds: PropTypes.string.isRequired,
sounds: PropTypes.bool.isRequired,
};
const mapStateToProps = (state) => ({
+9 -9
View File
@@ -5,12 +5,12 @@ import { setStatistics } from '../../actions/generalActions';
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';
import InputLabel from '@mui/material/InputLabel';
import MenuItem from '@mui/material/MenuItem';
import FormControl from '@mui/material/FormControl';
import Select from '@mui/material/Select';
import Typography from '@mui/material/Typography';
import FormHelperText from '@mui/material/FormHelperText';
class StatsSelector extends Component {
@@ -25,14 +25,14 @@ class StatsSelector extends Component {
<div>
<Typography style={{fontWeight: 'bold'}}>{Blockly.Msg.settings_statistics}</Typography>
<FormHelperText style={{color: 'black', lineHeight: 1.3, marginBottom: '8px'}}>{Blockly.Msg.settings_statistics_text}</FormHelperText>
<FormControl>
<FormControl variant="standard">
<InputLabel id="demo-simple-select-label">{Blockly.Msg.settings_statistics}</InputLabel>
<Select
variant="standard"
labelId="demo-simple-select-label"
id="demo-simple-select"
value={this.props.statistics}
onChange={(e) => this.props.setStatistics(e.target.value)}
>
onChange={(e) => this.props.setStatistics(e.target.value)}>
<MenuItem value={true}>{Blockly.Msg.settings_statistics_on}</MenuItem>
<MenuItem value={false}>{Blockly.Msg.settings_statistics_off}</MenuItem>
</Select>
+6 -6
View File
@@ -1,9 +1,9 @@
import React, { Component } from 'react';
import { withStyles } from '@material-ui/core/styles';
import IconButton from '@material-ui/core/IconButton';
import MaterialUISnackbar from '@material-ui/core/Snackbar';
import SnackbarContent from '@material-ui/core/SnackbarContent';
import withStyles from '@mui/styles/withStyles';
import IconButton from '@mui/material/IconButton';
import MaterialUISnackbar from '@mui/material/Snackbar';
import SnackbarContent from '@mui/material/SnackbarContent';
import { faTimes } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
@@ -69,8 +69,8 @@ class Snackbar extends Component {
style={{flexWrap: 'nowrap'}}
className={this.props.type === 'error' ? this.props.classes.error : this.props.classes.success}
action={
<IconButton onClick={this.onClose} style={{color: 'inherit'}}>
<FontAwesomeIcon icon={faTimes} size="xs"/>
<IconButton onClick={this.onClose} style={{color: 'inherit'}} size="large">
<FontAwesomeIcon icon={faTimes} size="xs" />
</IconButton>
}
message={this.props.message}
+86 -20
View File
@@ -1,47 +1,113 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { Button, Card } from "@mui/material";
import * as Blockly from "blockly";
import CardContent from "@mui/material/CardContent";
import Typography from "@mui/material/Typography";
import ReactMarkdown from "react-markdown";
import Dialog from "@mui/material/Dialog";
import DialogActions from "@mui/material/DialogActions";
import DialogContent from "@mui/material/DialogContent";
import Slide from "@mui/material/Slide";
import SensorInfo from "./SensorInfo";
import store from "../store";
import withWidth from '@material-ui/core/withWidth';
// FIXME checkout https://mui.com/components/use-media-query/#migrating-from-withwidth
const withWidth = () => (WrappedComponent) => (props) => <WrappedComponent {...props} width="xs" />;
import { Card } from '@material-ui/core';
import * as Blockly from 'blockly'
import CardContent from '@material-ui/core/CardContent';
import Typography from '@material-ui/core/Typography';
import ReactMarkdown from 'react-markdown';
const Transition = React.forwardRef(function Transition(props, ref) {
return <Slide direction="up" ref={ref} {...props} />;
});
class TooltipViewer extends Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
this.state = {
open: false,
};
}
toggleDialog = () => {
this.setState({ open: !this.state });
};
openDialog = () => {
this.setState({ open: true });
};
render() {
return (
<Card className="tooltipViewer" style={{ height: '100%', margin: '1vH 0 0 0', maxHeight: '19vH', overflow: 'auto' }} ref={this.myDiv}>
<Card
className="tooltipViewer"
style={{
height: "100%",
margin: "1vH 0 0 0",
maxHeight: "19vH",
overflow: "auto",
}}
ref={this.myDiv}
>
<CardContent>
<Typography variant="h5" component="h2">
{Blockly.Msg.tooltip_viewer}
</Typography>
<Typography variant="body2" component="p">
<ReactMarkdown linkTarget="_blank">{this.props.tooltip}</ReactMarkdown>
{this.props.helpurl !== '' ? <ReactMarkdown>{`${Blockly.Msg.tooltip_moreInformation} [${Blockly.Msg.labels_here}](${this.props.helpurl})`}</ReactMarkdown> : null}
<Typography variant="body2" component="span">
<ReactMarkdown linkTarget="_blank">
{this.props.tooltip}
</ReactMarkdown>
{store.getState().workspace.code.data ? (
<Button
label="Mehr"
variant="contained"
color="primary"
onClick={() => {
this.openDialog();
}}
>
Sensor Informationen
</Button>
) : (
<ReactMarkdown>{`${Blockly.Msg.tooltip_moreInformation} [${Blockly.Msg.labels_here}](${this.props.helpurl})`}</ReactMarkdown>
)}
</Typography>
</CardContent>
{store.getState().workspace.code.data ? (<Dialog
open={this.state.open}
TransitionComponent={Transition}
keepMounted
aria-describedby="alert-dialog-slide-description"
onClose={() => {
this.toggleDialog();
}}
maxWidth={"md"}
fullWidth={true}
>
<DialogContent>
<SensorInfo></SensorInfo>
</DialogContent>
<DialogActions>
<Button onClick={() => {
this.toggleDialog();
}}>Close</Button>
</DialogActions>
</Dialog>) : (null)}
</Card>
);
};
}
}
TooltipViewer.propTypes = {
tooltip: PropTypes.string.isRequired,
helpurl: PropTypes.string.isRequired
helpurl: PropTypes.string.isRequired,
};
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
tooltip: state.workspace.code.tooltip,
helpurl: state.workspace.code.helpurl
helpurl: state.workspace.code.helpurl,
});
export default connect(mapStateToProps, null)(withWidth()(TooltipViewer));
+112 -33
View File
@@ -4,17 +4,58 @@ import { connect } from "react-redux";
import { workspaceName } from "../../actions/workspaceActions";
import BlocklyWindow from "../Blockly/BlocklyWindow";
import CodeViewer from "../CodeViewer";
import WorkspaceFunc from "../Workspace/WorkspaceFunc";
import withWidth, { isWidthDown } from "@material-ui/core/withWidth";
import Grid from "@material-ui/core/Grid";
import Card from "@material-ui/core/Card";
import Typography from "@material-ui/core/Typography";
import Grid from "@mui/material/Grid";
import Card from "@mui/material/Card";
import Typography from "@mui/material/Typography";
import * as Blockly from "blockly";
import { initialXml } from "../Blockly/initialXml";
import IconButton from "@mui/material/IconButton";
import CodeViewer from "../CodeViewer";
import TooltipViewer from "../TooltipViewer";
import Tooltip from "@mui/material/Tooltip";
import ReactMarkdown from "react-markdown";
import { faCode } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import withStyles from '@mui/styles/withStyles';
import remarkGfm from "remark-gfm";
import remarkGemoji from "remark-gemoji";
import { isWidthDown } from "../../helpers/handleBreakpoints";
// FIXME checkout https://mui.com/components/use-media-query/#migrating-from-withwidth
const withWidth = () => (WrappedComponent) => (props) => <WrappedComponent {...props} width="xs" />;
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 {
constructor(props) {
super(props);
this.state = {
codeOn: false,
};
}
componentDidMount() {
this.props.workspaceName(this.props.name);
}
@@ -25,6 +66,10 @@ class Assessment extends Component {
}
}
onChange = () => {
this.setState({ codeOn: !this.state.codeOn });
};
render() {
var tutorialId = this.props.tutorial._id;
var currentTask = this.props.step;
@@ -35,63 +80,97 @@ class Assessment extends Component {
(task) => task._id === currentTask._id
);
var statusTask = status.tasks[taskIndex];
console.log(statusTask);
return (
<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" }}>
<WorkspaceFunc assessment />
</div>
<Grid container spacing={2} style={{ marginBottom: "5px" }}>
<Grid item xs={12} md={6} lg={8}>
<Grid
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()}
size="large">
<FontAwesomeIcon icon={faCode} size="xs" />
</IconButton>
</Tooltip>
<BlocklyWindow
initialXml={initialXml}
blockDisabled
blocklyCSS={{ height: "65vH" }}
/>
</Grid>
{this.state.codeOn ? (
<Grid item xs={12} md={4} lg={3}>
<CodeViewer />
</Grid>
) : null}
<Grid
item
xs={12}
md={6}
lg={4}
style={
isWidthDown("sm", this.props.width)
? { height: "max-content" }
: {}
}
md={3}
lg={3}
style={{
position: "relative",
// isWidthDown("sm", this.props.width)
// ? { height: "max-content" }
// : {}
}}
>
<Card
style={{
height: "calc(50% - 30px)",
height: "calc(44vH - 35px)",
padding: "10px",
marginBottom: "10px",
}}
>
<Typography variant="h5">
{Blockly.Msg.tutorials_assessment_task}
<Typography>
<ReactMarkdown remarkPlugins={[remarkGfm, remarkGemoji]}>
{currentTask.text}
</ReactMarkdown>
</Typography>
<Typography>{currentTask.text}</Typography>
</Card>
{/* <Card
style={{
height: "20vH",
padding: "10px",
marginBottom: "10px",
}}
> */}
<TooltipViewer />
{/* </Card> */}
<div
style={
isWidthDown("sm", this.props.width)
? { height: "500px" }
: { height: "50%" }
}
>
<CodeViewer />
</div>
></div>
</Grid>
</Grid>
</div>
@@ -113,5 +192,5 @@ const mapStateToProps = (state) => ({
});
export default connect(mapStateToProps, { workspaceName })(
withWidth()(Assessment)
withWidth()(withStyles(styles, { withTheme: true })(Assessment))
);
+137 -85
View File
@@ -1,53 +1,57 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { changeContent, deleteProperty, setError, deleteError } from '../../../actions/tutorialBuilderActions';
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import {
changeContent,
deleteProperty,
setError,
deleteError,
} from "../../../actions/tutorialBuilderActions";
import moment from 'moment';
import localization from 'moment/locale/de';
import * as Blockly from 'blockly/core';
import moment from "moment";
import localization from "moment/locale/de";
import * as Blockly from "blockly/core";
import { initialXml } from '../../Blockly//initialXml.js';
import BlocklyWindow from '../../Blockly/BlocklyWindow';
import { initialXml } from "../../Blockly//initialXml.js";
import BlocklyWindow from "../../Blockly/BlocklyWindow";
import { withStyles } from '@material-ui/core/styles';
import Switch from '@material-ui/core/Switch';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import FormHelperText from '@material-ui/core/FormHelperText';
import FormLabel from '@material-ui/core/FormLabel';
import Button from '@material-ui/core/Button';
import Grid from '@material-ui/core/Grid';
import withStyles from '@mui/styles/withStyles';
import Switch from "@mui/material/Switch";
import FormControlLabel from "@mui/material/FormControlLabel";
import FormHelperText from "@mui/material/FormHelperText";
import FormLabel from "@mui/material/FormLabel";
import Button from "@mui/material/Button";
import Grid from "@mui/material/Grid";
const styles = (theme) => ({
errorColor: {
color: theme.palette.error.dark
color: theme.palette.error.dark,
},
errorBorder: {
border: `1px solid ${theme.palette.error.dark}`
border: `1px solid ${theme.palette.error.dark}`,
},
errorButton: {
marginTop: '5px',
height: '40px',
marginTop: "5px",
height: "40px",
backgroundColor: theme.palette.error.dark,
'&:hover': {
backgroundColor: theme.palette.error.dark
}
}
"&:hover": {
backgroundColor: theme.palette.error.dark,
},
},
});
class BlocklyExample extends Component {
constructor(props) {
super(props);
this.state = {
checked: props.task ? props.task : props.value ? true : false,
input: null,
disabled: false
disabled: false,
};
}
componentDidMount() {
moment.updateLocale('de', localization);
moment.updateLocale("de", localization);
this.isError();
// if(this.props.task){
// this.props.setError(this.props.index, 'xml');
@@ -56,7 +60,14 @@ class BlocklyExample extends Component {
componentDidUpdate(props, state) {
if (props.task !== this.props.task || props.value !== this.props.value) {
this.setState({ checked: this.props.task ? this.props.task : this.props.value ? true : false },
this.setState(
{
checked: this.props.task
? this.props.task
: this.props.value
? true
: false,
},
() => this.isError()
);
}
@@ -77,12 +88,11 @@ class BlocklyExample extends Component {
// check if value is valid xml;
try {
Blockly.Xml.textToDom(xml);
this.props.deleteError(this.props.index, 'xml');
}
catch (err) {
this.props.deleteError(this.props.index, "xml");
} catch (err) {
xml = initialXml;
// 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) {
// instruction can also display only one block, which does not necessarily
@@ -90,31 +100,38 @@ class BlocklyExample extends Component {
xml = xml.replace('deletable="false"', 'deletable="true"');
}
this.setState({ xml: xml });
} else {
this.props.deleteError(this.props.index, "xml");
}
else {
this.props.deleteError(this.props.index, 'xml');
}
}
};
onChange = (value) => {
var oldValue = this.state.checked;
this.setState({ checked: value });
if (oldValue !== value && !value) {
this.props.deleteError(this.props.index, 'xml');
this.props.deleteProperty(this.props.index, 'xml');
this.props.deleteError(this.props.index, "xml");
this.props.deleteProperty(this.props.index, "xml");
}
}
};
setXml = () => {
var xml = this.props.xml;
this.props.changeContent(xml, this.props.index, 'xml');
this.setState({ input: moment(Date.now()).format('LTS') });
}
this.props.changeContent(xml, this.props.index, "xml");
this.setState({ input: moment(Date.now()).format("LTS") });
};
render() {
return (
<div style={{ marginBottom: '10px', padding: '18.5px 14px', borderRadius: '25px', border: '1px solid lightgrey', width: 'calc(100% - 28px)' }}>
{!this.props.task ?
<div
style={{
marginBottom: "10px",
padding: "18.5px 14px",
borderRadius: "25px",
border: "1px solid lightgrey",
width: "calc(100% - 28px)",
}}
>
{!this.props.task ? (
<FormControlLabel
labelPlacement="end"
label={"Blockly Beispiel"}
@@ -122,49 +139,80 @@ class BlocklyExample extends Component {
<Switch
checked={this.state.checked}
onChange={(e) => this.onChange(e.target.checked)}
color="primary"
/>
}
/>
: <FormLabel style={{ color: 'black' }}>{Blockly.Msg.builder_solution}</FormLabel>}
{this.state.checked ? !this.props.value || this.props.error ?
<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>
: 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}
) : (
<FormLabel style={{ color: "black" }}>
{Blockly.Msg.builder_solution}
</FormLabel>
)}
{this.state.checked ? (
!this.props.value || this.props.error ? (
<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>
) : 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 */}
{this.state.checked && this.state.xml ? (() => {
return (
<div style={{ marginTop: '10px' }}>
<Grid container className={!this.props.value || this.props.error ? this.props.classes.errorBorder : null}>
<Grid item xs={12}>
<BlocklyWindow
blockDisabled={this.props.task}
trashcan={false}
initialXml={this.state.xml}
blocklyCSS={{ height: '500px' }}
/>
</Grid>
</Grid>
<Button
className={!this.props.value || this.props.error ? this.props.classes.errorButton : null}
style={{ marginTop: '5px', height: '40px' }}
variant='contained'
color='primary'
disabled={this.state.disabled}
onClick={() => this.setXml()}
>
{this.props.task ? Blockly.Msg.builder_solution_submit : Blockly.Msg.builder_example_submit}
</Button>
</div>
)
})()
{this.state.checked && this.state.xml
? (() => {
return (
<div style={{ marginTop: "10px" }}>
<Grid
container
className={
!this.props.value || this.props.error
? this.props.classes.errorBorder
: null
}
>
<Grid item xs={12}>
<BlocklyWindow
blockDisabled={this.props.task}
trashcan={false}
initialXml={this.state.xml}
blocklyCSS={{ height: "500px" }}
/>
</Grid>
</Grid>
<Button
className={
!this.props.value || this.props.error
? this.props.classes.errorButton
: null
}
style={{ marginTop: "5px", height: "40px" }}
variant="contained"
color="primary"
disabled={this.state.disabled}
onClick={() => this.setXml()}
>
{this.props.task
? Blockly.Msg.builder_solution_submit
: Blockly.Msg.builder_example_submit}
</Button>
</div>
);
})()
: null}
</div>
);
};
}
}
BlocklyExample.propTypes = {
@@ -172,12 +220,16 @@ BlocklyExample.propTypes = {
deleteProperty: PropTypes.func.isRequired,
setError: PropTypes.func.isRequired,
deleteError: PropTypes.func.isRequired,
xml: PropTypes.string.isRequired
xml: PropTypes.string.isRequired,
};
const mapStateToProps = state => ({
xml: state.workspace.code.xml
const mapStateToProps = (state) => ({
xml: state.workspace.code.xml,
});
export default connect(mapStateToProps, { changeContent, deleteProperty, setError, deleteError })(withStyles(styles, { withTheme: true })(BlocklyExample));
export default connect(mapStateToProps, {
changeContent,
deleteProperty,
setError,
deleteError,
})(withStyles(styles, { withTheme: true })(BlocklyExample));
+122 -40
View File
@@ -10,6 +10,8 @@ import {
resetTutorial as resetTutorialBuilder,
} from "../../../actions/tutorialBuilderActions";
import {
getAllTutorials,
getUserTutorials,
getTutorials,
resetTutorial,
deleteTutorial,
@@ -19,26 +21,31 @@ import { clearMessages } from "../../../actions/messageActions";
import axios from "axios";
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 Textfield from "./Textfield";
import Difficulty from "./Difficulty";
import Step from "./Step";
import Dialog from "../../Dialog";
import Snackbar from "../../Snackbar";
import Public from "./Public";
import Review from "./Review";
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 Divider from "@material-ui/core/Divider";
import FormHelperText from "@material-ui/core/FormHelperText";
import Radio from "@material-ui/core/Radio";
import RadioGroup from "@material-ui/core/RadioGroup";
import FormControlLabel from "@material-ui/core/FormControlLabel";
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 withStyles from '@mui/styles/withStyles';
import Button from "@mui/material/Button";
import Backdrop from "@mui/material/Backdrop";
import CircularProgress from "@mui/material/CircularProgress";
import Divider from "@mui/material/Divider";
import FormHelperText from "@mui/material/FormHelperText";
import Radio from "@mui/material/Radio";
import RadioGroup from "@mui/material/RadioGroup";
import FormControlLabel from "@mui/material/FormControlLabel";
import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
import Select from "@mui/material/Select";
import * as Blockly from "blockly";
const styles = (theme) => ({
@@ -66,6 +73,8 @@ class Builder extends Component {
tutorial: "new",
open: false,
title: "",
public: false,
difficulty: "",
content: "",
string: false,
snackbar: false,
@@ -80,7 +89,11 @@ class Builder extends Component {
// retrieve tutorials only if a potential user is loaded - authentication
// is finished (success or failed)
if (!this.props.authProgress) {
this.props.getTutorials();
if (this.props.user.role === "admin") {
this.props.getAllTutorials();
} else {
this.props.getUserTutorials();
}
}
}
@@ -89,8 +102,12 @@ class Builder extends Component {
props.authProgress !== this.props.authProgress &&
!this.props.authProgress
) {
// authentication is completed
this.props.getTutorials();
if (this.props.user.role === "admin") {
// authentication is completed
this.props.getAllTutorials();
} else {
this.props.getUserTutorials();
}
}
if (props.message !== this.props.message) {
if (this.props.message.id === "GET_TUTORIALS_FAIL") {
@@ -258,6 +275,9 @@ class Builder extends Component {
var steps = this.props.steps;
var newTutorial = new FormData();
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) => {
if (step._id) {
newTutorial.append(`steps[${i}][_id]`, step._id);
@@ -283,21 +303,6 @@ class Builder extends Component {
// optional
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;
}
@@ -370,9 +375,19 @@ class Builder extends Component {
};
render() {
var filteredTutorials = this.props.tutorials.filter(
(tutorial) => tutorial.creator === this.props.user.email
);
if (this.props.user.role === "admin") {
var filteredTutorials = this.props.tutorials;
} else {
filteredTutorials = this.props.tutorials.filter(
(tutorial) => tutorial.creator === this.props.user.email
);
}
// } else {
// filteredTutorials = this.props.userTutorials.filter(
// (tutorial) => tutorial.creator === this.props.user.email
// );
return (
<div>
<Breadcrumbs
@@ -392,7 +407,7 @@ class Builder extends Component {
<FormControlLabel
style={{ color: "black" }}
value="new"
control={<Radio color="primary" />}
control={<Radio />}
label={Blockly.Msg.builder_createNew}
labelPlacement="end"
/>
@@ -402,7 +417,7 @@ class Builder extends Component {
style={{ color: "black" }}
disabled={this.props.index === 0}
value="change"
control={<Radio color="primary" />}
control={<Radio />}
label={Blockly.Msg.builder_changeExisting}
labelPlacement="end"
/>
@@ -410,7 +425,7 @@ class Builder extends Component {
style={{ color: "black" }}
disabled={this.props.index === 0}
value="delete"
control={<Radio color="primary" />}
control={<Radio />}
label={Blockly.Msg.builder_deleteExisting}
labelPlacement="end"
/>
@@ -455,14 +470,31 @@ class Builder extends Component {
<FormControl variant="outlined" style={{ width: "100%" }}>
<InputLabel id="select-outlined-label">Tutorial</InputLabel>
<Select
variant="standard"
color="primary"
labelId="select-outlined-label"
value={this.props.id}
onChange={(e) => this.onChangeId(e.target.value)}
label="Tutorial"
>
label="Tutorial">
{filteredTutorials.map((tutorial) => (
<MenuItem value={tutorial._id}>{tutorial.title}</MenuItem>
<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>
)} */
))}
</Select>
</FormControl>
@@ -487,6 +519,45 @@ class Builder extends Component {
label={"Titel"}
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) => (
<Step step={step} index={i} key={i} />
@@ -619,6 +690,8 @@ class Builder extends Component {
}
Builder.propTypes = {
getAllTutorials: PropTypes.func.isRequired,
getUserTutorials: PropTypes.func.isRequired,
getTutorials: PropTypes.func.isRequired,
resetTutorial: PropTypes.func.isRequired,
clearMessages: PropTypes.func.isRequired,
@@ -631,6 +704,9 @@ Builder.propTypes = {
resetTutorialBuilder: PropTypes.func.isRequired,
tutorialProgress: PropTypes.func.isRequired,
title: PropTypes.string.isRequired,
difficulty: PropTypes.number.isRequired,
public: PropTypes.bool.isRequired,
review: PropTypes.bool.isRequired,
id: PropTypes.string.isRequired,
steps: PropTypes.array.isRequired,
change: PropTypes.number.isRequired,
@@ -645,12 +721,16 @@ Builder.propTypes = {
const mapStateToProps = (state) => ({
title: state.builder.title,
difficulty: state.builder.difficulty,
review: state.builder.review,
public: state.builder.public,
id: state.builder.id,
steps: state.builder.steps,
change: state.builder.change,
error: state.builder.error,
json: state.builder.json,
isProgress: state.builder.progress,
userTutorials: state.tutorial.userTutorials,
tutorials: state.tutorial.tutorials,
message: state.message,
user: state.auth.user,
@@ -665,6 +745,8 @@ export default connect(mapStateToProps, {
tutorialId,
resetTutorialBuilder,
getTutorials,
getUserTutorials,
getAllTutorials,
resetTutorial,
tutorialProgress,
clearMessages,
@@ -0,0 +1,99 @@
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 '@mui/styles/withStyles';
import ReactStars from "react-rating-stars-component";
import * as Blockly from "blockly";
import FormGroup from "@mui/material/FormGroup";
import FormControlLabel from "@mui/material/FormControlLabel";
import FormControl from "@mui/material/FormControl";
import FormLabel from "@mui/material/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 variant="standard" 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));
+114 -59
View File
@@ -1,107 +1,162 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { changeContent, setError, deleteError } from '../../../actions/tutorialBuilderActions';
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import {
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 withWidth, { isWidthDown } from '@material-ui/core/withWidth';
import GridList from '@material-ui/core/GridList';
import GridListTile from '@material-ui/core/GridListTile';
import GridListTileBar from '@material-ui/core/GridListTileBar';
import FormHelperText from '@material-ui/core/FormHelperText';
import FormLabel from '@material-ui/core/FormLabel';
import * as Blockly from 'blockly'
import withStyles from '@mui/styles/withStyles';
import ImageList from "@mui/material/ImageList";
import ImageListItem from "@mui/material/ImageListItem";
import ImageListItemBar from "@mui/material/ImageListItemBar";
import FormHelperText from "@mui/material/FormHelperText";
import FormLabel from "@mui/material/FormLabel";
import * as Blockly from "blockly";
import { isWidthDown } from "../../../helpers/handleBreakpoints";
// FIXME checkout https://mui.com/components/use-media-query/#migrating-from-withwidth
const withWidth = () => (WrappedComponent) => (props) => <WrappedComponent {...props} width="xs" />;
const styles = theme => ({
multiGridListTile: {
const styles = (theme) => ({
multiImageListItem: {
background: theme.palette.primary.main,
opacity: 0.9,
height: '30px'
height: "30px",
},
multiGridListTileTitle: {
color: theme.palette.text.primary
multiImageListItemTitle: {
color: theme.palette.text.primary,
},
border: {
cursor: 'pointer',
'&:hover': {
width: 'calc(100% - 4px)',
height: 'calc(100% - 4px)',
border: `2px solid ${theme.palette.primary.main}`
}
cursor: "pointer",
"&:hover": {
width: "calc(100% - 4px)",
height: "calc(100% - 4px)",
border: `2px solid ${theme.palette.primary.main}`,
},
},
active: {
cursor: 'pointer',
width: 'calc(100% - 4px)',
height: 'calc(100% - 4px)',
border: `2px solid ${theme.palette.primary.main}`
cursor: "pointer",
width: "calc(100% - 4px)",
height: "calc(100% - 4px)",
border: `2px solid ${theme.palette.primary.main}`,
},
errorColor: {
color: theme.palette.error.dark,
lineHeight: 'initial',
marginBottom: '10px'
}
lineHeight: "initial",
marginBottom: "10px",
},
});
class Requirements extends Component {
onChange = (hardware) => {
var hardwareArray = this.props.value;
if (hardwareArray.filter(value => value === hardware).length > 0) {
hardwareArray = hardwareArray.filter(value => value !== hardware);
}
else {
if (hardwareArray.filter((value) => value === hardware).length > 0) {
hardwareArray = hardwareArray.filter((value) => value !== hardware);
} else {
hardwareArray.push(hardware);
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) {
this.props.setError(this.props.index, 'hardware');
this.props.setError(this.props.index, "hardware");
}
}
};
render() {
var cols = isWidthDown('md', this.props.width) ? isWidthDown('sm', this.props.width) ? isWidthDown('xs', this.props.width) ? 2 : 3 : 4 : 6;
var cols = isWidthDown("md", this.props.width)
? isWidthDown("sm", this.props.width)
? isWidthDown("xs", this.props.width)
? 2
: 3
: 4
: 6;
return (
<div style={{ marginBottom: '10px', padding: '18.5px 14px', borderRadius: '25px', 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}
<GridList cellHeight={100} cols={cols} spacing={10}>
<div
style={{
marginBottom: "10px",
padding: "18.5px 14px",
borderRadius: "25px",
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) => (
<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 }}>
<div style={{ margin: 'auto', width: 'max-content' }}>
<img src={`/media/hardware/${picture.src}`} alt={picture.name} height={100} />
<ImageListItem
key={i}
onClick={() => this.onChange(picture.id)}
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>
<GridListTileBar
classes={{ root: this.props.classes.multiGridListTile }}
<ImageListItemBar
classes={{ root: this.props.classes.multiImageListItem }}
title={
<div style={{ overflow: 'hidden', textOverflow: 'ellipsis' }} className={this.props.classes.multiGridListTileTitle}>
<div
style={{ overflow: "hidden", textOverflow: "ellipsis" }}
className={this.props.classes.multiImageListItemTitle}
>
{picture.name}
</div>
}
/>
</GridListTile>
</ImageListItem>
))}
</GridList>
</ImageList>
</div>
);
};
}
}
Requirements.propTypes = {
changeContent: PropTypes.func.isRequired,
setError: PropTypes.func.isRequired,
deleteError: PropTypes.func.isRequired,
change: PropTypes.number.isRequired
change: PropTypes.number.isRequired,
};
const mapStateToProps = state => ({
change: state.builder.change
const mapStateToProps = (state) => ({
change: state.builder.change,
});
export default connect(mapStateToProps, { changeContent, setError, deleteError })(withStyles(styles, { withTheme: true })(withWidth()(Requirements)));
export default connect(mapStateToProps, {
changeContent,
setError,
deleteError,
})(withStyles(styles, { withTheme: true })(withWidth()(Requirements)));
+6 -6
View File
@@ -3,12 +3,12 @@ import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { tutorialId, setError, deleteError } from '../../../actions/tutorialBuilderActions';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import OutlinedInput from '@material-ui/core/OutlinedInput';
import InputLabel from '@material-ui/core/InputLabel';
import FormControl from '@material-ui/core/FormControl';
import FormHelperText from '@material-ui/core/FormHelperText';
import withStyles from '@mui/styles/withStyles';
import Button from '@mui/material/Button';
import OutlinedInput from '@mui/material/OutlinedInput';
import InputLabel from '@mui/material/InputLabel';
import FormControl from '@mui/material/FormControl';
import FormHelperText from '@mui/material/FormHelperText';
import { faPlus, faMinus } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";

Some files were not shown because too many files have changed in this diff Show More