Currently, the IoT Hub Developer UI consists of two parts: The React.js Frontend and the Java Spring/Vert.X Backend. In a future release we plan to abandon the Java backend and migrate to a Node.js based version. This will enable our migration to the Electron Framework
The purpose of the server based part of the application is to serve the web frontend and to provide a connection to the IoT Hub APIs and a real time connection to the Messaging Network (AMQP 1.0). By default, it is run locally under port 8080.
First and foremost, the server is providing a static endpoint under /hubdev/ui
from which the bundled React.js frontend is served.
The connection to the IoT Hub messaging network is implemented using the Official client from Eclipse Hono Project:
This client creates both a telemetry and an event consumer and forwards all received messages using a Vert.X/ Sock.js Websocket Connection on /eventbus
.
The provided channels are device
(e.g. device.exampleDevice
) for telemetry/ event messages and status
(e.g. status.hubConnection
) for status information.
To follow Same-origin policy, all HTTP requests to the IoT Hub Device Registry are proxied by the backend, under /hubdev/api
(e.g. /hubdev/api/credentials/myTenantId?device-id=pi0
). This is also necessary because the API credentials to authorize as IoT Hub user are currently only available via application properties in the backend.
This HTTP endpoint is also used to provide the tenant-id to the frontend on /hubdev/api/tenant
.
The UI is written in React.js with a Redux State Container that uses Immutable.js.
We distinguish between three types of state: UI State, Application State and Form State.
- UI State is everything that affects just the View Layer e.g. animation state, display state of things like dropdown menus etc. This does not include display state of forms (like touched, focus etc.). UI State is either stored as component state directly inside the React component or using the React Context API.
- Application State is state that is relevant to the whole application e.g. device state or messages. This type of state is completely stored in Redux. This state is also partially cached in the localStorage of the browser.
- Form State is the state of the <form>s in the application and managed through Redux Form
As mentioned above, Redux is used as the main state container/ state management.
- Side Effects are handled using redux-thunk and axios.
- The state shape is normalized to simplify the reducer logic, as described in the official recipe for state normalization.
- The mapping between the nested API format of the IoT Hub APIs and the normalized Redux state is done using Normalizr which introduces normalize/denormalize functions that are based on schema definitions.
- The state itself is one big Immutable.js Map data structure. These data structures guarantee that state is never mutated (which is an anti pattern in Redux) but also increase performance.
The styleguide can be classified as mixture between the Bosch Styleguide and Google's Material Design.
- Styles are written in Sass for components that are not frequently reused (like actual menus) and with styled-compnents for common/ reused components.
- All layouts are based on Flexbox and sizing is done using rems (The 62.5% Trick) to guarantee responsiveness.
- Animations and transitions are mostly implemented using plain CSS transitions/animations except for places where unmounting transitions or Spring based animations are required. In these cases React Motion is used.
- Styles should be written in
.scss
and without vendor prefixes as webpack adds all vendor prefixes at compile time using autoprefixer
The frontend is tested with the Jest Testing Framework, which provides a test runner, assertions, mocks, snapshot testing and much more. Enzyme is used for component testing.
The IoT Hub Developer UI is optimized and bundled using Webpack and transpiled to ES5 using Babel.
Peculiarities of the bundler configuration imply the following:
-
SVGs can be imported just like regular JS-Components (react-svg-loader is used for inline-svg Components)
import Foo from "images/foo.svg"; // Inline svg import export default () => <Foo />;
-
absolute paths with
src
as implicit root should be used (see above) -
The linting rules (
.eslint
) on level "error" have to be followed or the compilation will fail. -
Styles should be written in
.scss
and without vendor prefixes as webpack adds all vendor prefixes at compile time using autoprefixer (see above)
In order to run the Java backend as well as building the frontend, you will need the following software installed on your local machine:
- Node.js (>=v.8.9.4)
- Google Chrome
- Java (>=v8)
- A text editor/ IDE
For UI development it is strongly recommended to also install the React DevTools and the Redux DevTools for Chrome.
Since the app will be migrated to Electron (which runs on v8), other browsers are no longer actively maintained.
yarn dev
Starts the Webpack Dev Server on port 9000 with hot reloading functionalities.
yarn test
Check if all Unit Tests pass - Uses Jest
yarn watch
Runs the tests in watch-mode
yarn storybook
starts an interactive component documentation server on port 9001
yarn prod
builds the frontend and saves it under
target/classes/public
React Storybook is used as interactive component documentation. It can also be used to develop a new component in isolation. Components that are reusable (located under src/components/common
) should always be documented here.