From 7b6c0866071ab80259d5d08238164b1f49862ebb Mon Sep 17 00:00:00 2001
From: dmrib
Date: Tue, 7 Apr 2020 08:02:15 -0300
Subject: [PATCH 01/40] Implement websocket connection
---
src/App.js | 47 +++++++++++++++++++++++++++++++++++++++++-
src/config/config.json | 4 ++++
2 files changed, 50 insertions(+), 1 deletion(-)
create mode 100644 src/config/config.json
diff --git a/src/App.js b/src/App.js
index bf0bedd..2a71a68 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,11 +1,16 @@
import React from 'react';
+import { useState, useRef, useEffect } from 'react';
import Content from './components/Content';
import Header from './components/Header';
import Footer from './components/Footer';
+import config from './config/config.json';
import './App.css';
import 'antd/dist/antd.css';
+const CONNECTION_ADDRESS = `ws://${config['HOST']}:${config['PORT']}`
+
+
/**
* App components aggregator.
*
@@ -13,9 +18,49 @@ import 'antd/dist/antd.css';
*/
function App()
{
+ // component state hooks
+ const socket = useRef(null);
+ const [socketState, setSocketState] = useState(0);
+
+
+ /**
+ * I am called when this component is mounted.
+ */
+ useEffect(() =>
+ {
+ // create websocket connection
+ socket.current = new WebSocket(CONNECTION_ADDRESS);
+
+ // on connection opened event callback
+ socket.current.onopen = (event) =>
+ {
+ console.log('Websocket connection established.')
+ setSocketState(socket.current.readyState);
+ }
+
+ // on connection closed event callback
+ socket.current.onclose = (event) =>
+ {
+ console.log("Websocket connection closed.");
+ setSocketState(socket.current.readyState);
+ }
+
+ // on websocket error event callback
+ socket.current.onerror = (event) =>
+ {
+ console.log('Websocket error: ', {event});
+ setSocketState(socket.current.readyState);
+ }
+
+ // cleanup on lifecycle end
+ return () => socket.current.close();
+
+ }, []);
+
+
return (
-
+
diff --git a/src/config/config.json b/src/config/config.json
new file mode 100644
index 0000000..008458e
--- /dev/null
+++ b/src/config/config.json
@@ -0,0 +1,4 @@
+{
+ "HOST": "localhost",
+ "PORT": 8765
+}
From bf48563087dcfeeb8c4372df64c449c7c93bdcd7 Mon Sep 17 00:00:00 2001
From: dmrib
Date: Tue, 7 Apr 2020 08:11:07 -0300
Subject: [PATCH 02/40] Define connection status style
---
src/components/Header/Header.css | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/components/Header/Header.css b/src/components/Header/Header.css
index 45e331a..c106775 100644
--- a/src/components/Header/Header.css
+++ b/src/components/Header/Header.css
@@ -39,3 +39,10 @@
align-items: center;
margin-right: 5%;
}
+
+.connection-status {
+ height: 15px;
+ width: 15px;
+ margin-right: 10px;
+ border-radius: 50%;
+}
From c5fe5da0c2c7226cfbd49b1d25c5585fca40b422 Mon Sep 17 00:00:00 2001
From: dmrib
Date: Tue, 7 Apr 2020 08:23:01 -0300
Subject: [PATCH 03/40] Create connection status indicator
---
.../Header/StatusIndicator/index.js | 52 ++++++++++++++++++
src/components/Header/index.js | 53 ++++++++++++++++++-
2 files changed, 103 insertions(+), 2 deletions(-)
create mode 100644 src/components/Header/StatusIndicator/index.js
diff --git a/src/components/Header/StatusIndicator/index.js b/src/components/Header/StatusIndicator/index.js
new file mode 100644
index 0000000..632966c
--- /dev/null
+++ b/src/components/Header/StatusIndicator/index.js
@@ -0,0 +1,52 @@
+import React from 'react';
+import { Popover, Typography } from 'antd';
+import PropTypes from 'prop-types';
+
+
+/**
+ * Websocket connection status indicator component.
+ *
+ * @component
+ */
+function StatusIndicator({color, message})
+{
+ return (
+
+
+ {`Predictor is ${message}!`}
+
+ }
+ placement="bottom"
+ trigger="hover"
+ align={{offset: [0, 8]}}
+ >
+
+
+
+
+
+ );
+}
+
+
+StatusIndicator.propTypes = {
+ /**
+ * Connection indicator current color.
+ */
+ color: PropTypes.string.isRequired,
+
+ /**
+ * Connection indicator current message.
+ */
+ message: PropTypes.string.isRequired
+}
+
+
+export default StatusIndicator;
diff --git a/src/components/Header/index.js b/src/components/Header/index.js
index 74dc8b4..1533ef9 100644
--- a/src/components/Header/index.js
+++ b/src/components/Header/index.js
@@ -1,16 +1,53 @@
import React from 'react';
+import { useEffect, useState } from 'react';
import Logo from "./logo.png";
-import { Icon, Popover } from 'antd';
+import StatusIndicator from './StatusIndicator';
+import PropTypes from 'prop-types';
import './Header.css'
+const CONNECTION = {
+ 0: {
+ message: 'connecting',
+ color: '#b5982d'
+ },
+ 1: {
+ message: 'connected',
+ color: '#39963f'
+ },
+ 2: {
+ message: 'closing',
+ color: '#b5982d'
+ },
+ 3: {
+ message: 'closed',
+ color: '#a83232'
+ }
+};
+
+
/**
* Linguiçator editor header component.
*
* @component
*/
-function Header()
+function Header({socketState})
{
+ // component state hooks
+ const [status, setStatus] = useState(CONNECTION[socketState].message);
+ const [colorCode, setColorCode] = useState(CONNECTION[socketState].color);
+
+
+ /**
+ * I am called whenever connection to predictor state changes.
+ */
+ useEffect(() =>
+ {
+ setStatus(CONNECTION[socketState].message);
+ setColorCode(CONNECTION[socketState].color);
+ }, [socketState]);
+
+
return (
From 4a127d0e55ed9b4e8232facbb0d839a06e37a68e Mon Sep 17 00:00:00 2001
From: dmrib
Date: Wed, 8 Apr 2020 18:36:55 -0300
Subject: [PATCH 12/40] Add redux as a dependency
---
package.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 04ca4f8..0c45039 100644
--- a/package.json
+++ b/package.json
@@ -10,7 +10,8 @@
"marked": "^0.8.0",
"react": "^16.12.0",
"react-dom": "^16.12.0",
- "react-scripts": "3.4.0"
+ "react-scripts": "3.4.0",
+ "redux": "^4.0.5"
},
"scripts": {
"start": "react-scripts start",
From be5ad8e8c01f79c953dd84bc6fe192f9f0d7b9da Mon Sep 17 00:00:00 2001
From: dmrib
Date: Wed, 8 Apr 2020 18:38:01 -0300
Subject: [PATCH 13/40] Add react-redux as a dependency
---
package.json | 1 +
1 file changed, 1 insertion(+)
diff --git a/package.json b/package.json
index 0c45039..5f3ea86 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,7 @@
"marked": "^0.8.0",
"react": "^16.12.0",
"react-dom": "^16.12.0",
+ "react-redux": "^7.2.0",
"react-scripts": "3.4.0",
"redux": "^4.0.5"
},
From 45f6dfdca0830f01bd7b954934eb57103f235433 Mon Sep 17 00:00:00 2001
From: dmrib
Date: Wed, 8 Apr 2020 19:26:16 -0300
Subject: [PATCH 14/40] Add redux-devtools-extension as a development
dependency
---
package.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 5f3ea86..c279f6f 100644
--- a/package.json
+++ b/package.json
@@ -38,6 +38,7 @@
},
"devDependencies": {
"better-docs": "^1.4.7",
- "jsdoc": "^3.6.3"
+ "jsdoc": "^3.6.3",
+ "redux-devtools-extension": "^2.13.8"
}
}
From 929a9cd164aa182f453e4599ff2a5a06d0539cd1 Mon Sep 17 00:00:00 2001
From: dmrib
Date: Wed, 8 Apr 2020 19:57:47 -0300
Subject: [PATCH 15/40] Implement set maximum prediction size action
---
src/store/actions/predictions.js | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
create mode 100644 src/store/actions/predictions.js
diff --git a/src/store/actions/predictions.js b/src/store/actions/predictions.js
new file mode 100644
index 0000000..cd73ed4
--- /dev/null
+++ b/src/store/actions/predictions.js
@@ -0,0 +1,20 @@
+/**
+ * I update predictions maximum size.
+ *
+ * @param {number} size - new predictions maximum size
+ *
+ * @returns {object} - action to be dispatched
+ */
+function setMaxSize(size) {
+ return {
+ type: 'SET_MAX_SIZE',
+ payload: {
+ size
+ }
+ };
+}
+
+
+export {
+ setMaxSize
+}
From 0197218e1cdcd0937102368e8201d80e07bcbe28 Mon Sep 17 00:00:00 2001
From: dmrib
Date: Wed, 8 Apr 2020 19:18:09 -0300
Subject: [PATCH 16/40] Create Predictions aggregate reducer
---
src/store/reducers/predictions.js | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
create mode 100644 src/store/reducers/predictions.js
diff --git a/src/store/reducers/predictions.js b/src/store/reducers/predictions.js
new file mode 100644
index 0000000..341ce91
--- /dev/null
+++ b/src/store/reducers/predictions.js
@@ -0,0 +1,31 @@
+/**
+ * Predictions store initial state.
+ */
+const INITIAL_STATE = {
+ 'maxSize': 75
+}
+
+
+/**
+ * Predictions reducer.
+ *
+ * @param {object} state - current predictions store state
+ * @param {object} action - dispatched action
+ *
+ * @returns {object} - updated state
+ */
+function predictions(state = INITIAL_STATE, action)
+{
+ switch (action.type) {
+ case 'SET_MAX_SIZE':
+ return {
+ ...state,
+ maxSize: action.payload.size
+ };
+ default:
+ return state;
+ }
+}
+
+
+export default predictions;
From 098114fa986806b8413ab53f4333262a2b31695f Mon Sep 17 00:00:00 2001
From: dmrib
Date: Wed, 8 Apr 2020 19:18:43 -0300
Subject: [PATCH 17/40] Create Redux store reducer
---
src/store/reducers/index.js | 7 +++++++
1 file changed, 7 insertions(+)
create mode 100644 src/store/reducers/index.js
diff --git a/src/store/reducers/index.js b/src/store/reducers/index.js
new file mode 100644
index 0000000..8202aad
--- /dev/null
+++ b/src/store/reducers/index.js
@@ -0,0 +1,7 @@
+import { combineReducers } from 'redux';
+import predictions from './predictions';
+
+
+export default combineReducers({
+ predictions
+});
From 7ffe0687b3d038823a4776d14fdfb934a770dce5 Mon Sep 17 00:00:00 2001
From: dmrib
Date: Wed, 8 Apr 2020 19:25:31 -0300
Subject: [PATCH 18/40] Create application Redux store
---
src/store/index.js | 12 ++++++++++++
1 file changed, 12 insertions(+)
create mode 100644 src/store/index.js
diff --git a/src/store/index.js b/src/store/index.js
new file mode 100644
index 0000000..802360d
--- /dev/null
+++ b/src/store/index.js
@@ -0,0 +1,12 @@
+import { createStore } from 'redux';
+import { composeWithDevTools } from 'redux-devtools-extension';
+import rootReducer from './reducers';
+
+
+/**
+ * Create application store with Redux-Dev-Tools support.
+ */
+const store = createStore(rootReducer, composeWithDevTools());
+
+
+export default store;
From c35d6b99965757120f5397e428145371d23fba6c Mon Sep 17 00:00:00 2001
From: dmrib
Date: Wed, 8 Apr 2020 19:25:50 -0300
Subject: [PATCH 19/40] Expose Redux store to components
---
src/App.js | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/src/App.js b/src/App.js
index 2a71a68..71ef76c 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,5 +1,7 @@
import React from 'react';
import { useState, useRef, useEffect } from 'react';
+import { Provider } from 'react-redux';
+import store from './store';
import Content from './components/Content';
import Header from './components/Header';
import Footer from './components/Footer';
@@ -59,11 +61,13 @@ function App()
return (
-
-
+
+
+
+
);
}
From a68cf8401b9771401b5bb33126cbbf73f5f15278 Mon Sep 17 00:00:00 2001
From: dmrib
Date: Wed, 8 Apr 2020 20:00:40 -0300
Subject: [PATCH 20/40] Expose set maximum prediction size action
---
src/components/Header/Settings/index.js | 20 ++++++++++++++++++++
src/store/actions/predictions.js | 3 ++-
2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/src/components/Header/Settings/index.js b/src/components/Header/Settings/index.js
index f4418f5..6bf3e1b 100644
--- a/src/components/Header/Settings/index.js
+++ b/src/components/Header/Settings/index.js
@@ -1,4 +1,6 @@
import React from 'react';
+import { useDispatch } from 'react-redux';
+import { setMaxSize } from '../../../store/actions/predictions';
import { SettingFilled } from '@ant-design/icons';
import { Typography, Icon, Popover, Slider } from 'antd';
import 'antd/dist/antd.css';
@@ -11,6 +13,23 @@ import 'antd/dist/antd.css';
*/
function Settings()
{
+ // action dispatch hook
+ const dispatch = useDispatch();
+
+
+ /**
+ * I am a callback for prediction maximum size slider value changed.
+ *
+ * @param {number} size - new maximum prediction size
+ *
+ * @returns {undefined} - nothing
+ */
+ function setMaximumPredictionSize(size)
+ {
+ dispatch(setMaxSize(size));
+ }
+
+
return(
diff --git a/src/store/actions/predictions.js b/src/store/actions/predictions.js
index cd73ed4..b6d11c5 100644
--- a/src/store/actions/predictions.js
+++ b/src/store/actions/predictions.js
@@ -5,7 +5,8 @@
*
* @returns {object} - action to be dispatched
*/
-function setMaxSize(size) {
+function setMaxSize(size)
+{
return {
type: 'SET_MAX_SIZE',
payload: {
From 7d623d92fc976c02f8f7abc2fb096c6da0b0bcf7 Mon Sep 17 00:00:00 2001
From: dmrib
Date: Thu, 9 Apr 2020 10:43:30 -0300
Subject: [PATCH 21/40] Implement set idle time until prediction action
---
src/store/actions/predictions.js | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/src/store/actions/predictions.js b/src/store/actions/predictions.js
index b6d11c5..70ec148 100644
--- a/src/store/actions/predictions.js
+++ b/src/store/actions/predictions.js
@@ -16,6 +16,25 @@ function setMaxSize(size)
}
+/**
+ * I update idle time until predictions are scheduled.
+ *
+ * @param {number} time - time until predictions in miliseconds
+ *
+ * @returns {object} - action to be dispatched
+ */
+function setIdleTime(time)
+{
+ return {
+ type: 'SET_IDLE_TIME',
+ payload: {
+ time
+ }
+ };
+}
+
+
export {
- setMaxSize
+ setMaxSize,
+ setIdleTime
}
From 9fb44ecb8536869a1c2d2d708a5e6b232f172639 Mon Sep 17 00:00:00 2001
From: dmrib
Date: Thu, 9 Apr 2020 10:44:14 -0300
Subject: [PATCH 22/40] Implement set idle time until prediction reducer
---
src/store/reducers/predictions.js | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/store/reducers/predictions.js b/src/store/reducers/predictions.js
index 341ce91..bd20004 100644
--- a/src/store/reducers/predictions.js
+++ b/src/store/reducers/predictions.js
@@ -2,8 +2,9 @@
* Predictions store initial state.
*/
const INITIAL_STATE = {
- 'maxSize': 75
-}
+ maxSize: 75,
+ idleTime: 3000
+};
/**
@@ -22,6 +23,11 @@ function predictions(state = INITIAL_STATE, action)
...state,
maxSize: action.payload.size
};
+ case 'SET_IDLE_TIME':
+ return {
+ ...state,
+ idleTime: action.payload.time
+ }
default:
return state;
}
From 4612d5b5b7e8a7a3cfbd208a3ddedb762c17f907 Mon Sep 17 00:00:00 2001
From: dmrib
Date: Thu, 9 Apr 2020 10:51:20 -0300
Subject: [PATCH 23/40] Style line separators on settings
---
src/components/Header/Header.css | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/components/Header/Header.css b/src/components/Header/Header.css
index e0825be..9ab820e 100644
--- a/src/components/Header/Header.css
+++ b/src/components/Header/Header.css
@@ -58,6 +58,12 @@ html {
border-radius: 100%;
}
+.settings-separator {
+ background-color: #432f44;
+ height: 1px;
+ border: 0;
+}
+
.ant-slider-track {
background-color: #a7425c;
}
From c02cd1fb34aed9e7603c27b5d8393420510b03bb Mon Sep 17 00:00:00 2001
From: dmrib
Date: Thu, 9 Apr 2020 10:44:42 -0300
Subject: [PATCH 24/40] Make idle time until prediction adjustable
---
src/components/Header/Settings/index.js | 38 ++++++++++++++++++++++++-
1 file changed, 37 insertions(+), 1 deletion(-)
diff --git a/src/components/Header/Settings/index.js b/src/components/Header/Settings/index.js
index 6bf3e1b..65eaf21 100644
--- a/src/components/Header/Settings/index.js
+++ b/src/components/Header/Settings/index.js
@@ -1,6 +1,6 @@
import React from 'react';
import { useDispatch } from 'react-redux';
-import { setMaxSize } from '../../../store/actions/predictions';
+import { setMaxSize, setIdleTime } from '../../../store/actions/predictions';
import { SettingFilled } from '@ant-design/icons';
import { Typography, Icon, Popover, Slider } from 'antd';
import 'antd/dist/antd.css';
@@ -30,6 +30,19 @@ function Settings()
}
+ /**
+ * I am a callback for idle time until prediction slider value changed.
+ *
+ * @param {number} time - new idle time until prediction
+ *
+ * @returns {undefined} - nothing
+ */
+ function setIdleSecondsUntilPrediction(time)
+ {
+ dispatch(setIdleTime(time * 1000));
+ }
+
+
return(
+
+
+
+
+
+ Idle seconds until prediction:
+
+
+
+
}
trigger="hover"
From 74a9ba23c4c16a8f716be322c432c9f2e86ef78d Mon Sep 17 00:00:00 2001
From: dmrib
Date: Thu, 9 Apr 2020 13:19:59 -0300
Subject: [PATCH 25/40] Implement reset prediction action
---
src/store/actions/predictions.js | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/src/store/actions/predictions.js b/src/store/actions/predictions.js
index 70ec148..cd4b530 100644
--- a/src/store/actions/predictions.js
+++ b/src/store/actions/predictions.js
@@ -34,7 +34,22 @@ function setIdleTime(time)
}
+/**
+ * I reset the current prediction.
+ *
+ * @returns {object} - action to be dispatched
+ */
+function resetPrediction()
+{
+ return {
+ type: 'RESET_PREDICTION',
+ payload: {}
+ }
+}
+
+
export {
setMaxSize,
- setIdleTime
+ setIdleTime,
+ resetPrediction
}
From 7e77dd241ce362122ae47991e04e202b4bee62de Mon Sep 17 00:00:00 2001
From: dmrib
Date: Thu, 9 Apr 2020 13:21:51 -0300
Subject: [PATCH 26/40] Implement reset prediction reducer
---
src/store/reducers/predictions.js | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/src/store/reducers/predictions.js b/src/store/reducers/predictions.js
index bd20004..b83aeb9 100644
--- a/src/store/reducers/predictions.js
+++ b/src/store/reducers/predictions.js
@@ -2,8 +2,11 @@
* Predictions store initial state.
*/
const INITIAL_STATE = {
+ hasPrediction: false,
+ idleTime: 3000,
+ isPredicting: false,
maxSize: 75,
- idleTime: 3000
+ prediction: ''
};
@@ -28,6 +31,14 @@ function predictions(state = INITIAL_STATE, action)
...state,
idleTime: action.payload.time
}
+ case 'RESET_PREDICTION':
+ return {
+ ...state,
+ isPredicting: false,
+ expectedId: null,
+ prediction: '',
+ hasPrediction: false
+ }
default:
return state;
}
From 2154d5e43ac573098282bd2631c50ef4b6fa8f07 Mon Sep 17 00:00:00 2001
From: dmrib
Date: Thu, 9 Apr 2020 13:22:58 -0300
Subject: [PATCH 27/40] Implement wait prediction action
---
src/store/actions/predictions.js | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/src/store/actions/predictions.js b/src/store/actions/predictions.js
index cd4b530..a67acbb 100644
--- a/src/store/actions/predictions.js
+++ b/src/store/actions/predictions.js
@@ -48,8 +48,27 @@ function resetPrediction()
}
+/**
+ * I wait for a prediction from backstage.
+ *
+ * @param {string} id - expected prediction id
+ *
+ * @returns {object} - action to be dispatched
+ */
+function waitPrediction(id)
+{
+ return {
+ type: 'WAIT_PREDICTION',
+ payload: {
+ id
+ }
+ }
+}
+
+
export {
setMaxSize,
setIdleTime,
- resetPrediction
+ resetPrediction,
+ waitPrediction
}
From ea319d78f20e4d1507088b906d053d21215b0307 Mon Sep 17 00:00:00 2001
From: dmrib
Date: Thu, 9 Apr 2020 13:23:16 -0300
Subject: [PATCH 28/40] Implement wait prediction reducer
---
src/store/reducers/predictions.js | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/store/reducers/predictions.js b/src/store/reducers/predictions.js
index b83aeb9..3c6bd26 100644
--- a/src/store/reducers/predictions.js
+++ b/src/store/reducers/predictions.js
@@ -2,6 +2,7 @@
* Predictions store initial state.
*/
const INITIAL_STATE = {
+ expectedId: null,
hasPrediction: false,
idleTime: 3000,
isPredicting: false,
@@ -39,6 +40,12 @@ function predictions(state = INITIAL_STATE, action)
prediction: '',
hasPrediction: false
}
+ case 'WAIT_PREDICTION':
+ return {
+ ...state,
+ isPredicting: true,
+ expectedId: action.payload.id
+ }
default:
return state;
}
From 1808c1e42104919734c84c8ca3d3b410a4474688 Mon Sep 17 00:00:00 2001
From: dmrib
Date: Thu, 9 Apr 2020 13:33:36 -0300
Subject: [PATCH 29/40] Add uuid as a dependency
---
package.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/package.json b/package.json
index c279f6f..54fcf57 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,8 @@
"react-dom": "^16.12.0",
"react-redux": "^7.2.0",
"react-scripts": "3.4.0",
- "redux": "^4.0.5"
+ "redux": "^4.0.5",
+ "uuid": "^7.0.3"
},
"scripts": {
"start": "react-scripts start",
From 5cf43b157a166780b716dd0fa0469f564b28a0e8 Mon Sep 17 00:00:00 2001
From: dmrib
Date: Thu, 9 Apr 2020 13:33:20 -0300
Subject: [PATCH 30/40] Make predictions request on user idle
---
src/App.js | 8 ++++-
src/components/Content/index.js | 61 ++++++++++++++++++++++++++++++++-
2 files changed, 67 insertions(+), 2 deletions(-)
diff --git a/src/App.js b/src/App.js
index 71ef76c..b4e74e5 100644
--- a/src/App.js
+++ b/src/App.js
@@ -54,6 +54,12 @@ function App()
setSocketState(socket.current.readyState);
}
+ // on websocket message received event callback
+ socket.current.onmessage = (event) =>
+ {
+ console.log(`Received: "${event.data}"`);
+ };
+
// cleanup on lifecycle end
return () => socket.current.close();
@@ -64,7 +70,7 @@ function App()
diff --git a/src/components/Content/index.js b/src/components/Content/index.js
index 0d6e078..3b4e409 100644
--- a/src/components/Content/index.js
+++ b/src/components/Content/index.js
@@ -1,6 +1,10 @@
import React from 'react';
import { useEffect, useState } from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+import { resetPrediction } from '../../store/actions/predictions';
+import { waitPrediction } from '../../store/actions/predictions';
import { sanitize } from 'dompurify';
+import { v4 as uuidv4 } from 'uuid';
import marked from 'marked';
import './Content.css'
@@ -10,11 +14,14 @@ import './Content.css'
*
* @component
*/
-function Content()
+function Content({socket})
{
// component state hooks
const [text, setText] = useState('');
const [preview, setPreview] = useState('');
+ const [scheduled, setScheduled] = useState(null);
+ const dispatch = useDispatch();
+ const predictor = useSelector(state => state.predictions);
/**
@@ -26,6 +33,57 @@ function Content()
}, [text]);
+ /**
+ * I ask a prediction from the backstage.
+ *
+ * @returns {undefined} - nothing
+ */
+ function askForPrediction()
+ {
+ // generate prediction request id
+ const id = uuidv4();
+
+ // update application state to wait for prediction
+ dispatch(waitPrediction(id));
+
+ // create prediction request payload
+ const data = JSON.stringify({
+ id,
+ resource: '/predict',
+ data: {
+ text,
+ length: predictor.maxSize
+ }
+ });
+
+ // send payload through socket
+ socket.send(data);
+ }
+
+
+ /**
+ * I update predictions schedule state.
+ *
+ * @returns {undefined} - nothing
+ */
+ function updateSchedule()
+ {
+ // prediction scheduled: cancel current scheduled prediction
+ if (scheduled !== null)
+ {
+ clearTimeout(scheduled);
+ setScheduled(null);
+ }
+
+ // reset prediction state on store
+ dispatch(resetPrediction());
+
+ // schedule next prediction attempt
+ const id = setTimeout(askForPrediction, predictor.idleTime);
+ setScheduled(id);
+ }
+
+
/**
* I am a callback for input text changed events.
*
@@ -36,6 +94,7 @@ function Content()
function onTextChange(event)
{
setText(event.target.value);
+ updateSchedule();
}
From 3a0bdd35758d9545e383e88feb6eed59c8727bc8 Mon Sep 17 00:00:00 2001
From: dmrib
Date: Thu, 9 Apr 2020 13:44:47 -0300
Subject: [PATCH 31/40] Animate Salami while waiting for predictions
---
src/components/Header/Predictor/index.js | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/components/Header/Predictor/index.js b/src/components/Header/Predictor/index.js
index 202a8dd..b3c6810 100644
--- a/src/components/Header/Predictor/index.js
+++ b/src/components/Header/Predictor/index.js
@@ -1,4 +1,5 @@
import React from 'react';
+import { useSelector } from 'react-redux';
import { Popover, Icon } from 'antd';
import { ReactComponent as Salami } from '../salami.svg';
@@ -10,6 +11,9 @@ import { ReactComponent as Salami } from '../salami.svg';
*/
function Predictor()
{
+ // component state hooks
+ const shouldSpin = useSelector(state => state.predictions.isPredicting);
+
return(
);
From 89f3f2f880bb8d62b7516cce44de9ca72d7c84ec Mon Sep 17 00:00:00 2001
From: dmrib
Date: Sat, 11 Apr 2020 18:35:50 -0300
Subject: [PATCH 32/40] Implement show hint action
---
src/store/actions/predictions.js | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/src/store/actions/predictions.js b/src/store/actions/predictions.js
index a67acbb..ccb6f21 100644
--- a/src/store/actions/predictions.js
+++ b/src/store/actions/predictions.js
@@ -66,9 +66,28 @@ function waitPrediction(id)
}
+/**
+ * I show a prediction hint.
+ *
+ * @param {string} prediction - prediction text
+ *
+ * @returns {object} - action to be dispatched
+ */
+function showHint(prediction)
+{
+ return {
+ type: 'SHOW_HINT',
+ payload: {
+ prediction
+ }
+ }
+}
+
+
export {
setMaxSize,
setIdleTime,
resetPrediction,
- waitPrediction
+ waitPrediction,
+ showHint
}
From db08e660e1462b9f58c11994b19a6e55b5546cca Mon Sep 17 00:00:00 2001
From: dmrib
Date: Sat, 11 Apr 2020 18:36:14 -0300
Subject: [PATCH 33/40] Implement show hint reducer
---
src/store/reducers/predictions.js | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/store/reducers/predictions.js b/src/store/reducers/predictions.js
index 3c6bd26..ae90736 100644
--- a/src/store/reducers/predictions.js
+++ b/src/store/reducers/predictions.js
@@ -46,6 +46,13 @@ function predictions(state = INITIAL_STATE, action)
isPredicting: true,
expectedId: action.payload.id
}
+ case 'SHOW_HINT':
+ return {
+ ...state,
+ prediction: action.payload.prediction,
+ isPredicting: false,
+ hasPrediction: true
+ }
default:
return state;
}
From 9ecb9690a0744eb1fec457fe86694dd23999e000 Mon Sep 17 00:00:00 2001
From: dmrib
Date: Sat, 11 Apr 2020 18:42:08 -0300
Subject: [PATCH 34/40] Handle incoming predictions on socket connection
---
src/App.js | 6 -----
src/components/Content/index.js | 39 ++++++++++++++++++++++++++++++++-
2 files changed, 38 insertions(+), 7 deletions(-)
diff --git a/src/App.js b/src/App.js
index b4e74e5..9851966 100644
--- a/src/App.js
+++ b/src/App.js
@@ -54,12 +54,6 @@ function App()
setSocketState(socket.current.readyState);
}
- // on websocket message received event callback
- socket.current.onmessage = (event) =>
- {
- console.log(`Received: "${event.data}"`);
- };
-
// cleanup on lifecycle end
return () => socket.current.close();
diff --git a/src/components/Content/index.js b/src/components/Content/index.js
index 3b4e409..b3acf05 100644
--- a/src/components/Content/index.js
+++ b/src/components/Content/index.js
@@ -1,7 +1,7 @@
import React from 'react';
import { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
-import { resetPrediction } from '../../store/actions/predictions';
+import { resetPrediction, showHint } from '../../store/actions/predictions';
import { waitPrediction } from '../../store/actions/predictions';
import { sanitize } from 'dompurify';
import { v4 as uuidv4 } from 'uuid';
@@ -33,6 +33,43 @@ function Content({socket})
}, [text]);
+ /**
+ * I set the callback for on message events on my socket.
+ */
+ useEffect(() =>
+ {
+ // socket connection is established: set on message event callback
+ if (socket !== null)
+ {
+ socket.onmessage = (event) =>
+ {
+ // parse message data into object
+ const prediction = JSON.parse(event.data);
+
+ // handle received prediction
+ handlePrediction(prediction);
+ }
+ }
+ });
+
+
+ /**
+ * I handle an incoming prediction from backstage.
+ *
+ * @param {object} prediction - received prediction
+ *
+ * @returns {undefined} - nothing
+ */
+ function handlePrediction(prediction)
+ {
+ // prediction is expected: show it as hint
+ if (prediction.id === predictor.expectedId)
+ {
+ dispatch(showHint(prediction.data));
+ }
+ }
+
+
/**
* I ask a prediction from the backstage.
*
From e3af40c0c12d943adec576675be97460d700d85d Mon Sep 17 00:00:00 2001
From: dmrib
Date: Sat, 11 Apr 2020 18:46:43 -0300
Subject: [PATCH 35/40] Parse text before sending for backstage predictions
---
src/components/Content/index.js | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/src/components/Content/index.js b/src/components/Content/index.js
index b3acf05..a536c53 100644
--- a/src/components/Content/index.js
+++ b/src/components/Content/index.js
@@ -77,6 +77,15 @@ function Content({socket})
*/
function askForPrediction()
{
+ // build prediction prefix
+ const prefix = text.slice(-300);
+
+ // no input string: abort
+ if (prefix === '')
+ {
+ return;
+ }
+
// generate prediction request id
const id = uuidv4();
@@ -88,7 +97,7 @@ function Content({socket})
id,
resource: '/predict',
data: {
- text,
+ text: prefix,
length: predictor.maxSize
}
});
From 07717a935743e0e13b0f6cb2c768a25f5dee989b Mon Sep 17 00:00:00 2001
From: dmrib
Date: Sat, 11 Apr 2020 18:48:20 -0300
Subject: [PATCH 36/40] Make Salami reactive to incoming predictions
---
src/components/Header/Predictor/index.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/components/Header/Predictor/index.js b/src/components/Header/Predictor/index.js
index b3c6810..9221389 100644
--- a/src/components/Header/Predictor/index.js
+++ b/src/components/Header/Predictor/index.js
@@ -12,7 +12,7 @@ import { ReactComponent as Salami } from '../salami.svg';
function Predictor()
{
// component state hooks
- const shouldSpin = useSelector(state => state.predictions.isPredicting);
+ const predictor = useSelector(state => state.predictions);
return(
- {'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'}
+ {predictor.prediction}
}
+ visible = {predictor.hasPrediction}
placement="bottomRight"
style={{
color: '#a7425c'
}}
- align={{offset: [0, -5]}}
>
);
From c8968710d48b6d0a464a36b5a20fa9699be81721 Mon Sep 17 00:00:00 2001
From: dmrib
Date: Sat, 11 Apr 2020 18:39:01 -0300
Subject: [PATCH 37/40] Override antd styling for popvers
---
src/components/Header/Header.css | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/components/Header/Header.css b/src/components/Header/Header.css
index 9ab820e..e424e45 100644
--- a/src/components/Header/Header.css
+++ b/src/components/Header/Header.css
@@ -134,3 +134,11 @@ html {
border: solid 2px #a7425c;
color: #a7425c;
}
+
+.ant-popover {
+ max-width: 200px;
+}
+
+.ant-popover p {
+ margin-bottom: 5px;
+}
From d033f15c8e85766d76d09135da25b5d38ad53797 Mon Sep 17 00:00:00 2001
From: dmrib
Date: Sat, 11 Apr 2020 18:48:54 -0300
Subject: [PATCH 38/40] Implement predictions appending to text body
---
src/components/Content/index.js | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/src/components/Content/index.js b/src/components/Content/index.js
index a536c53..bf57abf 100644
--- a/src/components/Content/index.js
+++ b/src/components/Content/index.js
@@ -143,6 +143,17 @@ function Content({socket})
updateSchedule();
}
+ function onKeyDown(event)
+ {
+ if(event.keyCode === 9)
+ {
+ event.preventDefault();
+ setText(text + predictor.prediction);
+ dispatch(resetPrediction());
+ }
+
+ }
+
return (
@@ -151,6 +162,7 @@ function Content({socket})
className="content-editor"
value={text}
onChange={onTextChange}
+ onKeyDown={onKeyDown}
>
Date: Sat, 11 Apr 2020 19:02:26 -0300
Subject: [PATCH 39/40] Update project documentation
---
docs/App.html | 6 +-
docs/App.js.html | 63 +-
docs/Content.html | 442 ++-
docs/Footer.html | 4 +-
docs/Header.html | 40 +-
docs/Identity.html | 274 ++
docs/Predictor.html | 233 ++
docs/Settings.html | 596 +++
docs/StatusIndicator.html | 274 ++
docs/build/entry.css | 4 +-
docs/build/entry.css.map | 2 +-
docs/build/entry.js | 3355 ++++++++++++++++-
docs/build/entry.js.map | 2 +-
docs/build/salami.bcf222bb.svg | 1 +
docs/components_Content_index.js.html | 122 +-
docs/components_Footer_index.js.html | 4 +-
docs/components_Header_Identity_index.js.html | 131 +
.../components_Header_Predictor_index.js.html | 140 +
docs/components_Header_Settings_index.js.html | 200 +
...nents_Header_StatusIndicator_index.js.html | 146 +
docs/components_Header_index.js.html | 84 +-
docs/entry.js | 14 +-
docs/global.html | 1344 +++++++
docs/index.html | 4 +-
docs/store_actions_predictions.js.html | 187 +
docs/store_index.js.html | 106 +
docs/store_reducers_predictions.js.html | 156 +
27 files changed, 7837 insertions(+), 97 deletions(-)
create mode 100644 docs/Identity.html
create mode 100644 docs/Predictor.html
create mode 100644 docs/Settings.html
create mode 100644 docs/StatusIndicator.html
create mode 100644 docs/build/salami.bcf222bb.svg
create mode 100644 docs/components_Header_Identity_index.js.html
create mode 100644 docs/components_Header_Predictor_index.js.html
create mode 100644 docs/components_Header_Settings_index.js.html
create mode 100644 docs/components_Header_StatusIndicator_index.js.html
create mode 100644 docs/global.html
create mode 100644 docs/store_actions_predictions.js.html
create mode 100644 docs/store_index.js.html
create mode 100644 docs/store_reducers_predictions.js.html
diff --git a/docs/App.html b/docs/App.html
index 8508bf5..de21330 100644
--- a/docs/App.html
+++ b/docs/App.html
@@ -44,7 +44,7 @@
linguiçator-editor
@@ -149,7 +149,7 @@
View Source
- App.js, line 14
+ App.js, line 21
@@ -218,7 +218,7 @@