Skip to content
This repository has been archived by the owner on Aug 27, 2020. It is now read-only.

Commit

Permalink
Merge branch 'release/0.3.2'
Browse files Browse the repository at this point in the history
  • Loading branch information
hisapy committed Sep 29, 2016
2 parents 018aa80 + b514256 commit dac0e35
Show file tree
Hide file tree
Showing 12 changed files with 139 additions and 34 deletions.
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ A **Task** is something that is not complex enough to be defined as a **Feature*
The title of a an issue that is expected to be treated as a **BUG** must be prefixed with **BUG:**, i.e., **BUG: Wrong new notifications count**.

Submit your pull requests to the corresponding branch according to the branching model mentioned at the beginning of this section.

Last but not least, [stop using `git pull`](https://adamcod.es/2014/12/10/git-pull-correct-workflow.html)
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
# phoenix-webpack-relay-react (pwr2)
# Phoenix, Webpack, React and Relay (pwr2)

Docker image based on Ubuntu providing a base setup for a Phoenix+Webpack+Relay+React project, with some sugar and conventions to develop and build your own web applications.

_We will improve docs and code including test coverage in the next releases_

**NOTICE:** The default branch for this repo is **develop**. Check the [README](https://github.com/iporaitech/pwr2-docker/blob/master/README.md) on master to see what's in the last release.

## What is this for?

You can use this to start your own Elixir/Phoenix based web application with React+Relay - styled with Material Design, in the front-end all bundled with Webpack.

So far we've implemented the following:

* A GraphQL endpoint implemented in Elixir with Absinthe.
* Authentication using JWTs (JSON Web Tokens) via GraphQL (LoginMutation & LogoutMutation).
* Hardcoded Role based Authorization.
* StarWars GraphQL example.
* GraphiQL console.
* Some interesting React/Relay components in the client(browser), including a router.
* CSS Modules _integration_ with Material Design Lite.
* Testing framework for the backend (Elixir/Phoenix).


## Requirements

To run this software you need to install [Docker](https://www.docker.com/) on your system. It is very simple and there are a lot of guides and tutorials out there on the Internet.
Expand Down Expand Up @@ -97,7 +113,7 @@ Once the containers are up and running you can copy the source code of the base

Once all setup and with the app running and assuming your `HTTP_PORT` is 4000, you can:

0. Login with credentials available in [priv/repo/seeds.exs](priv/repo/seeds.exs). Logout is also available **BUT DISPLAYING AN ERROR when trying lo Login with wrong credentials is not implemented yet**.
0. Login with credentials available in [priv/repo/seeds.exs](priv/repo/seeds.exs). Logout is also available.
1. Visit http://localhost:4000/admin/graphiql to access a [GraphiQL](https://github.com/graphql/graphiql) IDE.
2. Visit http://localhost:4000/admin/star-wars to experiment with our implementation of the [Relay Star Wars example](https://github.com/relayjs/relay-examples/tree/master/star-wars). The _[database](./web/graphql/star_wars_db.ex)_ for this example is implemented as an [Elixir.Agent](http://elixir-lang.org/docs/stable/elixir/Agent.html)
3. You can also use something like Google Chrome's Advanced Rest Client(ARC) or any other JSON API client and (with the corresponding Authorization header) send queries to http://localhost:4000/graphql like:
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Webapp.Mixfile do

def project do
[app: :webapp,
version: "0.3.0",
version: "0.3.2",
elixir: "~> 1.3",
elixirc_paths: elixirc_paths(Mix.env),
compilers: [:phoenix, :gettext] ++ Mix.compilers,
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "pwr2-docker-ui",
"description": "Javascript dependencies for pwr2-docker, a Docker image based on Ubuntu providing a base setup for a Phoenix+Webpack+Relay+React project, with some sugar and conventions to develop and build your own web applications.",
"main": "webpack.config.js",
"version": "0.3.0",
"version": "0.3.2",
"contributors": [
{
"name": "Iporaitech and others",
Expand Down Expand Up @@ -33,6 +33,7 @@
},
"dependencies": {
"babel-runtime": "^6.11.6",
"classnames": "^2.2.5",
"es6-promise": "^3.2.1",
"graphiql": "^0.7.3",
"graphql": "^0.6.2",
Expand All @@ -48,5 +49,5 @@
"react-router-relay": "https://github.com/iporaitech/react-router-relay/tarball/build",
"sync-request": "^3.0.1"
},
"license" : "MIT"
"license": "MIT"
}
7 changes: 5 additions & 2 deletions web/graphql/types/auth_mutations.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ defmodule Webapp.GraphQL.Types.AuthMutations do
use Absinthe.Relay.Schema.Notation
import Comeonin.Bcrypt, only: [checkpw: 2, dummy_checkpw: 0]

#TODO: Create resolve functions for these mutations in their own module and test them.
# It will be easier to test the resolvers in isolation than embedded in the muations.
#TODO:
# 1. Create resolve functions for these mutations in their own module and test them. It
# will be easier to test the resolvers in isolation than embedded in the muations.
# 2. Refactor to use Scalar types for email and password.
# See http://graphql.org/learn/schema/#scalar-types

object :auth_mutations do
payload field :login do
Expand Down
2 changes: 1 addition & 1 deletion web/static/js/layout/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// file: layout/index.js
import React from 'react';
import { Link } from 'react-router';
import LogoutLink from 'lib/LogoutLink';
import LogoutLink from 'shared/LogoutLink';
import mdlUpgrade from 'lib/mdlUpgrade';
import styles from 'material-design-lite/material.css';

Expand Down
63 changes: 42 additions & 21 deletions web/static/js/#/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,29 @@
import React from 'react';
import Relay from 'react-relay';
import mdlUpgrade from 'lib/mdlUpgrade';
import Loading from 'shared/loading';
import material from 'material-design-lite/material.css';
import classNames from 'classnames/bind';
import styles from './styles.css';
import { withRouter } from 'react-router';
import LoginMutation from './mutation';
import Auth from 'lib/auth';

const cx = classNames.bind(styles);

class Login extends React.Component {

constructor(props) {
super(props);
this.state = {
error: false
hasError: false,
isLoading: false
}
}

handleSubmit(event) {
event.preventDefault();
this.setState({isLoading: true});

this.props.relay.commitUpdate(
new LoginMutation({
Expand All @@ -34,40 +40,55 @@ class Login extends React.Component {
} else {
router.replace('/')
}
},
onFailure: transaction => {
this.setState({hasError: true});
this.setState({isLoading: false});
}
}
);
}

render() {
// We use classNames for CSS that depends on MDL javascript
const inputClassName = cx(
"mdl-js-textfield",
'mdl-textfield',
'mdl-textfield--floating-label',
{"is-invalid": this.state.hasError}
);
const { isLoading } = this.state;

return (
<div className="mdl-js-layout" styleName="login-layout">
<main styleName="login-content">
<div styleName="mdl-card mdl-shadow--6dp">
<div styleName="mdl-card__title mdl-color--primary mdl-color-text--white">
<div styleName="card">
<div styleName="card-title">
<h2 styleName="mdl-card__title-text">Login</h2>
</div>
<form onSubmit={this.handleSubmit.bind(this)}>
<div styleName="mdl-card__supporting-text">
<div className="mdl-js-textfield" styleName="mdl-textfield mdl-textfield--floating-label">
<input ref="email" styleName="mdl-textfield__input" type="text" id="email" />
<label styleName="mdl-textfield__label" htmlFor="email">Email</label>
<div>
{ isLoading && (<Loading />)}
<div styleName="mdl-card__supporting-text">
{ this.state.hasError && (
<span styleName="login-error">Incorrect email or password</span>
)}
<div className={inputClassName}>
<input ref="email" styleName="mdl-textfield__input" type="text" id="email" />
<label styleName="mdl-textfield__label" htmlFor="email">Email</label>
</div>
<div className={inputClassName}>
<input ref="password" styleName="mdl-textfield__input" type="password" id="userpass" />
<label styleName="mdl-textfield__label" htmlFor="userpass">Password</label>
</div>
</div>
<div className="mdl-js-textfield" styleName="mdl-textfield">
<input ref="password" styleName="mdl-textfield__input" type="password" id="userpass" />
<label styleName="mdl-textfield__label" htmlFor="userpass">Password</label>
<div styleName="mdl-card__actions">
<button
className="mdl-js-button mdl-js-ripple-effect mdl-button mdl-button--colored">
Enter
</button>
</div>
</div>
<div styleName="mdl-card__actions">
<button
className="mdl-js-button mdl-js-ripple-effect"
styleName="mdl-button mdl-button--colored">
Enter
</button>
{this.state.error && (
<p>Bad login information</p>
)}
</div>
</form>
</div>
</main>
Expand All @@ -80,7 +101,7 @@ class Login extends React.Component {
// style.css contains customizations on some mdl classes
export default Relay.createContainer(
withRouter(
mdlUpgrade(Login, Object.assign({}, material, styles), {allowMultiple: true})
mdlUpgrade(Login, Object.assign({}, material, styles))
),{
fragments: {}
}
Expand Down
6 changes: 2 additions & 4 deletions web/static/js/#/mutation.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ import Relay from 'react-relay';

export default class extends Relay.Mutation {
getMutation() {
return Relay.QL`mutation {
login
}`;
return Relay.QL`mutation {login}`;
}

getVariables() {
Expand All @@ -17,7 +15,7 @@ export default class extends Relay.Mutation {
// TODO: Add field to LoginPayload to get errors
getFatQuery() {
return Relay.QL`
fragment on LoginPayload {
fragment on LoginPayload @relay(pattern: true) {
accessToken
}
`;
Expand Down
16 changes: 16 additions & 0 deletions web/static/js/#/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,19 @@
padding: 24px;
flex: none;
}

.card {
composes: mdl-card mdl-shadow--6dp from "material-design-lite/material.css";
}

.card-title {
composes: mdl-card__title mdl-color--primary mdl-color-text--white
from "material-design-lite/material.css";
}

.login-error {
composes: mdl-typography--caption-color-contrast from "material-design-lite/material.css";
color: red;
text-align: center;
font-size: 14px;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// file: layout/LogoutLink.js
// file: shared/LogoutLink.js
import React from 'react';
import Relay from 'react-relay';
import Auth from 'lib/auth';
Expand Down
34 changes: 34 additions & 0 deletions web/static/js/shared/loading/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// file: shared/LoadingOverlay.js
import React from 'react';
import mdlUpgrade from 'lib/mdlUpgrade';
import material from 'material-design-lite/material.css';
import classNames from 'classnames/bind';
import styles from './styles.css';

const cx = classNames.bind(styles);

class Loading extends React.Component {
static propTypes = {
overlay: React.PropTypes.bool
}
static defaultProps = {
overlay: true
}

render(){
const className = cx(
'mdl-spinner',
'mdl-js-spinner',
"is-active"
);
return (
this.props.overlay ?
<div styleName="overlay">
<div className={className}></div>
</div>
: <div className={className}></div>
)
}
}

export default mdlUpgrade(Loading, Object.assign({}, material, styles));
14 changes: 14 additions & 0 deletions web/static/js/shared/loading/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

.overlay {
background-color: rgba(255, 255, 255, 0.7);
width: 100%;
height: 80%;
position: absolute;
z-index: 10;
display: flex;
justify-content: center;
}

.overlay div {
align-self: center;
}

0 comments on commit dac0e35

Please # to comment.