mirror of
				https://github.com/fspc/workstand.git
				synced 2025-11-04 00:45:35 -05:00 
			
		
		
		
	Refactor member list to be searchable (#27)
Trigger! * Added members API endpoint. * Stubbed out member table. Search is broken. * Better, faster member search! * Add add member button.
This commit is contained in:
		
							parent
							
								
									65e71becf4
								
							
						
					
					
						commit
						560141298a
					
				@ -1,13 +1,16 @@
 | 
			
		||||
import ContentAdd from 'material-ui/svg-icons/content/add';
 | 
			
		||||
import fetch from 'isomorphic-fetch';
 | 
			
		||||
import FloatingActionButton from 'material-ui/FloatingActionButton';
 | 
			
		||||
import moment from 'moment';
 | 
			
		||||
import { polyFill } from 'es6-promise';
 | 
			
		||||
import RaisedButton from 'material-ui/RaisedButton';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import RaisedButton from 'material-ui/RaisedButton';
 | 
			
		||||
 | 
			
		||||
import Member from './Member';
 | 
			
		||||
import Purpose from './Purpose';
 | 
			
		||||
import SignedInList from './SignedInList';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export default class SignIn extends React.Component {
 | 
			
		||||
  constructor(props) {
 | 
			
		||||
    super(props);
 | 
			
		||||
@ -132,6 +135,7 @@ export default class SignIn extends React.Component {
 | 
			
		||||
              searchText={this.state.searchText}
 | 
			
		||||
            />
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div className="mdl-cell mdl-cell--4-col">
 | 
			
		||||
            <Purpose
 | 
			
		||||
              handleChange={this.handlePurposeChoice}
 | 
			
		||||
@ -139,7 +143,6 @@ export default class SignIn extends React.Component {
 | 
			
		||||
            />
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div className="mdl-grid">
 | 
			
		||||
          <div className="mdl-cell mdl-cell--2-col mdl-cell--10-offset">
 | 
			
		||||
            <RaisedButton onClick={this.signIn} label="Sign-in" />
 | 
			
		||||
@ -147,6 +150,9 @@ export default class SignIn extends React.Component {
 | 
			
		||||
        </div>
 | 
			
		||||
        <div className="mdl-grid">
 | 
			
		||||
          <SignedInList members={this.state.signedIn} />
 | 
			
		||||
          <FloatingActionButton href="/members/new/">
 | 
			
		||||
            <ContentAdd />
 | 
			
		||||
          </FloatingActionButton>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,155 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { polyFill } from 'es6-promise';
 | 
			
		||||
import fetch from 'isomorphic-fetch';
 | 
			
		||||
import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table';
 | 
			
		||||
import FlatButton from 'material-ui/FlatButton';
 | 
			
		||||
import { Toolbar, ToolbarGroup, ToolbarSeparator, ToolbarTitle } from 'material-ui/Toolbar';
 | 
			
		||||
import TextField from 'material-ui/TextField';
 | 
			
		||||
import RaisedButton from 'material-ui/RaisedButton';
 | 
			
		||||
 | 
			
		||||
function checkStatus(response) {
 | 
			
		||||
  if (response.status >= 200 && response.status < 300) {
 | 
			
		||||
    return response;
 | 
			
		||||
  }
 | 
			
		||||
  const error = new Error(response.statusText);
 | 
			
		||||
  error.response = response;
 | 
			
		||||
  throw error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function parseJSON(response) {
 | 
			
		||||
  return response.json();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default class MemberTable extends React.Component {
 | 
			
		||||
  constructor(props) {
 | 
			
		||||
    super(props);
 | 
			
		||||
 | 
			
		||||
    this.state = {
 | 
			
		||||
      members: [],
 | 
			
		||||
      searchText: '',
 | 
			
		||||
      filteredMembers: [],
 | 
			
		||||
      error: undefined,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this.handleUpdate = this.handleUpdate.bind(this);
 | 
			
		||||
    this.handleSearch = this.handleSearch.bind(this);
 | 
			
		||||
    this.clearSearch = this.clearSearch.bind(this);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  componentDidMount() {
 | 
			
		||||
    fetch('/api/v1/members/')
 | 
			
		||||
      .then(checkStatus)
 | 
			
		||||
      .then(parseJSON)
 | 
			
		||||
      .then((data) => {
 | 
			
		||||
        this.setState({ members: data });
 | 
			
		||||
        console.log('request succeeded with JSON response', data);
 | 
			
		||||
      })
 | 
			
		||||
      .catch((error) => {
 | 
			
		||||
        console.log('request failed', error);
 | 
			
		||||
      });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleUpdate(event, value) {
 | 
			
		||||
    this.setState({ ...this.state, searchText: value });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  clearSearch() {
 | 
			
		||||
    this.setState({
 | 
			
		||||
      ...this.state,
 | 
			
		||||
      searchText: '',
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleSearch() {
 | 
			
		||||
    const value = this.state.searchText.trim();
 | 
			
		||||
    const self = this;
 | 
			
		||||
 | 
			
		||||
    fetch(`/members/search/${value}/`)
 | 
			
		||||
      .then((response) => {
 | 
			
		||||
        if (response.status === 200) {
 | 
			
		||||
          return response.json();
 | 
			
		||||
        }
 | 
			
		||||
        throw new Error('Bad response from server');
 | 
			
		||||
      })
 | 
			
		||||
      .then((data) => {
 | 
			
		||||
        if (data.results.length > 0) {
 | 
			
		||||
          self.setState({
 | 
			
		||||
            ...this.state,
 | 
			
		||||
            error: '',
 | 
			
		||||
            filteredMembers: this.state.members.filter((member) => {
 | 
			
		||||
              const ids = data.results.map(m => m.id);
 | 
			
		||||
              console.log(ids);
 | 
			
		||||
 | 
			
		||||
              if (ids.indexOf(member.id) !== -1) {
 | 
			
		||||
                return member;
 | 
			
		||||
              }
 | 
			
		||||
            }),
 | 
			
		||||
          });
 | 
			
		||||
        } else {
 | 
			
		||||
          self.setState({ ...this.state, error: 'Member not found.' });
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  render() {
 | 
			
		||||
    const memberRows = this.state.members.map(member => (
 | 
			
		||||
      <TableRow selectable={false} key={member.id}>
 | 
			
		||||
        <TableRowColumn>{member.first_name}</TableRowColumn>
 | 
			
		||||
        <TableRowColumn>{member.last_name}</TableRowColumn>
 | 
			
		||||
        <TableRowColumn>{member.email}</TableRowColumn>
 | 
			
		||||
        <TableRowColumn><FlatButton label="Edit" href={`/members/edit/${member.id}`} primary /></TableRowColumn>
 | 
			
		||||
      </TableRow>
 | 
			
		||||
      ));
 | 
			
		||||
 | 
			
		||||
    const filteredMemberRows = this.state.filteredMembers.map(member => (
 | 
			
		||||
      <TableRow selectable={false} key={member.id}>
 | 
			
		||||
        <TableRowColumn>{member.first_name}</TableRowColumn>
 | 
			
		||||
        <TableRowColumn>{member.last_name}</TableRowColumn>
 | 
			
		||||
        <TableRowColumn>{member.email}</TableRowColumn>
 | 
			
		||||
        <TableRowColumn><FlatButton label="Edit" href={`/members/edit/${member.id}`} primary /></TableRowColumn>
 | 
			
		||||
      </TableRow>
 | 
			
		||||
      ));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <div className="mdl-grid">
 | 
			
		||||
        <div className="mdl-cell mdl-cell--12-col">
 | 
			
		||||
          <h3>Members</h3>
 | 
			
		||||
          <Toolbar>
 | 
			
		||||
            <ToolbarGroup>
 | 
			
		||||
              <TextField
 | 
			
		||||
                hintText="ma@example.com OR name"
 | 
			
		||||
                floatingLabelText="Search for member"
 | 
			
		||||
                onChange={this.handleUpdate}
 | 
			
		||||
                value={this.state.searchText}
 | 
			
		||||
              />
 | 
			
		||||
              <RaisedButton label="Search" primary onClick={this.handleSearch} />
 | 
			
		||||
              <RaisedButton label="Clear" onClick={this.clearSearch} secondary />
 | 
			
		||||
            </ToolbarGroup>
 | 
			
		||||
          </Toolbar>
 | 
			
		||||
          <Table selectable={false}>
 | 
			
		||||
            <TableHeader adjustForCheckbox={false} displaySelectAll={false}>
 | 
			
		||||
              <TableRow>
 | 
			
		||||
                <TableHeaderColumn>First name</TableHeaderColumn>
 | 
			
		||||
                <TableHeaderColumn>Last Name</TableHeaderColumn>
 | 
			
		||||
                <TableHeaderColumn>Email</TableHeaderColumn>
 | 
			
		||||
                <TableHeaderColumn />
 | 
			
		||||
              </TableRow>
 | 
			
		||||
            </TableHeader>
 | 
			
		||||
            <TableBody displayRowCheckbox={false}>
 | 
			
		||||
              {filteredMemberRows.length ?
 | 
			
		||||
                filteredMemberRows : undefined
 | 
			
		||||
              }
 | 
			
		||||
              {memberRows.length && !this.state.searchText ?
 | 
			
		||||
              memberRows :
 | 
			
		||||
              <TableRow>
 | 
			
		||||
                <TableRowColumn>{'Members loading.'}</TableRowColumn>
 | 
			
		||||
              </TableRow>
 | 
			
		||||
            }
 | 
			
		||||
            </TableBody>
 | 
			
		||||
          </Table>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								bikeshop_project/assets/js/members/index.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								bikeshop_project/assets/js/members/index.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import ReactDOM from 'react-dom';
 | 
			
		||||
import injectTapEventPlugin from 'react-tap-event-plugin';
 | 
			
		||||
import getMuiTheme from 'material-ui/styles/getMuiTheme';
 | 
			
		||||
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
 | 
			
		||||
import MemberTable from './components/MemberTable';
 | 
			
		||||
 | 
			
		||||
// Needed for onTouchTap
 | 
			
		||||
// http://stackoverflow.com/a/34015469/988941
 | 
			
		||||
injectTapEventPlugin();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const App = () => (
 | 
			
		||||
  <MuiThemeProvider muiTheme={getMuiTheme()}>
 | 
			
		||||
    <div>
 | 
			
		||||
      <h1>Members</h1>
 | 
			
		||||
      <MemberTable />
 | 
			
		||||
    </div>
 | 
			
		||||
  </MuiThemeProvider>
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
ReactDOM.render(<App />, document.getElementById('root'));
 | 
			
		||||
@ -18,16 +18,30 @@ from django.conf.urls import include, url
 | 
			
		||||
from django.contrib import admin
 | 
			
		||||
from django.contrib.auth.views import login, logout_then_login
 | 
			
		||||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
 | 
			
		||||
from rest_framework import routers
 | 
			
		||||
from rest_framework_jwt.views import obtain_jwt_token
 | 
			
		||||
 | 
			
		||||
import registration
 | 
			
		||||
from core import urls as core_urls
 | 
			
		||||
from registration import urls as member_urls
 | 
			
		||||
 | 
			
		||||
routeLists = [
 | 
			
		||||
    registration.urls.apiRoutes,
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
router = routers.DefaultRouter()
 | 
			
		||||
for routeList in routeLists:
 | 
			
		||||
    for route in routeList:
 | 
			
		||||
        router.register(route[0], route[1])
 | 
			
		||||
 | 
			
		||||
urlpatterns = [
 | 
			
		||||
    url(r'^', include(core_urls)),
 | 
			
		||||
    url(r'^login/', login, {'template_name': 'login.html'}, name='login'),
 | 
			
		||||
    url(r'^logout/', logout_then_login, name='logout'),
 | 
			
		||||
    url(r'^members/', include(member_urls)),
 | 
			
		||||
    url(r'^admin/', admin.site.urls),
 | 
			
		||||
    url(r'^api/v1/', include(router.urls)),
 | 
			
		||||
    url(r'^api/v1/token-auth/', obtain_jwt_token),
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
if getattr(settings, 'DEBUG'):
 | 
			
		||||
 | 
			
		||||
@ -53,7 +53,9 @@
 | 
			
		||||
      </div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
    <div id="root"></div>
 | 
			
		||||
    {% render_bundle 'main' %}
 | 
			
		||||
    {% render_bundle 'signin' %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
{% render_bundle 'webpack' %}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								bikeshop_project/registration/serializers.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								bikeshop_project/registration/serializers.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
from rest_framework import serializers
 | 
			
		||||
from rest_framework.serializers import ModelSerializer
 | 
			
		||||
 | 
			
		||||
from .models import Member
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MemberSerializer(ModelSerializer):
 | 
			
		||||
    first_name = serializers.CharField(allow_blank=True, required=False)
 | 
			
		||||
    last_name = serializers.CharField(allow_blank=True, required=False)
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Member
 | 
			
		||||
        fields = ('first_name', 'last_name', 'email', 'id')
 | 
			
		||||
@ -1,22 +1,7 @@
 | 
			
		||||
{% extends 'dashboard.html' %}
 | 
			
		||||
{% load render_bundle from webpack_loader %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
    <div class="mdl-cell mdl-cell--6-col">
 | 
			
		||||
        <ul class="demo-list-three mdl-list">
 | 
			
		||||
            {% for member in members %}
 | 
			
		||||
          <li class="mdl-list__item mdl-list__item--three-line">
 | 
			
		||||
            <span class="mdl-list__item-primary-content">
 | 
			
		||||
              <i class="material-icons mdl-list__item-avatar">person</i>
 | 
			
		||||
              <span>{{ member.full_name }}</span>
 | 
			
		||||
              <span class="mdl-list__item-text-body">
 | 
			
		||||
                {{ member.email }}
 | 
			
		||||
              </span>
 | 
			
		||||
            </span>
 | 
			
		||||
            <span class="mdl-list__item-secondary-content">
 | 
			
		||||
              <a class="mdl-list__item-secondary-action" href="{% url 'member_edit' member_id=member.id %}"><i class="material-icons">edit</i></a>
 | 
			
		||||
            </span>
 | 
			
		||||
          </li>
 | 
			
		||||
            {% endfor %}
 | 
			
		||||
        </ul>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div id="root"></div>
 | 
			
		||||
    {% render_bundle 'members' %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
@ -1,6 +1,11 @@
 | 
			
		||||
from django.conf.urls import url
 | 
			
		||||
 | 
			
		||||
from .views import MemberFormView, MemberSearchView, MemberSignIn, Members
 | 
			
		||||
from .views import MemberFormView, MemberSearchView, MemberSignIn, Members, MemberViewSet
 | 
			
		||||
 | 
			
		||||
apiRoutes = (
 | 
			
		||||
    (r'members', MemberViewSet),
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
urlpatterns = [
 | 
			
		||||
    url(r'^new/$', MemberFormView.as_view(), name='member_new'),
 | 
			
		||||
    url(r'^search/(?P<query>[\w@\.\+]+)/$', MemberSearchView.as_view(), name='member_search'),
 | 
			
		||||
 | 
			
		||||
@ -9,12 +9,13 @@ from django.utils.decorators import method_decorator
 | 
			
		||||
from django.views.decorators.csrf import csrf_exempt
 | 
			
		||||
from django.views.generic import TemplateView, View
 | 
			
		||||
from haystack.query import SearchQuerySet
 | 
			
		||||
from rest_framework import serializers
 | 
			
		||||
from rest_framework import viewsets
 | 
			
		||||
from rest_framework.renderers import JSONRenderer
 | 
			
		||||
from rest_framework.serializers import ModelSerializer
 | 
			
		||||
 | 
			
		||||
from core.models import Visit
 | 
			
		||||
from registration.utils import signin_member, get_signed_in_members
 | 
			
		||||
from .serializers import MemberSerializer
 | 
			
		||||
from .forms import MemberForm
 | 
			
		||||
from .models import Member
 | 
			
		||||
 | 
			
		||||
@ -64,15 +65,6 @@ class MemberSearchView(View):
 | 
			
		||||
        return HttpResponse(data, content_type='application/json')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MemberSerializer(ModelSerializer):
 | 
			
		||||
    first_name = serializers.CharField(allow_blank=True, required=False)
 | 
			
		||||
    last_name = serializers.CharField(allow_blank=True, required=False)
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Member
 | 
			
		||||
        fields = ('first_name', 'last_name', 'email', 'id')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VisitSerializer(ModelSerializer):
 | 
			
		||||
    member = MemberSerializer()
 | 
			
		||||
 | 
			
		||||
@ -109,3 +101,8 @@ class Members(TemplateView):
 | 
			
		||||
    def get(self, request):
 | 
			
		||||
        members = Member.objects.all()
 | 
			
		||||
        return self.render_to_response(dict(members=members))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MemberViewSet(viewsets.ModelViewSet):
 | 
			
		||||
    queryset = Member.objects.all()
 | 
			
		||||
    serializer_class = MemberSerializer
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
const path = require("path");
 | 
			
		||||
const path = require('path');
 | 
			
		||||
const webpack = require('webpack');
 | 
			
		||||
const BundleTracker = require('webpack-bundle-tracker');
 | 
			
		||||
const ExtractTextPlugin = require('extract-text-webpack-plugin');
 | 
			
		||||
@ -7,17 +7,19 @@ const autoprefixer =  require('autoprefixer');
 | 
			
		||||
module.exports = {
 | 
			
		||||
  context: __dirname,
 | 
			
		||||
  devtool: 'inline-source-map',
 | 
			
		||||
    entry: './assets/js/index', // entry point of our app. assets/js/index.js should require other js modules and dependencies it needs
 | 
			
		||||
 | 
			
		||||
  entry: {
 | 
			
		||||
    signin: './assets/js/index',
 | 
			
		||||
    members: './assets/js/members/index',
 | 
			
		||||
  },
 | 
			
		||||
  output: {
 | 
			
		||||
    path: path.resolve('./assets/bundles/'),
 | 
			
		||||
        filename: "[name]-[hash].js"
 | 
			
		||||
    filename: '[name]-[hash].js',
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  plugins: [
 | 
			
		||||
    new BundleTracker({ filename: './webpack-stats.json' }),
 | 
			
		||||
    new ExtractTextPlugin('react-toolbox.css', { allChunks: true }),
 | 
			
		||||
        new webpack.NoErrorsPlugin()
 | 
			
		||||
    new webpack.NoErrorsPlugin(),
 | 
			
		||||
  ],
 | 
			
		||||
 | 
			
		||||
  module: {
 | 
			
		||||
@ -27,22 +29,22 @@ module.exports = {
 | 
			
		||||
        exclude: /node_modules/,
 | 
			
		||||
        loader: 'babel-loader',
 | 
			
		||||
        query: {
 | 
			
		||||
                    presets: ['es2015', 'stage-0', 'react']
 | 
			
		||||
                }
 | 
			
		||||
          presets: ['es2015', 'stage-0', 'react'],
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        test: /(\.scss|\.css)$/,
 | 
			
		||||
                loader: ExtractTextPlugin.extract('style', 'css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss!sass?sourceMap!toolbox')
 | 
			
		||||
          }
 | 
			
		||||
        ]
 | 
			
		||||
        loader: ExtractTextPlugin.extract('style', 'css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss!sass?sourceMap!toolbox'),
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
  },
 | 
			
		||||
  resolve: {
 | 
			
		||||
    modulesDirectories: [
 | 
			
		||||
      'node_modules',
 | 
			
		||||
      'bower_components',
 | 
			
		||||
            path.resolve(__dirname, './node_modules')
 | 
			
		||||
      path.resolve(__dirname, './node_modules'),
 | 
			
		||||
    ],
 | 
			
		||||
        extensions: ['', '.js', '.jsx', '.scss']
 | 
			
		||||
    extensions: ['', '.js', '.jsx', '.scss'],
 | 
			
		||||
  },
 | 
			
		||||
    postcss: [autoprefixer]
 | 
			
		||||
}
 | 
			
		||||
  postcss: [autoprefixer],
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -6,11 +6,14 @@ const ExtractTextPlugin = require('extract-text-webpack-plugin');
 | 
			
		||||
var config = require('./webpack.base.config.js')
 | 
			
		||||
 | 
			
		||||
// Use webpack dev server
 | 
			
		||||
config.entry = [
 | 
			
		||||
config.entry = {
 | 
			
		||||
    webpack: [
 | 
			
		||||
        'webpack-dev-server/client?http://webpack.docker:3000',
 | 
			
		||||
        'webpack/hot/only-dev-server',
 | 
			
		||||
    './assets/js/index'
 | 
			
		||||
]
 | 
			
		||||
    ],
 | 
			
		||||
    signin: './assets/js/index',
 | 
			
		||||
    members: './assets/js/members/index',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// override django's STATIC_URL for webpack bundles
 | 
			
		||||
config.output.publicPath = 'http://webpack.docker:3000/assets/bundles/'
 | 
			
		||||
 | 
			
		||||
@ -11,3 +11,4 @@ djangorestframework
 | 
			
		||||
django-webpack-loader
 | 
			
		||||
requests
 | 
			
		||||
PyYAML
 | 
			
		||||
djangorestframework-jwt==1.9.0
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user