mirror of
				https://github.com/fspc/workstand.git
				synced 2025-10-31 08:25:35 -04: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 fetch from 'isomorphic-fetch'; | ||||||
|  | import FloatingActionButton from 'material-ui/FloatingActionButton'; | ||||||
| import moment from 'moment'; | import moment from 'moment'; | ||||||
| import { polyFill } from 'es6-promise'; | import { polyFill } from 'es6-promise'; | ||||||
| import RaisedButton from 'material-ui/RaisedButton'; |  | ||||||
| import React from 'react'; | import React from 'react'; | ||||||
|  | import RaisedButton from 'material-ui/RaisedButton'; | ||||||
| 
 | 
 | ||||||
| import Member from './Member'; | import Member from './Member'; | ||||||
| import Purpose from './Purpose'; | import Purpose from './Purpose'; | ||||||
| import SignedInList from './SignedInList'; | import SignedInList from './SignedInList'; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| export default class SignIn extends React.Component { | export default class SignIn extends React.Component { | ||||||
|   constructor(props) { |   constructor(props) { | ||||||
|     super(props); |     super(props); | ||||||
| @ -132,6 +135,7 @@ export default class SignIn extends React.Component { | |||||||
|               searchText={this.state.searchText} |               searchText={this.state.searchText} | ||||||
|             /> |             /> | ||||||
|           </div> |           </div> | ||||||
|  | 
 | ||||||
|           <div className="mdl-cell mdl-cell--4-col"> |           <div className="mdl-cell mdl-cell--4-col"> | ||||||
|             <Purpose |             <Purpose | ||||||
|               handleChange={this.handlePurposeChoice} |               handleChange={this.handlePurposeChoice} | ||||||
| @ -139,7 +143,6 @@ export default class SignIn extends React.Component { | |||||||
|             /> |             /> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
| 
 |  | ||||||
|         <div className="mdl-grid"> |         <div className="mdl-grid"> | ||||||
|           <div className="mdl-cell mdl-cell--2-col mdl-cell--10-offset"> |           <div className="mdl-cell mdl-cell--2-col mdl-cell--10-offset"> | ||||||
|             <RaisedButton onClick={this.signIn} label="Sign-in" /> |             <RaisedButton onClick={this.signIn} label="Sign-in" /> | ||||||
| @ -147,6 +150,9 @@ export default class SignIn extends React.Component { | |||||||
|         </div> |         </div> | ||||||
|         <div className="mdl-grid"> |         <div className="mdl-grid"> | ||||||
|           <SignedInList members={this.state.signedIn} /> |           <SignedInList members={this.state.signedIn} /> | ||||||
|  |           <FloatingActionButton href="/members/new/"> | ||||||
|  |             <ContentAdd /> | ||||||
|  |           </FloatingActionButton> | ||||||
|         </div> |         </div> | ||||||
|       </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 import admin | ||||||
| from django.contrib.auth.views import login, logout_then_login | from django.contrib.auth.views import login, logout_then_login | ||||||
| from django.contrib.staticfiles.urls import staticfiles_urlpatterns | 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 core import urls as core_urls | ||||||
| from registration import urls as member_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 = [ | urlpatterns = [ | ||||||
|     url(r'^', include(core_urls)), |     url(r'^', include(core_urls)), | ||||||
|     url(r'^login/', login, {'template_name': 'login.html'}, name='login'), |     url(r'^login/', login, {'template_name': 'login.html'}, name='login'), | ||||||
|     url(r'^logout/', logout_then_login, name='logout'), |     url(r'^logout/', logout_then_login, name='logout'), | ||||||
|     url(r'^members/', include(member_urls)), |     url(r'^members/', include(member_urls)), | ||||||
|     url(r'^admin/', admin.site.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'): | if getattr(settings, 'DEBUG'): | ||||||
|  | |||||||
| @ -53,7 +53,9 @@ | |||||||
|       </div> |       </div> | ||||||
| {% endblock %} | {% endblock %} | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| {% block content %} | {% block content %} | ||||||
|     <div id="root"></div> |     <div id="root"></div> | ||||||
|     {% render_bundle 'main' %} |     {% render_bundle 'signin' %} | ||||||
| {% endblock %} | {% 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' %} | {% extends 'dashboard.html' %} | ||||||
|  | {% load render_bundle from webpack_loader %} | ||||||
| 
 | 
 | ||||||
| {% block content %} | {% block content %} | ||||||
|     <div class="mdl-cell mdl-cell--6-col"> |     <div id="root"></div> | ||||||
|         <ul class="demo-list-three mdl-list"> |     {% render_bundle 'members' %} | ||||||
|             {% 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> |  | ||||||
| {% endblock %} | {% endblock %} | ||||||
| @ -1,6 +1,11 @@ | |||||||
| from django.conf.urls import url | 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 = [ | urlpatterns = [ | ||||||
|     url(r'^new/$', MemberFormView.as_view(), name='member_new'), |     url(r'^new/$', MemberFormView.as_view(), name='member_new'), | ||||||
|     url(r'^search/(?P<query>[\w@\.\+]+)/$', MemberSearchView.as_view(), name='member_search'), |     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.decorators.csrf import csrf_exempt | ||||||
| from django.views.generic import TemplateView, View | from django.views.generic import TemplateView, View | ||||||
| from haystack.query import SearchQuerySet | from haystack.query import SearchQuerySet | ||||||
| from rest_framework import serializers | from rest_framework import viewsets | ||||||
| from rest_framework.renderers import JSONRenderer | from rest_framework.renderers import JSONRenderer | ||||||
| from rest_framework.serializers import ModelSerializer | from rest_framework.serializers import ModelSerializer | ||||||
| 
 | 
 | ||||||
| from core.models import Visit | from core.models import Visit | ||||||
| from registration.utils import signin_member, get_signed_in_members | from registration.utils import signin_member, get_signed_in_members | ||||||
|  | from .serializers import MemberSerializer | ||||||
| from .forms import MemberForm | from .forms import MemberForm | ||||||
| from .models import Member | from .models import Member | ||||||
| 
 | 
 | ||||||
| @ -64,15 +65,6 @@ class MemberSearchView(View): | |||||||
|         return HttpResponse(data, content_type='application/json') |         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): | class VisitSerializer(ModelSerializer): | ||||||
|     member = MemberSerializer() |     member = MemberSerializer() | ||||||
| 
 | 
 | ||||||
| @ -109,3 +101,8 @@ class Members(TemplateView): | |||||||
|     def get(self, request): |     def get(self, request): | ||||||
|         members = Member.objects.all() |         members = Member.objects.all() | ||||||
|         return self.render_to_response(dict(members=members)) |         return self.render_to_response(dict(members=members)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class MemberViewSet(viewsets.ModelViewSet): | ||||||
|  |     queryset = Member.objects.all() | ||||||
|  |     serializer_class = MemberSerializer | ||||||
|  | |||||||
| @ -1,48 +1,50 @@ | |||||||
| const path = require("path"); | const path = require('path'); | ||||||
| const webpack = require('webpack'); | const webpack = require('webpack'); | ||||||
| const BundleTracker = require('webpack-bundle-tracker'); | const BundleTracker = require('webpack-bundle-tracker'); | ||||||
| const ExtractTextPlugin = require('extract-text-webpack-plugin'); | const ExtractTextPlugin = require('extract-text-webpack-plugin'); | ||||||
| const autoprefixer =  require('autoprefixer'); | const autoprefixer = require('autoprefixer'); | ||||||
| 
 | 
 | ||||||
| module.exports = { | module.exports = { | ||||||
|     context: __dirname, |   context: __dirname, | ||||||
|     devtool: 'inline-source-map', |   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', | ||||||
|  |   }, | ||||||
| 
 | 
 | ||||||
|     output: { |   plugins: [ | ||||||
|         path: path.resolve('./assets/bundles/'), |     new BundleTracker({ filename: './webpack-stats.json' }), | ||||||
|         filename: "[name]-[hash].js" |     new ExtractTextPlugin('react-toolbox.css', { allChunks: true }), | ||||||
|     }, |     new webpack.NoErrorsPlugin(), | ||||||
|  |   ], | ||||||
| 
 | 
 | ||||||
|     plugins: [ |   module: { | ||||||
|         new BundleTracker({filename: './webpack-stats.json'}), |     loaders: [ | ||||||
|         new ExtractTextPlugin('react-toolbox.css', { allChunks: true }), |       { | ||||||
|         new webpack.NoErrorsPlugin() |         test: /\.jsx?$/, | ||||||
|  |         exclude: /node_modules/, | ||||||
|  |         loader: 'babel-loader', | ||||||
|  |         query: { | ||||||
|  |           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'), | ||||||
|  |       }, | ||||||
|     ], |     ], | ||||||
| 
 |   }, | ||||||
|     module: { |   resolve: { | ||||||
|         loaders: [ |     modulesDirectories: [ | ||||||
|             { |       'node_modules', | ||||||
|                 test: /\.jsx?$/, |       'bower_components', | ||||||
|                 exclude: /node_modules/, |       path.resolve(__dirname, './node_modules'), | ||||||
|                 loader: 'babel-loader', |     ], | ||||||
|                 query: { |     extensions: ['', '.js', '.jsx', '.scss'], | ||||||
|                     presets: ['es2015', 'stage-0', 'react'] |   }, | ||||||
|                 } |   postcss: [autoprefixer], | ||||||
|             }, | }; | ||||||
|             { |  | ||||||
|                 test: /(\.scss|\.css)$/, |  | ||||||
|                 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') |  | ||||||
|         ], |  | ||||||
|         extensions: ['', '.js', '.jsx', '.scss'] |  | ||||||
|     }, |  | ||||||
|     postcss: [autoprefixer] |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -6,11 +6,14 @@ const ExtractTextPlugin = require('extract-text-webpack-plugin'); | |||||||
| var config = require('./webpack.base.config.js') | var config = require('./webpack.base.config.js') | ||||||
| 
 | 
 | ||||||
| // Use webpack dev server
 | // Use webpack dev server
 | ||||||
| config.entry = [ | config.entry = { | ||||||
|     'webpack-dev-server/client?http://webpack.docker:3000', |     webpack: [ | ||||||
|     'webpack/hot/only-dev-server', |         'webpack-dev-server/client?http://webpack.docker:3000', | ||||||
|     './assets/js/index' |         'webpack/hot/only-dev-server', | ||||||
| ] |     ], | ||||||
|  |     signin: './assets/js/index', | ||||||
|  |     members: './assets/js/members/index', | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| // override django's STATIC_URL for webpack bundles
 | // override django's STATIC_URL for webpack bundles
 | ||||||
| config.output.publicPath = 'http://webpack.docker:3000/assets/bundles/' | config.output.publicPath = 'http://webpack.docker:3000/assets/bundles/' | ||||||
|  | |||||||
| @ -11,3 +11,4 @@ djangorestframework | |||||||
| django-webpack-loader | django-webpack-loader | ||||||
| requests | requests | ||||||
| PyYAML | PyYAML | ||||||
|  | djangorestframework-jwt==1.9.0 | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user