Compare commits

...

31 Commits
4.0.1 ... 7.3.0

Author SHA1 Message Date
Alberto
efd859ba83 7.3.0 2017-01-18 16:33:09 +00:00
Alberto
72dae24ebe 7.2.0 2017-01-17 17:05:38 +00:00
ceolter
0aa2f7a2be Merge remote-tracking branch 'origin/master' 2017-01-03 14:13:12 +00:00
ceolter
6a94aee204 fixed example, the percent bar was not correct height 2017-01-03 14:13:03 +00:00
Sean Landsman
e0dfa732c7 7.1.1 2016-12-22 15:16:58 +00:00
Sean Landsman
d26876876f 7.0.0 2016-11-30 16:41:47 +00:00
Sean Landsman
3148c047b6 6.4.0 2016-11-11 13:42:22 +00:00
seanlandsman
33b006b783 6.3.0 2016-11-04 15:45:15 +00:00
seanlandsman
3b5ee65790 Release of 6.2.0 2016-10-11 16:13:26 +01:00
Sean Landsman
4829b2f6cd Release of 6.1.0 2016-10-03 13:02:15 +01:00
Sean Landsman
67af64ea9d Release of 6.0.1 2016-09-15 15:05:56 +01:00
ceolter
99dfa1e4f9 new component model 2016-09-14 15:58:15 +01:00
ceolter
1e9ef53316 new component model 2016-09-14 15:02:35 +01:00
ceolter
b5949d8d5d new component model 2016-09-14 12:15:30 +01:00
ceolter
b4b8c85172 new component model 2016-09-12 22:20:20 +01:00
ceolter
c703eaf89c new component model 2016-09-12 13:45:37 +01:00
ceolter
8804a01de3 release 5.4.0 2016-09-09 14:21:19 +01:00
ceolter
0dc55bd393 release 5.3.2 2016-09-02 16:45:32 +01:00
ceolter
eee08a9284 release 5.3.2 2016-09-02 16:43:50 +01:00
ceolter
68ba430896 release 5.3.2 2016-09-02 16:43:20 +01:00
ceolter
5a8da199c2 release 5.3.0 2016-08-30 17:14:43 +01:00
ceolter
bc2a8d959c release 5.2.x 2016-08-18 09:38:28 +01:00
ceolter
3fb8e85645 release 5.1.x 2016-08-12 17:09:29 +01:00
ceolter
46aeeb228a fixed rendering issues when grouping was set 2016-07-28 16:10:08 +01:00
ceolter
44c06b41e3 release of 5.0.0 2016-07-10 11:19:28 +01:00
ceolter
f984c4175b Merge remote-tracking branch 'origin/master' 2016-06-23 11:11:14 +01:00
ceolter
d94d79c1b1 release of 5.0.0-alpha.0 2016-06-23 11:11:05 +01:00
Niall Crosby
cd7c199f4d Merge pull request #9 from cumanacr/master
fix: filename references
2016-06-01 10:01:49 +01:00
Cristian Umaña
49fca88d58 fix: filename references 2016-05-30 13:53:15 -06:00
ceolter
a22d3da8ce release of 4.2.x 2016-05-27 17:23:27 +01:00
Ceolter
c6d9f41393 changes to match v4.0.0 of ag-Grid 2016-04-25 20:30:04 +01:00
20 changed files with 355 additions and 95 deletions

View File

@@ -2,10 +2,15 @@
ag-Grid React Example ag-Grid React Example
============== ==============
Example of running ag-Grid inside React application. Examples of running ag-Grid inside React application.
See the [www.ag-grid.com](http://www.ag-grid.com). See the [www.ag-grid.com](http://www.ag-grid.com).
There are two examples:
1. standard - shows a typical grid demonstrating many ag-Grid features
2. large - shows a very large grid (767 columns and 1,000 rows) using React cell renderers
Building Building
============== ==============
@@ -13,6 +18,5 @@ Building
To build: To build:
- `npm install` - `npm install`
- `npm install webpack -g` - `npm install webpack -g`
- `npm start` - `npm run standard` or `npm run large`
- navigate to localhost:8080 - navigate to localhost:8080

View File

@@ -1,5 +1,8 @@
<html> <html>
<!-- This index file is common for both the standard and large examples. As to which project you are running
depends on whether you use 'npm run standard' or 'npm run large' -->
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<script type="text/javascript" src="dist/bundle.js" charset="utf-8"></script> <script type="text/javascript" src="dist/bundle.js" charset="utf-8"></script>

View File

@@ -1,10 +1,11 @@
{ {
"name": "ag-grid-react-example", "name": "ag-grid-react-example",
"version": "4.0.0", "version": "7.3.0",
"description": "Example Reach applicaiton using ag-Grid.", "description": "Example Reach applicaiton using ag-Grid.",
"main": "dist/ag-grid-react-example.js", "main": "dist/ag-grid-react-example.js",
"scripts": { "scripts": {
"start": "webpack-dev-server --progress --colors --hot --inline" "standard": "webpack-dev-server --config webpack.config.standard.js --progress --colors --hot --inline",
"large": "webpack-dev-server --config webpack.config.large.js --progress --colors --hot --inline"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -26,6 +27,7 @@
"babel-loader": "6.2.1", "babel-loader": "6.2.1",
"babel-preset-es2015": "6.3.13", "babel-preset-es2015": "6.3.13",
"babel-preset-react": "6.3.13", "babel-preset-react": "6.3.13",
"babel-core": "^6.0.0",
"css-loader": "0.23.1", "css-loader": "0.23.1",
"style-loader": "0.13.0", "style-loader": "0.13.0",
"webpack": "1.12.11", "webpack": "1.12.11",
@@ -34,8 +36,8 @@
"dependencies": { "dependencies": {
"react": "0.14.6", "react": "0.14.6",
"react-dom": "0.14.6", "react-dom": "0.14.6",
"ag-grid": "4.0.x", "ag-grid": "7.3.x",
"ag-grid-enterprise": "4.0.x", "ag-grid-enterprise": "7.3.x",
"ag-grid-react": "4.0.x" "ag-grid-react": "7.3.x"
} }
} }

18
src-large/index.js Normal file
View File

@@ -0,0 +1,18 @@
'use strict';
import ReactDOM from 'react-dom';
import React from 'react';
import LargeGrid from './largeGrid.jsx';
// is there a better way of doing this?
import 'ag-grid-root/dist/styles/ag-grid.css';
import 'ag-grid-root/dist/styles/theme-fresh.css';
// waiting for dom to load before booting react. we could alternatively
// put the index.js reference at the end fo the index.html, but i prefer this way.
document.addEventListener('DOMContentLoaded', ()=> {
var container = document.getElementById('myAppContainer');
ReactDOM.render(
React.createElement(LargeGrid),
container
);
});

71
src-large/largeGrid.jsx Normal file
View File

@@ -0,0 +1,71 @@
import React from 'react';
import {reactCellRendererFactory} from 'ag-grid-react';
import SimpleCellRenderer from './simpleCellRenderer.jsx';
import {AgGridReact} from 'ag-grid-react';
// put this line in to use ag-Grid enterprise
// import 'ag-grid-enterprise';
export default class MyApp extends React.Component {
constructor() {
super();
this.createColumnNames();
this.state = {
columnDefs: this.createColumnDefs(),
rowData: this.createRowData()
};
}
createColumnNames() {
// creates column names by iterating the alphabet twice, eg {'aa','ab','ac',.....'zz'}
var alphabet = 'abcdefghijklmnopqrstuvwxyz'.split('');
this.columnNames = [];
alphabet.forEach( letter1 => {
alphabet.forEach( letter2 => {
this.columnNames.push(letter1 + letter2);
});
});
}
createRowData() {
var rowData = [];
for (var i = 0; i<1000; i++) {
var item = {};
this.columnNames.forEach( colName => {
item[colName] = '('+colName.toUpperCase()+','+i+')'
});
rowData.push(item);
}
return rowData;
}
createColumnDefs() {
var columnDefs = [];
this.columnNames.forEach( colName => {
columnDefs.push({
headerName: colName.toUpperCase(),
field: colName,
cellRendererFramework: SimpleCellRenderer,
width: 100
});
});
return columnDefs;
}
render() {
return (
<div style={{height: '100%'}} className="ag-fresh">
<AgGridReact columnDefs={this.state.columnDefs} rowData={this.state.rowData} />
</div>
);
}
}

View File

@@ -0,0 +1,15 @@
import React from 'react';
export default class SimpleCellRenderer extends React.Component {
render() {
// the class below does nothing, it's just for testing, so we can inspect the dom of
// the result and looking for it, to validate that this cellRenderer is actually getting used.
return (
<span className="simple-cell-renderer">{this.props.value}</span>
);
}
}
SimpleCellRenderer.propTypes = {
params: React.PropTypes.object
};

View File

@@ -1,8 +1,7 @@
import SkillsCellRenderer from './SkillsCellRenderer.jsx'; import SkillsCellRenderer from './SkillsCellRenderer.jsx';
import NameCellEditor from './NameCellEditor.jsx';
import ProficiencyCellRenderer from './ProficiencyCellRenderer.jsx'; import ProficiencyCellRenderer from './ProficiencyCellRenderer.jsx';
import RefData from './RefData'; import RefData from './RefData';
import {reactCellRendererFactory} from 'ag-grid-react';
import {reactFilterFactory} from 'ag-grid-react';
import SkillsFilter from './SkillsFilter.jsx'; import SkillsFilter from './SkillsFilter.jsx';
import ProficiencyFilter from './ProficiencyFilter.jsx'; import ProficiencyFilter from './ProficiencyFilter.jsx';
@@ -16,10 +15,13 @@ export default class ColDefFactory {
{ {
headerName: 'Employee', headerName: 'Employee',
children: [ children: [
{headerName: "Name", field: "name", {headerName: "Name", field: "name", enableRowGroup: true, enablePivot: true,
width: 150, pinned: true}, width: 150, pinned: true, editable: true,
{headerName: "Country", field: "country", width: 150, // use a React cellEditor
// not bothering with React for country, as it's a simple HTML string cellEditorFramework: NameCellEditor
},
{headerName: "Country", field: "country", width: 150, enableRowGroup: true, enablePivot: true,
// an example of using a non-React cell renderer
cellRenderer: countryCellRenderer, pinned: true, cellRenderer: countryCellRenderer, pinned: true,
filterParams: {cellRenderer: countryCellRenderer, cellHeight: 20}}, filterParams: {cellRenderer: countryCellRenderer, cellHeight: 20}},
] ]
@@ -27,17 +29,18 @@ export default class ColDefFactory {
{ {
headerName: 'IT Skills', headerName: 'IT Skills',
children: [ children: [
{headerName: "Skills", width: 125, suppressSorting: true, field: 'skills', {headerName: "Skills", width: 125, suppressSorting: true, field: 'skills', enableRowGroup: true, enablePivot: true,
// using ag-Grid's React cellRenderer factory // supply a React component
cellRenderer: reactCellRendererFactory(SkillsCellRenderer), cellRendererFramework: SkillsCellRenderer,
// using ag-Grid's React filter factory // supply a React component
filter: reactFilterFactory(SkillsFilter) filterFramework: SkillsFilter
}, },
{headerName: "Proficiency", field: "proficiency", filter: 'number', width: 120, {headerName: "Proficiency", field: "proficiency", width: 120, enableValue: true,
// using ag-Grid's React cellRenderer factory // supply a React component
cellRenderer: reactCellRendererFactory(ProficiencyCellRenderer), cellRendererFramework: ProficiencyCellRenderer,
// using ag-Grid's React filter factory // supply a React component
filter: reactFilterFactory(ProficiencyFilter)} filterFramework: ProficiencyFilter
}
] ]
}, },
{ {
@@ -56,8 +59,12 @@ export default class ColDefFactory {
// this is a simple cell renderer, putting together static html, no // this is a simple cell renderer, putting together static html, no
// need to use React for it. // need to use React for it.
function countryCellRenderer(params) { function countryCellRenderer(params) {
if (params.value) {
var flag = "<img border='0' width='15' height='10' " + var flag = "<img border='0' width='15' height='10' " +
"style='margin-bottom: 2px' src='http://flags.fmcdn.net/data/flags/mini/" "style='margin-bottom: 2px' src='http://flags.fmcdn.net/data/flags/mini/"
+ RefData.COUNTRY_CODES[params.value] + ".png'>"; + RefData.COUNTRY_CODES[params.value] + ".png'>";
return flag + " " + params.value; return flag + " " + params.value;
} else {
return null;
}
} }

View File

@@ -0,0 +1,117 @@
import React from 'react';
import RefData from './RefData';
var KEY_BACKSPACE = 8;
var KEY_DELETE = 46;
var KEY_F2 = 113;
// cell renderer for the proficiency column. this is a very basic cell editor,
export default class NameCellEditor extends React.Component {
constructor(props) {
super(props);
// the entire ag-Grid properties are passed as one single object inside the params
this.state = this.createInitialState(props);
}
// work out how to present the data based on what the user hit. you don't need to do any of
// this for your ag-Grid cellEditor to work, however it makes sense to do this so the user
// experience is similar to Excel
createInitialState(props) {
var startValue;
var putCursorAtEndOnFocus = false;
var highlightAllOnFocus = false;
if (props.keyPress === KEY_BACKSPACE || props.keyPress === KEY_DELETE) {
// if backspace or delete pressed, we clear the cell
startValue = '';
} else if (props.charPress) {
// if a letter was pressed, we start with the letter
startValue = props.charPress;
} else {
// otherwise we start with the current value
startValue = props.value;
if (props.keyPress === KEY_F2) {
this.putCursorAtEndOnFocus = true;
} else {
this.highlightAllOnFocus = true;
}
}
return {
value: startValue,
putCursorAtEndOnFocus: putCursorAtEndOnFocus,
highlightAllOnFocus: highlightAllOnFocus
}
}
render() {
return (
<input ref="textField" value={this.state.value} onChange={this.onChangeListener.bind(this)}/>
);
}
onChangeListener(event) {
// if doing React, you will probably be using a library for managing immutable
// objects better. to keep this example simple, we don't use one.
var newState = {
value: event.target.value,
putCursorAtEndOnFocus: this.state.putCursorAtEndOnFocus,
highlightAllOnFocus: this.state.highlightAllOnFocus
};
this.setState(newState);
}
// called by ag-Grid, to get the final value
getValue() {
return this.state.value;
}
// cannot use componentDidMount because although the component might be ready from React's point of
// view, it may not yet be in the browser (put in by ag-Grid) so focus will not work
afterGuiAttached() {
// get ref from React component
var eInput = this.refs.textField;
eInput.focus();
if (this.highlightAllOnFocus) {
eInput.select();
} else {
// when we started editing, we want the carot at the end, not the start.
// this comes into play in two scenarios: a) when user hits F2 and b)
// when user hits a printable character, then on IE (and only IE) the carot
// was placed after the first character, thus 'apply' would end up as 'pplea'
var length = eInput.value ? eInput.value.length : 0;
if (length > 0) {
eInput.setSelectionRange(length, length);
}
}
}
// if we want the editor to appear in a popup, then return true.
isPopup() {
return false;
}
// return true here if you don't want to allow editing on the cell.
isCancelBeforeStart() {
return false;
}
// just to demonstrate, if you type in 'cancel' then the edit will not take effect
isCancelAfterEnd() {
if (this.state.value && this.state.value.toUpperCase()==='CANCEL') {
return true;
} else {
return false;
}
}
}
// the grid will always pass in one props called 'params',
// which is the grid passing you the params for the cellRenderer.
// this piece is optional. the grid will always pass the 'params'
// props, so little need for adding this validation meta-data.
NameCellEditor.propTypes = {
params: React.PropTypes.object
};

View File

@@ -0,0 +1,25 @@
import React from 'react';
import RefData from './RefData';
// cell renderer for the proficiency column. this is a very basic cell renderer,
// it is arguable that we should not of used React and just returned a string of
// html as a normal ag-Grid cellRenderer.
export default class ProficiencyCellRenderer extends React.Component {
render() {
var backgroundColor;
if (this.props.value < 20) {
backgroundColor = 'red';
} else if (this.props.value < 60) {
backgroundColor = '#ff9900';
} else {
backgroundColor = '#00A000';
}
return (
<div className="div-percent-bar" style={{ width: this.props.value + '%', backgroundColor: backgroundColor }}>
<div className="div-percent-value">{this.props.value}%</div>
</div>
);
}
}

View File

@@ -1,5 +1,4 @@
import React from 'react'; import React from 'react';
import RefData from './RefData';
var PROFICIENCY_NAMES = ['No Filter', 'Above 40%', 'Above 60%', 'Above 80%']; var PROFICIENCY_NAMES = ['No Filter', 'Above 40%', 'Above 60%', 'Above 80%'];
@@ -7,22 +6,16 @@ var PROFICIENCY_NAMES = ['No Filter', 'Above 40%', 'Above 60%', 'Above 80%'];
// a React filter component with ag-Grid. // a React filter component with ag-Grid.
export default class ProficiencyFilter extends React.Component { export default class ProficiencyFilter extends React.Component {
constructor() { constructor(props) {
super(); super();
this.state = { this.state = {
selected: PROFICIENCY_NAMES[0] selected: PROFICIENCY_NAMES[0]
}; };
} }
// called by agGrid
init(params) {
this.filterChangedCallback = params.filterChangedCallback;
this.valueGetter = params.valueGetter;
}
// called by agGrid // called by agGrid
doesFilterPass(params) { doesFilterPass(params) {
var value = this.valueGetter(params); var value = this.props.valueGetter(params);
var valueAsNumber = parseFloat(value); var valueAsNumber = parseFloat(value);
switch (this.state.selected) { switch (this.state.selected) {
@@ -40,11 +33,9 @@ export default class ProficiencyFilter extends React.Component {
onButtonPressed(name) { onButtonPressed(name) {
console.log(name); console.log(name);
this.setState({ var newState = {selected: name};
selected: name // set the state, and once it is done, then call filterChangedCallback
}, ()=> { this.setState(newState, this.props.filterChangedCallback);
this.filterChangedCallback();
});
console.log(name); console.log(name);
} }

View File

@@ -5,9 +5,9 @@ export default class SkillsCellRenderer extends React.Component {
render() { render() {
var skills = []; var skills = [];
var rowData = this.props.params.data; var rowData = this.props.data;
RefData.IT_SKILLS.forEach( (skill) => { RefData.IT_SKILLS.forEach( (skill) => {
if (rowData.skills[skill]) { if (rowData && rowData.skills && rowData.skills[skill]) {
skills.push(<img key={skill} src={'images/skills/' + skill + '.png'} width={16} title={skill} />); skills.push(<img key={skill} src={'images/skills/' + skill + '.png'} width={16} title={skill} />);
} }
}); });

View File

@@ -8,11 +8,9 @@ import RefData from './RefData';
// React design skills. // React design skills.
export default class SkillsFilter extends React.Component { export default class SkillsFilter extends React.Component {
constructor() { constructor(props) {
super(); super(props);
this.state = { this.state = {
skills: RefData.IT_SKILLS,
skillNames: RefData.IT_SKILLS_NAMES,
android: false, android: false,
css: false, css: false,
html5: false, html5: false,
@@ -21,9 +19,24 @@ export default class SkillsFilter extends React.Component {
}; };
} }
// called by agGrid getModel() {
init(params) { return {
this.filterChangedCallback = params.filterChangedCallback; android: this.state.android,
css: this.state.css,
html5: this.state.html5,
mac: this.state.mac,
windows: this.state.windows
}
}
setModel(model) {
this.setState({
android: model.android,
css: model.css,
html5: model.html5,
mac: model.mac,
windows: model.windows
});
} }
// called by agGrid // called by agGrid
@@ -32,7 +45,7 @@ export default class SkillsFilter extends React.Component {
var rowSkills = params.data.skills; var rowSkills = params.data.skills;
var passed = true; var passed = true;
this.state.skills.forEach( (skill) => { RefData.IT_SKILLS.forEach( (skill) => {
if (this.state[skill]) { if (this.state[skill]) {
if (!rowSkills[skill]) { if (!rowSkills[skill]) {
passed = false; passed = false;
@@ -54,15 +67,16 @@ export default class SkillsFilter extends React.Component {
var newValue = event.target.checked; var newValue = event.target.checked;
var newModel = {}; var newModel = {};
newModel[skill] = newValue; newModel[skill] = newValue;
this.setState(newModel, ()=> {this.filterChangedCallback();} ); // set the state, and once it is done, then call filterChangedCallback
this.setState(newModel, this.props.filterChangedCallback );
} }
render() { render() {
var skillsTemplates = []; var skillsTemplates = [];
this.state.skills.forEach( (skill, index) => { RefData.IT_SKILLS.forEach( (skill, index) => {
var skillName = this.state.skillNames[index]; var skillName = RefData.IT_SKILLS_NAMES[index];
var template = ( var template = (
<label key={skill} style={{border: '1px solid lightgrey', margin: 4, padding: 4, display: 'inline-block'}}> <label key={skill} style={{border: '1px solid lightgrey', margin: 4, padding: 4, display: 'inline-block'}}>
<span> <span>
@@ -91,7 +105,6 @@ export default class SkillsFilter extends React.Component {
// these are other method that agGrid calls that we // these are other method that agGrid calls that we
// could of implemented, but they are optional and // could of implemented, but they are optional and
// we have no use for them in this particular filter. // we have no use for them in this particular filter.
//getApi() {}
//afterGuiAttached(params) {} //afterGuiAttached(params) {}
//onNewRowsLoaded() {} //onNewRowsLoaded() {}
//onAnyFilterChanged() {} //onAnyFilterChanged() {}

View File

@@ -2,7 +2,7 @@
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import React from 'react'; import React from 'react';
import MyApp from './MyApp.jsx'; import MyApp from './myApp.jsx';
// is there a better way of doing this? // is there a better way of doing this?
import 'ag-grid-root/dist/styles/ag-grid.css'; import 'ag-grid-root/dist/styles/ag-grid.css';
import 'ag-grid-root/dist/styles/theme-fresh.css'; import 'ag-grid-root/dist/styles/theme-fresh.css';

View File

@@ -10,7 +10,7 @@ label {
.div-percent-bar { .div-percent-bar {
display: inline-block; display: inline-block;
height: 100%; height: 20px;
position: relative; position: relative;
} }

View File

@@ -4,7 +4,7 @@ import {AgGridReact} from 'ag-grid-react';
import RefData from './RefData'; import RefData from './RefData';
import RowDataFactory from './RowDataFactory'; import RowDataFactory from './RowDataFactory';
import ColDefFactory from './ColDefFactory.jsx'; import ColDefFactory from './ColDefFactory.jsx';
import './MyApp.css'; import './myApp.css';
// take this line out if you do not want to use ag-Grid-Enterprise // take this line out if you do not want to use ag-Grid-Enterprise
import 'ag-grid-enterprise'; import 'ag-grid-enterprise';
@@ -162,7 +162,8 @@ export default class MyApp extends React.Component {
columnDefs={this.state.columnDefs} columnDefs={this.state.columnDefs}
rowData={this.state.rowData} rowData={this.state.rowData}
// no binding, just providing harde coded strings for the properties // no binding, just providing hard coded strings for the properties
suppressRowClickSelection="true"
rowSelection="multiple" rowSelection="multiple"
enableColResize="true" enableColResize="true"
enableSorting="true" enableSorting="true"

View File

@@ -1,34 +0,0 @@
import React from 'react';
import RefData from './RefData';
// cell renderer for the proficiency column. this is a very basic cell renderer,
// it is arguable that we should not of used React and just returned a string of
// html as a normal ag-Grid cellRenderer.
export default class ProficiencyCellRenderer extends React.Component {
render() {
var params = this.props.params;
var backgroundColor;
if (params.value < 20) {
backgroundColor = 'red';
} else if (params.value < 60) {
backgroundColor = '#ff9900';
} else {
backgroundColor = '#00A000';
}
return (
<div className="div-percent-bar" style={{ width: params.value + '%', backgroundColor: backgroundColor }}>
<div className="div-percent-value">{params.value}%</div>
</div>
);
}
}
// the grid will always pass in one props called 'params',
// which is the grid passing you the params for the cellRenderer.
// this piece is optional. the grid will always pass the 'params'
// props, so little need for adding this validation meta-data.
ProficiencyCellRenderer.propTypes = {
params: React.PropTypes.object
};

View File

@@ -1,5 +1,5 @@
module.exports = { module.exports = {
entry: "./src/index.js", entry: "./src-large/index.js",
output: { output: {
path: __dirname, path: __dirname,
filename: "dist/bundle.js" filename: "dist/bundle.js"

View File

@@ -0,0 +1,27 @@
module.exports = {
entry: "./src-standard/index.js",
output: {
path: __dirname,
filename: "dist/bundle.js"
},
module: {
loaders: [
{
test: /\.css$/,
loader: "style!css"
},
{
test: /\.js$|\.jsx$/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015']
}
}
]
},
resolve: {
alias: {
"ag-grid-root" : __dirname + "/node_modules/ag-grid"
}
}
};