diff --git a/src/web/widgets/Grbl/ControllerState.jsx b/src/web/widgets/Grbl/ControllerState.jsx
new file mode 100644
index 000000000..60f5b6088
--- /dev/null
+++ b/src/web/widgets/Grbl/ControllerState.jsx
@@ -0,0 +1,51 @@
+import React, { Component, PropTypes } from 'react';
+import shallowCompare from 'react-addons-shallow-compare';
+import Modal from '../../components/Modal';
+import i18n from '../../lib/i18n';
+import {
+ MODAL_CONTROLLER_STATE
+} from './constants';
+//import styles from './index.styl';
+
+class ControllerState extends Component {
+ static propTypes = {
+ state: PropTypes.object,
+ actions: PropTypes.object
+ };
+
+ shouldComponentUpdate(nextProps, nextState) {
+ return shallowCompare(this, nextProps, nextState);
+ }
+ render() {
+ const { state, actions } = this.props;
+ const { modal } = state;
+ const show = (modal.name === MODAL_CONTROLLER_STATE);
+ const maxHeight = Math.max(window.innerHeight / 2, 200);
+
+ return (
+
+
+ {i18n._('Controller State')}
+
+
+ {JSON.stringify(state.controller.state, null, 2)}
+
+
+
+
+
+ );
+ }
+}
+
+export default ControllerState;
diff --git a/src/web/widgets/Grbl/Grbl.jsx b/src/web/widgets/Grbl/Grbl.jsx
index cb6b1742b..476951463 100644
--- a/src/web/widgets/Grbl/Grbl.jsx
+++ b/src/web/widgets/Grbl/Grbl.jsx
@@ -6,6 +6,7 @@ import mapGCodeToText from '../../lib/gcode-text';
import i18n from '../../lib/i18n';
import Panel from '../../components/Panel';
import Toggler from '../../components/Toggler';
+import ControllerState from './ControllerState';
import Toolbar from './Toolbar';
import Overrides from './Overrides';
import styles from './index.styl';
@@ -46,6 +47,7 @@ class Grbl extends Component {
return (
+
{!_.isEmpty(ov) &&
diff --git a/src/web/widgets/Grbl/Toolbar.jsx b/src/web/widgets/Grbl/Toolbar.jsx
index e68b46fe0..44fb20545 100644
--- a/src/web/widgets/Grbl/Toolbar.jsx
+++ b/src/web/widgets/Grbl/Toolbar.jsx
@@ -1,9 +1,13 @@
+import classNames from 'classnames';
import React, { Component, PropTypes } from 'react';
import shallowCompare from 'react-addons-shallow-compare';
import { DropdownButton, MenuItem } from 'react-bootstrap';
import i18n from '../../lib/i18n';
import controller from '../../lib/controller';
import styles from './index.styl';
+import {
+ MODAL_CONTROLLER_STATE
+} from './constants';
class Toolbar extends Component {
static propTypes = {
@@ -15,7 +19,7 @@ class Toolbar extends Component {
return shallowCompare(this, nextProps, nextState);
}
render() {
- const { state } = this.props;
+ const { state, actions } = this.props;
const { canClick } = state;
return (
@@ -24,67 +28,13 @@ class Toolbar extends Component {
-
-
-
-
-
-
-
-
@@ -96,12 +46,40 @@ class Toolbar extends Component {
pullRight
disabled={!canClick}
>
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/web/widgets/Grbl/constants.js b/src/web/widgets/Grbl/constants.js
new file mode 100644
index 000000000..8fc680327
--- /dev/null
+++ b/src/web/widgets/Grbl/constants.js
@@ -0,0 +1,6 @@
+import constants from 'namespace-constants';
+
+module.exports = constants('widgets/Grbl', [
+ 'MODAL_NONE',
+ 'MODAL_CONTROLLER_STATE'
+]);
diff --git a/src/web/widgets/Grbl/icon-status-report-16.png b/src/web/widgets/Grbl/icon-status-report-16.png
new file mode 100644
index 000000000..9f2b07bdb
Binary files /dev/null and b/src/web/widgets/Grbl/icon-status-report-16.png differ
diff --git a/src/web/widgets/Grbl/index.jsx b/src/web/widgets/Grbl/index.jsx
index 1c04a7720..26e7f14fe 100644
--- a/src/web/widgets/Grbl/index.jsx
+++ b/src/web/widgets/Grbl/index.jsx
@@ -10,6 +10,9 @@ import Grbl from './Grbl';
import {
GRBL
} from '../../constants';
+import {
+ MODAL_NONE
+} from './constants';
import styles from './index.styl';
class GrblWidget extends Component {
@@ -22,6 +25,47 @@ class GrblWidget extends Component {
};
actions = {
+ openModal: (name = MODAL_NONE, params = {}) => {
+ // Prevent body from scrolling when a modal is opened
+ const body = document.querySelector('body');
+ const bodyStyle = {
+ overflowY: body.style.overflowY
+ };
+ bodyStyle.overflowY = body.style.overflowY;
+ body.style.overflowY = 'hidden';
+
+ this.setState({
+ modal: {
+ name: name,
+ bodyStyle: bodyStyle,
+ params: params
+ }
+ });
+ },
+ closeModal: () => {
+ const body = document.querySelector('body');
+ if (this.state.modal.bodyStyle) {
+ body.style.overflowY = this.state.modal.bodyStyle.overflowY;
+ }
+
+ this.setState({
+ modal: {
+ name: MODAL_NONE,
+ params: {}
+ }
+ });
+ },
+ updateModalParams: (params = {}) => {
+ this.setState({
+ modal: {
+ ...this.state.modal,
+ params: {
+ ...this.state.modal.params,
+ ...params
+ }
+ }
+ });
+ },
toggleQueueReports: () => {
const expanded = this.state.panel.queueReports.expanded;
@@ -118,6 +162,10 @@ class GrblWidget extends Component {
type: controller.type,
state: controller.state
},
+ modal: {
+ name: MODAL_NONE,
+ params: {}
+ },
panel: {
queueReports: {
expanded: store.get('widgets.grbl.panel.queueReports.expanded')
diff --git a/src/web/widgets/Grbl/index.styl b/src/web/widgets/Grbl/index.styl
index 79fb39576..d38d295ff 100644
--- a/src/web/widgets/Grbl/index.styl
+++ b/src/web/widgets/Grbl/index.styl
@@ -18,9 +18,18 @@
.toolbar {
margin-bottom: 10px;
+}
+
+.icon {
+ display: inline-block;
- button {
- min-width: 24px;
+ &.icon-status-report {
+ width: 16px;
+ height: 16px;
+ background-image: url("./icon-status-report-16.png");
+ background-repeat: no-repeat;
+ vertical-align: middle;
+ margin-bottom: 2px;
}
}
diff --git a/src/web/widgets/Smoothie/ControllerState.jsx b/src/web/widgets/Smoothie/ControllerState.jsx
new file mode 100644
index 000000000..60f5b6088
--- /dev/null
+++ b/src/web/widgets/Smoothie/ControllerState.jsx
@@ -0,0 +1,51 @@
+import React, { Component, PropTypes } from 'react';
+import shallowCompare from 'react-addons-shallow-compare';
+import Modal from '../../components/Modal';
+import i18n from '../../lib/i18n';
+import {
+ MODAL_CONTROLLER_STATE
+} from './constants';
+//import styles from './index.styl';
+
+class ControllerState extends Component {
+ static propTypes = {
+ state: PropTypes.object,
+ actions: PropTypes.object
+ };
+
+ shouldComponentUpdate(nextProps, nextState) {
+ return shallowCompare(this, nextProps, nextState);
+ }
+ render() {
+ const { state, actions } = this.props;
+ const { modal } = state;
+ const show = (modal.name === MODAL_CONTROLLER_STATE);
+ const maxHeight = Math.max(window.innerHeight / 2, 200);
+
+ return (
+
+
+ {i18n._('Controller State')}
+
+
+ {JSON.stringify(state.controller.state, null, 2)}
+
+
+
+
+
+ );
+ }
+}
+
+export default ControllerState;
diff --git a/src/web/widgets/Smoothie/Smoothie.jsx b/src/web/widgets/Smoothie/Smoothie.jsx
index 1925cf61f..af3537d0d 100644
--- a/src/web/widgets/Smoothie/Smoothie.jsx
+++ b/src/web/widgets/Smoothie/Smoothie.jsx
@@ -5,6 +5,7 @@ import mapGCodeToText from '../../lib/gcode-text';
import i18n from '../../lib/i18n';
import Panel from '../../components/Panel';
import Toggler from '../../components/Toggler';
+import ControllerState from './ControllerState';
import Toolbar from './Toolbar';
import Overrides from './Overrides';
import styles from './index.styl';
@@ -34,6 +35,7 @@ class Smoothie extends Component {
return (
+
{(ovF !== undefined || ovS !== undefined) &&
diff --git a/src/web/widgets/Smoothie/Toolbar.jsx b/src/web/widgets/Smoothie/Toolbar.jsx
index 882a99c8b..de07ea01f 100644
--- a/src/web/widgets/Smoothie/Toolbar.jsx
+++ b/src/web/widgets/Smoothie/Toolbar.jsx
@@ -1,9 +1,13 @@
+import classNames from 'classnames';
import React, { Component, PropTypes } from 'react';
import shallowCompare from 'react-addons-shallow-compare';
import { DropdownButton, MenuItem } from 'react-bootstrap';
import i18n from '../../lib/i18n';
import controller from '../../lib/controller';
import styles from './index.styl';
+import {
+ MODAL_CONTROLLER_STATE
+} from './constants';
class Toolbar extends Component {
static propTypes = {
@@ -15,7 +19,7 @@ class Toolbar extends Component {
return shallowCompare(this, nextProps, nextState);
}
render() {
- const { state } = this.props;
+ const { state, actions } = this.props;
const { canClick } = state;
return (
@@ -24,49 +28,13 @@ class Toolbar extends Component {
-
-
-
-
-
-
@@ -78,9 +46,25 @@ class Toolbar extends Component {
pullRight
disabled={!canClick}
>
-
-
-
+
+
+
+
+
+
+
diff --git a/src/web/widgets/Smoothie/constants.js b/src/web/widgets/Smoothie/constants.js
new file mode 100644
index 000000000..faec6671e
--- /dev/null
+++ b/src/web/widgets/Smoothie/constants.js
@@ -0,0 +1,6 @@
+import constants from 'namespace-constants';
+
+module.exports = constants('widgets/Smoothie', [
+ 'MODAL_NONE',
+ 'MODAL_CONTROLLER_STATE'
+]);
diff --git a/src/web/widgets/Smoothie/icon-status-report-16.png b/src/web/widgets/Smoothie/icon-status-report-16.png
new file mode 100644
index 000000000..9f2b07bdb
Binary files /dev/null and b/src/web/widgets/Smoothie/icon-status-report-16.png differ
diff --git a/src/web/widgets/Smoothie/index.jsx b/src/web/widgets/Smoothie/index.jsx
index b20aa6628..0adbc1c63 100644
--- a/src/web/widgets/Smoothie/index.jsx
+++ b/src/web/widgets/Smoothie/index.jsx
@@ -10,6 +10,9 @@ import Smoothie from './Smoothie';
import {
SMOOTHIE
} from '../../constants';
+import {
+ MODAL_NONE
+} from './constants';
import styles from './index.styl';
class SmoothieWidget extends Component {
@@ -22,6 +25,47 @@ class SmoothieWidget extends Component {
};
actions = {
+ openModal: (name = MODAL_NONE, params = {}) => {
+ // Prevent body from scrolling when a modal is opened
+ const body = document.querySelector('body');
+ const bodyStyle = {
+ overflowY: body.style.overflowY
+ };
+ bodyStyle.overflowY = body.style.overflowY;
+ body.style.overflowY = 'hidden';
+
+ this.setState({
+ modal: {
+ name: name,
+ bodyStyle: bodyStyle,
+ params: params
+ }
+ });
+ },
+ closeModal: () => {
+ const body = document.querySelector('body');
+ if (this.state.modal.bodyStyle) {
+ body.style.overflowY = this.state.modal.bodyStyle.overflowY;
+ }
+
+ this.setState({
+ modal: {
+ name: MODAL_NONE,
+ params: {}
+ }
+ });
+ },
+ updateModalParams: (params = {}) => {
+ this.setState({
+ modal: {
+ ...this.state.modal,
+ params: {
+ ...this.state.modal.params,
+ ...params
+ }
+ }
+ });
+ },
toggleQueueReports: () => {
const expanded = this.state.panel.queueReports.expanded;
@@ -118,6 +162,10 @@ class SmoothieWidget extends Component {
type: controller.type,
state: controller.state
},
+ modal: {
+ name: MODAL_NONE,
+ params: {}
+ },
panel: {
queueReports: {
expanded: store.get('widgets.smoothie.panel.queueReports.expanded')
diff --git a/src/web/widgets/Smoothie/index.styl b/src/web/widgets/Smoothie/index.styl
index 79fb39576..d38d295ff 100644
--- a/src/web/widgets/Smoothie/index.styl
+++ b/src/web/widgets/Smoothie/index.styl
@@ -18,9 +18,18 @@
.toolbar {
margin-bottom: 10px;
+}
+
+.icon {
+ display: inline-block;
- button {
- min-width: 24px;
+ &.icon-status-report {
+ width: 16px;
+ height: 16px;
+ background-image: url("./icon-status-report-16.png");
+ background-repeat: no-repeat;
+ vertical-align: middle;
+ margin-bottom: 2px;
}
}
diff --git a/src/web/widgets/TinyG/ControllerState.jsx b/src/web/widgets/TinyG/ControllerState.jsx
new file mode 100644
index 000000000..60f5b6088
--- /dev/null
+++ b/src/web/widgets/TinyG/ControllerState.jsx
@@ -0,0 +1,51 @@
+import React, { Component, PropTypes } from 'react';
+import shallowCompare from 'react-addons-shallow-compare';
+import Modal from '../../components/Modal';
+import i18n from '../../lib/i18n';
+import {
+ MODAL_CONTROLLER_STATE
+} from './constants';
+//import styles from './index.styl';
+
+class ControllerState extends Component {
+ static propTypes = {
+ state: PropTypes.object,
+ actions: PropTypes.object
+ };
+
+ shouldComponentUpdate(nextProps, nextState) {
+ return shallowCompare(this, nextProps, nextState);
+ }
+ render() {
+ const { state, actions } = this.props;
+ const { modal } = state;
+ const show = (modal.name === MODAL_CONTROLLER_STATE);
+ const maxHeight = Math.max(window.innerHeight / 2, 200);
+
+ return (
+
+
+ {i18n._('Controller State')}
+
+
+ {JSON.stringify(state.controller.state, null, 2)}
+
+
+
+
+
+ );
+ }
+}
+
+export default ControllerState;
diff --git a/src/web/widgets/TinyG/TinyG.jsx b/src/web/widgets/TinyG/TinyG.jsx
index 0ee698703..fc65636cb 100644
--- a/src/web/widgets/TinyG/TinyG.jsx
+++ b/src/web/widgets/TinyG/TinyG.jsx
@@ -6,6 +6,7 @@ import mapGCodeToText from '../../lib/gcode-text';
import i18n from '../../lib/i18n';
import Panel from '../../components/Panel';
import Toggler from '../../components/Toggler';
+import ControllerState from './ControllerState';
import Toolbar from './Toolbar';
import {
TINYG_MACHINE_STATE_INITIALIZING,
@@ -70,6 +71,7 @@ class TinyG extends Component {
return (
+
diff --git a/src/web/widgets/TinyG/Toolbar.jsx b/src/web/widgets/TinyG/Toolbar.jsx
index 3137178c4..1ae5700c4 100644
--- a/src/web/widgets/TinyG/Toolbar.jsx
+++ b/src/web/widgets/TinyG/Toolbar.jsx
@@ -1,9 +1,13 @@
+import classNames from 'classnames';
import React, { Component, PropTypes } from 'react';
import shallowCompare from 'react-addons-shallow-compare';
import { DropdownButton, MenuItem } from 'react-bootstrap';
import i18n from '../../lib/i18n';
import controller from '../../lib/controller';
import styles from './index.styl';
+import {
+ MODAL_CONTROLLER_STATE
+} from './constants';
class Toolbar extends Component {
static propTypes = {
@@ -15,7 +19,7 @@ class Toolbar extends Component {
return shallowCompare(this, nextProps, nextState);
}
render() {
- const { state } = this.props;
+ const { state, actions } = this.props;
const { canClick } = state;
return (
@@ -24,64 +28,13 @@ class Toolbar extends Component {
-
-
-
-
-
-
-
@@ -93,14 +46,44 @@ class Toolbar extends Component {
pullRight
disabled={!canClick}
>
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/src/web/widgets/TinyG/constants.js b/src/web/widgets/TinyG/constants.js
new file mode 100644
index 000000000..cb22ed1d5
--- /dev/null
+++ b/src/web/widgets/TinyG/constants.js
@@ -0,0 +1,6 @@
+import constants from 'namespace-constants';
+
+module.exports = constants('widgets/TinyG', [
+ 'MODAL_NONE',
+ 'MODAL_CONTROLLER_STATE'
+]);
diff --git a/src/web/widgets/TinyG/icon-status-report-16.png b/src/web/widgets/TinyG/icon-status-report-16.png
new file mode 100644
index 000000000..9f2b07bdb
Binary files /dev/null and b/src/web/widgets/TinyG/icon-status-report-16.png differ
diff --git a/src/web/widgets/TinyG/index.jsx b/src/web/widgets/TinyG/index.jsx
index ae3a727e7..a379ffffe 100644
--- a/src/web/widgets/TinyG/index.jsx
+++ b/src/web/widgets/TinyG/index.jsx
@@ -10,6 +10,9 @@ import TinyG from './TinyG';
import {
TINYG
} from '../../constants';
+import {
+ MODAL_NONE
+} from './constants';
import styles from './index.styl';
class TinyGWidget extends Component {
@@ -22,6 +25,47 @@ class TinyGWidget extends Component {
};
actions = {
+ openModal: (name = MODAL_NONE, params = {}) => {
+ // Prevent body from scrolling when a modal is opened
+ const body = document.querySelector('body');
+ const bodyStyle = {
+ overflowY: body.style.overflowY
+ };
+ bodyStyle.overflowY = body.style.overflowY;
+ body.style.overflowY = 'hidden';
+
+ this.setState({
+ modal: {
+ name: name,
+ bodyStyle: bodyStyle,
+ params: params
+ }
+ });
+ },
+ closeModal: () => {
+ const body = document.querySelector('body');
+ if (this.state.modal.bodyStyle) {
+ body.style.overflowY = this.state.modal.bodyStyle.overflowY;
+ }
+
+ this.setState({
+ modal: {
+ name: MODAL_NONE,
+ params: {}
+ }
+ });
+ },
+ updateModalParams: (params = {}) => {
+ this.setState({
+ modal: {
+ ...this.state.modal,
+ params: {
+ ...this.state.modal.params,
+ ...params
+ }
+ }
+ });
+ },
toggleQueueReports: () => {
const expanded = this.state.panel.queueReports.expanded;
@@ -118,6 +162,10 @@ class TinyGWidget extends Component {
type: controller.type,
state: controller.state
},
+ modal: {
+ name: MODAL_NONE,
+ params: {}
+ },
panel: {
queueReports: {
expanded: store.get('widgets.tinyg.panel.queueReports.expanded')
diff --git a/src/web/widgets/TinyG/index.styl b/src/web/widgets/TinyG/index.styl
index 94d02218a..415478edd 100644
--- a/src/web/widgets/TinyG/index.styl
+++ b/src/web/widgets/TinyG/index.styl
@@ -20,9 +20,18 @@
.toolbar {
margin-bottom: 10px;
+}
+
+.icon {
+ display: inline-block;
- button {
- min-width: 24px;
+ &.icon-status-report {
+ width: 16px;
+ height: 16px;
+ background-image: url("./icon-status-report-16.png");
+ background-repeat: no-repeat;
+ vertical-align: middle;
+ margin-bottom: 2px;
}
}