From a8f65142d698faa83f3e27c657cd75e497671517 Mon Sep 17 00:00:00 2001 From: John Lee Date: Sat, 9 Jun 2018 14:10:22 -0700 Subject: [PATCH] frontend setup complete --- daemon/web/.eslintrc.json | 5 +- daemon/web/actions/_constants.js | 3 ++ daemon/web/actions/dashboard.js | 13 +++++ daemon/web/actions/login.js | 13 +++++ daemon/web/actions/main.js | 13 +++++ daemon/web/{ => common}/client.js | 2 +- .../web/components/{metrics => }/LogView.js | 0 daemon/web/index.js | 8 +-- daemon/web/package-lock.json | 52 +++++++++++++++---- daemon/web/package.json | 5 +- daemon/web/{components => pages/app}/App.js | 18 ++++--- daemon/web/pages/containers/containers.js | 30 +++++++++++ .../dashboard}/Dashboard.js | 24 +++++++-- .../web/{components => pages/login}/Login.js | 47 ++++++++++++----- .../Home.js => pages/main/Main.js} | 52 ++++++++++++++++--- daemon/web/store/dashboard.js | 21 ++++++++ daemon/web/store/index.js | 19 +++++++ daemon/web/store/login.js | 21 ++++++++ daemon/web/store/main.js | 21 ++++++++ daemon/web/styles/colors.sass | 0 daemon/web/{ => styles}/index.sass | 3 ++ daemon/web/styles/typography.sass | 0 22 files changed, 322 insertions(+), 48 deletions(-) create mode 100644 daemon/web/actions/_constants.js create mode 100644 daemon/web/actions/dashboard.js create mode 100644 daemon/web/actions/login.js create mode 100644 daemon/web/actions/main.js rename daemon/web/{ => common}/client.js (98%) rename daemon/web/components/{metrics => }/LogView.js (100%) rename daemon/web/{components => pages/app}/App.js (86%) create mode 100644 daemon/web/pages/containers/containers.js rename daemon/web/{components => pages/dashboard}/Dashboard.js (81%) rename daemon/web/{components => pages/login}/Login.js (63%) rename daemon/web/{components/Home.js => pages/main/Main.js} (80%) create mode 100644 daemon/web/store/dashboard.js create mode 100644 daemon/web/store/index.js create mode 100644 daemon/web/store/login.js create mode 100644 daemon/web/store/main.js create mode 100644 daemon/web/styles/colors.sass rename daemon/web/{ => styles}/index.sass (95%) create mode 100644 daemon/web/styles/typography.sass diff --git a/daemon/web/.eslintrc.json b/daemon/web/.eslintrc.json index 6407d7c4..562714d1 100644 --- a/daemon/web/.eslintrc.json +++ b/daemon/web/.eslintrc.json @@ -5,12 +5,15 @@ }, "extends": "airbnb", "rules": { + "import/prefer-default-export": 0, "prefer-template": 0, "react/jsx-filename-extension": 0, "react/require-default-props": 0, + "react/forbid-prop-types": 0, "react/jsx-closing-bracket-location": 0, "object-curly-newline": 0, - "arrow-body-style": [2, "as-needed"], + "jsx-a11y/anchor-is-valid": 0, + "arrow-body-style": [2, "as-needed", { "requireReturnForObjectLiteral": true }], "comma-dangle": ["error", "always-multiline", { "arrays": "always", "objects": "always", diff --git a/daemon/web/actions/_constants.js b/daemon/web/actions/_constants.js new file mode 100644 index 00000000..5b0da2f4 --- /dev/null +++ b/daemon/web/actions/_constants.js @@ -0,0 +1,3 @@ +export const TEST_DASHBOARD_ACTION = 'TEST_DASHBOARD_ACTION'; +export const TEST_LOGIN_ACTION = 'TEST_LOGIN_ACTION'; +export const TEST_HOME_ACTION = 'TEST_HOME_ACTION'; diff --git a/daemon/web/actions/dashboard.js b/daemon/web/actions/dashboard.js new file mode 100644 index 00000000..bc92a53d --- /dev/null +++ b/daemon/web/actions/dashboard.js @@ -0,0 +1,13 @@ +import { + TEST_DASHBOARD_ACTION, +} from './_constants'; + + +export const testAction = payload => (dispatch) => { + // remove later + console.log('dashboard action fired!'); + dispatch({ + type: TEST_DASHBOARD_ACTION, + payload, + }); +}; diff --git a/daemon/web/actions/login.js b/daemon/web/actions/login.js new file mode 100644 index 00000000..c6fd21f3 --- /dev/null +++ b/daemon/web/actions/login.js @@ -0,0 +1,13 @@ +import { + TEST_LOGIN_ACTION, +} from './_constants'; + + +export const testAction = payload => (dispatch) => { + // remove later + console.log('login action fired!'); + dispatch({ + type: TEST_LOGIN_ACTION, + payload, + }); +}; diff --git a/daemon/web/actions/main.js b/daemon/web/actions/main.js new file mode 100644 index 00000000..370c8f6e --- /dev/null +++ b/daemon/web/actions/main.js @@ -0,0 +1,13 @@ +import { + TEST_MAIN_ACTION, +} from './_constants'; + + +export const testAction = payload => (dispatch) => { + // remove later + console.log('main action fired!'); + dispatch({ + type: TEST_MAIN_ACTION, + payload, + }); +}; diff --git a/daemon/web/client.js b/daemon/web/common/client.js similarity index 98% rename from daemon/web/client.js rename to daemon/web/common/client.js index 7cd995ce..17a215b3 100644 --- a/daemon/web/client.js +++ b/daemon/web/common/client.js @@ -1,4 +1,4 @@ -import encodeURL from './common/encodeURL'; +import encodeURL from './encodeURL'; export default class InertiaClient { constructor(url) { diff --git a/daemon/web/components/metrics/LogView.js b/daemon/web/components/LogView.js similarity index 100% rename from daemon/web/components/metrics/LogView.js rename to daemon/web/components/LogView.js diff --git a/daemon/web/index.js b/daemon/web/index.js index 9fe84e0d..9d8cebb9 100644 --- a/daemon/web/index.js +++ b/daemon/web/index.js @@ -1,7 +1,9 @@ import React from 'react'; import ReactDOM from 'react-dom'; +import { Provider } from 'react-redux'; -import App from './components/App'; -import './index.sass'; +import App from './pages/app/App'; +import store from './store'; +import './styles/index.sass'; -ReactDOM.render(, document.getElementById('app')); +ReactDOM.render(, document.getElementById('app')); diff --git a/daemon/web/package-lock.json b/daemon/web/package-lock.json index 09b11a50..54fcd4b0 100644 --- a/daemon/web/package-lock.json +++ b/daemon/web/package-lock.json @@ -340,7 +340,6 @@ "version": "0.7.1", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-0.7.1.tgz", "integrity": "sha1-Jsu1r/ZBRLCoJb4YRuCxbPoAsR4=", - "dev": true, "requires": { "ast-types-flow": "0.0.7", "commander": "^2.11.0" @@ -454,8 +453,7 @@ "ast-types-flow": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", - "dev": true + "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=" }, "async": { "version": "1.5.2", @@ -509,7 +507,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-0.1.0.tgz", "integrity": "sha1-YvWdvFnJ+SQnWco0mWDnov48NsA=", - "dev": true, "requires": { "ast-types-flow": "0.0.7" } @@ -2648,8 +2645,7 @@ "damerau-levenshtein": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz", - "integrity": "sha1-AxkcQyy27qFou3fzpV/9zLiXhRQ=", - "dev": true + "integrity": "sha1-AxkcQyy27qFou3fzpV/9zLiXhRQ=" }, "dargs": { "version": "5.1.0", @@ -3019,8 +3015,7 @@ "emoji-regex": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.5.1.tgz", - "integrity": "sha512-PAHp6TxrCy7MGMFidro8uikr+zlJJKJ/Q6mm2ExZ7HwkyR9lSVFfE3kt36qcwa24BQL7y0G9axycGjK1A/0uNQ==", - "dev": true + "integrity": "sha512-PAHp6TxrCy7MGMFidro8uikr+zlJJKJ/Q6mm2ExZ7HwkyR9lSVFfE3kt36qcwa24BQL7y0G9axycGjK1A/0uNQ==" }, "emojis-list": { "version": "2.1.0", @@ -3438,7 +3433,6 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.0.3.tgz", "integrity": "sha1-VFg9GuRCSDFi4EDhPMMYZUZRAOU=", - "dev": true, "requires": { "aria-query": "^0.7.0", "array-includes": "^3.0.3", @@ -6113,7 +6107,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz", "integrity": "sha1-6AGxs5mF4g//yHtA43SAgOLcrH8=", - "dev": true, "requires": { "array-includes": "^3.0.3" } @@ -6337,6 +6330,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==" }, + "lodash-es": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.10.tgz", + "integrity": "sha512-iesFYPmxYYGTcmQK0sL8bX3TGHyM6b2qREaB4kamHfQyfPJP0xgoGxp19nsH16nsfquLdiyKyX3mQkfiSGV8Rg==" + }, "lodash.assign": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", @@ -8513,6 +8511,19 @@ "prop-types": "^15.6.0" } }, + "react-redux": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.0.7.tgz", + "integrity": "sha512-5VI8EV5hdgNgyjfmWzBbdrqUkrVRKlyTKk1sGH3jzM2M2Mhj/seQgPXaz6gVAj2lz/nz688AdTqMO18Lr24Zhg==", + "requires": { + "hoist-non-react-statics": "^2.5.0", + "invariant": "^2.0.0", + "lodash": "^4.17.5", + "lodash-es": "^4.17.5", + "loose-envify": "^1.1.0", + "prop-types": "^15.6.0" + } + }, "react-router": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/react-router/-/react-router-4.2.0.tgz", @@ -8675,6 +8686,27 @@ } } }, + "redux": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.0.tgz", + "integrity": "sha512-NnnHF0h0WVE/hXyrB6OlX67LYRuaf/rJcbWvnHHEPCF/Xa/AZpwhs/20WyqzQae5x4SD2F9nPObgBh2rxAgLiA==", + "requires": { + "loose-envify": "^1.1.0", + "symbol-observable": "^1.2.0" + }, + "dependencies": { + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" + } + } + }, + "redux-thunk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz", + "integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==" + }, "regenerate": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz", diff --git a/daemon/web/package.json b/daemon/web/package.json index bb8c315b..615c6cf3 100644 --- a/daemon/web/package.json +++ b/daemon/web/package.json @@ -22,13 +22,17 @@ "babel-preset-react": "6.24.1", "babel-preset-stage-3": "6.24.1", "css-loader": "0.28.11", + "eslint-plugin-jsx-a11y": "6.0.3", "history": "4.7.2", "html-webpack-plugin": "3.2.0", "node-sass": "4.9.0", "prop-types": "15.6.1", "react": "16.3.2", "react-dom": "16.3.2", + "react-redux": "5.0.7", "react-router-dom": "4.2.2", + "redux": "4.0.0", + "redux-thunk": "2.3.0", "sass-loader": "7.0.1", "style-loader": "0.21.0", "webpack": "4.8.3", @@ -39,7 +43,6 @@ "eslint": "4.19.1", "eslint-config-airbnb": "16.1.0", "eslint-plugin-import": "2.12.0", - "eslint-plugin-jsx-a11y": "6.0.3", "eslint-plugin-react": "7.8.1" } } diff --git a/daemon/web/components/App.js b/daemon/web/pages/app/App.js similarity index 86% rename from daemon/web/components/App.js rename to daemon/web/pages/app/App.js index ee5db2e5..684c68c2 100644 --- a/daemon/web/components/App.js +++ b/daemon/web/pages/app/App.js @@ -3,9 +3,9 @@ import { HashRouter, Redirect, Route } from 'react-router-dom'; import PropTypes from 'prop-types'; import createHistory from 'history/createBrowserHistory'; -import InertiaClient from '../client'; -import Login from './Login'; -import Home from './Home'; +// import InertiaClient from '../../common/client'; +import Login from '../login/Login'; +import Main from '../main/Main'; const styles = { container: { @@ -27,7 +27,7 @@ const AuthRoute = ({ authenticated, component: Component, props, ...rest }) => ( ); AuthRoute.propTypes = { authenticated: PropTypes.bool, - component: PropTypes.node, + component: PropTypes.any, props: PropTypes.shape(), }; @@ -40,14 +40,16 @@ const PropsRoute = ({ component: Component, props, ...rest }) => ( )} /> ); PropsRoute.propTypes = { - component: PropTypes.node, + component: PropTypes.any, props: PropTypes.shape(), }; export default class App extends React.Component { static async isAuthenticated() { - const response = await InertiaClient.validate(); - return (response.status === 200); + // TODO: disable route guards + // const response = await InertiaClient.validate(); + // return (response.status === 200); + return true; } constructor(props) { @@ -104,7 +106,7 @@ export default class App extends React.Component { diff --git a/daemon/web/pages/containers/containers.js b/daemon/web/pages/containers/containers.js new file mode 100644 index 00000000..4043b860 --- /dev/null +++ b/daemon/web/pages/containers/containers.js @@ -0,0 +1,30 @@ +import React from 'react'; +import { connect } from 'react-redux'; + +const styles = { +}; + +class ContainersWrapper extends React.Component { + constructor(props) { + super(props); + this.state = {}; + } + + render() { + return ( +
+

Hello!

+
+ ); + } +} +ContainersWrapper.propTypes = {}; + +const mapStateToProps = () => { return {}; }; + +const mapDispatchToProps = () => { return {}; }; + +const Containers = connect(mapStateToProps, mapDispatchToProps)(ContainersWrapper); + + +export default Containers; diff --git a/daemon/web/components/Dashboard.js b/daemon/web/pages/dashboard/Dashboard.js similarity index 81% rename from daemon/web/components/Dashboard.js rename to daemon/web/pages/dashboard/Dashboard.js index bc146c61..ed648227 100644 --- a/daemon/web/components/Dashboard.js +++ b/daemon/web/pages/dashboard/Dashboard.js @@ -1,8 +1,11 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; -import InertiaClient from '../client'; -import LogView from './metrics/LogView'; +import InertiaClient from '../../common/client'; +import LogView from '../../components/LogView'; +import * as dashboardActions from '../../actions/dashboard'; const styles = { container: { @@ -26,7 +29,7 @@ function promiseState(p) { .then(v => (v === t ? 'pending' : ('fulfilled', () => 'rejected'))); } -export default class Dashboard extends React.Component { +class DashboardWrapper extends React.Component { constructor(props) { super(props); this.state = { @@ -122,6 +125,19 @@ export default class Dashboard extends React.Component { ); } } -Dashboard.propTypes = { +DashboardWrapper.propTypes = { container: PropTypes.string, }; + +const mapStateToProps = ({ Dashboard }) => { + return { + testState: Dashboard.testState, + }; +}; + +const mapDispatchToProps = dispatch => bindActionCreators({ ...dashboardActions }, dispatch); + +const Dashboard = connect(mapStateToProps, mapDispatchToProps)(DashboardWrapper); + + +export default Dashboard; diff --git a/daemon/web/components/Login.js b/daemon/web/pages/login/Login.js similarity index 63% rename from daemon/web/components/Login.js rename to daemon/web/pages/login/Login.js index 30a8407a..d065f53a 100644 --- a/daemon/web/components/Login.js +++ b/daemon/web/pages/login/Login.js @@ -1,6 +1,10 @@ import React from 'react'; import PropTypes from 'prop-types'; -import InertiaClient from '../client'; +import { bindActionCreators } from 'redux'; +import { connect } from 'react-redux'; + +// import InertiaClient from '../../common/client'; +import * as loginActions from '../../actions/login'; const styles = { container: { @@ -26,7 +30,7 @@ const styles = { }, }; -export default class Login extends React.Component { +class LoginWrapper extends React.Component { constructor(props) { super(props); this.state = { @@ -40,14 +44,18 @@ export default class Login extends React.Component { } async handleLoginSubmit() { - const response = await InertiaClient.login( - this.state.username, - this.state.password, - ); - if (response.status !== 200) { - this.setState({ loginAlert: 'Username and/or password is incorrect' }); - return; - } + // TODO: disable authentication until we get it working + console.log(this.state.username, this.state.password); + this.props.testAction(); + // const response = await InertiaClient.login( + // this.state.username, + // this.state.password, + // ); + + // if (response.status !== 200) { + // this.setState({ loginAlert: 'Username and/or password is incorrect' }); + // return; + // } this.props.history.push('/home'); } @@ -84,6 +92,21 @@ export default class Login extends React.Component { ); } } -Login.propTypes = { - history: PropTypes.func, +LoginWrapper.propTypes = { + history: PropTypes.object, + testAction: PropTypes.func, +}; + + +const mapStateToProps = ({ Login }) => { + return { + testState: Login.testState, + }; }; + +const mapDispatchToProps = dispatch => bindActionCreators({ ...loginActions }, dispatch); + +const Login = connect(mapStateToProps, mapDispatchToProps)(LoginWrapper); + + +export default Login; diff --git a/daemon/web/components/Home.js b/daemon/web/pages/main/Main.js similarity index 80% rename from daemon/web/components/Home.js rename to daemon/web/pages/main/Main.js index 00362214..9d08b160 100644 --- a/daemon/web/components/Home.js +++ b/daemon/web/pages/main/Main.js @@ -1,8 +1,17 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; +import { + Link, + Route, + Switch, +} from 'react-router-dom'; -import InertiaClient from '../client'; -import Dashboard from './Dashboard'; +import InertiaClient from '../../common/client'; +import Containers from '../containers/containers'; +import Dashboard from '../dashboard/Dashboard'; +import * as mainActions from '../../actions/main'; // hardcode all styles for now, until we flesh out UI @@ -126,7 +135,7 @@ SidebarText.propTypes = { children: PropTypes.node, }; -export default class Home extends React.Component { +class MainWrapper extends React.Component { constructor(props) { super(props); this.state = { @@ -221,6 +230,9 @@ export default class Home extends React.Component { }}> logout + + Click to go to Dashboard + Click to go to Containers
@@ -238,15 +250,39 @@ export default class Home extends React.Component {
- + + } + /> + } + /> +
); } } -Home.propTypes = { - history: PropTypes.func, +MainWrapper.propTypes = { + history: PropTypes.object, + match: PropTypes.object, +}; + + +const mapStateToProps = ({ Main }) => { + return { + testState: Main.testState, + }; }; + +const mapDispatchToProps = dispatch => bindActionCreators({ ...mainActions }, dispatch); + +const Main = connect(mapStateToProps, mapDispatchToProps)(MainWrapper); + + +export default Main; diff --git a/daemon/web/store/dashboard.js b/daemon/web/store/dashboard.js new file mode 100644 index 00000000..2cd3b586 --- /dev/null +++ b/daemon/web/store/dashboard.js @@ -0,0 +1,21 @@ +import { + TEST_DASHBOARD_ACTION, +} from '../actions/_constants'; + +const initialState = { + testState: 'tree', +}; + +const Dashboard = (state = initialState, action) => { + switch (action.type) { + case TEST_DASHBOARD_ACTION: { + return { ...state, testState: action.payload }; + } + + default: { + return state; + } + } +}; + +export default Dashboard; diff --git a/daemon/web/store/index.js b/daemon/web/store/index.js new file mode 100644 index 00000000..b9db1e5d --- /dev/null +++ b/daemon/web/store/index.js @@ -0,0 +1,19 @@ +import { combineReducers, createStore, applyMiddleware } from 'redux'; +import thunk from 'redux-thunk'; +import Dashboard from './dashboard'; +import Main from './main'; +import Login from './login'; + + +const rootReducer = combineReducers({ + Dashboard, + Main, + Login, +}); + +const store = createStore( + rootReducer, + applyMiddleware(thunk) +); + +export default store; diff --git a/daemon/web/store/login.js b/daemon/web/store/login.js new file mode 100644 index 00000000..0f571779 --- /dev/null +++ b/daemon/web/store/login.js @@ -0,0 +1,21 @@ +import { + TEST_LOGIN_ACTION, +} from '../actions/_constants'; + +const initialState = { + testState: 'tree', +}; + +const Login = (state = initialState, action) => { + switch (action.type) { + case TEST_LOGIN_ACTION: { + return { ...state, testState: action.payload }; + } + + default: { + return state; + } + } +}; + +export default Login; diff --git a/daemon/web/store/main.js b/daemon/web/store/main.js new file mode 100644 index 00000000..ea5f0aa7 --- /dev/null +++ b/daemon/web/store/main.js @@ -0,0 +1,21 @@ +import { + TEST_MAIN_ACTION, +} from '../actions/_constants'; + +const initialState = { + testState: 'tree', +}; + +const Main = (state = initialState, action) => { + switch (action.type) { + case TEST_MAIN_ACTION: { + return { ...state, testState: action.payload }; + } + + default: { + return state; + } + } +}; + +export default Main; diff --git a/daemon/web/styles/colors.sass b/daemon/web/styles/colors.sass new file mode 100644 index 00000000..e69de29b diff --git a/daemon/web/index.sass b/daemon/web/styles/index.sass similarity index 95% rename from daemon/web/index.sass rename to daemon/web/styles/index.sass index 198c0750..f66d56b9 100644 --- a/daemon/web/index.sass +++ b/daemon/web/styles/index.sass @@ -1,3 +1,6 @@ +@import ./colors +@import ./typography + html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, diff --git a/daemon/web/styles/typography.sass b/daemon/web/styles/typography.sass new file mode 100644 index 00000000..e69de29b