Merge pull request #79 from sensebox/ui-updates

ui-updates
This commit is contained in:
Mario Pesch 2021-07-01 15:58:35 +02:00 committed by GitHub
commit ed36a27ac2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 1414 additions and 974 deletions

37
package-lock.json generated
View File

@ -11,6 +11,7 @@
"@blockly/block-plus-minus": "^2.0.10", "@blockly/block-plus-minus": "^2.0.10",
"@blockly/field-slider": "^2.1.1", "@blockly/field-slider": "^2.1.1",
"@blockly/plugin-typed-variable-modal": "^3.1.1", "@blockly/plugin-typed-variable-modal": "^3.1.1",
"@blockly/zoom-to-fit": "^1.0.5",
"@fortawesome/fontawesome-svg-core": "^1.2.30", "@fortawesome/fontawesome-svg-core": "^1.2.30",
"@fortawesome/free-solid-svg-icons": "^5.14.0", "@fortawesome/free-solid-svg-icons": "^5.14.0",
"@fortawesome/react-fontawesome": "^0.1.11", "@fortawesome/react-fontawesome": "^0.1.11",
@ -21,7 +22,7 @@
"@testing-library/react": "^9.5.0", "@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1", "@testing-library/user-event": "^7.2.1",
"axios": "^0.21.0", "axios": "^0.21.0",
"blockly": "^3.20200924.0", "blockly": "^5.20210325.1",
"file-saver": "^2.0.2", "file-saver": "^2.0.2",
"mnemonic-id": "^3.2.7", "mnemonic-id": "^3.2.7",
"moment": "^2.28.0", "moment": "^2.28.0",
@ -1488,6 +1489,17 @@
"node": ">=8.17.0" "node": ">=8.17.0"
} }
}, },
"node_modules/@blockly/zoom-to-fit": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@blockly/zoom-to-fit/-/zoom-to-fit-1.0.5.tgz",
"integrity": "sha512-+dm8bpJB0AkrEMQPr7nEMYKiEA8Loh7V8ZVa0s25PkxGP9BLqt9NIxUCQjshInhCr11Dlctq7C7noqK+tTVS4w==",
"engines": {
"node": ">=8.17.0"
},
"peerDependencies": {
"blockly": ">=5.20210325.0"
}
},
"node_modules/@cnakazawa/watch": { "node_modules/@cnakazawa/watch": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz",
@ -5866,11 +5878,12 @@
} }
}, },
"node_modules/blockly": { "node_modules/blockly": {
"version": "3.20200924.0", "version": "5.20210325.1",
"resolved": "https://registry.npmjs.org/blockly/-/blockly-3.20200924.0.tgz", "resolved": "https://registry.npmjs.org/blockly/-/blockly-5.20210325.1.tgz",
"integrity": "sha512-mOZiXi908oNFAcVb8Q5LKJNRZ5jtBJtgNilddqTYMAXEdqSY/BhcnU2rgytWARDnu2iSQlI374kEafCNuUEWKQ==", "integrity": "sha512-qrilYPovJeDfxKDWm1YBUCPVNElh/iyC1szaHTIPZHj9C9YPpSzZOeFyyrPBbYRudzbo8kjBOWMtHnN1bLjkoQ==",
"license": "Apache-2.0",
"dependencies": { "dependencies": {
"jsdom": "^15.2.1" "jsdom": "15.2.1"
} }
}, },
"node_modules/blockly/node_modules/jsdom": { "node_modules/blockly/node_modules/jsdom": {
@ -26225,6 +26238,12 @@
"@blockly/plugin-modal": "^1.20200427.4" "@blockly/plugin-modal": "^1.20200427.4"
} }
}, },
"@blockly/zoom-to-fit": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@blockly/zoom-to-fit/-/zoom-to-fit-1.0.5.tgz",
"integrity": "sha512-+dm8bpJB0AkrEMQPr7nEMYKiEA8Loh7V8ZVa0s25PkxGP9BLqt9NIxUCQjshInhCr11Dlctq7C7noqK+tTVS4w==",
"requires": {}
},
"@cnakazawa/watch": { "@cnakazawa/watch": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz",
@ -29635,11 +29654,11 @@
} }
}, },
"blockly": { "blockly": {
"version": "3.20200924.0", "version": "5.20210325.1",
"resolved": "https://registry.npmjs.org/blockly/-/blockly-3.20200924.0.tgz", "resolved": "https://registry.npmjs.org/blockly/-/blockly-5.20210325.1.tgz",
"integrity": "sha512-mOZiXi908oNFAcVb8Q5LKJNRZ5jtBJtgNilddqTYMAXEdqSY/BhcnU2rgytWARDnu2iSQlI374kEafCNuUEWKQ==", "integrity": "sha512-qrilYPovJeDfxKDWm1YBUCPVNElh/iyC1szaHTIPZHj9C9YPpSzZOeFyyrPBbYRudzbo8kjBOWMtHnN1bLjkoQ==",
"requires": { "requires": {
"jsdom": "^15.2.1" "jsdom": "15.2.1"
}, },
"dependencies": { "dependencies": {
"jsdom": { "jsdom": {

View File

@ -6,6 +6,7 @@
"@blockly/block-plus-minus": "^2.0.10", "@blockly/block-plus-minus": "^2.0.10",
"@blockly/field-slider": "^2.1.1", "@blockly/field-slider": "^2.1.1",
"@blockly/plugin-typed-variable-modal": "^3.1.1", "@blockly/plugin-typed-variable-modal": "^3.1.1",
"@blockly/zoom-to-fit": "^1.0.5",
"@fortawesome/fontawesome-svg-core": "^1.2.30", "@fortawesome/fontawesome-svg-core": "^1.2.30",
"@fortawesome/free-solid-svg-icons": "^5.14.0", "@fortawesome/free-solid-svg-icons": "^5.14.0",
"@fortawesome/react-fontawesome": "^0.1.11", "@fortawesome/react-fontawesome": "^0.1.11",
@ -16,7 +17,7 @@
"@testing-library/react": "^9.5.0", "@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1", "@testing-library/user-event": "^7.2.1",
"axios": "^0.21.0", "axios": "^0.21.0",
"blockly": "^3.20200924.0", "blockly": "^5.20210325.1",
"file-saver": "^2.0.2", "file-saver": "^2.0.2",
"mnemonic-id": "^3.2.7", "mnemonic-id": "^3.2.7",
"moment": "^2.28.0", "moment": "^2.28.0",

View File

@ -27,7 +27,7 @@
<!-- Matomo Image Tracker--> <!-- Matomo Image Tracker-->
<img <img
src="https://piwik.sensebox.kaufen/matomo.php?idsite=9&amp;rec=1" src="https://piwik.sensebox.kaufen/matomo.php?idsite=9&amp;rec=1"
style="border: 0" style="border: 0; display: none"
alt="" alt=""
/> />
<!-- End Matomo --> <!-- End Matomo -->

View File

@ -38,13 +38,11 @@ export const getTutorials = () => (dispatch, getState) => {
axios.get(`${process.env.REACT_APP_BLOCKLY_API}/tutorial`) axios.get(`${process.env.REACT_APP_BLOCKLY_API}/tutorial`)
.then(res => { .then(res => {
var tutorials = res.data.tutorials; var tutorials = res.data.tutorials;
console.log(tutorials);
existingTutorials(tutorials, getState().tutorial.status).then(status => { existingTutorials(tutorials, getState().tutorial.status).then(status => {
dispatch({ dispatch({
type: TUTORIAL_SUCCESS, type: TUTORIAL_SUCCESS,
payload: status payload: status
}); });
console.log('zwei');
dispatch(updateStatus(status)); dispatch(updateStatus(status));
dispatch({ dispatch({
type: GET_TUTORIALS, type: GET_TUTORIALS,
@ -167,7 +165,6 @@ export const tutorialCheck = (status, step) => (dispatch, getState) => {
type: status === 'success' ? TUTORIAL_SUCCESS : TUTORIAL_ERROR, type: status === 'success' ? TUTORIAL_SUCCESS : TUTORIAL_ERROR,
payload: tutorialsStatus payload: tutorialsStatus
}); });
console.log('drei');
dispatch(updateStatus(tutorialsStatus)); dispatch(updateStatus(tutorialsStatus));
dispatch(tutorialChange()); dispatch(tutorialChange());
dispatch(returnSuccess('', '', 'TUTORIAL_CHECK_SUCCESS')); dispatch(returnSuccess('', '', 'TUTORIAL_CHECK_SUCCESS'));

View File

@ -17,7 +17,6 @@ export const onChangeCode = () => (dispatch, getState) => {
var xmlDom = Blockly.Xml.workspaceToDom(workspace); var xmlDom = Blockly.Xml.workspaceToDom(workspace);
code.xml = Blockly.Xml.domToPrettyText(xmlDom); code.xml = Blockly.Xml.domToPrettyText(xmlDom);
var selectedBlock = Blockly.selected var selectedBlock = Blockly.selected
console.log(selectedBlock)
if (selectedBlock !== null) { if (selectedBlock !== null) {
code.helpurl = selectedBlock.helpUrl code.helpurl = selectedBlock.helpUrl
code.tooltip = selectedBlock.tooltip code.tooltip = selectedBlock.tooltip

View File

@ -1,20 +1,18 @@
import React, { Component } from 'react'; import React, { Component } from "react";
import PropTypes from 'prop-types'; import PropTypes from "prop-types";
import { connect } from 'react-redux'; import { connect } from "react-redux";
import { onChangeWorkspace, clearStats } from '../../actions/workspaceActions'; import { onChangeWorkspace, clearStats } from "../../actions/workspaceActions";
import BlocklyComponent from './BlocklyComponent'; import BlocklyComponent from "./BlocklyComponent";
import BlocklySvg from './BlocklySvg'; import BlocklySvg from "./BlocklySvg";
import * as Blockly from 'blockly/core';
import './blocks/index';
import './generator/index';
import { initialXml } from './initialXml.js';
import * as Blockly from "blockly/core";
import "./blocks/index";
import "./generator/index";
import { ZoomToFitControl } from "@blockly/zoom-to-fit";
import { initialXml } from "./initialXml.js";
class BlocklyWindow extends Component { class BlocklyWindow extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.simpleWorkspace = React.createRef(); this.simpleWorkspace = React.createRef();
@ -33,6 +31,8 @@ class BlocklyWindow extends Component {
} }
}); });
Blockly.svgResize(workspace); Blockly.svgResize(workspace);
const zoomToFit = new ZoomToFitControl(workspace);
zoomToFit.init();
} }
componentDidUpdate(props) { componentDidUpdate(props) {
@ -51,50 +51,68 @@ class BlocklyWindow extends Component {
var xmlDom = Blockly.Xml.textToDom(xml); var xmlDom = Blockly.Xml.textToDom(xml);
Blockly.Xml.clearWorkspaceAndLoadFromXml(xmlDom, workspace); Blockly.Xml.clearWorkspaceAndLoadFromXml(xmlDom, workspace);
// var toolbox = workspace.getToolbox(); // var toolbox = workspace.getToolbox();
// console.log(toolbox);
// workspace.updateToolbox(toolbox.toolboxDef_); // workspace.updateToolbox(toolbox.toolboxDef_);
} }
Blockly.svgResize(workspace); Blockly.svgResize(workspace);
} }
render() { render() {
return ( return (
<div> <div>
<BlocklyComponent ref={this.simpleWorkspace} <BlocklyComponent
ref={this.simpleWorkspace}
style={this.props.svg ? { height: 0 } : this.props.blocklyCSS} style={this.props.svg ? { height: 0 } : this.props.blocklyCSS}
readOnly={this.props.readOnly !== undefined ? this.props.readOnly : false} readOnly={
trashcan={this.props.trashcan !== undefined ? this.props.trashcan : true} this.props.readOnly !== undefined ? this.props.readOnly : false
}
trashcan={
this.props.trashcan !== undefined ? this.props.trashcan : true
}
renderer={this.props.renderer} renderer={this.props.renderer}
zoom={{ // https://developers.google.com/blockly/guides/configure/web/zoom zoom={{
controls: this.props.zoomControls !== undefined ? this.props.zoomControls : true, // https://developers.google.com/blockly/guides/configure/web/zoom
controls:
this.props.zoomControls !== undefined
? this.props.zoomControls
: true,
wheel: false, wheel: false,
startScale: 1, startScale: 1,
maxScale: 3, maxScale: 3,
minScale: 0.3, minScale: 0.3,
scaleSpeed: 1.2 scaleSpeed: 1.2,
}} }}
grid={this.props.grid !== undefined && !this.props.grid ? {} : grid={
{ // https://developers.google.com/blockly/guides/configure/web/grid this.props.grid !== undefined && !this.props.grid
? {}
: {
// https://developers.google.com/blockly/guides/configure/web/grid
spacing: 20, spacing: 20,
length: 1, length: 1,
colour: '#4EAF47', // senseBox-green colour: "#4EAF47", // senseBox-green
snap: false snap: false,
}} }
media={'/media/blockly/'} }
move={this.props.move !== undefined && !this.props.move ? {} : media={"/media/blockly/"}
{ // https://developers.google.com/blockly/guides/configure/web/move move={
this.props.move !== undefined && !this.props.move
? {}
: {
// https://developers.google.com/blockly/guides/configure/web/move
scrollbars: true, scrollbars: true,
drag: true, drag: true,
wheel: false wheel: false,
}} }
initialXml={this.props.initialXml ? this.props.initialXml : initialXml} }
> initialXml={
</BlocklyComponent > this.props.initialXml ? this.props.initialXml : initialXml
{this.props.svg && this.props.initialXml ? <BlocklySvg initialXml={this.props.initialXml} /> : null} }
></BlocklyComponent>
{this.props.svg && this.props.initialXml ? (
<BlocklySvg initialXml={this.props.initialXml} />
) : null}
</div> </div>
); );
}; }
} }
BlocklyWindow.propTypes = { BlocklyWindow.propTypes = {
@ -104,9 +122,11 @@ BlocklyWindow.propTypes = {
language: PropTypes.string.isRequired language: PropTypes.string.isRequired
}; };
const mapStateToProps = state => ({ const mapStateToProps = (state) => ({
renderer: state.general.renderer, renderer: state.general.renderer,
language: state.general.language language: state.general.language
}); });
export default connect(mapStateToProps, { onChangeWorkspace, clearStats })(BlocklyWindow); export default connect(mapStateToProps, { onChangeWorkspace, clearStats })(
BlocklyWindow
);

View File

@ -16,7 +16,7 @@ Blockly.Blocks['controls_whileUntil'] = {
this.setHelpUrl(Blockly.Msg.CONTROLS_WHILEUNTIL_HELPURL); this.setHelpUrl(Blockly.Msg.CONTROLS_WHILEUNTIL_HELPURL);
this.setColour(getColour().loops); this.setColour(getColour().loops);
this.appendValueInput('BOOL') this.appendValueInput('BOOL')
.setCheck(getCompatibleTypes(Boolean)) .setCheck(getCompatibleTypes('boolean'))
.appendField(new Blockly.FieldDropdown(OPERATORS), 'MODE'); .appendField(new Blockly.FieldDropdown(OPERATORS), 'MODE');
this.appendStatementInput('DO') this.appendStatementInput('DO')
.appendField(Blockly.Msg.CONTROLS_WHILEUNTIL_INPUT_DO); .appendField(Blockly.Msg.CONTROLS_WHILEUNTIL_INPUT_DO);
@ -53,19 +53,19 @@ Blockly.Blocks['controls_for'] = {
{ {
"type": "input_value", "type": "input_value",
"name": "FROM", "name": "FROM",
"check": getCompatibleTypes(Number), "check": getCompatibleTypes('int'),
"align": "RIGHT" "align": "RIGHT"
}, },
{ {
"type": "input_value", "type": "input_value",
"name": "TO", "name": "TO",
"check": getCompatibleTypes(Number), "check": getCompatibleTypes('int'),
"align": "RIGHT" "align": "RIGHT"
}, },
{ {
"type": "input_value", "type": "input_value",
"name": "BY", "name": "BY",
"check": getCompatibleTypes(Number), "check": getCompatibleTypes('int'),
"align": "RIGHT" "align": "RIGHT"
} }
], ],
@ -104,7 +104,7 @@ Blockly.Blocks['controls_forEach'] = {
{ {
"type": "input_value", "type": "input_value",
"name": "LIST", "name": "LIST",
"check": getCompatibleTypes(Array) "check": getCompatibleTypes('Array')
} }
], ],
"previousStatement": null, "previousStatement": null,
@ -197,7 +197,7 @@ Blockly.Blocks['controls_repeat_ext'] = {
{ {
"type": "input_value", "type": "input_value",
"name": "TIMES", "name": "TIMES",
"check": getCompatibleTypes(Number), "check": getCompatibleTypes('int'),
} }
], ],
"previousStatement": null, "previousStatement": null,

View File

@ -1148,9 +1148,7 @@ Blockly.Blocks['procedures_callnoreturn'] = {
// This should only be possible programatically and may indicate a problem // This should only be possible programatically and may indicate a problem
// with event grouping. If you see this message please investigate. If the // with event grouping. If you see this message please investigate. If the
// use ends up being valid we may need to reorder events in the undo stack. // use ends up being valid we may need to reorder events in the undo stack.
console.log(
'Saw an existing group while responding to a definition change'
);
} }
Blockly.Events.setGroup(event.group); Blockly.Events.setGroup(event.group);
if (event.newValue) { if (event.newValue) {

View File

@ -73,7 +73,6 @@ Blockly.Blocks['sensebox_osem_connection'] = {
* Blockly.Blocks['controls_flow_statements'].LOOP_TYPES.push('custom_loop'); * Blockly.Blocks['controls_flow_statements'].LOOP_TYPES.push('custom_loop');
*/ */
selectedBox = this.getFieldValue('BoxID'); selectedBox = this.getFieldValue('BoxID');
console.log(selectedBox)
if (selectedBox !== '' && boxes) { if (selectedBox !== '' && boxes) {
var accessToken = boxes.find(element => element._id === selectedBox).access_token var accessToken = boxes.find(element => element._id === selectedBox).access_token
if (accessToken !== undefined) { if (accessToken !== undefined) {
@ -160,7 +159,6 @@ Blockly.Blocks['sensebox_send_to_osem'] = {
for (var i = 0; i < box.sensors.length; i++) { for (var i = 0; i < box.sensors.length; i++) {
dropdown.push([box.sensors[i].title, box.sensors[i]._id]) dropdown.push([box.sensors[i].title, box.sensors[i]._id])
} }
console.log(dropdown)
} }
if (dropdown.length > 1) { if (dropdown.length > 1) {
var options = dropdown.slice(1) var options = dropdown.slice(1)

View File

@ -1,4 +1,36 @@
import * as Blockly from "blockly/core";
import { getColour } from "../helpers/colour";
import * as Types from "../helpers/types";
Blockly.Blocks["sensebox_multiplexer_init"] = {
init: function () {
this.appendDummyInput().appendField(Blockly.Msg.senseBox_multiplexer_init);
this.appendValueInput("nrChannels").setCheck(
Types.getCompatibleTypes("int")
);
this.appendDummyInput().appendField(
Blockly.Msg.senseBox_multplexer_nchannels
);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setInputsInline("true");
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.senseBox_multiplexer_init_tooltip);
this.setHelpUrl(Blockly.Msg.senseBox_multiplexer_init_helpurl);
},
};
Blockly.Blocks["sensebox_multiplexer_changeChannel"] = {
init: function () {
this.appendDummyInput().appendField(
Blockly.Msg.senseBox_multiplexer_changeChannel
);
this.appendValueInput("Channel").setCheck(Types.getCompatibleTypes("int"));
this.setInputsInline("true");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setColour(getColour().sensebox);
this.setTooltip(Blockly.Msg.sensebox_multiplexer_changeChannel_tooltip);
this.setHelpUrl(Blockly.Msg.sensebox_multiplexer_changeChannel_helpurl);
},
};

View File

@ -1,43 +1,46 @@
import Blockly from 'blockly/core'; import Blockly from "blockly/core";
import { getColour } from '../helpers/colour'; import { getColour } from "../helpers/colour";
import { getCompatibleTypes } from '../helpers/types' import { getCompatibleTypes } from "../helpers/types";
Blockly.Blocks["variables_set_dynamic"] = {
Blockly.Blocks['variables_set_dynamic'] = {
init: function () { init: function () {
// const type = myVar.type; // const type = myVar.type;
this.setColour(getColour().variables); this.setColour(getColour().variables);
this.setPreviousStatement(true, null); this.setPreviousStatement(true, null);
this.setNextStatement(true, null); this.setNextStatement(true, null);
this.appendValueInput('VALUE') this.appendValueInput("VALUE")
.appendField('set', 'set') .appendField("set", "set")
.appendField('', 'type') .appendField("", "type")
.appendField(new Blockly.FieldVariable('VAR'), 'VAR') .appendField(new Blockly.FieldVariable("VAR"), "VAR")
.appendField('to'); .appendField("to");
}, },
onchange: function (e) { onchange: function (e) {
let variableID = this.getFieldValue('VAR'); let variableID = this.getFieldValue("VAR");
let variable = Blockly.getMainWorkspace().getVariableMap().getVariableById(variableID) let variable = Blockly.getMainWorkspace()
this.getField('type').setValue(variable.type); .getVariableMap()
this.getInput('VALUE').setCheck(getCompatibleTypes(variable.type)); .getVariableById(variableID);
if (variable !== null) {
} this.getField("type").setValue(variable.type);
this.getInput("VALUE").setCheck(getCompatibleTypes(variable.type));
} }
},
};
Blockly.Blocks['variables_get_dynamic'] = { Blockly.Blocks["variables_get_dynamic"] = {
init: function () { init: function () {
this.setColour(getColour().variables); this.setColour(getColour().variables);
this.appendDummyInput() this.appendDummyInput()
.appendField('', 'type') .appendField("", "type")
.appendField(new Blockly.FieldVariable('VAR'), 'VAR'); .appendField(new Blockly.FieldVariable("VAR"), "VAR");
this.setOutput(true); this.setOutput(true);
}, },
onchange: function (e) { onchange: function (e) {
let variableID = this.getFieldValue('VAR'); let variableID = this.getFieldValue("VAR");
let variable = Blockly.getMainWorkspace().getVariableMap().getVariableById(variableID) let variable = Blockly.getMainWorkspace()
this.getField('type').setValue(variable.type); .getVariableMap()
.getVariableById(variableID);
if (variable !== null) {
this.getField("type").setValue(variable.type);
} }
} },
};

View File

@ -7,6 +7,7 @@ import "./sensebox-web";
import "./sensebox-display"; import "./sensebox-display";
import "./sensebox-lora"; import "./sensebox-lora";
import "./sensebox-led"; import "./sensebox-led";
import "./sensebox";
import "./sensebox-rtc"; import "./sensebox-rtc";
import "./sensebox-ble"; import "./sensebox-ble";
import "./sensebox-sd"; import "./sensebox-sd";

View File

@ -68,7 +68,6 @@ Blockly.Arduino['procedures_defreturn'] = function (block) {
}; };
function translateType(type) { function translateType(type) {
console.log(type);
switch (type) { switch (type) {
case 'int': case 'int':

View File

@ -33,7 +33,6 @@ Blockly.Arduino.sensebox_ws2818_led = function () {
var dropdown_pin = this.getFieldValue('Port'); var dropdown_pin = this.getFieldValue('Port');
var position = Blockly.Arduino.valueToCode(this, 'POSITION', Blockly.Arduino.ORDER_ATOMIC) || '0'; var position = Blockly.Arduino.valueToCode(this, 'POSITION', Blockly.Arduino.ORDER_ATOMIC) || '0';
var color = Blockly.Arduino.valueToCode(this, 'COLOR', Blockly.Arduino.ORDER_ATOMIC) || '0' var color = Blockly.Arduino.valueToCode(this, 'COLOR', Blockly.Arduino.ORDER_ATOMIC) || '0'
console.log(color)
var code = `rgb_led_${dropdown_pin}.setPixelColor(${position},rgb_led_${dropdown_pin}.Color(${color}));\nrgb_led_${dropdown_pin}.show();\n`; var code = `rgb_led_${dropdown_pin}.setPixelColor(${position},rgb_led_${dropdown_pin}.Color(${color}));\nrgb_led_${dropdown_pin}.show();\n`;
return code; return code;
}; };

View File

@ -1,3 +1,38 @@
import * as Blockly from 'blockly/core'; import * as Blockly from "blockly/core";
import { Block } from 'blockly';
/*
* Multiplexer
*/
Blockly.Arduino.sensebox_multiplexer_init = function () {
// Blockly.Arduino.libraries_['library_spi'] = '#include <SPI.h>';
var nrChannels =
Blockly.Arduino.valueToCode(
this,
"nrChannels",
Blockly.Arduino.ORDER_ATOMIC
) | 0;
var array = [];
for (var i = 0; i < nrChannels; i++) {
array.push(i);
}
Blockly.Arduino.libraries_["library_wire"] = "#include <Wire.h>";
Blockly.Arduino.definitions_[
"define_multiplexer"
] = `byte multiplexAddress = 0x77;
byte channels[] = {${array}};`;
// Blockly.Arduino.setupCode_['sensebox_display_begin'] = 'senseBoxIO.powerI2C(true);\ndelay(2000);\ndisplay.begin(SSD1306_SWITCHCAPVCC, 0x3D);\ndisplay.display();\ndelay(100);\ndisplay.clearDisplay();';
var code = "";
return code;
};
Blockly.Arduino.sensebox_multiplexer_changeChannel = function () {
var channel = Blockly.Arduino.valueToCode(
this,
"Channel",
Blockly.Arduino.ORDER_ATOMIC
);
var code = `Wire.beginTransmission(0x77);
Wire.write(1 << channels[${channel - 1}]);
Wire.endTransmission();`;
return code;
};

View File

@ -1,36 +1,44 @@
import Blockly from 'blockly'; import Blockly from "blockly";
const setVariableFunction = function (defaultValue) { const setVariableFunction = function (defaultValue) {
return function (block) { return function (block) {
const variableName = Blockly['Arduino'].variableDB_.getName( const variableName = Blockly["Arduino"].variableDB_.getName(
block.getFieldValue('VAR'), block.getFieldValue("VAR"),
Blockly.Variables.NAME_TYPE Blockly.Variables.NAME_TYPE
); );
const variableValue = Blockly['Arduino'].valueToCode( const variableValue = Blockly["Arduino"].valueToCode(
block, block,
'VALUE', "VALUE",
Blockly['Arduino'].ORDER_ATOMIC Blockly["Arduino"].ORDER_ATOMIC
); );
const allVars = Blockly.getMainWorkspace().getVariableMap().getAllVariables(); const allVars = Blockly.getMainWorkspace()
const myVar = allVars.filter(v => v.name === variableName)[0] .getVariableMap()
var code = '' .getAllVariables();
const myVar = allVars.filter((v) => v.name === variableName)[0];
var code = "";
switch (myVar.type) { switch (myVar.type) {
default: default:
Blockly.Arduino.variables_[myVar + myVar.type] = myVar.type + " " + myVar.name + ';\n'; Blockly.Arduino.variables_[variableName + myVar.type] =
code = variableName + ' = ' + (variableValue || defaultValue) + ';\n'; myVar.type + " " + myVar.name + ";\n";
code = variableName + " = " + (variableValue || defaultValue) + ";\n";
break; break;
case 'Array': case "Array":
var arrayType; var arrayType;
var number; var number;
if (this.getChildren().length > 0) { if (this.getChildren().length > 0) {
if (this.getChildren()[0].type === 'lists_create_empty') { if (this.getChildren()[0].type === "lists_create_empty") {
arrayType = this.getChildren()[0].getFieldValue("type");
arrayType = this.getChildren()[0].getFieldValue('type'); number = Blockly.Arduino.valueToCode(
number = Blockly.Arduino.valueToCode(this.getChildren()[0], 'NUMBER', Blockly['Arduino'].ORDER_ATOMIC); this.getChildren()[0],
Blockly.Arduino.variables_[myVar + myVar.type] = `${arrayType} ${myVar.name} [${number}];\n`; "NUMBER",
Blockly["Arduino"].ORDER_ATOMIC
);
Blockly.Arduino.variables_[
myVar + myVar.type
] = `${arrayType} ${myVar.name} [${number}];\n`;
} }
} }
break; break;
@ -40,13 +48,13 @@ const setVariableFunction = function (defaultValue) {
}; };
const getVariableFunction = function (block) { const getVariableFunction = function (block) {
const variableName = Blockly['Arduino'].variableDB_.getName( const variableName = Blockly["Arduino"].variableDB_.getName(
block.getFieldValue('VAR'), block.getFieldValue("VAR"),
Blockly.Variables.NAME_TYPE Blockly.Variables.NAME_TYPE
); );
var code = variableName; var code = variableName;
return [code, Blockly['Arduino'].ORDER_ATOMIC]; return [code, Blockly["Arduino"].ORDER_ATOMIC];
}; };
Blockly['Arduino']['variables_set_dynamic'] = setVariableFunction() Blockly["Arduino"]["variables_set_dynamic"] = setVariableFunction();
Blockly['Arduino']['variables_get_dynamic'] = getVariableFunction; Blockly["Arduino"]["variables_get_dynamic"] = getVariableFunction;

View File

@ -105,135 +105,3 @@ export const getCompatibleTypes = (type) => {
}; };
export const VARIABLE_TYPES = [['SHORT_NUMBER', 'char'], ['NUMBER', 'int'], ['DECIMAL', 'long'], ['TEXT', 'String'], ['CHARACTER', 'char'], ['BOOLEAN', 'boolean'], ['NULL', 'void'], ['UNDEF', 'undefined']]; export const VARIABLE_TYPES = [['SHORT_NUMBER', 'char'], ['NUMBER', 'int'], ['DECIMAL', 'long'], ['TEXT', 'String'], ['CHARACTER', 'char'], ['BOOLEAN', 'boolean'], ['NULL', 'void'], ['UNDEF', 'undefined']];
// /**
// * Some Types have circular dependencies on their compatibilities, so add them
// * after declaration.
// */
// Blockly.Types.NUMBER.addCompatibleTypes([
// Blockly.Types.BOOLEAN,
// Blockly.Types.SHORT_NUMBER,
// Blockly.Types.LARGE_NUMBER,
// Blockly.Types.DECIMAL]);
// Blockly.Types.SHORT_NUMBER.addCompatibleTypes([
// Blockly.Types.BOOLEAN,
// Blockly.Types.NUMBER,
// Blockly.Types.LARGE_NUMBER,
// Blockly.Types.DECIMAL]);
// Blockly.Types.LARGE_NUMBER.addCompatibleTypes([
// Blockly.Types.BOOLEAN,
// Blockly.Types.SHORT_NUMBER,
// Blockly.Types.NUMBER,
// Blockly.Types.DECIMAL]);
// /**
// * Adds another type to the Blockly.Types collection.
// * @param {string} typeId_ Identifiable name of the type.
// * @param {string} typeMsgName_ Name of the member variable from Blockly.Msg
// * object to identify the translateble string.for the Type name.
// * @param {Array<Blockly.Type>} compatibleTypes_ List of types this Type is
// * compatible with.
// */
// Blockly.Types.addType = function (typeId_, typeMsgName_, compatibleTypes_) {
// // The Id is used as the key from the value pair in the BlocklyTypes object
// var key = typeId_.toUpperCase().replace(/ /g, '_');
// if (Blockly.Types[key] !== undefined) {
// throw 'The Blockly type ' + key + ' already exists.';
// }
// Blockly.Types[key] = new Blockly.Type({
// typeId: typeId_,
// typeName: typeMsgName_,
// compatibleTypes: compatibleTypes_
// });
// };
// /**
// * Converts the static types dictionary in to a an array with 2-item arrays.
// * This array only contains the valid types, excluding any error or temp types.
// * @return {!Array<Array<string>>} Blockly types in the format described above.
// */
// Blockly.Types.getValidTypeArray = function () {
// var typesArray = [];
// for (var typeKey in Blockly.Types) {
// if ((typeKey !== 'UNDEF') && (typeKey !== 'CHILD_BLOCK_MISSING') &&
// (typeKey !== 'NULL') && (typeKey !== 'ARRAY') &&
// (typeof Blockly.Types[typeKey] !== 'function') &&
// !(Blockly.Types[typeKey] instanceof RegExp)) {
// typesArray.push([Blockly.Types[typeKey].typeName, typeKey]);
// }
// }
// return typesArray;
// };
// /**
// * Navigates through child blocks of the argument block to get this block type.
// * @param {!Blockly.Block} block Block to navigate through children.
// * @return {Blockly.Type} Type of the input block.
// */
// Blockly.Types.getChildBlockType = function (block) {
// var blockType = null;
// var nextBlock = block;
// // Only checks first input block, so it decides the type. Incoherences amongst
// // multiple inputs dealt at a per-block level with their own block warnings
// while (nextBlock && (nextBlock.getBlockType === undefined) &&
// (nextBlock.inputList.length > 0) &&
// (nextBlock.inputList[0].connection)) {
// nextBlock = nextBlock.inputList[0].connection.targetBlock();
// }
// if (nextBlock === block) {
// // Set variable block is empty, so no type yet
// blockType = Blockly.Types.CHILD_BLOCK_MISSING;
// } else if (nextBlock === null) {
// // Null return from targetBlock indicates no block connected
// blockType = Blockly.Types.CHILD_BLOCK_MISSING;
// } else {
// var func = nextBlock.getBlockType;
// if (func) {
// blockType = nextBlock.getBlockType();
// } else {
// // Most inner block, supposed to define a type, is missing getBlockType()
// blockType = Blockly.Types.NULL;
// }
// }
// return blockType;
// };
// /**
// * Regular expressions to identify an integer.
// * @private
// */
// Blockly.Types.regExpInt_ = new RegExp(/^-?\d+$/);
// /**
// * Regular expressions to identify a decimal.
// * @private
// */
// Blockly.Types.regExpFloat_ = new RegExp(/^-?[0-9]*[.][0-9]+$/);
// /**
// * Uses regular expressions to identify if the input number is an integer or a
// * floating point.
// * @param {string} numberString String of the number to identify.
// * @return {!Blockly.Type} Blockly type.
// */
// Blockly.Types.identifyNumber = function (numberString) {
// if (Blockly.Types.regExpInt_.test(numberString)) {
// var intValue = parseInt(numberString);
// if (isNaN(intValue)) {
// return Blockly.Types.NULL;
// }
// if (intValue > 32767 || intValue < -32768) {
// return Blockly.Types.LARGE_NUMBER;
// }
// return Blockly.Types.NUMBER;
// } else if (Blockly.Types.regExpFloat_.test(numberString)) {
// return Blockly.Types.DECIMAL;
// }
// return Blockly.Types.NULL;
// };

View File

@ -13,6 +13,7 @@ import { OSEM } from "./de/sensebox-osem";
import { RTC } from "./de/sensebox-rtc"; import { RTC } from "./de/sensebox-rtc";
import { SD } from "./de/sensebox-sd"; import { SD } from "./de/sensebox-sd";
import { SENSORS } from "./de/sensebox-sensors"; import { SENSORS } from "./de/sensebox-sensors";
import { SENSEBOX } from "./de/sensebox";
import { TELEGRAM } from "./de/sensebox-telegram"; import { TELEGRAM } from "./de/sensebox-telegram";
import { WEB } from "./de/sensebox-web"; import { WEB } from "./de/sensebox-web";
import { TEXT } from "./de/text"; import { TEXT } from "./de/text";
@ -39,6 +40,7 @@ export const De = {
...RTC, ...RTC,
...SD, ...SD,
...SENSORS, ...SENSORS,
...SENSEBOX,
...TELEGRAM, ...TELEGRAM,
...WEB, ...WEB,
...TEXT, ...TEXT,

View File

@ -0,0 +1,16 @@
export const SENSEBOX = {
/**
* Multiplexer
*/
senseBox_multiplexer_init: "Initialisiere Multiplexer mit ",
senseBox_multiplexer_init_tooltip:
"Schließe den Multiplexer mit einem JST-JST Kabel an einen der 5 I2C-Ports an. Nun kannst du bis zu 8 gleiche Sensoren verwenden über die entsprechenden Kanäle ansprechen. Gib im Block die Anzahl der verwendeten Kanäle an",
senseBox_multiplexer_init_helpurl:
"https://docs.sensebox.de/hardware/zubehoer-multiplexer/",
senseBox_multplexer_nchannels: "Kanälen",
senseBox_multiplexer_changeChannel: "Wechsel Kanal auf:",
sensebox_multiplexer_changeChannel_tooltip:
"Wähle den entsprechenden Kanal aus",
sensebox_multiplexer_changeChannel_helpurl:
"https://docs.sensebox.de/hardware/zubehoer-multiplexer/",
};

View File

@ -1,4 +1,3 @@
export const UI = { export const UI = {
/** /**
* Toolbox * Toolbox
@ -11,6 +10,16 @@ export const UI = {
toolbox_time: "Zeit", toolbox_time: "Zeit",
toolbox_functions: "Funktionen", toolbox_functions: "Funktionen",
toolbox_variables: "Variablen", toolbox_variables: "Variablen",
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_BOOLEAN: "Boolean (boolean)",
variables_NULL: "void (void)",
variables_UNDEF: "undefined",
/** /**
* Tooltips * Tooltips
@ -35,8 +44,8 @@ export const UI = {
tooltip_share_project: "Projekt teilen", tooltip_share_project: "Projekt teilen",
tooltip_reset_workspace: "Workspace zurücksetzen", tooltip_reset_workspace: "Workspace zurücksetzen",
tooltip_copy_link: "Link kopieren", tooltip_copy_link: "Link kopieren",
tooltip_trashcan_hide: 'gelöschte Blöcke ausblenden', tooltip_trashcan_hide: "gelöschte Blöcke ausblenden",
tooltip_trashcan_delete: 'Blöcke endgültig löschen', tooltip_trashcan_delete: "Blöcke endgültig löschen",
tooltip_project_title: "Titel des Projektes", tooltip_project_title: "Titel des Projektes",
tooltip_check_solution: "Lösung kontrollieren", tooltip_check_solution: "Lösung kontrollieren",
tooltip_copy_code: "Code in die Zwischenablage kopieren", tooltip_copy_code: "Code in die Zwischenablage kopieren",
@ -46,24 +55,42 @@ export const UI = {
* *
*/ */
messages_delete_project_failed: "Fehler beim Löschen des Projektes. Versuche es noch einmal.", messages_delete_project_failed:
messages_reset_workspace_success: "Das Projekt wurde erfolgreich zurückgesetzt", "Fehler beim Löschen des Projektes. Versuche es noch einmal.",
messages_PROJECT_UPDATE_SUCCESS: "Das Projekt wurde erfolgreich aktualisiert.", messages_reset_workspace_success:
messages_GALLERY_UPDATE_SUCCESS: "Das Galerie-Projekt wurde erfolgreich aktualisiert.", "Das Projekt wurde erfolgreich zurückgesetzt",
messages_PROJECT_UPDATE_FAIL: "Fehler beim Aktualisieren des Projektes. Versuche es noch einmal.", messages_PROJECT_UPDATE_SUCCESS:
messages_GALLERY_UPDATE_FAIL: "Fehler beim Aktualisieren des Galerie-Projektes. Versuche es noch einmal.", "Das Projekt wurde erfolgreich aktualisiert.",
messages_GALLERY_UPDATE_SUCCESS:
"Das Galerie-Projekt wurde erfolgreich aktualisiert.",
messages_PROJECT_UPDATE_FAIL:
"Fehler beim Aktualisieren des Projektes. Versuche es noch einmal.",
messages_GALLERY_UPDATE_FAIL:
"Fehler beim Aktualisieren des Galerie-Projektes. Versuche es noch einmal.",
messages_gallery_save_fail_1: "Fehler beim Speichern des ", messages_gallery_save_fail_1: "Fehler beim Speichern des ",
messages_gallery_save_fail_2: "Projektes. Versuche es noch einmal.", messages_gallery_save_fail_2: "Projektes. Versuche es noch einmal.",
messages_SHARE_SUCCESS: 'Programm teilen', messages_SHARE_SUCCESS: "Programm teilen",
messages_SHARE_FAIL: "Fehler beim Erstellen eines Links zum Teilen deines Programmes. Versuche es noch einmal.", messages_SHARE_FAIL:
messages_copylink_success: 'Link erfolgreich in Zwischenablage gespeichert.', "Fehler beim Erstellen eines Links zum Teilen deines Programmes. Versuche es noch einmal.",
messages_rename_success_01: 'Das Projekt wurde erfolgreich in ', messages_copylink_success: "Link erfolgreich in Zwischenablage gespeichert.",
messages_rename_success_02: 'umbenannt.', messages_rename_success_01: "Das Projekt wurde erfolgreich in ",
messages_newblockly_head: "Willkommen zur neuen Version Blockly für die senseBox", messages_rename_success_02: "umbenannt.",
messages_newblockly_text: "Die neue Blockly-Version befindet sich derzeit in der Testphase. Wenn Sie einen Fehler finden, melden Sie diesen bitte in unserem [Forum](https://forum.sensebox.de/t/neue-blockly-version-beta-test-und-feedback/1176). Eine Übersicht über alle neuen Funktionen finden Sie [hier](/news)", messages_newblockly_head:
messages_GET_TUTORIAL_FAIL: 'Zurück zur Tutorials-Übersicht', "Willkommen zur neuen Version Blockly für die senseBox",
messages_LOGIN_FAIL: 'Der Benutzername oder das Passwort ist nicht korrekt.', messages_newblockly_text:
"Die neue Blockly-Version befindet sich derzeit in der Testphase. Wenn Sie einen Fehler finden, melden Sie diesen bitte in unserem [Forum](https://forum.sensebox.de/t/neue-blockly-version-beta-test-und-feedback/1176). Eine Übersicht über alle neuen Funktionen finden Sie [hier](/news)",
messages_GET_TUTORIAL_FAIL: "Zurück zur Tutorials-Übersicht",
messages_LOGIN_FAIL: "Der Benutzername oder das Passwort ist nicht korrekt.",
messages_copy_code: "Code wurde in die Zwischenablage kopiert", messages_copy_code: "Code wurde in die Zwischenablage kopiert",
/**
* Reset Dialog
*/
resetDialog_headline: "Workspace zurücksetzen?",
resetDialog_text:
"Möchtest du wirklich die Workspace zurücksetzen? Hierbei werden alle Blöcke gelöscht!",
/** /**
* Share Dialog * Share Dialog
*/ */
@ -76,7 +103,8 @@ export const UI = {
*/ */
renamedialog_headline: "Projekt benennen", renamedialog_headline: "Projekt benennen",
renamedialog_text: "Bitte gib einen Namen für das Projekt ein und bestätige diesen mit einem Klick auf 'Bestätigen'.", renamedialog_text:
"Bitte gib einen Namen für das Projekt ein und bestätige diesen mit einem Klick auf 'Bestätigen'.",
/** /**
* Compile Dialog * Compile Dialog
@ -84,7 +112,8 @@ export const UI = {
*/ */
compiledialog_headline: "Fehler", compiledialog_headline: "Fehler",
compiledialog_text: "Beim kompilieren ist ein Fehler aufgetreten. Überprüfe deine Blöcke und versuche es erneut", compiledialog_text:
"Beim kompilieren ist ein Fehler aufgetreten. Überprüfe deine Blöcke und versuche es erneut",
/** /**
* Buttons * Buttons
@ -113,13 +142,16 @@ export const UI = {
*/ */
settings_head: "Einstellungen", settings_head: "Einstellungen",
settings_language: "Sprache", settings_language: "Sprache",
settings_language_text: "Auswahl der Sprache gilt für die gesamte Anwendung. Es kann zwischen Deutsch und Englisch unterschieden werden.", settings_language_text:
"Auswahl der Sprache gilt für die gesamte Anwendung. Es kann zwischen Deutsch und Englisch unterschieden werden.",
settings_language_de: "Deutsch", settings_language_de: "Deutsch",
settings_language_en: "Englisch", settings_language_en: "Englisch",
settings_renderer: "Renderer", settings_renderer: "Renderer",
settings_renderer_text: "Der eingestellte Renderer bestimmt das Aussehen der Blöcke. Es kann zwischen 'Geras' und 'Zelos' unterschieden werden, wobei 'Zelos' insbesondere für eine Touch-Anwendung geeignet ist.", settings_renderer_text:
"Der eingestellte Renderer bestimmt das Aussehen der Blöcke. Es kann zwischen 'Geras' und 'Zelos' unterschieden werden, wobei 'Zelos' insbesondere für eine Touch-Anwendung geeignet ist.",
settings_statistics: "Statistiken", settings_statistics: "Statistiken",
settings_statistics_text: "Die Anzeige von Statistiken zur Nutzung der Blöcke oberhalb der Arbeitsfläche kann ein- oder ausgeblendet werden.", settings_statistics_text:
"Die Anzeige von Statistiken zur Nutzung der Blöcke oberhalb der Arbeitsfläche kann ein- oder ausgeblendet werden.",
settings_statistics_on: "An", settings_statistics_on: "An",
settings_statistics_off: "Aus", settings_statistics_off: "Aus",
@ -128,23 +160,24 @@ export const UI = {
*/ */
notfound_head: "Die von Ihnen angeforderte Seite kann nicht gefunden werden.", notfound_head: "Die von Ihnen angeforderte Seite kann nicht gefunden werden.",
notfound_text: "Die gesuchte Seite wurde möglicherweise entfernt, ihr Name wurde geändert oder sie ist vorübergehend nicht verfügbar.", notfound_text:
"Die gesuchte Seite wurde möglicherweise entfernt, ihr Name wurde geändert oder sie ist vorübergehend nicht verfügbar.",
/** /**
* Labels * Labels
*/ */
labels_donotshowagain: 'Dialog nicht mehr anzeigen', labels_donotshowagain: "Dialog nicht mehr anzeigen",
labels_here: "hier", labels_here: "hier",
labels_username: 'E-Mail oder Nutzername', labels_username: "E-Mail oder Nutzername",
labels_password: "Passwort", labels_password: "Passwort",
/** /**
* Badges * Badges
*/ */
badges_explaination: "Eine Übersicht über alle erhaltenen Badges im Kontext Blockly for senseBox findest du ", badges_explaination:
"Eine Übersicht über alle erhaltenen Badges im Kontext Blockly for senseBox findest du ",
badges_ASSIGNE_BADGE_SUCCESS_01: "Herzlichen Glückwunsch! Du hast den Badge ", badges_ASSIGNE_BADGE_SUCCESS_01: "Herzlichen Glückwunsch! Du hast den Badge ",
badges_ASSIGNE_BADGE_SUCCESS_02: " erhalten.", badges_ASSIGNE_BADGE_SUCCESS_02: " erhalten.",
/** /**
@ -153,10 +186,11 @@ export const UI = {
tutorials_assessment_task: "Aufgabe", tutorials_assessment_task: "Aufgabe",
tutorials_hardware_head: "Für die Umsetzung benötigst du folgende Hardware:", tutorials_hardware_head: "Für die Umsetzung benötigst du folgende Hardware:",
tutorials_hardware_moreInformation: "Weitere Informationen zur Hardware-Komponente findest du", tutorials_hardware_moreInformation:
"Weitere Informationen zur Hardware-Komponente findest du",
tutorials_hardware_here: "hier", tutorials_hardware_here: "hier",
tutorials_requirements: "Bevor du mit diesem Tutorial fortfährst solltest du folgende Tutorials erfolgreich abgeschlossen haben:", tutorials_requirements:
"Bevor du mit diesem Tutorial fortfährst solltest du folgende Tutorials erfolgreich abgeschlossen haben:",
/** /**
* Tutorial Builder * Tutorial Builder
@ -165,17 +199,19 @@ export const UI = {
builder_solution: "Lösung", builder_solution: "Lösung",
builder_solution_submit: "Lösung einreichen", builder_solution_submit: "Lösung einreichen",
builder_example_submit: "Beispiel einreichen", builder_example_submit: "Beispiel einreichen",
builder_comment: "Anmerkung: Man kann den initialen Setup()- bzw. Endlosschleifen()-Block löschen. Zusätzlich ist es möglich u.a. nur einen beliebigen Block auszuwählen, ohne dass dieser als deaktiviert dargestellt wird.", builder_comment:
builder_hardware_order: "Beachte, dass die Reihenfolge des Auswählens maßgebend ist.", "Anmerkung: Man kann den initialen Setup()- bzw. Endlosschleifen()-Block löschen. Zusätzlich ist es möglich u.a. nur einen beliebigen Block auszuwählen, ohne dass dieser als deaktiviert dargestellt wird.",
builder_hardware_order:
"Beachte, dass die Reihenfolge des Auswählens maßgebend ist.",
builder_hardware_helper: "Wähle mindestens eine Hardware-Komponente aus.", builder_hardware_helper: "Wähle mindestens eine Hardware-Komponente aus.",
builder_requirements_head: "Voraussetzungen", builder_requirements_head: "Voraussetzungen",
builder_requirements_order: "Beachte, dass die Reihenfolge des Anhakens maßgebend ist.", builder_requirements_order:
"Beachte, dass die Reihenfolge des Anhakens maßgebend ist.",
/** /**
* Login * Login
*/ */
login_head: "Anmelden", login_head: "Anmelden",
login_osem_account_01: "Du benötigst einen ", login_osem_account_01: "Du benötigst einen ",
login_osem_account_02: "Account um dich einzuloggen", login_osem_account_02: "Account um dich einzuloggen",
@ -204,8 +240,6 @@ export const UI = {
codeviewer_arduino: "Arduino Quellcode", codeviewer_arduino: "Arduino Quellcode",
codeviewer_xml: "XML Blöcke", codeviewer_xml: "XML Blöcke",
/** /**
* Overlay * Overlay
*/ */
@ -221,4 +255,11 @@ export const UI = {
tooltip_viewer: "Hilfe", tooltip_viewer: "Hilfe",
tooltip_moreInformation: "Mehr Informationen findest du ", tooltip_moreInformation: "Mehr Informationen findest du ",
tooltip_hint: "Wähle einen Block aus um dir die Hilfe anzeigen zu lassen", tooltip_hint: "Wähle einen Block aus um dir die Hilfe anzeigen zu lassen",
}
/**
* IDEDrawer
*/
drawer_ideerror_head: "Hoppla da ist was schief gegangen.",
drawer_ideerror_text:
"Beim kompilieren ist ein Fehler aufgetreten, überprüfe deine Blöcke.",
};

View File

@ -6,6 +6,7 @@ import { LOGIC } from "./en/logic";
import { LOOPS } from "./en/loops"; import { LOOPS } from "./en/loops";
import { MATH } from "./en/math"; import { MATH } from "./en/math";
import { MQTT } from "./en/mqtt"; import { MQTT } from "./en/mqtt";
import { SENSEBOX } from "./en/sensebox";
import { DISPLAY } from "./en/sensebox-display"; import { DISPLAY } from "./en/sensebox-display";
import { LED } from "./en/sensebox-led"; import { LED } from "./en/sensebox-led";
import { LORA } from "./en/sensebox-lora"; import { LORA } from "./en/sensebox-lora";
@ -39,6 +40,7 @@ export const En = {
...RTC, ...RTC,
...SD, ...SD,
...SENSORS, ...SENSORS,
...SENSEBOX,
...TELEGRAM, ...TELEGRAM,
...WEB, ...WEB,
...TEXT, ...TEXT,

View File

@ -0,0 +1,16 @@
export const SENSEBOX = {
/**
* Multiplexer
*/
senseBox_multiplexer_init: "Initialise Multiplexer with ",
senseBox_multiplexer_init_tooltip:
"Connect the multiplexer with a JST-JST cable to one of the 5 I2C ports. Now you can use up to 8 sensors of the same type and address them via the corresponding channels. Enter the number of used channels in the block",
senseBox_multiplexer_init_helpurl:
"https://en.docs.sensebox.de/hardware/zubehoer-multiplexer/",
senseBox_multplexer_nchannels: "Channels",
senseBox_multiplexer_changeChannel: "Change active channel to:",
sensebox_multiplexer_changeChannel_tooltip:
"Changes the active channel to the selected number",
sensebox_multiplexer_changeChannel_helpurl:
"https://en.docs.sensebox.de/hardware/zubehoer-multiplexer/",
};

View File

@ -1,7 +1,4 @@
export const UI = { export const UI = {
/** /**
* Toolbox * Toolbox
*/ */
@ -13,6 +10,16 @@ export const UI = {
toolbox_time: "Time", toolbox_time: "Time",
toolbox_functions: "Functions", toolbox_functions: "Functions",
toolbox_variables: "Variables", toolbox_variables: "Variables",
variable_NUMBER: "Number (int)",
variable_SHORT_NUMBER: "char",
variable_LONG: " Zahl (long)",
variable_DECIMAL: "Decimal (float)",
variables_TEXT: "Text (string)",
variables_ARRAY: "Array (array)",
variables_CHARACTER: "char (char)",
variables_BOOLEAN: "Boolean (boolean)",
variables_NULL: "void (void)",
variables_UNDEF: "undefined",
/** /**
* Tooltips * Tooltips
@ -51,22 +58,36 @@ export const UI = {
messages_delete_project_failed: "Error deleting the project. Try again.", messages_delete_project_failed: "Error deleting the project. Try again.",
messages_reset_workspace_success: "The project has been successfully reset.", messages_reset_workspace_success: "The project has been successfully reset.",
messages_PROJECT_UPDATE_SUCCESS: "The project was successfully updated.", messages_PROJECT_UPDATE_SUCCESS: "The project was successfully updated.",
messages_GALLERY_UPDATE_SUCCESS: "The gallery project was successfully updated.", messages_GALLERY_UPDATE_SUCCESS:
"The gallery project was successfully updated.",
messages_PROJECT_UPDATE_FAIL: "Error updating the project. Try again.", messages_PROJECT_UPDATE_FAIL: "Error updating the project. Try again.",
messages_GALLERY_UPDATE_FAIL: "Error updating the gallery project. Try again.", messages_GALLERY_UPDATE_FAIL:
"Error updating the gallery project. Try again.",
messages_gallery_save_fail_1: "Error saving the ", messages_gallery_save_fail_1: "Error saving the ",
messages_gallery_save_fail_2: "Project. Try again.", messages_gallery_save_fail_2: "Project. Try again.",
messages_SHARE_SUCCESS: 'Share program', messages_SHARE_SUCCESS: "Share program",
messages_SHARE_FAIL: "Error creating a link to share your program. Try again.", messages_SHARE_FAIL:
messages_copylink_success: 'Link successfully saved to clipboard.', "Error creating a link to share your program. Try again.",
messages_rename_success_01: 'The project was successfully saved to ', messages_copylink_success: "Link successfully saved to clipboard.",
messages_rename_success_02: 'renamed.', messages_rename_success_01: "The project was successfully saved to ",
messages_newblockly_head: 'Welcome to the new version Blockly for the senseBox', messages_rename_success_02: "renamed.",
messages_newblockly_text: "The new Blockly version is currently in testing. If you find any errors please report them in our [forum](https://forum.sensebox.de/t/neue-blockly-version-beta-test-und-feedback/1176). You can find an overview of all new features [here](/news)", messages_newblockly_head:
messages_GET_TUTORIAL_FAIL: 'Back to tutorials overview', "Welcome to the new version Blockly for the senseBox",
messages_LOGIN_FAIL: 'The username or password is incorrect.', messages_newblockly_text:
"The new Blockly version is currently in testing. If you find any errors please report them in our [forum](https://forum.sensebox.de/t/neue-blockly-version-beta-test-und-feedback/1176). You can find an overview of all new features [here](/news)",
messages_GET_TUTORIAL_FAIL: "Back to tutorials overview",
messages_LOGIN_FAIL: "The username or password is incorrect.",
messages_login_error: "Enter both a username and a password.", messages_login_error: "Enter both a username and a password.",
messages_copy_code: "Copy code to clipboard succesfull", messages_copy_code: "Copy code to clipboard succesfull",
/**
* Reset Dialog
*/
resetDialog_headline: "Reset workspace?",
resetDialog_text:
"Do you really want to reset the workspace? All blocks will be deleted!",
/** /**
* Share Dialog * Share Dialog
*/ */
@ -79,16 +100,16 @@ export const UI = {
*/ */
renamedialog_headline: "Rename project", renamedialog_headline: "Rename project",
renamedialog_text: "Please enter a name for the project and confirm it by clicking 'Confirm'.", renamedialog_text:
"Please enter a name for the project and confirm it by clicking 'Confirm'.",
/** /**
* Compile Dialog * Compile Dialog
* *
*/ */
compiledialog_headline: "Error", compiledialog_headline: "Error",
compiledialog_text: "While compiling an error occured. Please check your blocks and try again", compiledialog_text:
"While compiling an error occured. Please check your blocks and try again",
/** /**
* Buttons * Buttons
@ -105,8 +126,6 @@ export const UI = {
button_tutorial_overview: "Tutorial overview", button_tutorial_overview: "Tutorial overview",
button_login: "Login", button_login: "Login",
/** /**
* *
*/ */
@ -118,50 +137,56 @@ export const UI = {
*/ */
settings_head: "Settings", settings_head: "Settings",
settings_language: "Language", settings_language: "Language",
settings_language_text: "Selection of the language applies to the entire application. A distinction can be made between German and English.", settings_language_text:
"Selection of the language applies to the entire application. A distinction can be made between German and English.",
settings_language_de: "German", settings_language_de: "German",
settings_language_en: "English", settings_language_en: "English",
settings_renderer: "Renderer", settings_renderer: "Renderer",
settings_renderer_text: "The selected renderer determines the appearance of the blocks. A distinction can be made between 'Geras' and 'Zelos', whereby 'Zelos' is particularly suitable for a touch application.", settings_renderer_text:
"The selected renderer determines the appearance of the blocks. A distinction can be made between 'Geras' and 'Zelos', whereby 'Zelos' is particularly suitable for a touch application.",
settings_statistics: "Statistics", settings_statistics: "Statistics",
settings_statistics_text: "The display of statistics on the usage of the blocks above the workspace can be shown or hidden.", settings_statistics_text:
"The display of statistics on the usage of the blocks above the workspace can be shown or hidden.",
settings_statistics_on: "On", settings_statistics_on: "On",
settings_statistics_off: "Off", settings_statistics_off: "Off",
/** /**
* 404 * 404
*/ */
notfound_head: "The page you requested cannot be found.", notfound_head: "The page you requested cannot be found.",
notfound_text: "The page you are looking for may have been removed, its name changed, or it may be temporarily unavailable.", notfound_text:
"The page you are looking for may have been removed, its name changed, or it may be temporarily unavailable.",
/** /**
* Labels * Labels
*/ */
labels_donotshowagain: 'Do not show dialog again', labels_donotshowagain: "Do not show dialog again",
labels_here: 'here', labels_here: "here",
labels_username: 'Email or username', labels_username: "Email or username",
labels_password: "Password", labels_password: "Password",
/** /**
* Badges * Badges
*/ */
badges_explaination: "An overview of all badges received in the Blockly for senseBox context can be found ", badges_explaination:
badges_ASSIGNE_BADGE_SUCCESS_01: "Congratulations! You have received the badge ", "An overview of all badges received in the Blockly for senseBox context can be found ",
badges_ASSIGNE_BADGE_SUCCESS_01:
"Congratulations! You have received the badge ",
badges_ASSIGNE_BADGE_SUCCESS_02: ".", badges_ASSIGNE_BADGE_SUCCESS_02: ".",
/** /**
* Tutorials * Tutorials
*/ */
tutorials_assessment_task: "Task", tutorials_assessment_task: "Task",
tutorials_hardware_head: "For the implementation you need the following hardware:", tutorials_hardware_head:
tutorials_hardware_moreInformation: "You can find more information about the hardware component.", "For the implementation you need the following hardware:",
tutorials_hardware_moreInformation:
"You can find more information about the hardware component.",
tutorials_hardware_here: "here", tutorials_hardware_here: "here",
tutorials_requirements: "Before continuing with this tutorial, you should have successfully completed the following tutorials:", tutorials_requirements:
"Before continuing with this tutorial, you should have successfully completed the following tutorials:",
/** /**
* Tutorial Builder * Tutorial Builder
@ -170,24 +195,24 @@ export const UI = {
builder_solution: "Solution", builder_solution: "Solution",
builder_solution_submit: "Submit Solution", builder_solution_submit: "Submit Solution",
builder_example_submit: "Submit example", builder_example_submit: "Submit example",
builder_comment: "Note: You can delete the initial setup() or infinite loop() block. Additionally, it is possible to select only any block, among others, without displaying it as disabled.", builder_comment:
"Note: You can delete the initial setup() or infinite loop() block. Additionally, it is possible to select only any block, among others, without displaying it as disabled.",
builder_hardware_order: "Note that the order of selection is authoritative.", builder_hardware_order: "Note that the order of selection is authoritative.",
builder_hardware_helper: "Select at least one hardware component.", builder_hardware_helper: "Select at least one hardware component.",
builder_requirements_head: "Requirements.", builder_requirements_head: "Requirements.",
builder_requirements_order: "Note that the order of ticking is authoritative.", builder_requirements_order:
"Note that the order of ticking is authoritative.",
/** /**
* Login * Login
*/ */
login_head: "Login", login_head: "Login",
login_osem_account_01: "You need to have an ", login_osem_account_01: "You need to have an ",
login_osem_account_02: "Account to login", login_osem_account_02: "Account to login",
login_lostpassword: "Lost your password?", login_lostpassword: "Lost your password?",
login_createaccount: "If you don't have an openSenseMap account please register on ", login_createaccount:
"If you don't have an openSenseMap account please register on ",
/** /**
* Navbar * Navbar
@ -212,9 +237,6 @@ export const UI = {
codeviewer_arduino: "Arduino Source Code", codeviewer_arduino: "Arduino Source Code",
codeviewer_xml: "XML Blocks", codeviewer_xml: "XML Blocks",
/** /**
* Overlay * Overlay
*/ */
@ -223,7 +245,6 @@ export const UI = {
compile_overlay_text: "Then copy it to your senseBox MCU", compile_overlay_text: "Then copy it to your senseBox MCU",
compile_overlay_help: "You need help? Have a look here: ", compile_overlay_help: "You need help? Have a look here: ",
/** /**
* Tooltip Viewer * Tooltip Viewer
*/ */
@ -232,4 +253,9 @@ export const UI = {
tooltip_moreInformation: "More informations can be found ", tooltip_moreInformation: "More informations can be found ",
tooltip_hint: "Select a Block to show the hint", tooltip_hint: "Select a Block to show the hint",
} /**
* IDEDrawer
*/
drawer_ideerror_head: "Oops something went wrong",
drawer_ideerror_text: "An error occurred while compiling, check your blocks",
};

View File

@ -16,15 +16,16 @@ class Toolbox extends React.Component {
this.props.workspace, this.props.workspace,
"callbackName", "callbackName",
[ [
["SHORT_NUMBER", "char"], [`${Blockly.Msg.variable_SHORT_NUMBER}`, "char"],
["NUMBER", "int"], [`${Blockly.Msg.variable_NUMBER}`, "int"],
["DECIMAL", "float"], [`${Blockly.Msg.variable_LONG}`, "long"],
["TEXT", "String"], [`${Blockly.Msg.variable_DECIMAL}`, "float"],
["ARRAY", "Array"], [`${Blockly.Msg.variables_TEXT}`, "String"],
["CHARACTER", "char"], [`${Blockly.Msg.variables_ARRAY}`, "Array"],
["BOOLEAN", "boolean"], [`${Blockly.Msg.variables_CHARACTER}`, "char"],
["NULL", "void"], [`${Blockly.Msg.variables_BOOLEAN}`, "boolean"],
["UNDEF", "undefined"], [`${Blockly.Msg.variables_NULL}`, "void"],
[`${Blockly.Msg.variables_UNDEF}`, "undefined"],
] ]
); );
typedVarModal.init(); typedVarModal.init();
@ -74,6 +75,20 @@ class Toolbox extends React.Component {
<Block type="sensebox_sensor_watertemperature" /> <Block type="sensebox_sensor_watertemperature" />
{/* <Block type="sensebox_windspeed" /> */} {/* <Block type="sensebox_windspeed" /> */}
<Block type="sensebox_soundsensor_dfrobot" /> <Block type="sensebox_soundsensor_dfrobot" />
<Block type="sensebox_multiplexer_init">
<Value name="nrChannels">
<Block type="math_number">
<Field name="NUM">1</Field>
</Block>
</Value>
</Block>
<Block type="sensebox_multiplexer_changeChannel">
<Value name="Channel">
<Block type="math_number">
<Field name="NUM">1</Field>
</Block>
</Value>
</Block>
</Category> </Category>
<Category name="WIFI" colour={getColour().sensebox}> <Category name="WIFI" colour={getColour().sensebox}>
<Block type="sensebox_wifi" /> <Block type="sensebox_wifi" />

View File

@ -15,7 +15,6 @@ class Content extends Component {
componentDidMount() { componentDidMount() {
if (this.props.language === 'de_DE') { if (this.props.language === 'de_DE') {
console.log("change Language")
Blockly.setLocale(De); Blockly.setLocale(De);
} else if (this.props.language === 'en_US') { } else if (this.props.language === 'en_US') {
Blockly.setLocale(En); Blockly.setLocale(En);
@ -23,13 +22,10 @@ class Content extends Component {
} }
componentDidUpdate(props) { componentDidUpdate(props) {
console.log(this.props.language)
if (props.language !== this.props.language) { if (props.language !== this.props.language) {
if (this.props.language === 'de_DE') { if (this.props.language === 'de_DE') {
console.log("change Language")
Blockly.setLocale(De); Blockly.setLocale(De);
} else if (this.props.language === 'en_US') { } else if (this.props.language === 'en_US') {
console.log("change Language")
Blockly.setLocale(En); Blockly.setLocale(En);
} }
} }

View File

@ -56,8 +56,6 @@ class Project extends Component {
getProject = () => { getProject = () => {
var id = this.props.location.pathname.replace(/\/[a-z]{1,}\//, ''); var id = this.props.location.pathname.replace(/\/[a-z]{1,}\//, '');
var param = this.props.location.pathname.replace(`/${id}`, '').replace('/', ''); var param = this.props.location.pathname.replace(`/${id}`, '').replace('/', '');
console.log('param', param);
console.log(id);
this.props.getProject(param, id); this.props.getProject(param, id);
} }

View File

@ -1,57 +1,70 @@
import React, { Component } from 'react'; import React, { Component } from "react";
import PropTypes from 'prop-types'; import PropTypes from "prop-types";
import { connect } from 'react-redux'; import { connect } from "react-redux";
import { getProjects, resetProject } from '../../actions/projectActions'; import { getProjects, resetProject } from "../../actions/projectActions";
import { clearMessages } from '../../actions/messageActions'; import { clearMessages } from "../../actions/messageActions";
import { Link, withRouter } from 'react-router-dom'; import { Link, withRouter } from "react-router-dom";
import Breadcrumbs from '../Breadcrumbs'; import Breadcrumbs from "../Breadcrumbs";
import BlocklyWindow from '../Blockly/BlocklyWindow'; import BlocklyWindow from "../Blockly/BlocklyWindow";
import Snackbar from '../Snackbar'; import Snackbar from "../Snackbar";
import WorkspaceFunc from '../Workspace/WorkspaceFunc'; import WorkspaceFunc from "../Workspace/WorkspaceFunc";
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from "@material-ui/core/styles";
import Grid from '@material-ui/core/Grid'; import Grid from "@material-ui/core/Grid";
import Paper from '@material-ui/core/Paper'; import Paper from "@material-ui/core/Paper";
import Divider from '@material-ui/core/Divider'; import Divider from "@material-ui/core/Divider";
import Typography from '@material-ui/core/Typography'; import Typography from "@material-ui/core/Typography";
import Backdrop from '@material-ui/core/Backdrop'; import Backdrop from "@material-ui/core/Backdrop";
import CircularProgress from '@material-ui/core/CircularProgress'; import CircularProgress from "@material-ui/core/CircularProgress";
const styles = (theme) => ({ const styles = (theme) => ({
link: { link: {
color: theme.palette.primary.main, color: theme.palette.primary.main,
textDecoration: 'none', textDecoration: "none",
'&:hover': { "&:hover": {
color: theme.palette.primary.main, color: theme.palette.primary.main,
textDecoration: 'underline' textDecoration: "underline",
} },
} },
}); });
class ProjectHome extends Component { class ProjectHome extends Component {
state = { state = {
snackbar: false, snackbar: false,
type: '', type: "",
key: '', key: "",
message: '' message: "",
} };
componentDidMount() { componentDidMount() {
var type = this.props.location.pathname.replace('/', ''); var type = this.props.location.pathname.replace("/", "");
this.props.getProjects(type); this.props.getProjects(type);
if (this.props.message) { if (this.props.message) {
if (this.props.message.id === 'PROJECT_DELETE_SUCCESS') { if (this.props.message.id === "PROJECT_DELETE_SUCCESS") {
this.setState({ snackbar: true, key: Date.now(), message: `Dein Projekt wurde erfolgreich gelöscht.`, type: 'success' }); this.setState({
} snackbar: true,
else if (this.props.message.id === 'GALLERY_DELETE_SUCCESS') { key: Date.now(),
this.setState({ snackbar: true, key: Date.now(), message: `Dein Galerie-Projekt wurde erfolgreich gelöscht.`, type: 'success' }); message: `Dein Projekt wurde erfolgreich gelöscht.`,
} type: "success",
else if (this.props.message.id === 'GET_PROJECT_FAIL') { });
this.setState({ snackbar: true, key: Date.now(), message: `Dein angefragtes ${type === 'gallery' ? 'Galerie-' : ''}Projekt konnte nicht gefunden werden.`, type: 'error' }); } else if (this.props.message.id === "GALLERY_DELETE_SUCCESS") {
this.setState({
snackbar: true,
key: Date.now(),
message: `Dein Galerie-Projekt wurde erfolgreich gelöscht.`,
type: "success",
});
} else if (this.props.message.id === "GET_PROJECT_FAIL") {
this.setState({
snackbar: true,
key: Date.now(),
message: `Dein angefragtes ${
type === "gallery" ? "Galerie-" : ""
}Projekt konnte nicht gefunden werden.`,
type: "error",
});
} }
} }
} }
@ -59,14 +72,23 @@ class ProjectHome extends Component {
componentDidUpdate(props) { componentDidUpdate(props) {
if (props.location.pathname !== this.props.location.pathname) { if (props.location.pathname !== this.props.location.pathname) {
this.setState({ snackbar: false }); this.setState({ snackbar: false });
this.props.getProjects(this.props.location.pathname.replace('/', '')); this.props.getProjects(this.props.location.pathname.replace("/", ""));
} }
if (props.message !== this.props.message) { if (props.message !== this.props.message) {
if (this.props.message.id === 'PROJECT_DELETE_SUCCESS') { if (this.props.message.id === "PROJECT_DELETE_SUCCESS") {
this.setState({ snackbar: true, key: Date.now(), message: `Dein Projekt wurde erfolgreich gelöscht.`, type: 'success' }); this.setState({
} snackbar: true,
else if (this.props.message.id === 'GALLERY_DELETE_SUCCESS') { key: Date.now(),
this.setState({ snackbar: true, key: Date.now(), message: `Dein Galerie-Projekt wurde erfolgreich gelöscht.`, type: 'success' }); message: `Dein Projekt wurde erfolgreich gelöscht.`,
type: "success",
});
} else if (this.props.message.id === "GALLERY_DELETE_SUCCESS") {
this.setState({
snackbar: true,
key: Date.now(),
message: `Dein Galerie-Projekt wurde erfolgreich gelöscht.`,
type: "success",
});
} }
} }
} }
@ -77,60 +99,107 @@ class ProjectHome extends Component {
} }
render() { render() {
var data = this.props.location.pathname === '/project' ? 'Projekte' : 'Galerie'; var data =
this.props.location.pathname === "/project" ? "Projekte" : "Galerie";
return ( return (
<div> <div>
<Breadcrumbs content={[{ link: this.props.location.pathname, title: data }]} /> <Breadcrumbs
content={[{ link: this.props.location.pathname, title: data }]}
/>
<h1>{data}</h1> <h1>{data}</h1>
{this.props.progress ? {this.props.progress ? (
<Backdrop open invisible> <Backdrop open invisible>
<CircularProgress color="primary" /> <CircularProgress color="primary" />
</Backdrop> </Backdrop>
: ) : (
<div> <div>
{this.props.projects.length > 0 ? {this.props.projects.length > 0 ? (
<Grid container spacing={2}> <Grid container spacing={2}>
{this.props.projects.map((project, i) => { {this.props.projects.map((project, i) => {
return ( return (
<Grid item xs={12} sm={6} md={4} xl={3} key={i}> <Grid item xs={12} sm={6} md={4} xl={3} key={i}>
<Paper style={{ padding: '1rem', position: 'relative', overflow: 'hidden' }}> <Paper
<Link to={`/${data === 'Projekte' ? 'project' : 'gallery'}/${project._id}`} style={{ textDecoration: 'none', color: 'inherit' }}> style={{
padding: "1rem",
position: "relative",
overflow: "hidden",
}}
>
<Link
to={`/${
data === "Projekte" ? "project" : "gallery"
}/${project._id}`}
style={{ textDecoration: "none", color: "inherit" }}
>
<h3 style={{ marginTop: 0 }}>{project.title}</h3> <h3 style={{ marginTop: 0 }}>{project.title}</h3>
<Divider style={{ marginTop: '1rem', marginBottom: '10px' }} /> <Divider
style={{ marginTop: "1rem", marginBottom: "10px" }}
/>
<BlocklyWindow <BlocklyWindow
svg svg
blockDisabled blockDisabled
initialXml={project.xml} initialXml={project.xml}
/> />
<Typography variant='body2' style={{ fontStyle: 'italic', margin: 0, marginTop: '-10px' }}>{project.description}</Typography> <Typography
variant="body2"
style={{
fontStyle: "italic",
margin: 0,
marginTop: "-10px",
}}
>
{project.description}
</Typography>
</Link> </Link>
{this.props.user && this.props.user.email === project.creator ? {this.props.user &&
this.props.user.email === project.creator ? (
<div> <div>
<Divider style={{ marginTop: '10px', marginBottom: '10px' }} /> <Divider
<div style={{ float: 'right' }}> style={{
marginTop: "10px",
marginBottom: "10px",
}}
/>
<div style={{ float: "right" }}>
<WorkspaceFunc <WorkspaceFunc
multiple multiple
project={project} project={project}
projectType={this.props.location.pathname.replace('/', '')} projectType={this.props.location.pathname.replace(
"/",
""
)}
/> />
</div> </div>
</div> </div>
: null} ) : null}
</Paper> </Paper>
</Grid> </Grid>
) );
})} })}
</Grid> </Grid>
: <div> ) : (
<Typography style={{ marginBottom: '10px' }}>Es sind aktuell keine Projekte vorhanden.</Typography> <div>
{this.props.location.pathname.replace('/', '') === 'project' ? <Typography style={{ marginBottom: "10px" }}>
<Typography>Erstelle jetzt dein <Link to={'/'} className={this.props.classes.link}>eigenes Projekt</Link> oder lasse dich von Projektbeispielen in der <Link to={'/gallery'} className={this.props.classes.link}>Galerie</Link> inspirieren.</Typography> Es sind aktuell keine Projekte vorhanden.
: null} </Typography>
{this.props.location.pathname.replace("/", "") === "project" ? (
<Typography>
Erstelle jetzt dein{" "}
<Link to={"/"} className={this.props.classes.link}>
eigenes Projekt
</Link>{" "}
oder lasse dich von Projektbeispielen in der{" "}
<Link to={"/gallery"} className={this.props.classes.link}>
Galerie
</Link>{" "}
inspirieren.
</Typography>
) : null}
</div> </div>
} )}
</div> </div>
} )}
<Snackbar <Snackbar
open={this.state.snackbar} open={this.state.snackbar}
message={this.state.message} message={this.state.message}
@ -139,7 +208,7 @@ class ProjectHome extends Component {
/> />
</div> </div>
); );
}; }
} }
ProjectHome.propTypes = { ProjectHome.propTypes = {
@ -149,15 +218,18 @@ ProjectHome.propTypes = {
projects: PropTypes.array.isRequired, projects: PropTypes.array.isRequired,
progress: PropTypes.bool.isRequired, progress: PropTypes.bool.isRequired,
user: PropTypes.object, user: PropTypes.object,
message: PropTypes.object.isRequired message: PropTypes.object.isRequired,
}; };
const mapStateToProps = state => ({ const mapStateToProps = (state) => ({
projects: state.project.projects, projects: state.project.projects,
progress: state.project.progress, progress: state.project.progress,
user: state.auth.user, user: state.auth.user,
message: state.message message: state.message,
}); });
export default connect(mapStateToProps, {
export default connect(mapStateToProps, { getProjects, resetProject, clearMessages })(withStyles(styles, { withTheme: true })(withRouter(ProjectHome))); getProjects,
resetProject,
clearMessages,
})(withStyles(styles, { withTheme: true })(withRouter(ProjectHome)));

View File

@ -1,20 +1,20 @@
import React, { Component } from 'react'; import React, { Component } from "react";
import PropTypes from 'prop-types'; import PropTypes from "prop-types";
import { connect } from 'react-redux'; import { connect } from "react-redux";
import { workspaceName } from '../../actions/workspaceActions'; import { workspaceName } from "../../actions/workspaceActions";
import BlocklyWindow from '../Blockly/BlocklyWindow'; import BlocklyWindow from "../Blockly/BlocklyWindow";
import CodeViewer from '../CodeViewer'; import CodeViewer from "../CodeViewer";
import WorkspaceFunc from '../Workspace/WorkspaceFunc'; import WorkspaceFunc from "../Workspace/WorkspaceFunc";
import withWidth, { isWidthDown } from '@material-ui/core/withWidth'; import withWidth, { isWidthDown } from "@material-ui/core/withWidth";
import Grid from '@material-ui/core/Grid'; import Grid from "@material-ui/core/Grid";
import Card from '@material-ui/core/Card'; import Card from "@material-ui/core/Card";
import Typography from '@material-ui/core/Typography'; import Typography from "@material-ui/core/Typography";
import * as Blockly from 'blockly' import * as Blockly from "blockly";
import { initialXml } from "../Blockly/initialXml";
class Assessment extends Component { class Assessment extends Component {
componentDidMount() { componentDidMount() {
this.props.workspaceName(this.props.name); this.props.workspaceName(this.props.name);
} }
@ -28,48 +28,90 @@ class Assessment extends Component {
render() { render() {
var tutorialId = this.props.tutorial._id; var tutorialId = this.props.tutorial._id;
var currentTask = this.props.step; var currentTask = this.props.step;
var status = this.props.status.filter(status => status._id === tutorialId)[0]; var status = this.props.status.filter(
var taskIndex = status.tasks.findIndex(task => task._id === currentTask._id); (status) => status._id === tutorialId
)[0];
var taskIndex = status.tasks.findIndex(
(task) => task._id === currentTask._id
);
var statusTask = status.tasks[taskIndex]; var statusTask = status.tasks[taskIndex];
return ( return (
<div className="assessmentDiv" style={{ width: '100%' }}> <div className="assessmentDiv" style={{ width: "100%" }}>
<Typography variant='h4' style={{ float: 'left', marginBottom: '5px', height: '40px', display: 'table' }}>{currentTask.headline}</Typography> <Typography
<div style={{ float: 'right', height: '40px' }}><WorkspaceFunc assessment /></div> variant="h4"
<Grid container spacing={2} style={{ marginBottom: '5px' }}> 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={6} lg={8}>
<BlocklyWindow <BlocklyWindow
initialXml={statusTask ? statusTask.xml ? statusTask.xml : null : null} initialXml={initialXml}
blockDisabled blockDisabled
blocklyCSS={{ height: '65vH' }} blocklyCSS={{ height: "65vH" }}
/> />
</Grid> </Grid>
<Grid item xs={12} md={6} lg={4} style={isWidthDown('sm', this.props.width) ? { height: 'max-content' } : {}}> <Grid
<Card style={{ height: 'calc(50% - 30px)', padding: '10px', marginBottom: '10px' }}> item
<Typography variant='h5'>{Blockly.Msg.tutorials_assessment_task}</Typography> xs={12}
md={6}
lg={4}
style={
isWidthDown("sm", this.props.width)
? { height: "max-content" }
: {}
}
>
<Card
style={{
height: "calc(50% - 30px)",
padding: "10px",
marginBottom: "10px",
}}
>
<Typography variant="h5">
{Blockly.Msg.tutorials_assessment_task}
</Typography>
<Typography>{currentTask.text}</Typography> <Typography>{currentTask.text}</Typography>
</Card> </Card>
<div style={isWidthDown('sm', this.props.width) ? { height: '500px' } : { height: '50%' }}> <div
style={
isWidthDown("sm", this.props.width)
? { height: "500px" }
: { height: "50%" }
}
>
<CodeViewer /> <CodeViewer />
</div> </div>
</Grid> </Grid>
</Grid> </Grid>
</div> </div>
); );
}; }
} }
Assessment.propTypes = { Assessment.propTypes = {
status: PropTypes.array.isRequired, status: PropTypes.array.isRequired,
change: PropTypes.number.isRequired, change: PropTypes.number.isRequired,
workspaceName: PropTypes.func.isRequired, workspaceName: PropTypes.func.isRequired,
tutorial: PropTypes.object.isRequired tutorial: PropTypes.object.isRequired,
}; };
const mapStateToProps = state => ({ const mapStateToProps = (state) => ({
change: state.tutorial.change, change: state.tutorial.change,
status: state.tutorial.status, status: state.tutorial.status,
tutorial: state.tutorial.tutorials[0] tutorial: state.tutorial.tutorials[0],
}); });
export default connect(mapStateToProps, { workspaceName })(withWidth()(Assessment)); export default connect(mapStateToProps, { workspaceName })(
withWidth()(Assessment)
);

View File

@ -60,7 +60,6 @@ class Badge extends Component {
this.setState({badges: res.data.badges, badgeName: this.props.badge ? res.data.badges.filter(badge => badge._id === this.props.badge)[0].name : '' }); this.setState({badges: res.data.badges, badgeName: this.props.badge ? res.data.badges.filter(badge => badge._id === this.props.badge)[0].name : '' });
}) })
.catch(err => { .catch(err => {
console.log(err);
}); });
}; };

View File

@ -1,57 +1,95 @@
import React, { Component } from 'react'; import React, { Component } from "react";
import Hardware from './Hardware'; import Hardware from "./Hardware";
import Requirement from './Requirement'; import Requirement from "./Requirement";
import BlocklyWindow from '../Blockly/BlocklyWindow'; import BlocklyWindow from "../Blockly/BlocklyWindow";
import Grid from '@material-ui/core/Grid';
import Typography from '@material-ui/core/Typography';
import ReactMarkdown from 'react-markdown'
import Grid from "@material-ui/core/Grid";
import Typography from "@material-ui/core/Typography";
import ReactMarkdown from "react-markdown";
class Instruction extends Component { class Instruction extends Component {
render() { render() {
var step = this.props.step; var step = this.props.step;
var isHardware = step.hardware && step.hardware.length > 0; var isHardware = step.hardware && step.hardware.length > 0;
var areRequirements = step.requirements && step.requirements.length > 0; var areRequirements = step.requirements && step.requirements.length > 0;
return ( return (
<div> <div>
<Typography variant='h4' style={{ marginBottom: '5px' }}>{step.headline}</Typography> <Typography variant="h4" style={{ marginBottom: "5px" }}>
<Typography style={isHardware ? {} : { marginBottom: '5px' }}><ReactMarkdown className={'tutorial'} linkTarget={'_blank'} skipHtml={false}>{step.text}</ReactMarkdown></Typography> {step.headline}
{isHardware ? </Typography>
<Hardware picture={step.hardware} /> : null} <Typography style={isHardware ? {} : { marginBottom: "5px" }}>
{areRequirements > 0 ? <ReactMarkdown
<Requirement requirements={step.requirements} /> : null} className={"tutorial"}
{step.media ? linkTarget={"_blank"}
step.media.picture ? skipHtml={false}
<div style={{ display: 'flex', justifyContent: 'center', marginBottom: '5px' }}> >
<img src={`${process.env.REACT_APP_BLOCKLY_API}/media/${step.media.picture.path}`} alt='' style={{ maxHeight: '40vH', maxWidth: '100%' }} /> {step.text}
</div> </ReactMarkdown>
: step.media.youtube ? </Typography>
/*16:9; width: 800px; height: width/16*9=450px*/ {isHardware ? <Hardware picture={step.hardware} /> : null}
<div style={{ maxWidth: '800px', margin: 'auto' }}> {areRequirements > 0 ? (
<div style={{ position: 'relative', height: 0, paddingBottom: 'calc(100% / 16 * 9)' }}> <Requirement requirements={step.requirements} />
<iframe title={step.media.youtube} style={{ position: 'absolute', top: '0', left: '0', width: '100%', maxWidth: '800px', height: '100%', maxHeight: '450px' }} src={`https://www.youtube.com/embed/${step.media.youtube}`} frameBorder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowFullScreen /> ) : null}
</div> {step.media ? (
</div> step.media.picture ? (
: null <div
: null} style={{
{step.xml ? display: "flex",
<Grid container spacing={2} style={{ marginBottom: '5px' }}> justifyContent: "center",
<Grid item xs={12} style={{display: 'flex', justifyContent: 'center'}}> marginBottom: "5px",
<BlocklyWindow }}
svg >
blockDisabled <img
initialXml={step.xml} src={`${process.env.REACT_APP_BLOCKLY_API}/media/${step.media.picture.path}`}
alt=""
style={{ maxHeight: "40vH", maxWidth: "100%" }}
/> />
</div>
) : step.media.youtube ? (
/*16:9; width: 800px; height: width/16*9=450px*/
<div style={{ maxWidth: "800px", margin: "auto" }}>
<div
style={{
position: "relative",
height: 0,
paddingBottom: "calc(100% / 16 * 9)",
}}
>
<iframe
title={step.media.youtube}
style={{
position: "absolute",
top: "0",
left: "0",
width: "100%",
maxWidth: "800px",
height: "100%",
maxHeight: "450px",
}}
src={`https://www.youtube.com/embed/${step.media.youtube}`}
frameBorder="0"
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
/>
</div>
</div>
) : null
) : null}
{step.xml ? (
<Grid container spacing={2} style={{ marginBottom: "5px" }}>
<Grid
item
xs={12}
style={{ display: "flex", justifyContent: "center" }}
>
<BlocklyWindow svg blockDisabled initialXml={step.xml} />
</Grid> </Grid>
</Grid> </Grid>
: null} ) : null}
</div> </div>
); );
}; }
} }
export default Instruction; export default Instruction;

View File

@ -85,7 +85,7 @@ class StepperVertical extends Component {
return ( return (
<Step key={i}> <Step key={i}>
<Tooltip title={step.headline} placement='right' arrow > <Tooltip title={step.headline} placement='right' arrow >
<div style={i === activeStep ? {padding: '5px 0'} : {padding: '5px 0', cursor: 'pointer'}} onClick={i === activeStep ? null : () => {console.log(i); this.props.tutorialStep(i)}}> <div style={i === activeStep ? {padding: '5px 0'} : {padding: '5px 0', cursor: 'pointer'}} onClick={i === activeStep ? null : () => { this.props.tutorialStep(i)}}>
<StepLabel <StepLabel
StepIconComponent={'div'} StepIconComponent={'div'}
classes={{ classes={{

View File

@ -28,7 +28,6 @@ class Tutorial extends Component {
// retrieve tutorial only if a potential user is loaded - authentication // retrieve tutorial only if a potential user is loaded - authentication
// is finished (success or failed) // is finished (success or failed)
if(!this.props.progress){ if(!this.props.progress){
console.log(this.props);
this.props.getTutorial(this.props.match.params.tutorialId); this.props.getTutorial(this.props.match.params.tutorialId);
} }
} }

View File

@ -1,77 +1,89 @@
import React, { Component } from 'react'; import React, { Component } from "react";
import PropTypes from 'prop-types'; import PropTypes from "prop-types";
import { connect } from 'react-redux'; import { connect } from "react-redux";
import { login } from '../../actions/authActions' import { login } from "../../actions/authActions";
import { clearMessages } from '../../actions/messageActions' import { clearMessages } from "../../actions/messageActions";
import { withRouter } from 'react-router-dom'; import { withRouter } from "react-router-dom";
import Snackbar from '../Snackbar'; import Snackbar from "../Snackbar";
import Alert from '../Alert'; import Alert from "../Alert";
import Breadcrumbs from '../Breadcrumbs'; import Breadcrumbs from "../Breadcrumbs";
import Button from '@material-ui/core/Button'; import Button from "@material-ui/core/Button";
import IconButton from '@material-ui/core/IconButton'; import IconButton from "@material-ui/core/IconButton";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons"; import { faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons";
import TextField from '@material-ui/core/TextField'; import TextField from "@material-ui/core/TextField";
import Divider from '@material-ui/core/Divider'; import Divider from "@material-ui/core/Divider";
import InputAdornment from '@material-ui/core/InputAdornment'; import InputAdornment from "@material-ui/core/InputAdornment";
import CircularProgress from '@material-ui/core/CircularProgress'; import CircularProgress from "@material-ui/core/CircularProgress";
import Link from '@material-ui/core/Link'; import Link from "@material-ui/core/Link";
import * as Blockly from 'blockly' import * as Blockly from "blockly";
export class Login extends Component { export class Login extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
redirect: props.location.state ? props.location.state.from.pathname : null, redirect: props.location.state
email: '', ? props.location.state.from.pathname
password: '', : null,
email: "",
password: "",
snackbar: false, snackbar: false,
type: '', type: "",
key: '', key: "",
message: '', message: "",
showPassword: false showPassword: false,
}; };
} }
componentDidUpdate(props) { componentDidUpdate(props) {
console.log(this.state.redirect);
const { message } = this.props; const { message } = this.props;
if (message !== props.message) { if (message !== props.message) {
if (message.id === 'LOGIN_SUCCESS') { if (message.id === "LOGIN_SUCCESS") {
if (this.state.redirect) { if (this.state.redirect) {
this.props.history.push(this.state.redirect); this.props.history.push(this.state.redirect);
} } else {
else {
this.props.history.goBack(); this.props.history.goBack();
} }
} }
// Check for login error // Check for login error
else if (message.id === 'LOGIN_FAIL') { else if (message.id === "LOGIN_FAIL") {
this.setState({ email: '', password: '', snackbar: true, key: Date.now(), message: Blockly.Msg.messages_LOGIN_FAIL, type: 'error' }); console.log("login fail");
this.setState({
email: "",
password: "",
snackbar: true,
key: Date.now(),
message: Blockly.Msg.messages_LOGIN_FAIL,
type: "error",
});
} }
} }
} }
onChange = e => { onChange = (e) => {
this.setState({ [e.target.name]: e.target.value }); this.setState({ [e.target.name]: e.target.value });
}; };
onSubmit = e => { onSubmit = (e) => {
e.preventDefault(); e.preventDefault();
const { email, password } = this.state; const { email, password } = this.state;
if (email !== '' && password !== '') { if (email !== "" && password !== "") {
// create user object // create user object
const user = { const user = {
email, email,
password password,
}; };
this.props.login(user); this.props.login(user);
} else { } else {
this.setState({ snackbar: true, key: Date.now(), message: Blockly.Msg.messages_login_error, type: 'error' }); this.setState({
snackbar: true,
key: Date.now(),
message: Blockly.Msg.messages_login_error,
type: "error",
});
} }
}; };
@ -86,12 +98,25 @@ export class Login extends Component {
render() { render() {
return ( return (
<div> <div>
<Breadcrumbs content={[{ link: '/user/login', title: Blockly.Msg.button_login }]} /> <Breadcrumbs
content={[{ link: "/user/login", title: Blockly.Msg.button_login }]}
/>
<div style={{ maxWidth: '500px', marginLeft: 'auto', marginRight: 'auto' }}> <div
style={{ maxWidth: "500px", marginLeft: "auto", marginRight: "auto" }}
>
<h1>{Blockly.Msg.login_head}</h1> <h1>{Blockly.Msg.login_head}</h1>
<Alert> <Alert>
{Blockly.Msg.login_osem_account_01} <Link color='primary' rel="noreferrer" target="_blank" href={'https://opensensemap.org/'}>openSenseMap</Link> {Blockly.Msg.login_osem_account_02}. {Blockly.Msg.login_osem_account_01}{" "}
<Link
color="primary"
rel="noreferrer"
target="_blank"
href={"https://opensensemap.org/"}
>
openSenseMap
</Link>{" "}
{Blockly.Msg.login_osem_account_02}.
</Alert> </Alert>
<Snackbar <Snackbar
open={this.state.snackbar} open={this.state.snackbar}
@ -100,51 +125,83 @@ export class Login extends Component {
key={this.state.key} key={this.state.key}
/> />
<TextField <TextField
style={{ marginBottom: '10px' }} style={{ marginBottom: "10px" }}
// variant='outlined' // variant='outlined'
type='text' type="text"
label={Blockly.Msg.labels_username} label={Blockly.Msg.labels_username}
name='email' name="email"
value={this.state.email} value={this.state.email}
onChange={this.onChange} onChange={this.onChange}
fullWidth={true} fullWidth={true}
/> />
<TextField <TextField
// variant='outlined' // variant='outlined'
type={this.state.showPassword ? 'text' : 'password'} type={this.state.showPassword ? "text" : "password"}
label={Blockly.Msg.labels_password} label={Blockly.Msg.labels_password}
name='password' name="password"
value={this.state.password} value={this.state.password}
InputProps={{ InputProps={{
endAdornment: endAdornment: (
<InputAdornment <InputAdornment position="end">
position="end"
>
<IconButton <IconButton
onClick={this.handleClickShowPassword} onClick={this.handleClickShowPassword}
onMouseDown={this.handleMouseDownPassword} onMouseDown={this.handleMouseDownPassword}
edge="end" edge="end"
> >
<FontAwesomeIcon size='xs' icon={this.state.showPassword ? faEyeSlash : faEye} /> <FontAwesomeIcon
size="xs"
icon={this.state.showPassword ? faEyeSlash : faEye}
/>
</IconButton> </IconButton>
</InputAdornment> </InputAdornment>
),
}} }}
onChange={this.onChange} onChange={this.onChange}
fullWidth={true} fullWidth={true}
/> />
<p> <p>
<Button color="primary" variant='contained' onClick={this.onSubmit} style={{ width: '100%' }}> <Button
{this.props.progress ? color="primary"
<div style={{ height: '24.5px' }}><CircularProgress color="inherit" size={20} /></div> variant="contained"
: Blockly.Msg.button_login} onClick={this.onSubmit}
style={{ width: "100%" }}
>
{this.props.progress ? (
<div style={{ height: "24.5px" }}>
<CircularProgress color="inherit" size={20} />
</div>
) : (
Blockly.Msg.button_login
)}
</Button> </Button>
</p> </p>
<p style={{ textAlign: 'center', fontSize: '0.8rem' }}> <p style={{ textAlign: "center", fontSize: "0.8rem" }}>
<Link rel="noreferrer" target="_blank" href={'https://opensensemap.org/'} color="primary">{Blockly.Msg.login_lostpassword}</Link> <Link
rel="noreferrer"
target="_blank"
href={"https://opensensemap.org/"}
color="primary"
>
{Blockly.Msg.login_lostpassword}
</Link>
</p> </p>
<Divider variant='fullWidth' /> <Divider variant="fullWidth" />
<p style={{ textAlign: 'center', paddingRight: "34px", paddingLeft: "34px" }}> <p
{Blockly.Msg.login_createaccount}<Link rel="noreferrer" target="_blank" href={'https://opensensemap.org/'}>openSenseMap</Link>. style={{
textAlign: "center",
paddingRight: "34px",
paddingLeft: "34px",
}}
>
{Blockly.Msg.login_createaccount}
<Link
rel="noreferrer"
target="_blank"
href={"https://opensensemap.org/"}
>
openSenseMap
</Link>
.
</p> </p>
</div> </div>
</div> </div>
@ -156,12 +213,14 @@ Login.propTypes = {
message: PropTypes.object.isRequired, message: PropTypes.object.isRequired,
login: PropTypes.func.isRequired, login: PropTypes.func.isRequired,
clearMessages: PropTypes.func.isRequired, clearMessages: PropTypes.func.isRequired,
progress: PropTypes.bool.isRequired progress: PropTypes.bool.isRequired,
}; };
const mapStateToProps = state => ({ const mapStateToProps = (state) => ({
message: state.message, message: state.message,
progress: state.auth.progress progress: state.auth.progress,
}); });
export default connect(mapStateToProps, { login, clearMessages })(withRouter(Login)); export default connect(mapStateToProps, { login, clearMessages })(
withRouter(Login)
);

View File

@ -1,127 +1,172 @@
import React, { Component } from 'react'; import React, { Component } from "react";
import PropTypes from 'prop-types'; import PropTypes from "prop-types";
import { connect } from 'react-redux'; import { connect } from "react-redux";
import { workspaceName } from '../../actions/workspaceActions'; import { workspaceName } from "../../actions/workspaceActions";
import { detectWhitespacesAndReturnReadableResult } from '../../helpers/whitespace'; import { detectWhitespacesAndReturnReadableResult } from "../../helpers/whitespace";
import Dialog from '../Dialog';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import Backdrop from '@material-ui/core/Backdrop';
import CircularProgress from '@material-ui/core/CircularProgress';
import IconButton from '@material-ui/core/IconButton';
import Tooltip from '@material-ui/core/Tooltip';
import TextField from '@material-ui/core/TextField';
import { withStyles } from "@material-ui/core/styles";
import Button from "@material-ui/core/Button";
import Backdrop from "@material-ui/core/Backdrop";
import CircularProgress from "@material-ui/core/CircularProgress";
import IconButton from "@material-ui/core/IconButton";
import Tooltip from "@material-ui/core/Tooltip";
import Divider from "@material-ui/core/Divider";
import { faClipboardCheck } from "@fortawesome/free-solid-svg-icons"; import { faClipboardCheck } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import * as Blockly from 'blockly/core'; import * as Blockly from "blockly/core";
import Copy from '../copy.svg'; import Copy from "../copy.svg";
import Prism from "prismjs";
import "prismjs/themes/prism.css";
import "prismjs/plugins/line-numbers/prism-line-numbers";
import "prismjs/plugins/line-numbers/prism-line-numbers.css";
import MuiDrawer from "@material-ui/core/Drawer";
const styles = (theme) => ({ const styles = (theme) => ({
backdrop: { backdrop: {
zIndex: theme.zIndex.drawer + 1, zIndex: theme.zIndex.drawer + 1,
color: '#fff', color: "#fff",
}, },
iconButton: { iconButton: {
backgroundColor: theme.palette.button.compile, backgroundColor: theme.palette.button.compile,
color: theme.palette.primary.contrastText, color: theme.palette.primary.contrastText,
width: '40px', width: "40px",
height: '40px', height: "40px",
'&:hover': { "&:hover": {
backgroundColor: theme.palette.button.compile, backgroundColor: theme.palette.button.compile,
color: theme.palette.primary.contrastText, color: theme.palette.primary.contrastText,
} },
}, },
button: { button: {
backgroundColor: theme.palette.button.compile, backgroundColor: theme.palette.button.compile,
color: theme.palette.primary.contrastText, color: theme.palette.primary.contrastText,
'&:hover': { "&:hover": {
backgroundColor: theme.palette.button.compile, backgroundColor: theme.palette.button.compile,
color: theme.palette.primary.contrastText, color: theme.palette.primary.contrastText,
} },
} },
}); });
const Drawer = withStyles((theme) => ({
paperAnchorBottom: {
backgroundColor: "black",
height: "20vH",
},
}))(MuiDrawer);
class Compile extends Component { class Compile extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
progress: false, progress: false,
open: false, open: false,
file: false, file: false,
title: '', title: "",
content: '', content: "",
name: props.name name: props.name,
error: "",
}; };
} }
componentDidMount() {
Prism.highlightAll();
}
componentDidUpdate(props) { componentDidUpdate(props) {
if (props.name !== this.props.name) { if (props.name !== this.props.name) {
this.setState({ name: this.props.name }); this.setState({ name: this.props.name });
} }
Prism.highlightAll();
} }
compile = () => { compile = () => {
this.setState({ progress: true }); this.setState({ progress: true });
const data = { const data = {
"board": process.env.REACT_APP_BOARD, board: process.env.REACT_APP_BOARD,
"sketch": this.props.arduino sketch: this.props.arduino,
}; };
fetch(`${process.env.REACT_APP_COMPILER_URL}/compile`, { fetch(`${process.env.REACT_APP_COMPILER_URL}/compile`, {
method: "POST", method: "POST",
headers: { 'Content-Type': 'application/json' }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(data) body: JSON.stringify(data),
}) })
.then(response => response.json()) .then((response) => response.json())
.then(data => { .then((data) => {
console.log(data); console.log(data);
if (data.code === "Internal Server Error") {
this.setState({
progress: false,
file: false,
open: true,
title: Blockly.Msg.compiledialog_headline,
content: Blockly.Msg.compiledialog_text,
error: data.message,
});
}
this.setState({ id: data.data.id }, () => { this.setState({ id: data.data.id }, () => {
this.createFileName(); this.createFileName();
}); });
}) })
.catch(err => { .catch((err) => {
console.log(err); console.log(err);
this.setState({ progress: false, file: false, open: true, title: Blockly.Msg.compiledialog_headline, content: Blockly.Msg.compiledialog_text }); //this.setState({ progress: false, file: false, open: true, title: Blockly.Msg.compiledialog_headline, content: Blockly.Msg.compiledialog_text });
}); });
} };
download = () => { download = () => {
const id = this.state.id; const id = this.state.id;
const filename = detectWhitespacesAndReturnReadableResult(this.state.name); const filename = detectWhitespacesAndReturnReadableResult(this.state.name);
this.toggleDialog(); this.toggleDialog();
this.props.workspaceName(this.state.name); 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'); window.open(
`${process.env.REACT_APP_COMPILER_URL}/download?id=${id}&board=${process.env.REACT_APP_BOARD}&filename=${filename}`,
"_self"
);
this.setState({ progress: false }); this.setState({ progress: false });
} };
toggleDialog = () => { toggleDialog = () => {
this.setState({ open: !this.state, progress: false }); this.setState({ open: !this.state, progress: false });
} };
createFileName = () => { createFileName = () => {
if (this.state.name) { if (this.state.name) {
this.download(); 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'.",
});
} }
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) => { setFileName = (e) => {
this.setState({ name: e.target.value }); 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() { render() {
return ( return (
<div style={{}}> <div style={{}}>
{this.props.iconButton ? {this.props.iconButton ? (
<Tooltip title={Blockly.Msg.tooltip_compile_code} arrow style={{ marginRight: '5px' }}> <Tooltip
title={Blockly.Msg.tooltip_compile_code}
arrow
style={{ marginRight: "5px" }}
>
<IconButton <IconButton
className={`compileBlocks ${this.props.classes.iconButton}`} className={`compileBlocks ${this.props.classes.iconButton}`}
onClick={() => this.compile()} onClick={() => this.compile()}
@ -129,21 +174,73 @@ class Compile extends Component {
<FontAwesomeIcon icon={faClipboardCheck} size="l" /> <FontAwesomeIcon icon={faClipboardCheck} size="l" />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
: ) : (
<Button style={{ float: 'right', color: 'white' }} variant="contained" className={this.props.classes.button} onClick={() => this.compile()}> <Button
<FontAwesomeIcon icon={faClipboardCheck} style={{ marginRight: '5px' }} /> Kompilieren style={{ float: "right", color: "white" }}
variant="contained"
className={this.props.classes.button}
onClick={() => this.compile()}
>
<FontAwesomeIcon
icon={faClipboardCheck}
style={{ marginRight: "5px" }}
/>{" "}
Kompilieren
</Button> </Button>
} )}
<Backdrop className={this.props.classes.backdrop} open={this.state.progress}> <Backdrop
<div className='overlay'> className={this.props.classes.backdrop}
open={this.state.progress}
>
<div className="overlay">
<img src={Copy} width="400" alt="copyimage"></img> <img src={Copy} width="400" alt="copyimage"></img>
<h2>{Blockly.Msg.compile_overlay_head}</h2> <h2>{Blockly.Msg.compile_overlay_head}</h2>
<p>{Blockly.Msg.compile_overlay_text}</p> <p>{Blockly.Msg.compile_overlay_text}</p>
<p>{Blockly.Msg.compile_overlay_help}<a href="/faq" target="_blank">FAQ</a></p> <p>
{Blockly.Msg.compile_overlay_help}
<a href="/faq" target="_blank">
FAQ
</a>
</p>
<CircularProgress color="inherit" /> <CircularProgress color="inherit" />
</div> </div>
</Backdrop> </Backdrop>
<Dialog <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
open={this.state.open} open={this.state.open}
title={this.state.title} title={this.state.title}
content={this.state.content} content={this.state.content}
@ -156,23 +253,32 @@ class Compile extends Component {
<TextField autoFocus placeholder='Dateiname' value={this.state.name} onChange={this.setFileName} style={{ marginRight: '10px' }} /> <TextField autoFocus placeholder='Dateiname' value={this.state.name} onChange={this.setFileName} style={{ marginRight: '10px' }} />
<Button disabled={!this.state.name} variant='contained' color='primary' onClick={() => this.download()}>Eingabe</Button> <Button disabled={!this.state.name} variant='contained' color='primary' onClick={() => this.download()}>Eingabe</Button>
</div> </div>
: null} :
</Dialog>
<pre className="line-numbers" style={{ paddingBottom: 0, width: '100%', overflow: 'auto', scrollbarWidth: 'thin', height: '100%', margin: '15px 0', paddingTop: 0, whiteSpace: 'pre-wrap', backgroundColor: 'white' }}><code className="language-json">
{`${this.state.error}`}
</code></pre>
</AccordionDetails>
</Accordion>
}
</Dialog> */}
</div> </div>
); );
}; }
} }
Compile.propTypes = { Compile.propTypes = {
arduino: PropTypes.string.isRequired, arduino: PropTypes.string.isRequired,
name: PropTypes.string, name: PropTypes.string,
workspaceName: PropTypes.func.isRequired workspaceName: PropTypes.func.isRequired,
}; };
const mapStateToProps = state => ({ const mapStateToProps = (state) => ({
arduino: state.workspace.code.arduino, arduino: state.workspace.code.arduino,
name: state.workspace.name name: state.workspace.name,
}); });
export default connect(mapStateToProps, { workspaceName })(
export default connect(mapStateToProps, { workspaceName })(withStyles(styles, { withTheme: true })(Compile)); withStyles(styles, { withTheme: true })(Compile)
);

View File

@ -16,6 +16,8 @@ import Tooltip from '@material-ui/core/Tooltip';
import { faShare } from "@fortawesome/free-solid-svg-icons"; import { faShare } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import Dialog from '../Dialog';
import Button from '@material-ui/core/Button';
const styles = (theme) => ({ const styles = (theme) => ({
button: { button: {
@ -39,12 +41,21 @@ class ResetWorkspace extends Component {
this.inputRef = React.createRef(); this.inputRef = React.createRef();
this.state = { this.state = {
snackbar: false, snackbar: false,
open: false,
type: '', type: '',
key: '', key: '',
message: '', message: '',
}; };
} }
toggleDialog = () => {
this.setState({ open: !this.state});
}
openDialog = () => {
this.setState({open: true});
}
resetWorkspace = () => { resetWorkspace = () => {
const workspace = Blockly.getMainWorkspace(); const workspace = Blockly.getMainWorkspace();
Blockly.Events.disable(); // https://groups.google.com/forum/#!topic/blockly/m7e3g0TC75Y Blockly.Events.disable(); // https://groups.google.com/forum/#!topic/blockly/m7e3g0TC75Y
@ -69,7 +80,7 @@ class ResetWorkspace extends Component {
<Tooltip title={Blockly.Msg.tooltip_reset_workspace} arrow> <Tooltip title={Blockly.Msg.tooltip_reset_workspace} arrow>
<IconButton <IconButton
className={this.props.classes.button} className={this.props.classes.button}
onClick={() => this.resetWorkspace()} onClick={() => this.openDialog()}
> >
<FontAwesomeIcon icon={faShare} size="xs" flip='horizontal' /> <FontAwesomeIcon icon={faShare} size="xs" flip='horizontal' />
</IconButton> </IconButton>
@ -81,6 +92,17 @@ class ResetWorkspace extends Component {
type={this.state.type} type={this.state.type}
key={this.state.key} key={this.state.key}
/> />
<Dialog
open={this.state.open}
title={Blockly.Msg.resetDialog_headline}
content={Blockly.Msg.resetDialog_text}
onClose={() => { this.toggleDialog(); }}
onClick={() => { this.toggleDialog(); }}
button={Blockly.Msg.button_cancel}
> <div style={{ marginTop: '10px' }}>
<Button variant='contained' color='primary' onClick={() => { this.resetWorkspace(); this.toggleDialog(); }}>Zurücksetzen</Button>
</div></Dialog>
</div> </div>
); );
}; };

View File

@ -127,7 +127,6 @@ class SaveProject extends Component {
} }
render() { render() {
console.log(1, this.props);
return ( return (
<div style={this.props.style}> <div style={this.props.style}>
<Tooltip title={this.state.projectType === 'project' ? Blockly.Msg.tooltip_update_project : Blockly.Msg.tooltip_save_project} arrow> <Tooltip title={this.state.projectType === 'project' ? Blockly.Msg.tooltip_update_project : Blockly.Msg.tooltip_save_project} arrow>

View File

@ -1,12 +1,22 @@
import { MYBADGES_CONNECT, MYBADGES_DISCONNECT, USER_LOADED, USER_LOADING, AUTH_ERROR, LOGIN_SUCCESS, LOGIN_FAIL, LOGOUT_SUCCESS, LOGOUT_FAIL, REFRESH_TOKEN_SUCCESS } from '../actions/types'; import {
MYBADGES_CONNECT,
MYBADGES_DISCONNECT,
USER_LOADED,
USER_LOADING,
AUTH_ERROR,
LOGIN_SUCCESS,
LOGIN_FAIL,
LOGOUT_SUCCESS,
LOGOUT_FAIL,
REFRESH_TOKEN_SUCCESS,
} from "../actions/types";
const initialState = { const initialState = {
token: localStorage.getItem('token'), token: localStorage.getItem("token"),
refreshToken: localStorage.getItem('refreshToken'), refreshToken: localStorage.getItem("refreshToken"),
isAuthenticated: null, isAuthenticated: null,
progress: true, progress: true,
user: null user: null,
}; };
export default function foo(state = initialState, action) { export default function foo(state = initialState, action) {
@ -14,46 +24,46 @@ export default function foo(state = initialState, action){
case USER_LOADING: case USER_LOADING:
return { return {
...state, ...state,
progress: true progress: true,
}; };
case USER_LOADED: case USER_LOADED:
return { return {
...state, ...state,
isAuthenticated: true, isAuthenticated: true,
progress: false, progress: false,
user: action.payload user: action.payload,
}; };
case LOGIN_SUCCESS: case LOGIN_SUCCESS:
case REFRESH_TOKEN_SUCCESS: case REFRESH_TOKEN_SUCCESS:
localStorage.setItem('token', action.payload.token); localStorage.setItem("token", action.payload.token);
localStorage.setItem('refreshToken', action.payload.refreshToken); localStorage.setItem("refreshToken", action.payload.refreshToken);
return { return {
...state, ...state,
user: action.payload.user, user: action.payload.user,
token: action.payload.token, token: action.payload.token,
refreshToken: action.payload.refreshToken, refreshToken: action.payload.refreshToken,
isAuthenticated: true, isAuthenticated: true,
progress: false progress: false,
}; };
case MYBADGES_CONNECT: case MYBADGES_CONNECT:
case MYBADGES_DISCONNECT: case MYBADGES_DISCONNECT:
return { return {
...state, ...state,
user: action.payload user: action.payload,
}; };
case AUTH_ERROR: case AUTH_ERROR:
case LOGIN_FAIL: case LOGIN_FAIL:
case LOGOUT_SUCCESS: case LOGOUT_SUCCESS:
case LOGOUT_FAIL: case LOGOUT_FAIL:
localStorage.removeItem('token'); localStorage.removeItem("token");
localStorage.removeItem('refreshToken'); localStorage.removeItem("refreshToken");
return { return {
...state, ...state,
token: null, token: null,
refreshToken: null, refreshToken: null,
user: null, user: null,
isAuthenticated: false, isAuthenticated: false,
progress: false progress: false,
}; };
default: default:
return state; return state;

View File

@ -1022,6 +1022,11 @@
dependencies: dependencies:
"@blockly/plugin-modal" "^1.20200427.4" "@blockly/plugin-modal" "^1.20200427.4"
"@blockly/zoom-to-fit@^1.0.5":
"integrity" "sha512-+dm8bpJB0AkrEMQPr7nEMYKiEA8Loh7V8ZVa0s25PkxGP9BLqt9NIxUCQjshInhCr11Dlctq7C7noqK+tTVS4w=="
"resolved" "https://registry.npmjs.org/@blockly/zoom-to-fit/-/zoom-to-fit-1.0.5.tgz"
"version" "1.0.5"
"@cnakazawa/watch@^1.0.3": "@cnakazawa/watch@^1.0.3":
version "1.0.4" version "1.0.4"
resolved "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz" resolved "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz"