summary refs log tree commit diff
diff options
context:
space:
mode:
authorJorik Schellekens <joriks@matrix.org>2019-07-31 17:54:07 +0100
committerJorik Schellekens <joriks@matrix.org>2019-08-28 15:59:53 +0100
commit2a34815d485b6b8a10f45143e3277fd417e4f77d (patch)
tree11aa909c295b1a49d01a904cad8aac6e4405e56c
parentAdd endpoint to check if server has been setup. (diff)
downloadsynapse-2a34815d485b6b8a10f45143e3277fd417e4f77d.tar.xz
Add basic flow control
-rw-r--r--synapse_topology/view/webui/.babelrc13
-rw-r--r--synapse_topology/view/webui/index.html8
-rw-r--r--synapse_topology/view/webui/js/Action.jsx6
-rw-r--r--synapse_topology/view/webui/js/ActionButton.jsx5
-rw-r--r--synapse_topology/view/webui/js/App.jsx18
-rw-r--r--synapse_topology/view/webui/js/actions/index.js16
-rw-r--r--synapse_topology/view/webui/js/actions/types.js5
-rw-r--r--synapse_topology/view/webui/js/api/api.js41
-rw-r--r--synapse_topology/view/webui/js/api/constants.js14
-rw-r--r--synapse_topology/view/webui/js/components/BaseIntro.jsx10
-rw-r--r--synapse_topology/view/webui/js/components/ButtonDisplay.jsx5
-rw-r--r--synapse_topology/view/webui/js/components/ConfigSelector.jsx14
-rw-r--r--synapse_topology/view/webui/js/components/Loading.jsx5
-rw-r--r--synapse_topology/view/webui/js/components/ServerName.jsx20
-rw-r--r--synapse_topology/view/webui/js/components/StatsReporter.jsx16
-rw-r--r--synapse_topology/view/webui/js/components/UI.jsx44
-rw-r--r--synapse_topology/view/webui/js/containers/BaseIntro.js18
-rw-r--r--synapse_topology/view/webui/js/containers/ServerName.js21
-rw-r--r--synapse_topology/view/webui/js/containers/StatsReporter.js21
-rw-r--r--synapse_topology/view/webui/js/containers/UI.js16
-rw-r--r--synapse_topology/view/webui/js/index.jsx19
-rw-r--r--synapse_topology/view/webui/js/reducers/index.js13
-rw-r--r--synapse_topology/view/webui/js/reducers/reducer-advanced-config-ui.js7
-rw-r--r--synapse_topology/view/webui/js/reducers/reducer-base-config-ui.js73
-rw-r--r--synapse_topology/view/webui/js/reducers/reducer-base-config.js18
-rw-r--r--synapse_topology/view/webui/js/reducers/reducer-ui.js24
-rw-r--r--synapse_topology/view/webui/less/main.less29
-rw-r--r--synapse_topology/view/webui/less/themes.less10
-rw-r--r--synapse_topology/view/webui/package.json7
-rw-r--r--synapse_topology/view/webui/webpack.config.babel.js26
30 files changed, 455 insertions, 87 deletions
diff --git a/synapse_topology/view/webui/.babelrc b/synapse_topology/view/webui/.babelrc
index 66134c259a..d0d606027d 100644
--- a/synapse_topology/view/webui/.babelrc
+++ b/synapse_topology/view/webui/.babelrc
@@ -1,6 +1,9 @@
 {
-    "presets": [
-        "@babel/preset-env",
-	"@babel/preset-react",
-    ]
-}
+  "presets": [
+    "@babel/preset-env",
+    "@babel/preset-react",
+  ],
+  "plugins": [
+    "@babel/plugin-proposal-object-rest-spread"
+  ],
+}
\ No newline at end of file
diff --git a/synapse_topology/view/webui/index.html b/synapse_topology/view/webui/index.html
index 0d206e0bfb..cbd1fa003d 100644
--- a/synapse_topology/view/webui/index.html
+++ b/synapse_topology/view/webui/index.html
@@ -1,13 +1,13 @@
 <html>
 
 <head>
-    <meta charset="utf-8">
-    <title>Topology - The synapse configuration tool</title>
+  <meta charset="utf-8">
+  <title>Topology - The synapse configuration tool</title>
 </head>
 
 <body>
-    <div id="content" />
-    <script src="dist/bundle.js" type="text/javascript"></script>
+  <div id="content" />
+  <script src="dist/bundle.js" type="text/javascript"></script>
 </body>
 
 </html>
\ No newline at end of file
diff --git a/synapse_topology/view/webui/js/Action.jsx b/synapse_topology/view/webui/js/Action.jsx
deleted file mode 100644
index bdfc99778f..0000000000
--- a/synapse_topology/view/webui/js/Action.jsx
+++ /dev/null
@@ -1,6 +0,0 @@
-import React from 'react';
-
-import style from '../less/main.less';
-
-export default (props) =>
-    <div className={style.action}>{props.children}</div>
\ No newline at end of file
diff --git a/synapse_topology/view/webui/js/ActionButton.jsx b/synapse_topology/view/webui/js/ActionButton.jsx
deleted file mode 100644
index d43c12b93e..0000000000
--- a/synapse_topology/view/webui/js/ActionButton.jsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import React from 'react';
-
-export default (props) => (
-    <button>{props.text.toUpperCase()}</button>
-)
\ No newline at end of file
diff --git a/synapse_topology/view/webui/js/App.jsx b/synapse_topology/view/webui/js/App.jsx
deleted file mode 100644
index e8432fb841..0000000000
--- a/synapse_topology/view/webui/js/App.jsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import React, { Component } from 'react';
-
-import style from '../less/main.less';
-import ActionButton from './ActionButton.jsx';
-import Action from './Action.jsx';
-
-export default class App extends Component {
-    componentDidMount() {
-    }
-
-    render() {
-        return <Action>
-            <h1>Synapse Topology</h1>
-            <p>Let's get started.</p>
-            <div><ActionButton text="SETUP"></ActionButton></div>
-        </Action>
-    }
-}
\ No newline at end of file
diff --git a/synapse_topology/view/webui/js/actions/index.js b/synapse_topology/view/webui/js/actions/index.js
new file mode 100644
index 0000000000..67db477e57
--- /dev/null
+++ b/synapse_topology/view/webui/js/actions/index.js
@@ -0,0 +1,16 @@
+import { ADVANCE_UI, BACK_UI, SET_SERVERNAME } from './types';
+
+export const advance_ui = option => ({
+  type: ADVANCE_UI,
+  option
+});
+
+export const set_servername = servername => ({
+  type: SET_SERVERNAME,
+  servername
+});
+
+export const set_stats = conset => ({
+  type: SET_STATS,
+  consent
+});
\ No newline at end of file
diff --git a/synapse_topology/view/webui/js/actions/types.js b/synapse_topology/view/webui/js/actions/types.js
new file mode 100644
index 0000000000..71923b5414
--- /dev/null
+++ b/synapse_topology/view/webui/js/actions/types.js
@@ -0,0 +1,5 @@
+export const ADVANCE_UI = 'ADVANCE_UI';
+export const BACK_UI = 'BACK_UI';
+export const SET_SERVERNAME = 'SET_SERVERNAME';
+export const SET_STATS = 'SET_STATS';
+export const BASE_CONFIG_CHECKED = 'BASE_CONFIG_CHECKED';
\ No newline at end of file
diff --git a/synapse_topology/view/webui/js/api/api.js b/synapse_topology/view/webui/js/api/api.js
index 1454c6e844..7659ac95ac 100644
--- a/synapse_topology/view/webui/js/api/api.js
+++ b/synapse_topology/view/webui/js/api/api.js
@@ -1,41 +1,40 @@
 import fetchAbsolute from 'fetch-absolute';
 import {
-    API_URL,
-    SERVER_NAME,
-    SECRET_KEY,
-    CONFIG,
-    CONFIG_SOMETHING,
+  API_URL,
+  CONFIG,
+  CONFIG_LOCK,
+  CONFIG_SOMETHING,
+  SECRET_KEY,
+  SERVER_NAME,
+  SETUP_CHECK,
 } from './constants';
 
 const fetchAbs = fetchAbsolute(fetch)(API_URL)
 
-const get_server_name = () => {
-    fetchAbs(SERVER_NAME)
-        .then(res => res.json())
+export const get_server_name = () => {
+  fetchAbs(SERVER_NAME)
+    .then(res => res.json())
 };
 
-const post_server_name = () => {
+export const post_server_name = () => {
 
 };
 
-const get_secret_key = () => {
-    fetchAbs(SECRET_KEY)
-        .then(res => res.json())
+export const get_secret_key = () => {
+  fetchAbs(SECRET_KEY)
+    .then(res => res.json())
 
 };
 
-const get_config = () => {
+export const get_config = () => {
 
 };
 
-const post_config = () => {
+export const post_config = () => {
 
 };
 
-export {
-    get_server_name,
-    post_server_name,
-    get_secret_key,
-    get_config,
-    post_config,
-}
\ No newline at end of file
+// Checks if the server's base config has been setup.
+export const get_server_setup = () => fetchAbs(SETUP_CHECK)
+  .then(res => res.json()[CONFIG_LOCK])
+
diff --git a/synapse_topology/view/webui/js/api/constants.js b/synapse_topology/view/webui/js/api/constants.js
index dce1eb3227..11a5841999 100644
--- a/synapse_topology/view/webui/js/api/constants.js
+++ b/synapse_topology/view/webui/js/api/constants.js
@@ -3,11 +3,15 @@ const SERVER_NAME = "/servername";
 const SECRET_KEY = "/secretkey";
 const CONFIG = "/config";
 const CONFIG_SOMETHING = "/config_something";
+const SETUP_CHECK = "/setup";
+const CONFIG_LOCK = "server_config_in_use";
 
 export {
-    API_URL,
-    SERVER_NAME,
-    SECRET_KEY,
-    CONFIG,
-    CONFIG_SOMETHING,
+  API_URL,
+  CONFIG,
+  CONFIG_LOCK,
+  CONFIG_SOMETHING,
+  SECRET_KEY,
+  SERVER_NAME,
+  SETUP_CHECK
 }
\ No newline at end of file
diff --git a/synapse_topology/view/webui/js/components/BaseIntro.jsx b/synapse_topology/view/webui/js/components/BaseIntro.jsx
new file mode 100644
index 0000000000..b7d9398163
--- /dev/null
+++ b/synapse_topology/view/webui/js/components/BaseIntro.jsx
@@ -0,0 +1,10 @@
+import React from 'react';
+
+import style from '../../less/main.less';
+
+export default ({ onClick }) =>
+  <div className={style.contentWrapper}>
+    <h1>Synapse Topology</h1>
+    <p>Let's get started.</p>
+    <div><button onClick={onClick}>SETUP</button></div>
+  </div>
\ No newline at end of file
diff --git a/synapse_topology/view/webui/js/components/ButtonDisplay.jsx b/synapse_topology/view/webui/js/components/ButtonDisplay.jsx
new file mode 100644
index 0000000000..35495dccdf
--- /dev/null
+++ b/synapse_topology/view/webui/js/components/ButtonDisplay.jsx
@@ -0,0 +1,5 @@
+import React from 'react';
+
+import style from '../../less/main.less';
+
+export default ({ children }) => <div className={style.buttonDisplay}>{children}</div>
\ No newline at end of file
diff --git a/synapse_topology/view/webui/js/components/ConfigSelector.jsx b/synapse_topology/view/webui/js/components/ConfigSelector.jsx
new file mode 100644
index 0000000000..aab7e32dcd
--- /dev/null
+++ b/synapse_topology/view/webui/js/components/ConfigSelector.jsx
@@ -0,0 +1,14 @@
+import React, { useState } from 'react';
+
+import style from '../../less/main.less';
+
+export default () => {
+  return <div className={style.contentWrapper}>
+    <h1>Config selection</h1>
+    <p>The base config has already been setup. Please select a config to edit:</p>
+    <p>TODO: .. well .. this.</p>
+    <div>
+      <button />
+    </div>
+  </div >;
+}
\ No newline at end of file
diff --git a/synapse_topology/view/webui/js/components/Loading.jsx b/synapse_topology/view/webui/js/components/Loading.jsx
new file mode 100644
index 0000000000..1df72d3ebb
--- /dev/null
+++ b/synapse_topology/view/webui/js/components/Loading.jsx
@@ -0,0 +1,5 @@
+import React from 'react';
+
+import style from '../../less/main.less';
+
+export default () => <div className={style.contentWrapper}><h1>Synapse</h1></div>
\ No newline at end of file
diff --git a/synapse_topology/view/webui/js/components/ServerName.jsx b/synapse_topology/view/webui/js/components/ServerName.jsx
new file mode 100644
index 0000000000..3d49a8912f
--- /dev/null
+++ b/synapse_topology/view/webui/js/components/ServerName.jsx
@@ -0,0 +1,20 @@
+import React, { useState } from 'react';
+
+import style from '../../less/main.less';
+
+export default ({ onClick }) => {
+  const [servername, setServerName] = useState("");
+
+  const onChange = event => {
+    setServerName(event.target.value);
+  }
+
+  return <div className={style.contentWrapper}>
+    <h1>Select a server name</h1>
+    <p>This is very important. More information here.</p>
+    <input type="text" onChange={onChange} autoFocus placeholder="synapse.dev"></input>
+    <div>
+      <button disabled={servername ? undefined : true} onClick={() => onClick()}>I like it</button>
+    </div>
+  </div >;
+}
\ No newline at end of file
diff --git a/synapse_topology/view/webui/js/components/StatsReporter.jsx b/synapse_topology/view/webui/js/components/StatsReporter.jsx
new file mode 100644
index 0000000000..58ce01cacd
--- /dev/null
+++ b/synapse_topology/view/webui/js/components/StatsReporter.jsx
@@ -0,0 +1,16 @@
+import React from 'react';
+
+import style from '../../less/main.less';
+
+import ButtonDisplay from './ButtonDisplay';
+
+
+export default ({ onClick }) =>
+  <div className={style.contentWrapper}>
+    <h1>Anonymous Statistics</h1>
+    <p>Would you like to report anonymouse statistics to matrix.org?</p>
+    <ButtonDisplay>
+      <button onClick={() => onClick(true)}>YES</button>
+      <button onClick={() => onClick(false)} className={style.redButton}>NO</button>
+    </ButtonDisplay>
+  </div >
\ No newline at end of file
diff --git a/synapse_topology/view/webui/js/components/UI.jsx b/synapse_topology/view/webui/js/components/UI.jsx
new file mode 100644
index 0000000000..837836ac5a
--- /dev/null
+++ b/synapse_topology/view/webui/js/components/UI.jsx
@@ -0,0 +1,44 @@
+import React from 'react';
+
+import style from '../../less/main.less';
+
+import IntroUi from '../containers/BaseIntro';
+import ServerName from '../containers/ServerName';
+
+import {
+  BASE_INTRO_UI,
+  SERVER_NAME_UI,
+  STATS_REPORT_UI,
+  KEY_EXPORT_UI,
+  DELEGATION_OPTIONS_UI,
+  WELL_KNOWN_UI,
+  DNS_UI,
+  WORKER_UI,
+  ACME_UI,
+  REVERSE_PROXY_UI,
+  PORT_SELECTION_UI,
+  REVERSE_PROXY_TEMPLATE_UI
+} from '../reducers/reducer-base-config-ui';
+import StatsReporter from '../containers/StatsReporter';
+
+export default ({ active_ui, dispatch }) => {
+  switch (active_ui) {
+    case BASE_INTRO_UI:
+      return < IntroUi />
+    case SERVER_NAME_UI:
+      return <ServerName />
+    case STATS_REPORT_UI:
+      return <StatsReporter />
+    case KEY_EXPORT_UI:
+    case DELEGATION_OPTIONS_UI:
+    case WELL_KNOWN_UI:
+    case DNS_UI:
+    case WORKER_UI:
+    case ACME_UI:
+    case REVERSE_PROXY_UI:
+    case PORT_SELECTION_UI:
+    case REVERSE_PROXY_TEMPLATE_UI:
+    default:
+      return <h1>how did i get here?</h1>
+  }
+}
\ No newline at end of file
diff --git a/synapse_topology/view/webui/js/containers/BaseIntro.js b/synapse_topology/view/webui/js/containers/BaseIntro.js
new file mode 100644
index 0000000000..3095fec0a2
--- /dev/null
+++ b/synapse_topology/view/webui/js/containers/BaseIntro.js
@@ -0,0 +1,18 @@
+import { connect } from 'react-redux';
+
+import BaseIntro from '../components/BaseIntro';
+
+import { advance_ui } from '../actions';
+
+const mapStateToProps = (state, ownProps) => ({
+
+});
+
+const mapDispathToProps = (dispatch) => ({
+  onClick: () => dispatch(advance_ui())
+});
+
+export default connect(
+  null,
+  mapDispathToProps
+)(BaseIntro);
\ No newline at end of file
diff --git a/synapse_topology/view/webui/js/containers/ServerName.js b/synapse_topology/view/webui/js/containers/ServerName.js
new file mode 100644
index 0000000000..b7fa07982b
--- /dev/null
+++ b/synapse_topology/view/webui/js/containers/ServerName.js
@@ -0,0 +1,21 @@
+import { connect } from 'react-redux';
+
+import ServerName from '../components/ServerName';
+
+import { advance_ui, set_servername } from '../actions';
+
+const mapStateToProps = (state, ownProps) => ({
+
+});
+
+const mapDispathToProps = (dispatch) => ({
+  onClick: servername => {
+    dispatch(advance_ui());
+    dispatch(set_servername(servername));
+  }
+});
+
+export default connect(
+  null,
+  mapDispathToProps
+)(ServerName);
\ No newline at end of file
diff --git a/synapse_topology/view/webui/js/containers/StatsReporter.js b/synapse_topology/view/webui/js/containers/StatsReporter.js
new file mode 100644
index 0000000000..2aa1f717f7
--- /dev/null
+++ b/synapse_topology/view/webui/js/containers/StatsReporter.js
@@ -0,0 +1,21 @@
+import { connect } from 'react-redux';
+
+import StatsReporter from '../components/StatsReporter';
+
+import { advance_ui, set_stats } from '../actions';
+
+const mapStateToProps = (state, ownProps) => ({
+
+});
+
+const mapDispathToProps = (dispatch) => ({
+  onClick: consent => {
+    dispatch(advance_ui());
+    dispatch(set_stats(consent));
+  }
+});
+
+export default connect(
+  null,
+  mapDispathToProps
+)(StatsReporter);
\ No newline at end of file
diff --git a/synapse_topology/view/webui/js/containers/UI.js b/synapse_topology/view/webui/js/containers/UI.js
new file mode 100644
index 0000000000..08ebf296f2
--- /dev/null
+++ b/synapse_topology/view/webui/js/containers/UI.js
@@ -0,0 +1,16 @@
+import { connect } from 'react-redux';
+import UI from '../components/UI';
+
+const mapStateToProps = ({ ui }, ownProps) => ({
+  active_ui: ui.active_ui,
+  ...ownProps,
+})
+
+
+const mapDispathToProps = (dispatch, ownProps) => ({
+
+})
+
+export default connect(
+  mapStateToProps,
+)(UI)
\ No newline at end of file
diff --git a/synapse_topology/view/webui/js/index.jsx b/synapse_topology/view/webui/js/index.jsx
index 0f4f65dab8..2372becae2 100644
--- a/synapse_topology/view/webui/js/index.jsx
+++ b/synapse_topology/view/webui/js/index.jsx
@@ -1,5 +1,18 @@
 import React from 'react';
-import ReactDom from 'react-dom';
-import App from './App';
+import { render } from 'react-dom';
+import { Provider } from 'react-redux';
+import { createStore } from 'redux'
+import rootReducer from './reducers';
+import UI from './containers/UI';
 
-ReactDom.render(<App />, document.getElementById("content"));
\ No newline at end of file
+const store = createStore(
+  rootReducer,/* preloadedState, */
+  +  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
+);
+
+render(
+  <Provider store={store}>
+    <UI />
+  </Provider>,
+  document.getElementById("content")
+);
\ No newline at end of file
diff --git a/synapse_topology/view/webui/js/reducers/index.js b/synapse_topology/view/webui/js/reducers/index.js
new file mode 100644
index 0000000000..909393fe2d
--- /dev/null
+++ b/synapse_topology/view/webui/js/reducers/index.js
@@ -0,0 +1,13 @@
+import { combineReducers } from 'redux';
+import ui from './reducer-ui';
+import base_config from './reducer-base-config';
+import { get_server_setup } from '../api/api';
+
+export default combineReducers({
+  ui,
+  base_config
+});
+
+export const initial_state = () => ({
+  ui: { base_config_done: await get_server_setup() }
+})
\ No newline at end of file
diff --git a/synapse_topology/view/webui/js/reducers/reducer-advanced-config-ui.js b/synapse_topology/view/webui/js/reducers/reducer-advanced-config-ui.js
new file mode 100644
index 0000000000..72d24cf315
--- /dev/null
+++ b/synapse_topology/view/webui/js/reducers/reducer-advanced-config-ui.js
@@ -0,0 +1,7 @@
+const ADVANCED_CONFIG_UI_COMPONENTS = {
+  CONFIG_SELECTION_UI: "config_selection_ui"
+}
+
+export default (state, action) => {
+
+}
\ No newline at end of file
diff --git a/synapse_topology/view/webui/js/reducers/reducer-base-config-ui.js b/synapse_topology/view/webui/js/reducers/reducer-base-config-ui.js
new file mode 100644
index 0000000000..e40134b546
--- /dev/null
+++ b/synapse_topology/view/webui/js/reducers/reducer-base-config-ui.js
@@ -0,0 +1,73 @@
+import { ADVANCE_UI, BACK_UI } from '../actions/types';
+
+export const BASE_INTRO_UI = "INTRO_UI";
+export const SERVER_NAME_UI = "server_name_ui";
+export const STATS_REPORT_UI = "stats_report_ui";
+export const KEY_EXPORT_UI = "key_export_ui";
+export const DELEGATION_OPTIONS_UI = "delegation_options_ui";
+export const WELL_KNOWN_UI = "well_known_ui";
+export const DNS_UI = "dns_ui";
+export const WORKER_UI = "worker_ui";
+export const ACME_UI = "acme_ui";
+export const REVERSE_PROXY_UI = "reverse_proxy_ui";
+export const PORT_SELECTION_UI = "port_selection_ui";
+export const REVERSE_PROXY_TEMPLATE_UI = "reverse_proxy_tamplate_ui";
+
+export default (state, action) => {
+  switch (action.type) {
+    case ADVANCE_UI:
+      switch (state) {
+        case BASE_INTRO_UI:
+          return SERVER_NAME_UI;
+        case SERVER_NAME_UI:
+          return STATS_REPORT_UI;
+        case STATS_REPORT_UI:
+          return KEY_EXPORT_UI;
+        case DELEGATION_OPTIONS_UI:
+          switch (action.option) {
+            // TODO: figure these out
+            case "DNS":
+              return DNS_UI;
+            case "WELL_KNOWN":
+              return WELL_KNOWN_UI;
+            case "NO_DELEGATION":
+              return ACME_UI;
+            default:
+              return DELEGATION_OPTIONS_UI;
+          }
+        case WELL_KNOWN_UI:
+          return ACME_UI;
+        case DNS_UI:
+          return ACME_UI;
+        case ACME_UI:
+          return REVERSE_PROXY_UI;
+        case REVERSE_PROXY_UI:
+          return PORT_SELECTION_UI;
+        case PORT_SELECTION_UI:
+          return WORKER_UI;
+        case WORKER_UI:
+          return REVERSE_PROXY_TEMPLATE_UI;
+        default:
+          return BASE_INTRO_UI;
+      }
+
+    // TODO: Think about how back should work..
+    case BACK_UI:
+      switch (state) {
+        case STATS_REPORT_UI:
+          return SERVER_NAME_UI;
+        case KEY_EXPORT_UI:
+          return STATS_REPORT_UI;
+        case DELEGATION_OPTIONS_UI:
+          return KEY_EXPORT_UI;
+        case WELL_KNOWN_UI:
+          return DELEGATION_OPTIONS_UI;
+        case DNS_UI:
+          return WELL_KNOWN_UI;
+        default:
+          BASE_INTRO_UI;
+      }
+    default:
+      return state;
+  }
+}
diff --git a/synapse_topology/view/webui/js/reducers/reducer-base-config.js b/synapse_topology/view/webui/js/reducers/reducer-base-config.js
new file mode 100644
index 0000000000..9b496b5ee5
--- /dev/null
+++ b/synapse_topology/view/webui/js/reducers/reducer-base-config.js
@@ -0,0 +1,18 @@
+import { SET_SERVERNAME, SET_STATS } from "../actions/types";
+
+export default (state = { servername: undefined }, action) => {
+  switch (action.type) {
+    case SET_SERVERNAME:
+      return {
+        ...state,
+        servername: action.servername,
+      }
+    case SET_STATS:
+      return {
+        ...state,
+        report_stats: action.consent,
+      }
+    default:
+      return state;
+  }
+};
\ No newline at end of file
diff --git a/synapse_topology/view/webui/js/reducers/reducer-ui.js b/synapse_topology/view/webui/js/reducers/reducer-ui.js
new file mode 100644
index 0000000000..10aaa909e6
--- /dev/null
+++ b/synapse_topology/view/webui/js/reducers/reducer-ui.js
@@ -0,0 +1,24 @@
+import base_config_ui, { BASE_INTRO_UI } from './reducer-base-config-ui';
+import advanced_config_ui from './reducer-advanced-config-ui';
+import { BASE_CONFIG_CHECKED } from '../actions/types';
+import { advance_ui } from '../actions';
+
+export default (state, action) => {
+  switch (action.type) {
+    default:
+      switch (action.base_config_done) {
+        case true:
+          return advanced_ui(state, action);
+        case false:
+          return base_config_ui(state, action);
+      }
+
+    case BASE_CONFIG_CHECKED:
+      switch (action.base_config_done) {
+        case true:
+          return advanced_ui(state, action);
+        case false:
+          return base_config_ui(state, action);
+      }
+  }
+}
diff --git a/synapse_topology/view/webui/less/main.less b/synapse_topology/view/webui/less/main.less
index c6824971bf..3c61246b6e 100644
--- a/synapse_topology/view/webui/less/main.less
+++ b/synapse_topology/view/webui/less/main.less
@@ -25,7 +25,7 @@ body {
   color: @font;
 }
 
-.action {
+.contentWrapper {
   .theme();
   margin: 0 20% 0 20%;
   display: flex;
@@ -34,6 +34,14 @@ body {
   justify-content: space-evenly;
   height: 100%;
 
+  .buttonDisplay {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-evenly;
+    color: lighten(@font, 20%);
+  }
+
+
   button {
     border-radius: 0.5rem;
     font-size: 1rem;
@@ -44,6 +52,25 @@ body {
     display: inline-block;
     text-transform: capitalize;
     font-style: bold;
+    color: lighten(@font, 20%);
+  }
+
+  button[disabled] {
+    background-color: @tertiary;
+    color: @primary;
+  }
+
+  input {
+    padding: 0.4rem;
+    font-size: 1rem;
+    background-color: @secondary;
+    border-width: 0.1rem;
+    border-color: @primary;
+    border-radius: 0.5rem;
+    color: lighten(@font, 20%);
+  }
+  .redButton {
+    background-color: red;
   }
 }
 
diff --git a/synapse_topology/view/webui/less/themes.less b/synapse_topology/view/webui/less/themes.less
index 040170bf09..6941dc8b09 100644
--- a/synapse_topology/view/webui/less/themes.less
+++ b/synapse_topology/view/webui/less/themes.less
@@ -1,7 +1,7 @@
 .dark {
-    @primary: #0e1111;
-    @secondary: #232b2b;
-    @borders: #3b444b;
-    @font:  #f9f9f9;
-    @highlight: #4AEFF0;
+  @primary: #0e1111;
+  @secondary: #232b2b;
+  @tertiary: #3b444b;
+  @font:  #f9f9f9;
+  @highlight: #4AEFF0;
 }
\ No newline at end of file
diff --git a/synapse_topology/view/webui/package.json b/synapse_topology/view/webui/package.json
index 7122a42ae9..b385558088 100644
--- a/synapse_topology/view/webui/package.json
+++ b/synapse_topology/view/webui/package.json
@@ -10,6 +10,7 @@
     "@babel/cli": "^7.5.5",
     "@babel/core": "^7.5.5",
     "@babel/node": "^7.5.5",
+    "@babel/plugin-proposal-object-rest-spread": "^7.5.5",
     "@babel/preset-env": "^7.5.5",
     "@babel/preset-react": "^7.0.0",
     "@babel/register": "^7.5.5",
@@ -21,6 +22,7 @@
     "less-loader": "^5.0.0",
     "react": "^16.8.6",
     "react-dom": "^16.8.6",
+    "redux-devtools-extension": "^2.13.8",
     "style-loader": "^0.23.1",
     "webpack": "^4.38.0",
     "webpack-cli": "^3.3.6",
@@ -32,6 +34,9 @@
     "watch": "webpack --progress -d --config webpack.config.babel.js --watch"
   },
   "dependencies": {
-    "fetch-absolute": "^1.0.0"
+    "fetch-absolute": "^1.0.0",
+    "react-localize-redux": "^3.5.3",
+    "react-redux": "^7.1.0",
+    "redux": "^4.0.4"
   }
 }
diff --git a/synapse_topology/view/webui/webpack.config.babel.js b/synapse_topology/view/webui/webpack.config.babel.js
index 2d018ac623..d4226bad19 100644
--- a/synapse_topology/view/webui/webpack.config.babel.js
+++ b/synapse_topology/view/webui/webpack.config.babel.js
@@ -2,7 +2,7 @@ import 'webpack';
 import { Path } from 'path';
 
 export default {
-  entry:  __dirname + '/js/index.jsx',
+  entry: __dirname + '/js/index.jsx',
   output: {
     path: __dirname + '/dist',
     filename: 'bundle.js',
@@ -11,7 +11,7 @@ export default {
     extensions: ['.js', '.jsx', '.css']
   },
   module: {
-    rules:[
+    rules: [
       {
         test: /\.jsx$/,
         exclude: /node_modules/,
@@ -20,22 +20,22 @@ export default {
       {
         test: /\.less$/,
         use: [
-	  {
-	    loader: 'style-loader',
-	  },
-	  {
+          {
+            loader: 'style-loader',
+          },
+          {
             loader: 'css-loader',
             options: {
               sourceMap: true,
               modules: {
-		  localIdentName: '[local]___[hash:base64:5]'
-	      }
-	    },
+                localIdentName: '[local]___[hash:base64:5]'
+              }
+            },
+          },
+          {
+            loader: 'less-loader',
           },
-	  {
-	    loader: 'less-loader',
-	  },
-	],
+        ],
       },
       {
         test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,