Compare commits
85 Commits
AG-38_ARIA
...
b17.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bd8d4c987 | ||
|
|
318f78de84 | ||
|
|
9ca52a727d | ||
|
|
56ccdd028c | ||
|
|
a5ccb6d622 | ||
|
|
25e1f1c184 | ||
|
|
8dd0f96b32 | ||
|
|
cf0796eb84 | ||
|
|
a64626e67e | ||
|
|
95445e558c | ||
|
|
79a6206026 | ||
|
|
f8ac0e5c98 | ||
|
|
06d9e88e88 | ||
|
|
f860a740f3 | ||
|
|
90ec337474 | ||
|
|
05d4341dfc | ||
|
|
df77361fd4 | ||
|
|
983b5974cf | ||
|
|
b030235bbc | ||
|
|
351d93b8fb | ||
|
|
43af1237bd | ||
|
|
fc76e85d77 | ||
|
|
6979c51eaf | ||
|
|
f035ee7a9d | ||
|
|
a982e0f2a7 | ||
|
|
cbb4a31be6 | ||
|
|
d2b92b4c9a | ||
|
|
c8267730bf | ||
|
|
3992e3e928 | ||
|
|
8409183d6b | ||
|
|
7075f57d88 | ||
|
|
ad6bc068b2 | ||
|
|
c4310c2768 | ||
|
|
2228a8d0c9 | ||
|
|
966fa0fe69 | ||
|
|
9528d5a5bc | ||
|
|
3b5eaac21a | ||
|
|
73cc989512 | ||
|
|
5a45846cb7 | ||
|
|
2d8d5b125e | ||
|
|
818b7798ee | ||
|
|
15ba8d7e60 | ||
|
|
eab958c3e9 | ||
|
|
3a17b7f638 | ||
|
|
734d39e2d7 | ||
|
|
0d7cace354 | ||
|
|
fa0881bfcf | ||
|
|
62b9e3582a | ||
|
|
949797d4be | ||
|
|
a869fe3819 | ||
|
|
c611af4f39 | ||
|
|
7cab3190ae | ||
|
|
71fe653fcb | ||
|
|
ba1c213ce0 | ||
|
|
46217c9ad7 | ||
|
|
017642e4d7 | ||
|
|
79b0eda61b | ||
|
|
a70f248af5 | ||
|
|
32142b435b | ||
|
|
d71781899d | ||
|
|
9560f86bf5 | ||
|
|
9f4b270884 | ||
|
|
e5627d8b9f | ||
|
|
f8f0c21af2 | ||
|
|
b54d549959 | ||
|
|
464a0ea9f4 | ||
|
|
675cbe497c | ||
|
|
a4dbbf529d | ||
|
|
89d36b0bf4 | ||
|
|
9ff1a54e57 | ||
|
|
7ed2666aaf | ||
|
|
76258a8ee4 | ||
|
|
7564f1597a | ||
|
|
ef44ebc166 | ||
|
|
9c3c7a77c0 | ||
|
|
f8b8a0b066 | ||
|
|
e1871affe3 | ||
|
|
3226c0d6ba | ||
|
|
1b3fc21107 | ||
|
|
587af2e888 | ||
|
|
4ef1959a52 | ||
|
|
ddefba039a | ||
|
|
06ebb8bf18 | ||
|
|
e183a0503a | ||
|
|
19771949cb |
11
README.md
@@ -4,7 +4,14 @@ ag-Grid React Example
|
|||||||
|
|
||||||
Examples 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 [www.ag-grid.com](http://www.ag-grid.com) for an overview and full documentation.
|
||||||
|
|
||||||
|
Frameworks Supported
|
||||||
|
====================
|
||||||
|
Framework specific Getting Started guides:
|
||||||
|
[Angular 1](https://www.ag-grid.com/best-angularjs-data-grid/) | [Angular 2](https://www.ag-grid.com/best-angular-2-data-grid/) | [Aurelia](https://www.ag-grid.com/best-aurelia-data-grid/)
|
||||||
|
[Javascript](https://www.ag-grid.com/best-javascript-data-grid/) | [React](https://www.ag-grid.com/best-react-data-grid/) | [TypeScript](https://www.ag-grid.com/ag-grid-typescript-webpack-2/)
|
||||||
|
[VueJS](https://www.ag-grid.com/best-vuejs-data-grid/) | [Web Components](https://www.ag-grid.com/best-web-component-data-grid/)
|
||||||
|
|
||||||
There are two examples:
|
There are two examples:
|
||||||
|
|
||||||
@@ -18,5 +25,5 @@ Building
|
|||||||
To build:
|
To build:
|
||||||
- `npm install`
|
- `npm install`
|
||||||
- `npm install webpack -g`
|
- `npm install webpack -g`
|
||||||
- `npm run standard` or `npm run large`
|
- `npm run examples`, `npm run large` or `npm run trader`
|
||||||
- navigate to localhost:8080
|
- navigate to localhost:8080
|
||||||
|
|||||||
44
config/webpack.config.examples.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const SRC_DIR = path.resolve(__dirname, '../src-examples');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
entry: SRC_DIR + "/index.js",
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, '../'),
|
||||||
|
filename: "dist/react-examples.js"
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
loaders: [
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
loader: "style!css"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.js$|\.jsx$/,
|
||||||
|
include: SRC_DIR,
|
||||||
|
loader: 'babel-loader',
|
||||||
|
query: {
|
||||||
|
presets: ['react', 'es2015', 'stage-0']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
|
||||||
|
loader: 'file?name=[path]/[name].[ext]'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
"ag-grid": path.resolve('./node_modules/ag-grid'),
|
||||||
|
"ag-grid-enterprise": path.resolve('./node_modules/ag-grid-enterprise'),
|
||||||
|
react: path.resolve('./node_modules/react')
|
||||||
|
},
|
||||||
|
extensions: ['', '.js', '.jsx']
|
||||||
|
},
|
||||||
|
devServer: {
|
||||||
|
historyApiFallback: true,
|
||||||
|
contentBase: './',
|
||||||
|
hot: true
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
const webpack = require('webpack');
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const SRC_DIR = path.resolve(__dirname, 'src-trader-dashboard');
|
const SRC_DIR = path.resolve(__dirname, '../src-large-data');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: SRC_DIR + "/index.js",
|
entry: SRC_DIR + "/index.js",
|
||||||
output: {
|
output: {
|
||||||
path: __dirname,
|
path: path.resolve(__dirname, '../'),
|
||||||
filename: "dist/bundle.js"
|
filename: "dist/react-large.js"
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
loaders: [
|
loaders: [
|
||||||
@@ -20,14 +19,17 @@ module.exports = {
|
|||||||
include: SRC_DIR,
|
include: SRC_DIR,
|
||||||
loader: 'babel-loader',
|
loader: 'babel-loader',
|
||||||
query: {
|
query: {
|
||||||
presets: ['react', 'es2015']
|
presets: ['react', 'es2015', 'stage-0']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
"ag-grid-root" : __dirname + "/node_modules/ag-grid"
|
"ag-grid": path.resolve('./node_modules/ag-grid'),
|
||||||
}
|
"ag-grid-enterprise": path.resolve('./node_modules/ag-grid-enterprise'),
|
||||||
|
react: path.resolve('./node_modules/react')
|
||||||
|
},
|
||||||
|
extensions: ['', '.js', '.jsx']
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
35
config/webpack.config.trader.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const SRC_DIR = path.resolve(__dirname, '../src-trader-dashboard');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
entry: SRC_DIR + "/index.js",
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, '../'),
|
||||||
|
filename: "dist/react-trader.js"
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
loaders: [
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
loader: "style!css"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.js$|\.jsx$/,
|
||||||
|
include: SRC_DIR,
|
||||||
|
loader: 'babel-loader',
|
||||||
|
query: {
|
||||||
|
presets: ['react', 'es2015', 'stage-0']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
"ag-grid": path.resolve('./node_modules/ag-grid'),
|
||||||
|
"ag-grid-enterprise": path.resolve('./node_modules/ag-grid-enterprise'),
|
||||||
|
react: path.resolve('./node_modules/react')
|
||||||
|
},
|
||||||
|
extensions: ['', '.js', '.jsx']
|
||||||
|
}
|
||||||
|
};
|
||||||
26
gulpfile.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
const gulp = require('gulp');
|
||||||
|
const gulpTypescript = require('gulp-typescript');
|
||||||
|
const merge = require('merge2');
|
||||||
|
|
||||||
|
gulp.task('watch', watchTask);
|
||||||
|
gulp.task('rebuild-ag-grid-react', rebuildAgGridReact);
|
||||||
|
|
||||||
|
const tsConfig = '../ag-grid-react/tsconfig.json';
|
||||||
|
const tsProject = gulpTypescript.createProject(tsConfig);
|
||||||
|
|
||||||
|
function rebuildAgGridReact() {
|
||||||
|
const tsResult = gulp
|
||||||
|
.src('../ag-grid-react/src/**/*.ts')
|
||||||
|
.pipe(tsProject());
|
||||||
|
|
||||||
|
return merge([
|
||||||
|
tsResult.dts
|
||||||
|
.pipe(gulp.dest('node_modules/ag-grid-react/lib')),
|
||||||
|
tsResult.js
|
||||||
|
.pipe(gulp.dest('node_modules/ag-grid-react/lib'))
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function watchTask() {
|
||||||
|
gulp.watch(['../ag-grid-react/src/**/*'], rebuildAgGridReact);
|
||||||
|
}
|
||||||
8618
olympicWinners.json
89
package.json
@@ -1,20 +1,29 @@
|
|||||||
{
|
{
|
||||||
"name": "ag-grid-react-example",
|
"name": "ag-grid-react-example",
|
||||||
"version": "10.0.0",
|
"version": "17.0.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": {
|
||||||
"full-width": "webpack-dev-server --config webpack.config.full-width.js --progress --colors --hot --inline",
|
"trader": "webpack-dev-server --content-base src-trader-dashboard/ --config config/webpack.config.trader.js --progress --colors --hot --inline",
|
||||||
"standard": "webpack-dev-server --config webpack.config.standard.js --progress --colors --hot --inline",
|
"examples": "webpack-dev-server --content-base src-examples/ --config config/webpack.config.examples.js --progress --colors --hot --inline",
|
||||||
"grouped": "webpack-dev-server --config webpack.config.grouped.js --progress --colors --hot --inline",
|
"large": "webpack-dev-server --content-base src-large-data/ --config config/webpack.config.large.js --progress --colors --hot --inline",
|
||||||
"trader": "webpack-dev-server --content-base src-trader-dashboard/ --config webpack.config.trader.js --progress --colors --hot --inline",
|
|
||||||
"large": "webpack-dev-server --config webpack.config.large.js --progress --colors --hot --inline",
|
|
||||||
"clean": "rimraf dist",
|
"clean": "rimraf dist",
|
||||||
"build-standard": "npm run clean && webpack --config webpack.config.standard.js --progress --profile --bail"
|
"mkdirs": "mkdirp dist/trader/dist dist/examples/dist",
|
||||||
|
"copy-examples": "ncp src-examples/images dist/examples/images && ncp src-examples/index.html dist/examples/index.html && ncp dist/react-examples.js dist/examples/dist/react-examples.js && ncp src-examples/ dist/examples/src",
|
||||||
|
"copy-trader": "ncp src-trader-dashboard/index.html dist/trader/index.html && ncp dist/react-trader.js dist/trader/dist/react-trader.js",
|
||||||
|
"copy": "npm run copy-examples && npm run copy-trader",
|
||||||
|
"build-large": "webpack --config config/webpack.config.large.js --progress --profile --bail",
|
||||||
|
"build-examples": "webpack --config config/webpack.config.examples.js --progress --profile --bail",
|
||||||
|
"build-dashboard": "webpack --config config/webpack.config.trader.js --progress --profile --bail",
|
||||||
|
"build-all": "npm run build-examples && npm run build-dashboard",
|
||||||
|
"build": "npm run clean && npm run mkdirs && npm run build-all && npm run copy",
|
||||||
|
"copy-to-docs": "ncp dist/examples ../ag-grid-docs/src/framework-examples/react-examples/examples && ncp dist/trader ../ag-grid-docs/src/framework-examples/react-examples/trader",
|
||||||
|
"build-to-docs": "npm run build && npm run copy-to-docs",
|
||||||
|
"start": "npm run examples"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/ceolter/ag-grid-react-example.git"
|
"url": "https://github.com/ag-grid/ag-grid-react-example.git"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
@@ -25,35 +34,43 @@
|
|||||||
"author": "Niall Crosby <niall.crosby@gmail.com>",
|
"author": "Niall Crosby <niall.crosby@gmail.com>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/ceolter/ag-grid-react-example/issues"
|
"url": "https://github.com/ag-grid/ag-grid-react-example/issues"
|
||||||
},
|
},
|
||||||
"homepage": "http://www.ag-grid.com/",
|
"homepage": "http://www.ag-grid.com/",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-core": "6.24.x",
|
"babel-core": "6.24.x",
|
||||||
"babel-loader": "6.4.x",
|
"babel-loader": "6.4.x",
|
||||||
"babel-preset-es2015": "6.24.x",
|
"babel-preset-es2015": "6.24.x",
|
||||||
"babel-preset-react": "6.24.x",
|
"babel-preset-react": "6.24.x",
|
||||||
"babel-preset-stage-0": "6.24.x",
|
"babel-preset-stage-0": "6.24.x",
|
||||||
"babel-preset-stage-1": "6.24.x",
|
"babel-preset-stage-1": "6.24.x",
|
||||||
"css-loader": "0.23.x",
|
"css-loader": "0.23.x",
|
||||||
"style-loader": "0.13.x",
|
"mkdirp": "0.5.1",
|
||||||
"webpack": "1.12.x",
|
"ncp": "2.0.0",
|
||||||
"webpack-dev-server": "1.14.x"
|
"prop-types": "15.6.0",
|
||||||
},
|
"rimraf": "2.5.x",
|
||||||
"dependencies": {
|
"style-loader": "0.13.x",
|
||||||
"ag-grid": "10.0.x",
|
"webpack": "1.12.x",
|
||||||
"ag-grid-enterprise": "10.0.x",
|
"webpack-dev-server": "1.14.x",
|
||||||
"ag-grid-react": "10.0.x",
|
"gulp": "3.9.x",
|
||||||
"bootstrap": "^3.3.7",
|
"gulp-typescript": "3.1.x",
|
||||||
"d3": "4.9.1",
|
"merge2": "1.0.x",
|
||||||
"file-loader": "^0.11.1",
|
"typescript": "2.3.x"
|
||||||
"lodash": "4.17.4",
|
},
|
||||||
"react": "15.5.x",
|
"dependencies": {
|
||||||
"react-dom": "15.5.x",
|
"ag-grid": "^17.0.0",
|
||||||
"react-redux": "5.0.x",
|
"ag-grid-enterprise": "^17.0.0",
|
||||||
"redux": "3.6.x",
|
"ag-grid-react": "^17.0.0",
|
||||||
"rimraf": "2.5.x"
|
"bootstrap": "3.3.7",
|
||||||
}
|
"d3": "4.9.1",
|
||||||
|
"file-loader": "0.11.1",
|
||||||
|
"lodash": "4.17.4",
|
||||||
|
"react": "16.0.0",
|
||||||
|
"react-dom": "16.0.0",
|
||||||
|
"react-dom-factories": "1.0.2",
|
||||||
|
"react-redux": "5.0.x",
|
||||||
|
"react-router-dom": "4.2.x",
|
||||||
|
"redux": "3.6.x",
|
||||||
|
"url-search-params-polyfill": "1.2.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
35
src-examples/App.jsx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import React, {Component} from "react";
|
||||||
|
import {Redirect, Route, Switch} from "react-router-dom";
|
||||||
|
|
||||||
|
import NavItem from "./NavItem";
|
||||||
|
|
||||||
|
import RichGridDeclarativeExample from "./richGridDeclarativeExample/RichGridDeclarativeExample";
|
||||||
|
import SimpleReduxDynamicExample from "./simpleReduxDynamicComponentExample/SimpleReduxExample";
|
||||||
|
|
||||||
|
const SideBar = () => (
|
||||||
|
<div style={{float: "left", width: 335, marginRight: 25}}>
|
||||||
|
<ul className="nav nav-pills nav-stacked">
|
||||||
|
<NavItem to='/rich-grid-declarative'>Rich Grid with Declarative Markup</NavItem>
|
||||||
|
<NavItem to='/simple-redux-dynamic'>Simple Redux Dynamic Component Example</NavItem>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
class App extends Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div style={{display: "inline-block", width: "100%"}}>
|
||||||
|
<SideBar/>
|
||||||
|
<div style={{float: "left"}}>
|
||||||
|
<Switch>
|
||||||
|
<Redirect from="/" exact to="/rich-grid-declarative"/>
|
||||||
|
<Route exact path='/rich-grid-declarative' component={RichGridDeclarativeExample}/>
|
||||||
|
<Route exact path='/simple-redux-dynamic' component={SimpleReduxDynamicExample}/>
|
||||||
|
</Switch>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App
|
||||||
20
src-examples/NavItem.jsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import * as PropTypes from 'prop-types';
|
||||||
|
import {Route, Link} from 'react-router-dom'
|
||||||
|
|
||||||
|
// for bootstrap li active functionality
|
||||||
|
export default function NavItem({children, to, exact}) {
|
||||||
|
return (
|
||||||
|
<Route path={to} exact={exact} children={({match}) => (
|
||||||
|
<li className={match ? 'active' : null}>
|
||||||
|
<Link to={to}>{children}</Link>
|
||||||
|
</li>
|
||||||
|
)}/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
NavItem.propTypes = {
|
||||||
|
to: PropTypes.string.isRequired,
|
||||||
|
exact: PropTypes.bool,
|
||||||
|
children: PropTypes.node.isRequired,
|
||||||
|
};
|
||||||
BIN
src-examples/images/alberto.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
src-examples/images/favicon.ico
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
src-examples/images/fire.png
Normal file
|
After Width: | Height: | Size: 606 B |
BIN
src-examples/images/flags/ar.png
Normal file
|
After Width: | Height: | Size: 128 B |
BIN
src-examples/images/flags/br.png
Normal file
|
After Width: | Height: | Size: 256 B |
BIN
src-examples/images/flags/co.png
Normal file
|
After Width: | Height: | Size: 99 B |
BIN
src-examples/images/flags/de.png
Normal file
|
After Width: | Height: | Size: 99 B |
BIN
src-examples/images/flags/es.png
Normal file
|
After Width: | Height: | Size: 174 B |
BIN
src-examples/images/flags/fr.png
Normal file
|
After Width: | Height: | Size: 94 B |
BIN
src-examples/images/flags/gb.png
Normal file
|
After Width: | Height: | Size: 289 B |
BIN
src-examples/images/flags/gr.png
Normal file
|
After Width: | Height: | Size: 228 B |
BIN
src-examples/images/flags/ie.png
Normal file
|
After Width: | Height: | Size: 119 B |
BIN
src-examples/images/flags/is.png
Normal file
|
After Width: | Height: | Size: 154 B |
BIN
src-examples/images/flags/it.png
Normal file
|
After Width: | Height: | Size: 94 B |
BIN
src-examples/images/flags/mt.png
Normal file
|
After Width: | Height: | Size: 136 B |
BIN
src-examples/images/flags/no.png
Normal file
|
After Width: | Height: | Size: 154 B |
BIN
src-examples/images/flags/pe.png
Normal file
|
After Width: | Height: | Size: 89 B |
BIN
src-examples/images/flags/pt.png
Normal file
|
After Width: | Height: | Size: 227 B |
BIN
src-examples/images/flags/se.png
Normal file
|
After Width: | Height: | Size: 97 B |
BIN
src-examples/images/flags/uy.png
Normal file
|
After Width: | Height: | Size: 222 B |
BIN
src-examples/images/flags/ve.png
Normal file
|
After Width: | Height: | Size: 173 B |
BIN
src-examples/images/frost.png
Normal file
|
After Width: | Height: | Size: 739 B |
BIN
src-examples/images/horse.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
src-examples/images/niall.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
src-examples/images/phone.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
src-examples/images/sean.png
Normal file
|
After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 883 B After Width: | Height: | Size: 883 B |
|
Before Width: | Height: | Size: 902 B After Width: | Height: | Size: 902 B |
|
Before Width: | Height: | Size: 953 B After Width: | Height: | Size: 953 B |
|
Before Width: | Height: | Size: 394 B After Width: | Height: | Size: 394 B |
|
Before Width: | Height: | Size: 893 B After Width: | Height: | Size: 893 B |
BIN
src-examples/images/smiley-sad.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
src-examples/images/smiley.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
src-examples/images/statue.png
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
src-examples/images/sun.png
Normal file
|
After Width: | Height: | Size: 570 B |
132
src-examples/index.html
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<script type="text/javascript" src="../dist/react-examples.js" charset="utf-8"></script>
|
||||||
|
<!-- Example uses font awesome icons -->
|
||||||
|
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
line-height: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
div.card-body > a {
|
||||||
|
margin-top: 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-left: 4px;
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.align-right {
|
||||||
|
text-align: right
|
||||||
|
}
|
||||||
|
|
||||||
|
.customHeaderMenuButton {
|
||||||
|
margin-left: 4px;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customHeaderLabel {
|
||||||
|
margin-left: 5px;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customSortDownLabel {
|
||||||
|
float: left;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customSortUpLabel {
|
||||||
|
float: left;
|
||||||
|
margin-left: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customSortRemoveLabel {
|
||||||
|
float: left;
|
||||||
|
font-size: 11px;
|
||||||
|
margin-left: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active {
|
||||||
|
color: cornflowerblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customHeaderLabel {
|
||||||
|
margin-left: 5px;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customExpandButton {
|
||||||
|
float: right;
|
||||||
|
margin-left: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expanded {
|
||||||
|
animation-name: toExpanded;
|
||||||
|
animation-duration: 1s;
|
||||||
|
-ms-transform: rotate(180deg); /* IE 9 */
|
||||||
|
-webkit-transform: rotate(180deg); /* Chrome, Safari, Opera */
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapsed {
|
||||||
|
color: cornflowerblue;
|
||||||
|
animation-name: toCollapsed;
|
||||||
|
animation-duration: 1s;
|
||||||
|
-ms-transform: rotate(0deg); /* IE 9 */
|
||||||
|
-webkit-transform: rotate(0deg); /* Chrome, Safari, Opera */
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes toExpanded {
|
||||||
|
from {
|
||||||
|
color: cornflowerblue;
|
||||||
|
-ms-transform: rotate(0deg); /* IE 9 */
|
||||||
|
-webkit-transform: rotate(0deg); /* Chrome, Safari, Opera */
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
color: black;
|
||||||
|
-ms-transform: rotate(180deg); /* IE 9 */
|
||||||
|
-webkit-transform: rotate(180deg); /* Chrome, Safari, Opera */
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes toCollapsed {
|
||||||
|
from {
|
||||||
|
color: black;
|
||||||
|
-ms-transform: rotate(180deg); /* IE 9 */
|
||||||
|
-webkit-transform: rotate(180deg); /* Chrome, Safari, Opera */
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
color: cornflowerblue;
|
||||||
|
-ms-transform: rotate(0deg); /* IE 9 */
|
||||||
|
-webkit-transform: rotate(0deg); /* Chrome, Safari, Opera */
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
25
src-examples/index.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import {render} from "react-dom";
|
||||||
|
import {BrowserRouter} from "react-router-dom";
|
||||||
|
|
||||||
|
import "ag-grid/dist/styles/ag-grid.css";
|
||||||
|
import "ag-grid/dist/styles/theme-fresh.css";
|
||||||
|
import "../node_modules/bootstrap/dist/css/bootstrap.css";
|
||||||
|
|
||||||
|
import App from "./App";
|
||||||
|
|
||||||
|
// only required when using enterprise features
|
||||||
|
// import {LicenseManager} from "ag-grid-enterprise/main";
|
||||||
|
// LicenseManager.setLicenseKey("<your license key>");
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
render(
|
||||||
|
<BrowserRouter>
|
||||||
|
<App/>
|
||||||
|
</BrowserRouter>,
|
||||||
|
document.querySelector('#app')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
import React from 'react';
|
import React from "react";
|
||||||
|
import * as PropTypes from "prop-types";
|
||||||
|
|
||||||
// Date Component to be used in the date filter.
|
// Date Component to be used in the date filter.
|
||||||
// This is a very simple example of how a React component can be plugged as a DateComponentFramework
|
// This is a very simple example of how a React component can be plugged as a DateComponentFramework
|
||||||
// as you can see, the only requirement is that the React component implements the required methods
|
// as you can see, the only requirement is that the React component implements the required methods
|
||||||
// getDate and setDate and that it calls back into props.onDateChanged every time that the date changes.
|
// getDate and setDate and that it calls back into props.onDateChanged every time that the date changes.
|
||||||
export default class MyReactDateComponent extends React.Component {
|
export default class DateComponent extends React.Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -27,7 +28,7 @@ export default class MyReactDateComponent extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
//Inlining styles to make simpler the component
|
//Inlining styles to make simpler the component
|
||||||
let filterStyle = {
|
let filterStyle = {
|
||||||
margin:'2px'
|
margin: '2px'
|
||||||
};
|
};
|
||||||
let ddStyle = {
|
let ddStyle = {
|
||||||
width: '30px'
|
width: '30px'
|
||||||
@@ -36,7 +37,7 @@ export default class MyReactDateComponent extends React.Component {
|
|||||||
width: '30px'
|
width: '30px'
|
||||||
};
|
};
|
||||||
let yyyyStyle = {
|
let yyyyStyle = {
|
||||||
width: '60px'
|
width: '40px'
|
||||||
};
|
};
|
||||||
let resetStyle = {
|
let resetStyle = {
|
||||||
padding: '2px',
|
padding: '2px',
|
||||||
@@ -50,9 +51,12 @@ export default class MyReactDateComponent extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<div style={filterStyle}>
|
<div style={filterStyle}>
|
||||||
<span style={resetStyle} onClick={this.resetDate.bind(this)}>x</span>
|
<span style={resetStyle} onClick={this.resetDate.bind(this)}>x</span>
|
||||||
<input onInput = {this.onDateChanged.bind(this)} ref="dd" placeholder="dd" style={ddStyle} value={this.state.textBoxes.dd} maxLength="2"/>/
|
<input onInput={this.onDateChanged.bind(this)} ref="dd" placeholder="dd" style={ddStyle}
|
||||||
<input onInput = {this.onDateChanged.bind(this)} ref="mm" placeholder="mm" style={mmStyle} value={this.state.textBoxes.mm} maxLength="2"/>/
|
value={this.state.textBoxes.dd} maxLength="2"/>/
|
||||||
<input onInput = {this.onDateChanged.bind(this)} ref="yyyy" placeholder="yyyy" style={yyyyStyle} value={this.state.textBoxes.yyyy} maxLength="4"/>
|
<input onInput={this.onDateChanged.bind(this)} ref="mm" placeholder="mm" style={mmStyle}
|
||||||
|
value={this.state.textBoxes.mm} maxLength="2"/>/
|
||||||
|
<input onInput={this.onDateChanged.bind(this)} ref="yyyy" placeholder="yyyy" style={yyyyStyle}
|
||||||
|
value={this.state.textBoxes.yyyy} maxLength="4"/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -61,20 +65,20 @@ export default class MyReactDateComponent extends React.Component {
|
|||||||
// METHODS REQUIRED BY AG-GRID
|
// METHODS REQUIRED BY AG-GRID
|
||||||
//*********************************************************************************
|
//*********************************************************************************
|
||||||
|
|
||||||
getDate (){
|
getDate() {
|
||||||
//ag-grid will call us here when in need to check what the current date value is hold by this
|
//ag-grid will call us here when in need to check what the current date value is hold by this
|
||||||
//component.
|
//component.
|
||||||
return this.state.date;
|
return this.state.date;
|
||||||
}
|
}
|
||||||
|
|
||||||
setDate (date){
|
setDate(date) {
|
||||||
//ag-grid will call us here when it needs this component to update the date that it holds.
|
//ag-grid will call us here when it needs this component to update the date that it holds.
|
||||||
this.setState({
|
this.setState({
|
||||||
date:date,
|
date,
|
||||||
textBoxes:{
|
textBoxes: {
|
||||||
dd: date.getDate(),
|
dd: date ? date.getDate() : '',
|
||||||
mm: date.getMonth() + 1,
|
mm: date ? date.getMonth() + 1 : '',
|
||||||
yyyy: date.getFullYear()
|
yyyy: date ? date.getFullYear() : ''
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -83,10 +87,10 @@ export default class MyReactDateComponent extends React.Component {
|
|||||||
// LINKS THE INTERNAL STATE AND AG-GRID
|
// LINKS THE INTERNAL STATE AND AG-GRID
|
||||||
//*********************************************************************************
|
//*********************************************************************************
|
||||||
|
|
||||||
updateAndNotifyAgGrid (date, textBoxes){
|
updateAndNotifyAgGrid(date, textBoxes) {
|
||||||
this.setState ({
|
this.setState({
|
||||||
date: date,
|
date: date,
|
||||||
textBoxes:textBoxes
|
textBoxes: textBoxes
|
||||||
},
|
},
|
||||||
//Callback after the state is set. This is where we tell ag-grid that the date has changed so
|
//Callback after the state is set. This is where we tell ag-grid that the date has changed so
|
||||||
//it will proceed with the filtering and we can then expect ag-Grid to call us back to getDate
|
//it will proceed with the filtering and we can then expect ag-Grid to call us back to getDate
|
||||||
@@ -99,23 +103,23 @@ export default class MyReactDateComponent extends React.Component {
|
|||||||
// LINKING THE UI, THE STATE AND AG-GRID
|
// LINKING THE UI, THE STATE AND AG-GRID
|
||||||
//*********************************************************************************
|
//*********************************************************************************
|
||||||
|
|
||||||
resetDate (){
|
resetDate() {
|
||||||
let date = null;
|
let date = null;
|
||||||
let textBoxes = {
|
let textBoxes = {
|
||||||
dd : '',
|
dd: '',
|
||||||
mm : '',
|
mm: '',
|
||||||
yyyy : '',
|
yyyy: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
this.updateAndNotifyAgGrid(date, textBoxes)
|
this.updateAndNotifyAgGrid(date, textBoxes)
|
||||||
}
|
}
|
||||||
|
|
||||||
onDateChanged () {
|
onDateChanged() {
|
||||||
let date = this.parseDate(this.refs.dd.value, this.refs.mm.value, this.refs.yyyy.value);
|
let date = this.parseDate(this.refs.dd.value, this.refs.mm.value, this.refs.yyyy.value);
|
||||||
let textBoxes = {
|
let textBoxes = {
|
||||||
dd : this.refs.dd.value,
|
dd: this.refs.dd.value,
|
||||||
mm : this.refs.mm.value,
|
mm: this.refs.mm.value,
|
||||||
yyyy : this.refs.yyyy.value,
|
yyyy: this.refs.yyyy.value,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.updateAndNotifyAgGrid(date, textBoxes)
|
this.updateAndNotifyAgGrid(date, textBoxes)
|
||||||
@@ -125,7 +129,7 @@ export default class MyReactDateComponent extends React.Component {
|
|||||||
// INTERNAL LOGIC
|
// INTERNAL LOGIC
|
||||||
//*********************************************************************************
|
//*********************************************************************************
|
||||||
|
|
||||||
parseDate (dd, mm, yyyy){
|
parseDate(dd, mm, yyyy) {
|
||||||
//If any of the three input date fields are empty, stop and return null
|
//If any of the three input date fields are empty, stop and return null
|
||||||
if (dd.trim() === '' || mm.trim() === '' || yyyy.trim() === '') {
|
if (dd.trim() === '' || mm.trim() === '' || yyyy.trim() === '') {
|
||||||
return null;
|
return null;
|
||||||
@@ -138,7 +142,7 @@ export default class MyReactDateComponent extends React.Component {
|
|||||||
let date = new Date(year, month - 1, day);
|
let date = new Date(year, month - 1, day);
|
||||||
|
|
||||||
//If the date is not valid
|
//If the date is not valid
|
||||||
if (isNaN(date.getTime())){
|
if (isNaN(date.getTime())) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +154,7 @@ export default class MyReactDateComponent extends React.Component {
|
|||||||
//If the javascript date parts don't match the provided fields, we assume that the input is non
|
//If the javascript date parts don't match the provided fields, we assume that the input is non
|
||||||
//sensical... ie: Day=-1 or month=14, if this is the case, we return null
|
//sensical... ie: Day=-1 or month=14, if this is the case, we return null
|
||||||
//This also protects us from non sensical dates like dd=31, mm=2 of any year
|
//This also protects us from non sensical dates like dd=31, mm=2 of any year
|
||||||
if (date.getDate() != day || date.getMonth() + 1 != month || date.getFullYear() != year){
|
if (date.getDate() != day || date.getMonth() + 1 != month || date.getFullYear() != year) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,6 +166,6 @@ export default class MyReactDateComponent extends React.Component {
|
|||||||
// which is the grid passing you the params for the cellRenderer.
|
// which is the grid passing you the params for the cellRenderer.
|
||||||
// this piece is optional. the grid will always pass the 'params'
|
// this piece is optional. the grid will always pass the 'params'
|
||||||
// props, so little need for adding this validation meta-data.
|
// props, so little need for adding this validation meta-data.
|
||||||
MyReactDateComponent.propTypes = {
|
DateComponent.propTypes = {
|
||||||
params: React.PropTypes.object
|
params: PropTypes.object
|
||||||
};
|
};
|
||||||
@@ -1,31 +1,36 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import * as PropTypes from 'prop-types';
|
||||||
|
|
||||||
// Header component to be used as default for all the columns.
|
// Header component to be used as default for all the columns.
|
||||||
export default class MyReactHeaderGroupComponent extends React.Component {
|
export default class HeaderGroupComponent extends React.Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.props.columnGroup.getOriginalColumnGroup().addEventListener('expandedChanged', this.onExpandChanged.bind(this));
|
this.props.columnGroup.getOriginalColumnGroup().addEventListener('expandedChanged', this.onExpandChanged.bind(this));
|
||||||
this.state = {
|
this.state = {
|
||||||
expanded:null
|
expanded: null
|
||||||
}
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
this.onExpandChanged();
|
this.onExpandChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let arrowClassName = "customExpandButton " + (this.state.expanded ? " expanded": " collapsed");
|
let arrowClassName = "customExpandButton " + (this.state.expanded ? " expanded" : " collapsed");
|
||||||
|
|
||||||
return <div>
|
return <div>
|
||||||
<div className="customHeaderLabel"> {this.props.displayName}</div>
|
<div className="customHeaderLabel"> {this.props.displayName}</div>
|
||||||
<div onClick={this.expandOrCollapse.bind(this)} className={arrowClassName}><i className="fa fa-arrow-right" /></div>
|
<div onClick={this.expandOrCollapse.bind(this)} className={arrowClassName}><i
|
||||||
|
className="fa fa-arrow-right"/></div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
expandOrCollapse (){
|
expandOrCollapse() {
|
||||||
this.props.setExpanded(!this.state.expanded);
|
this.props.setExpanded(!this.state.expanded);
|
||||||
};
|
};
|
||||||
|
|
||||||
onExpandChanged (){
|
onExpandChanged() {
|
||||||
this.setState({
|
this.setState({
|
||||||
expanded: this.props.columnGroup.getOriginalColumnGroup().isExpanded()
|
expanded: this.props.columnGroup.getOriginalColumnGroup().isExpanded()
|
||||||
})
|
})
|
||||||
@@ -36,6 +41,6 @@ export default class MyReactHeaderGroupComponent extends React.Component {
|
|||||||
// which is the grid passing you the params for the cellRenderer.
|
// which is the grid passing you the params for the cellRenderer.
|
||||||
// this piece is optional. the grid will always pass the 'params'
|
// this piece is optional. the grid will always pass the 'params'
|
||||||
// props, so little need for adding this validation meta-data.
|
// props, so little need for adding this validation meta-data.
|
||||||
MyReactHeaderGroupComponent.propTypes = {
|
HeaderGroupComponent.propTypes = {
|
||||||
params: React.PropTypes.object
|
params: PropTypes.object
|
||||||
};
|
};
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import RefData from './RefData';
|
import * as PropTypes from 'prop-types';
|
||||||
|
|
||||||
var KEY_BACKSPACE = 8;
|
const KEY_BACKSPACE = 8;
|
||||||
var KEY_DELETE = 46;
|
const KEY_DELETE = 46;
|
||||||
var KEY_F2 = 113;
|
const KEY_F2 = 113;
|
||||||
|
|
||||||
// cell renderer for the proficiency column. this is a very basic cell editor,
|
// cell renderer for the proficiency column. this is a very basic cell editor,
|
||||||
export default class NameCellEditor extends React.Component {
|
export default class NameCellEditor extends React.Component {
|
||||||
@@ -19,9 +19,9 @@ export default class NameCellEditor extends React.Component {
|
|||||||
// experience is similar to Excel
|
// experience is similar to Excel
|
||||||
createInitialState(props) {
|
createInitialState(props) {
|
||||||
|
|
||||||
var startValue;
|
let startValue;
|
||||||
var putCursorAtEndOnFocus = false;
|
const putCursorAtEndOnFocus = false;
|
||||||
var highlightAllOnFocus = false;
|
const highlightAllOnFocus = false;
|
||||||
|
|
||||||
if (props.keyPress === KEY_BACKSPACE || props.keyPress === KEY_DELETE) {
|
if (props.keyPress === KEY_BACKSPACE || props.keyPress === KEY_DELETE) {
|
||||||
// if backspace or delete pressed, we clear the cell
|
// if backspace or delete pressed, we clear the cell
|
||||||
@@ -55,7 +55,7 @@ export default class NameCellEditor extends React.Component {
|
|||||||
onChangeListener(event) {
|
onChangeListener(event) {
|
||||||
// if doing React, you will probably be using a library for managing immutable
|
// 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.
|
// objects better. to keep this example simple, we don't use one.
|
||||||
var newState = {
|
const newState = {
|
||||||
value: event.target.value,
|
value: event.target.value,
|
||||||
putCursorAtEndOnFocus: this.state.putCursorAtEndOnFocus,
|
putCursorAtEndOnFocus: this.state.putCursorAtEndOnFocus,
|
||||||
highlightAllOnFocus: this.state.highlightAllOnFocus
|
highlightAllOnFocus: this.state.highlightAllOnFocus
|
||||||
@@ -72,7 +72,7 @@ export default class NameCellEditor extends React.Component {
|
|||||||
// view, it may not yet be in the browser (put in by ag-Grid) so focus will not work
|
// view, it may not yet be in the browser (put in by ag-Grid) so focus will not work
|
||||||
afterGuiAttached() {
|
afterGuiAttached() {
|
||||||
// get ref from React component
|
// get ref from React component
|
||||||
var eInput = this.refs.textField;
|
const eInput = this.refs.textField;
|
||||||
eInput.focus();
|
eInput.focus();
|
||||||
if (this.highlightAllOnFocus) {
|
if (this.highlightAllOnFocus) {
|
||||||
eInput.select();
|
eInput.select();
|
||||||
@@ -81,7 +81,7 @@ export default class NameCellEditor extends React.Component {
|
|||||||
// this comes into play in two scenarios: a) when user hits F2 and b)
|
// 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
|
// 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'
|
// was placed after the first character, thus 'apply' would end up as 'pplea'
|
||||||
var length = eInput.value ? eInput.value.length : 0;
|
const length = eInput.value ? eInput.value.length : 0;
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
eInput.setSelectionRange(length, length);
|
eInput.setSelectionRange(length, length);
|
||||||
}
|
}
|
||||||
@@ -100,7 +100,7 @@ export default class NameCellEditor extends React.Component {
|
|||||||
|
|
||||||
// just to demonstrate, if you type in 'cancel' then the edit will not take effect
|
// just to demonstrate, if you type in 'cancel' then the edit will not take effect
|
||||||
isCancelAfterEnd() {
|
isCancelAfterEnd() {
|
||||||
if (this.state.value && this.state.value.toUpperCase()==='CANCEL') {
|
if (this.state.value && this.state.value.toUpperCase() === 'CANCEL') {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@@ -113,5 +113,5 @@ export default class NameCellEditor extends React.Component {
|
|||||||
// this piece is optional. the grid will always pass the 'params'
|
// this piece is optional. the grid will always pass the 'params'
|
||||||
// props, so little need for adding this validation meta-data.
|
// props, so little need for adding this validation meta-data.
|
||||||
NameCellEditor.propTypes = {
|
NameCellEditor.propTypes = {
|
||||||
params: React.PropTypes.object
|
params: PropTypes.object
|
||||||
};
|
};
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import RefData from './RefData';
|
|
||||||
|
|
||||||
// cell renderer for the proficiency column. this is a very basic cell renderer,
|
// 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
|
// it is arguable that we should not of used React and just returned a string of
|
||||||
@@ -7,7 +6,7 @@ import RefData from './RefData';
|
|||||||
export default class ProficiencyCellRenderer extends React.Component {
|
export default class ProficiencyCellRenderer extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var backgroundColor;
|
let backgroundColor;
|
||||||
if (this.props.value < 20) {
|
if (this.props.value < 20) {
|
||||||
backgroundColor = 'red';
|
backgroundColor = 'red';
|
||||||
} else if (this.props.value < 60) {
|
} else if (this.props.value < 60) {
|
||||||
@@ -17,7 +16,7 @@ export default class ProficiencyCellRenderer extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="div-percent-bar" style={{ width: this.props.value + '%', backgroundColor: backgroundColor }}>
|
<div className="div-percent-bar" style={{width: this.props.value + '%', backgroundColor: backgroundColor}}>
|
||||||
<div className="div-percent-value">{this.props.value}%</div>
|
<div className="div-percent-value">{this.props.value}%</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
var PROFICIENCY_NAMES = ['No Filter', 'Above 40%', 'Above 60%', 'Above 80%'];
|
const PROFICIENCY_NAMES = ['No Filter', 'Above 40%', 'Above 60%', 'Above 80%'];
|
||||||
|
|
||||||
// the proficiency filter component. this demonstrates how to integrate
|
// the proficiency filter component. this demonstrates how to integrate
|
||||||
// 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(props) {
|
constructor(props) {
|
||||||
super();
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
selected: PROFICIENCY_NAMES[0]
|
selected: PROFICIENCY_NAMES[0]
|
||||||
};
|
};
|
||||||
@@ -15,14 +15,18 @@ export default class ProficiencyFilter extends React.Component {
|
|||||||
|
|
||||||
// called by agGrid
|
// called by agGrid
|
||||||
doesFilterPass(params) {
|
doesFilterPass(params) {
|
||||||
var value = this.props.valueGetter(params);
|
const value = this.props.valueGetter(params);
|
||||||
var valueAsNumber = parseFloat(value);
|
const valueAsNumber = parseFloat(value);
|
||||||
|
|
||||||
switch (this.state.selected) {
|
switch (this.state.selected) {
|
||||||
case PROFICIENCY_NAMES[1] : return valueAsNumber >= 40;
|
case PROFICIENCY_NAMES[1] :
|
||||||
case PROFICIENCY_NAMES[2] : return valueAsNumber >= 60;
|
return valueAsNumber >= 40;
|
||||||
case PROFICIENCY_NAMES[3] : return valueAsNumber >= 80;
|
case PROFICIENCY_NAMES[2] :
|
||||||
default : return true;
|
return valueAsNumber >= 60;
|
||||||
|
case PROFICIENCY_NAMES[3] :
|
||||||
|
return valueAsNumber >= 80;
|
||||||
|
default :
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -32,21 +36,28 @@ export default class ProficiencyFilter extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onButtonPressed(name) {
|
onButtonPressed(name) {
|
||||||
console.log(name);
|
const newState = {selected: name};
|
||||||
var newState = {selected: name};
|
|
||||||
// set the state, and once it is done, then call filterChangedCallback
|
// set the state, and once it is done, then call filterChangedCallback
|
||||||
this.setState(newState, this.props.filterChangedCallback);
|
this.setState(newState, this.props.filterChangedCallback);
|
||||||
console.log(name);
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getModel() {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
setModel(model) {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var rows = [];
|
const rows = [];
|
||||||
PROFICIENCY_NAMES.forEach( (name)=> {
|
PROFICIENCY_NAMES.forEach((name) => {
|
||||||
var selected = this.state.selected === name;
|
const selected = this.state.selected === name;
|
||||||
rows.push(
|
rows.push(
|
||||||
<div key={name}>
|
<div key={name}>
|
||||||
<label style={{paddingLeft: 4}}>
|
<label style={{paddingLeft: 4}}>
|
||||||
<input type="radio" checked={selected} name={Math.random()} onChange={this.onButtonPressed.bind(this, name)}/>
|
<input type="radio" checked={selected} name={Math.random()}
|
||||||
|
onChange={this.onButtonPressed.bind(this, name)}/>
|
||||||
{name}
|
{name}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@@ -55,7 +66,13 @@ export default class ProficiencyFilter extends React.Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div style={{textAlign: 'center', background: 'lightgray', width: '100%', display: 'block', borderBottom: '1px solid grey'}}>
|
<div style={{
|
||||||
|
textAlign: 'center',
|
||||||
|
background: 'lightgray',
|
||||||
|
width: '100%',
|
||||||
|
display: 'block',
|
||||||
|
borderBottom: '1px solid grey'
|
||||||
|
}}>
|
||||||
<b>Custom Proficiency Filter</b>
|
<b>Custom Proficiency Filter</b>
|
||||||
</div>
|
</div>
|
||||||
{rows}
|
{rows}
|
||||||
129
src-examples/richGridDeclarativeExample/RefData.js
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
export default class RefData {
|
||||||
|
}
|
||||||
|
|
||||||
|
RefData.FIRST_NAMES = [
|
||||||
|
"Sophie", "Isabelle", "Emily", "Olivia", "Lily", "Chloe", "Isabella",
|
||||||
|
"Amelia", "Jessica", "Sophia", "Ava", "Charlotte", "Mia", "Lucy", "Grace", "Ruby",
|
||||||
|
"Ella", "Evie", "Freya", "Isla", "Poppy", "Daisy", "Layla"
|
||||||
|
];
|
||||||
|
|
||||||
|
RefData.LAST_NAMES = [
|
||||||
|
"Beckham", "Black", "Braxton", "Brennan", "Brock", "Bryson", "Cadwell",
|
||||||
|
"Cage", "Carson", "Chandler", "Cohen", "Cole", "Corbin", "Dallas", "Dalton", "Dane",
|
||||||
|
"Donovan", "Easton", "Fisher", "Fletcher", "Grady", "Greyson", "Griffin", "Gunner",
|
||||||
|
"Hayden", "Hudson", "Hunter", "Jacoby", "Jagger", "Jaxon", "Jett", "Kade", "Kane",
|
||||||
|
"Keating", "Keegan", "Kingston", "Kobe"
|
||||||
|
];
|
||||||
|
|
||||||
|
RefData.COUNTRY_CODES = {
|
||||||
|
Ireland: "ie",
|
||||||
|
Spain: "es",
|
||||||
|
"United Kingdom": "gb",
|
||||||
|
France: "fr",
|
||||||
|
Germany: "de",
|
||||||
|
Sweden: "se",
|
||||||
|
Italy: "it",
|
||||||
|
Greece: "gr",
|
||||||
|
Iceland: "is",
|
||||||
|
Portugal: "pt",
|
||||||
|
Malta: "mt",
|
||||||
|
Norway: "no",
|
||||||
|
Brazil: "br",
|
||||||
|
Argentina: "ar",
|
||||||
|
Colombia: "co",
|
||||||
|
Peru: "pe",
|
||||||
|
Venezuela: "ve",
|
||||||
|
Uruguay: "uy"
|
||||||
|
};
|
||||||
|
|
||||||
|
RefData.COUNTRIES = [
|
||||||
|
{country: "Ireland", continent: "Europe", language: "English"},
|
||||||
|
{country: "Spain", continent: "Europe", language: "Spanish"},
|
||||||
|
{country: "United Kingdom", continent: "Europe", language: "English"},
|
||||||
|
{country: "France", continent: "Europe", language: "French"},
|
||||||
|
{country: "Germany", continent: "Europe", language: "(other)"},
|
||||||
|
{country: "Sweden", continent: "Europe", language: "(other)"},
|
||||||
|
{country: "Norway", continent: "Europe", language: "(other)"},
|
||||||
|
{country: "Italy", continent: "Europe", language: "(other)"},
|
||||||
|
{country: "Greece", continent: "Europe", language: "(other)"},
|
||||||
|
{country: "Iceland", continent: "Europe", language: "(other)"},
|
||||||
|
{country: "Portugal", continent: "Europe", language: "Portuguese"},
|
||||||
|
{country: "Malta", continent: "Europe", language: "(other)"},
|
||||||
|
{country: "Brazil", continent: "South America", language: "Portuguese"},
|
||||||
|
{country: "Argentina", continent: "South America", language: "Spanish"},
|
||||||
|
{country: "Colombia", continent: "South America", language: "Spanish"},
|
||||||
|
{country: "Peru", continent: "South America", language: "Spanish"},
|
||||||
|
{country: "Venezuela", continent: "South America", language: "Spanish"},
|
||||||
|
{country: "Uruguay", continent: "South America", language: "Spanish"}
|
||||||
|
];
|
||||||
|
|
||||||
|
RefData.DOB = [
|
||||||
|
new Date(2000, 0, 1),
|
||||||
|
new Date(2001, 1, 2),
|
||||||
|
new Date(2002, 2, 3),
|
||||||
|
new Date(2003, 3, 4),
|
||||||
|
new Date(2004, 4, 5),
|
||||||
|
new Date(2005, 5, 6),
|
||||||
|
new Date(2006, 6, 7),
|
||||||
|
new Date(2007, 7, 8),
|
||||||
|
new Date(2008, 8, 9),
|
||||||
|
new Date(2009, 9, 10),
|
||||||
|
new Date(2010, 10, 11),
|
||||||
|
new Date(2011, 11, 12)
|
||||||
|
];
|
||||||
|
|
||||||
|
RefData.ADDRESSES = [
|
||||||
|
'1197 Thunder Wagon Common, Cataract, RI, 02987-1016, US, (401) 747-0763',
|
||||||
|
'3685 Rocky Glade, Showtucket, NU, X1E-9I0, CA, (867) 371-4215',
|
||||||
|
'3235 High Forest, Glen Campbell, MS, 39035-6845, US, (601) 638-8186',
|
||||||
|
'2234 Sleepy Pony Mall , Drain, DC, 20078-4243, US, (202) 948-3634',
|
||||||
|
'2722 Hazy Turnabout, Burnt Cabins, NY, 14120-5642, US, (917) 604-6597',
|
||||||
|
'6686 Lazy Ledge, Two Rock, CA, 92639-3020, US, (619) 901-9911',
|
||||||
|
'2000 Dewy Limits, Wacahoota, NF, A4L-2V9, CA, (709) 065-3959',
|
||||||
|
'7710 Noble Pond Avenue, Bolivia, RI, 02931-1842, US, (401) 865-2160',
|
||||||
|
'3452 Sunny Vale, Pyro, ON, M8V-4Z0, CA, (519) 072-8609',
|
||||||
|
'4402 Dusty Cove, Many Farms, UT, 84853-8223, US, (435) 518-0673',
|
||||||
|
'5198 Silent Parade, Round Bottom, MD, 21542-9798, US, (301) 060-7245',
|
||||||
|
'8550 Shady Moor, Kitty Fork, CO, 80941-6207, US, (303) 502-3767',
|
||||||
|
'2131 Old Dell, Merry Midnight, AK, 99906-8842, US, (907) 369-2206',
|
||||||
|
'7390 Harvest Crest, Mosquito Crossing, RI, 02957-6116, US, (401) 463-6348',
|
||||||
|
'874 Little Point, Hot Coffee, BC, V3U-2P6, CA, (250) 706-9207',
|
||||||
|
'8834 Stony Pioneer Heights, Newlove, OR, 97419-8670, US, (541) 408-2213',
|
||||||
|
'9829 Grand Beach, Flint, UT, 84965-9900, US, (435) 700-5161',
|
||||||
|
'3799 Cozy Blossom Ramp, Ptarmigan, MS, 38715-0313, US, (769) 740-1526',
|
||||||
|
'3254 Silver Island Loop, Maunaloa, DE, 19869-3169, US, (302) 667-7671',
|
||||||
|
'1081 Middle Wood, Taylors Gut Landing, OR, 97266-2873, US, (541) 357-6310',
|
||||||
|
'1137 Umber Trail, Shacktown, NW, X3U-5Y8, CA, (867) 702-6883',
|
||||||
|
'9914 Hidden Bank, Wyoming, MO, 64635-9665, US, (636) 280-4192',
|
||||||
|
'7080 Misty Nectar Townline, Coward, AB, T9U-3N4, CA, (403) 623-2838',
|
||||||
|
'1184 Wishing Grounds, Vibank, NW, X7D-0V9, CA, (867) 531-2730',
|
||||||
|
'126 Easy Pointe, Grandview Beach, KY, 40928-9539, US, (502) 548-0956',
|
||||||
|
'6683 Colonial Street, Swan River, BC, V1A-9I8, CA, (778) 014-4257',
|
||||||
|
'960 Gentle Oak Lane, Shakopee, ND, 58618-6277, US, (701) 327-1219',
|
||||||
|
'6918 Cotton Pine Corner, Kenaston, IA, 52165-3975, US, (515) 906-7427',
|
||||||
|
'2368 Burning Woods, Ernfold, NY, 11879-9186, US, (646) 819-0355',
|
||||||
|
'5646 Quiet Shadow Chase, Tiger Tail, IA, 52283-5537, US, (712) 375-9225',
|
||||||
|
'5466 Foggy Mountain Dale, Sweet Home, MT, 59738-0251, US, (406) 881-1706',
|
||||||
|
'5313 Clear Willow Route, Amazon, BC, V0S-2S6, CA, (604) 340-7596',
|
||||||
|
'7000 Pleasant Autoroute, Spaceport City, UT, 84749-2448, US, (435) 154-3360',
|
||||||
|
'8359 Quaking Anchor Road, Gross, BC, V9O-0H5, CA, (250) 985-3859',
|
||||||
|
'5143 Amber Deer Hollow, New Deal, ND, 58446-0853, US, (701) 927-0322',
|
||||||
|
'6230 Jagged Bear Key, Young, AR, 72337-3811, US, (501) 805-7239',
|
||||||
|
'7207 Heather Vista, Devon, WY, 82520-1771, US, (307) 358-7092',
|
||||||
|
'9416 Red Rise Place, Spraytown, OK, 73809-4766, US, (580) 867-1973',
|
||||||
|
'3770 Golden Horse Diversion, Yelland, IL, 60471-1487, US, (224) 717-9349',
|
||||||
|
'4819 Honey Treasure Park, Alaska, NB, E1U-3I0, CA, (506) 656-9138',
|
||||||
|
'6187 Round Front, Land O Lakes, AK, 99873-6403, US, (907) 853-9063',
|
||||||
|
'9218 Crystal Highway, Pickelville, MT, 59847-9299, US, (406) 076-0024',
|
||||||
|
'6737 Bright Quay, Lazy Mountain, KY, 42390-4772, US, (606) 256-7288',
|
||||||
|
'237 Merry Campus, Twentysix, SC, 29330-4909, US, (864) 945-0157',
|
||||||
|
'446 Fallen Gate Rise, Petrolia, SC, 29959-9527, US, (864) 826-0553',
|
||||||
|
'2347 Indian Boulevard, Frisbee, VA, 23797-6458, US, (703) 656-8445',
|
||||||
|
'365 Emerald Grove Line, Level, NC, 28381-1514, US, (919) 976-7958',
|
||||||
|
'1207 Iron Extension, Klickitat, SC, 29197-8571, US, (803) 535-7888',
|
||||||
|
'6770 Cinder Glen, Caronport, OH, 45053-5002, US, (440) 369-4018',
|
||||||
|
'7619 Tawny Carrefour, Senlac, NV, 89529-9876, US, (775) 901-6433'];
|
||||||
|
|
||||||
|
RefData.IT_SKILLS = ['android', 'css', 'html5', 'mac', 'windows'];
|
||||||
|
|
||||||
|
RefData.IT_SKILLS_NAMES = ['Android', 'CSS', 'HTML 5', 'Mac', 'Windows'];
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
.ag-cell {
|
.ag-cell {
|
||||||
padding-top: 2px !important;
|
padding-top: 2px !important;
|
||||||
padding-bottom: 2px !important;
|
padding-bottom: 2px !important;
|
||||||
@@ -0,0 +1,338 @@
|
|||||||
|
import React, {Component} from "react";
|
||||||
|
import {AgGridColumn, AgGridReact} from "ag-grid-react";
|
||||||
|
import RowDataFactory from "./RowDataFactory";
|
||||||
|
import DateComponent from "./DateComponent.jsx";
|
||||||
|
import SkillsCellRenderer from './SkillsCellRenderer.jsx';
|
||||||
|
import NameCellEditor from './NameCellEditor.jsx';
|
||||||
|
import ProficiencyCellRenderer from './ProficiencyCellRenderer.jsx';
|
||||||
|
import RefData from './RefData';
|
||||||
|
import SkillsFilter from './SkillsFilter.jsx';
|
||||||
|
import ProficiencyFilter from './ProficiencyFilter.jsx';
|
||||||
|
import HeaderGroupComponent from './HeaderGroupComponent.jsx';
|
||||||
|
import SortableHeaderComponent from './SortableHeaderComponent.jsx';
|
||||||
|
|
||||||
|
import "./RichGridDeclarativeExample.css";
|
||||||
|
|
||||||
|
// take this line out if you do not want to use ag-Grid-Enterprise
|
||||||
|
import "ag-grid-enterprise";
|
||||||
|
|
||||||
|
export default class RichGridDeclarativeExample extends Component {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
quickFilterText: null,
|
||||||
|
showToolPanel: false,
|
||||||
|
rowData: new RowDataFactory().createRowData(),
|
||||||
|
icons: {
|
||||||
|
columnRemoveFromGroup: '<i class="fa fa-remove"/>',
|
||||||
|
filter: '<i class="fa fa-filter"/>',
|
||||||
|
sortAscending: '<i class="fa fa-long-arrow-down"/>',
|
||||||
|
sortDescending: '<i class="fa fa-long-arrow-up"/>',
|
||||||
|
groupExpanded: '<i class="fa fa-minus-square-o"/>',
|
||||||
|
groupContracted: '<i class="fa fa-plus-square-o"/>'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grid Events we're listening to */
|
||||||
|
onGridReady = (params) => {
|
||||||
|
this.api = params.api;
|
||||||
|
this.columnApi = params.columnApi;
|
||||||
|
};
|
||||||
|
|
||||||
|
onCellClicked = (event) => {
|
||||||
|
console.log('onCellClicked: ' + event.data.name + ', col ' + event.colIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
onRowSelected = (event) => {
|
||||||
|
console.log('onRowSelected: ' + event.node.data.name);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Demo related methods */
|
||||||
|
onToggleToolPanel = (event) => {
|
||||||
|
this.setState({showToolPanel: event.target.checked});
|
||||||
|
};
|
||||||
|
|
||||||
|
deselectAll() {
|
||||||
|
this.api.deselectAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
onQuickFilterText = (event) => {
|
||||||
|
this.setState({quickFilterText: event.target.value});
|
||||||
|
};
|
||||||
|
|
||||||
|
onRefreshData = () => {
|
||||||
|
this.setState({
|
||||||
|
rowData: new RowDataFactory().createRowData()
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
invokeSkillsFilterMethod = () => {
|
||||||
|
let skillsFilter = this.api.getFilterInstance('skills');
|
||||||
|
let componentInstance = skillsFilter.getFrameworkComponentInstance();
|
||||||
|
componentInstance.helloFromSkillsFilter();
|
||||||
|
};
|
||||||
|
|
||||||
|
dobFilter = () => {
|
||||||
|
let dateFilterComponent = this.api.getFilterInstance('dob');
|
||||||
|
dateFilterComponent.setFilterType('equals');
|
||||||
|
dateFilterComponent.setDateFrom('2000-01-01');
|
||||||
|
|
||||||
|
// as the date filter is a React component, and its using setState internally, we need
|
||||||
|
// to allow time for the state to be set (as setState is an async operation)
|
||||||
|
// simply wait for the next tick
|
||||||
|
setTimeout(() => {
|
||||||
|
this.api.onFilterChanged();
|
||||||
|
}, 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
static countryCellRenderer(params) {
|
||||||
|
if (params.value) {
|
||||||
|
return `<img border='0' width='15' height='10' style='margin-bottom: 2px' src='http://flags.fmcdn.net/data/flags/mini/${RefData.COUNTRY_CODES[params.value]}.png'> ${params.value}`;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static dateCellRenderer(params) {
|
||||||
|
return RichGridDeclarativeExample.pad(params.value.getDate(), 2) + '/' +
|
||||||
|
RichGridDeclarativeExample.pad(params.value.getMonth() + 1, 2) + '/' +
|
||||||
|
params.value.getFullYear();
|
||||||
|
}
|
||||||
|
|
||||||
|
static pad(num, totalStringSize) {
|
||||||
|
let asString = num + "";
|
||||||
|
while (asString.length < totalStringSize) asString = "0" + asString;
|
||||||
|
return asString;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div style={{width: '900px'}}>
|
||||||
|
<h1>Rich Grid with Declarative Markup Example</h1>
|
||||||
|
<div style={{display: "inline-block", width: "100%"}}>
|
||||||
|
<div style={{float: "left"}}>
|
||||||
|
<b>Employees Skills and Contact Details</b><span id="rowCount"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={{marginTop: 10}}>
|
||||||
|
<div>
|
||||||
|
<span>
|
||||||
|
Grid API:
|
||||||
|
<button onClick={() => { this.api.selectAll() }} className="btn btn-primary">Select All</button>
|
||||||
|
<button onClick={() => { this.api.deselectAll() }} className="btn btn-primary">Clear Selection</button>
|
||||||
|
</span>
|
||||||
|
<span style={{float: "right"}}>
|
||||||
|
Column API:
|
||||||
|
<button onClick={() => { this.columnApi.setColumnVisible('country', false) }} className="btn btn-primary">Hide Country Column</button>
|
||||||
|
<button onClick={() => { this.columnApi.setColumnVisible('country', true) }} className="btn btn-primary">Show Country Column</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div style={{display: "inline-block", width: "100%", marginTop: 10, marginBottom: 10}}>
|
||||||
|
<div style={{float: "left"}}>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" onChange={this.onToggleToolPanel} style={{marginRight: 5}}/>
|
||||||
|
Show Tool Panel
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div style={{float: "left", marginLeft: 20}}>
|
||||||
|
<button onClick={this.onRefreshData} className="btn btn-primary">Refresh Data</button>
|
||||||
|
</div>
|
||||||
|
<div style={{float: "left", marginLeft: 20}}>
|
||||||
|
<input type="text" onChange={this.onQuickFilterText} placeholder="Type text to filter..."/>
|
||||||
|
</div>
|
||||||
|
<div style={{float: "right"}}>
|
||||||
|
Filter API:
|
||||||
|
<button onClick={this.invokeSkillsFilterMethod}
|
||||||
|
className="btn btn-primary">Invoke Skills Filter Method
|
||||||
|
</button>
|
||||||
|
<button onClick={this.dobFilter} className="btn btn-primary">DOB equals to 01/01/2000ß</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={{height: 400, width: 900}} className="ag-fresh">
|
||||||
|
<AgGridReact
|
||||||
|
// listening for events
|
||||||
|
onGridReady={this.onGridReady}
|
||||||
|
onRowSelected={this.onRowSelected}
|
||||||
|
onCellClicked={this.onCellClicked}
|
||||||
|
|
||||||
|
// binding to simple properties
|
||||||
|
showToolPanel={this.state.showToolPanel}
|
||||||
|
quickFilterText={this.state.quickFilterText}
|
||||||
|
|
||||||
|
// binding to an object property
|
||||||
|
icons={this.state.icons}
|
||||||
|
|
||||||
|
// binding to array properties
|
||||||
|
rowData={this.state.rowData}
|
||||||
|
|
||||||
|
// no binding, just providing hard coded strings for the properties
|
||||||
|
// boolean properties will default to true if provided (ie enableColResize => enableColResize="true")
|
||||||
|
suppressRowClickSelection
|
||||||
|
rowSelection="multiple"
|
||||||
|
enableColResize
|
||||||
|
enableSorting
|
||||||
|
enableFilter
|
||||||
|
floatingFilter
|
||||||
|
groupHeaders
|
||||||
|
rowHeight="22"
|
||||||
|
|
||||||
|
// setting grid wide date component
|
||||||
|
dateComponentFramework={DateComponent}
|
||||||
|
|
||||||
|
// setting default column properties
|
||||||
|
defaultColDef={{
|
||||||
|
headerComponentFramework: SortableHeaderComponent,
|
||||||
|
headerComponentParams: {
|
||||||
|
menuIcon: 'fa-bars'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<AgGridColumn headerName="#" width={30} checkboxSelection suppressSorting suppressMenu suppressFilter pinned></AgGridColumn>
|
||||||
|
<AgGridColumn headerName="Employee" headerGroupComponentFramework={HeaderGroupComponent}>
|
||||||
|
<AgGridColumn field="name" width={150} enableRowGroup enablePivot pinned editable cellEditorFramework={NameCellEditor}></AgGridColumn>
|
||||||
|
<AgGridColumn field="country" width={150} enableRowGroup enablePivot pinned editable cellRenderer={RichGridDeclarativeExample.countryCellRenderer} filterParams={{cellRenderer: RichGridDeclarativeExample.countryCellRenderer, cellHeight:20}}></AgGridColumn>
|
||||||
|
<AgGridColumn field="dob" width={145} headerName="DOB" filter="date" pinned columnGroupShow="open" cellRenderer={RichGridDeclarativeExample.dateCellRenderer}></AgGridColumn>
|
||||||
|
</AgGridColumn>
|
||||||
|
<AgGridColumn headerName="IT Skills">
|
||||||
|
<AgGridColumn field="skills" width={120} enableRowGroup enablePivot suppressSorting cellRendererFramework={SkillsCellRenderer} filterFramework={SkillsFilter}></AgGridColumn>
|
||||||
|
<AgGridColumn field="proficiency" width={135} enableValue cellRendererFramework={ProficiencyCellRenderer} filterFramework={ProficiencyFilter}></AgGridColumn>
|
||||||
|
</AgGridColumn>
|
||||||
|
<AgGridColumn headerName="Contact">
|
||||||
|
<AgGridColumn field="mobile" width={150} filter="text"></AgGridColumn>
|
||||||
|
<AgGridColumn field="landline" width={150} filter="text"></AgGridColumn>
|
||||||
|
<AgGridColumn field="address" width={500} filter="text"></AgGridColumn>
|
||||||
|
</AgGridColumn>
|
||||||
|
</AgGridReact>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-sm-12"><h1>Rich Grid with Declarative Markup Example</h1></div>
|
||||||
|
</div>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-sm-12">
|
||||||
|
<h5>This example demonstrates many features of ag-Grid, with Grid and Column Definition defined declaratively (i.e. with markup).</h5>
|
||||||
|
<p><span style={{fontWeight: 500}}>Select All/Clear Selection</span>: Select or Deselect
|
||||||
|
All
|
||||||
|
Rows</p>
|
||||||
|
<p><span style={{fontWeight: 500}}>Hide/Show Country Column</span>: Select or Deselect
|
||||||
|
All
|
||||||
|
Rows
|
||||||
|
(expand the Employee column to show the Country column first)</p>
|
||||||
|
<p><span style={{fontWeight: 500}}>Toggle The Tool Panel</span>: Let your users Pivot,
|
||||||
|
Group
|
||||||
|
and
|
||||||
|
Aggregate using the Tool Panel</p>
|
||||||
|
<p><span style={{fontWeight: 500}}>Refresh Data</span>: Dynamically Update Grid Data</p>
|
||||||
|
<p><span style={{fontWeight: 500}}>Quick Filter</span>: Perform Quick Grid Wide
|
||||||
|
Filtering
|
||||||
|
with
|
||||||
|
the Quick Filter</p>
|
||||||
|
<p><span style={{fontWeight: 500}}>DOB Filter</span>: Set the DOB filter to 01/01/2000
|
||||||
|
using
|
||||||
|
the
|
||||||
|
Filter API (expand the Employee column to show the DOB column)</p>
|
||||||
|
<p><span style={{fontWeight: 500}}>Custom Headers</span>: Sort, Filter and Render
|
||||||
|
Headers
|
||||||
|
using
|
||||||
|
Header Components</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-sm-4">
|
||||||
|
<div className="card">
|
||||||
|
<div className="card-body">
|
||||||
|
<h4 className="card-title">Grid & Column API</h4>
|
||||||
|
<p className="card-text">Utilise Grid Features Programmatically Using the APIs
|
||||||
|
Available</p>
|
||||||
|
<a target="_blank" href="https://www.ag-grid.com/javascript-grid-api/"
|
||||||
|
className="btn btn-primary">Grid API</a>
|
||||||
|
<a target="_blank" href="https://www.ag-grid.com//javascript-grid-column-api/"
|
||||||
|
className="btn btn-primary">Column API</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-sm-4">
|
||||||
|
<div className="card">
|
||||||
|
<div className="card-body">
|
||||||
|
<h4 className="card-title">Header Components</h4>
|
||||||
|
<p className="card-text">Customer the Header with React Components</p>
|
||||||
|
<a target="_blank"
|
||||||
|
href="https://www.ag-grid.com//javascript-grid-header-rendering/#headerComponent"
|
||||||
|
className="btn btn-primary">Header Component</a>
|
||||||
|
<a target="_blank"
|
||||||
|
href="https://www.ag-grid.com//javascript-grid-header-rendering/#headerGroupComponent"
|
||||||
|
className="btn btn-primary">Header Group Component</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-sm-4">
|
||||||
|
<div className="card">
|
||||||
|
<div className="card-body">
|
||||||
|
<h4 className="card-title">Filters</h4>
|
||||||
|
<p className="card-text">Filter with Quick Filters, Floating Filters, Built In
|
||||||
|
Filters
|
||||||
|
or Using the
|
||||||
|
Filter API</p>
|
||||||
|
<a target="_blank" href="https://www.ag-grid.com//javascript-grid-filter-quick/"
|
||||||
|
className="btn btn-primary">Quick
|
||||||
|
Filter</a>
|
||||||
|
<a target="_blank"
|
||||||
|
href="https://www.ag-grid.com//javascript-grid-floating-filter-component/"
|
||||||
|
className="btn btn-primary">Floating Filters</a>
|
||||||
|
<a target="_blank" href="https://www.ag-grid.com//javascript-grid-filtering/"
|
||||||
|
className="btn btn-primary">Built in
|
||||||
|
Filters</a>
|
||||||
|
<a target="_blank"
|
||||||
|
href="https://www.ag-grid.com//javascript-grid-filtering/#accessing-filter-component-instances"
|
||||||
|
className="btn btn-primary">Filter API</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-sm-4">
|
||||||
|
<div className="card">
|
||||||
|
<div className="card-body">
|
||||||
|
<h4 className="card-title">Tool Panel</h4>
|
||||||
|
<p className="card-text">Let your users Pivot, Group and Aggregate using the
|
||||||
|
Tool
|
||||||
|
Panel</p>
|
||||||
|
<a target="_blank" href="https://www.ag-grid.com//javascript-grid-tool-panel/"
|
||||||
|
className="btn btn-primary">Tool Panel</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-sm-8">
|
||||||
|
<div className="card">
|
||||||
|
<div className="card-body">
|
||||||
|
<h4 className="card-title">The Rest</h4>
|
||||||
|
<p className="card-text">Pinned Columns, Checkbox Selection, Customer Renderers,
|
||||||
|
Data
|
||||||
|
Updates</p>
|
||||||
|
<a target="_blank"
|
||||||
|
href="https://www.ag-grid.com/best-react-data-grid/?framework=react"
|
||||||
|
className="btn btn-primary">React with ag-Grid</a>
|
||||||
|
<a target="_blank" href="https://www.ag-grid.com//javascript-grid-pinning/"
|
||||||
|
className="btn btn-primary">Pinned Column</a>
|
||||||
|
<a target="_blank"
|
||||||
|
href="https://www.ag-grid.com//javascript-grid-selection/#checkboxSelection"
|
||||||
|
className="btn btn-primary">Checkbox Selection</a>
|
||||||
|
<a target="_blank"
|
||||||
|
href="https://www.ag-grid.com//javascript-grid-cell-rendering/"
|
||||||
|
className="btn btn-primary">Cell
|
||||||
|
Renderers</a>
|
||||||
|
<a target="_blank" href="https://www.ag-grid.com/javascript-grid-data-update/"
|
||||||
|
className="btn btn-primary">Updating Data</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,10 +3,10 @@ import RefData from './RefData';
|
|||||||
export default class RowDataFactory {
|
export default class RowDataFactory {
|
||||||
|
|
||||||
createRowData() {
|
createRowData() {
|
||||||
var rowData = [];
|
const rowData = [];
|
||||||
|
|
||||||
for (var i = 0; i < 200; i++) {
|
for (let i = 0; i < 200; i++) {
|
||||||
var countryData = RefData.COUNTRIES[i % RefData.COUNTRIES.length];
|
const countryData = RefData.COUNTRIES[i % RefData.COUNTRIES.length];
|
||||||
rowData.push({
|
rowData.push({
|
||||||
name: RefData.FIRST_NAMES[i % RefData.FIRST_NAMES.length] + ' ' + RefData.LAST_NAMES[i % RefData.LAST_NAMES.length],
|
name: RefData.FIRST_NAMES[i % RefData.FIRST_NAMES.length] + ' ' + RefData.LAST_NAMES[i % RefData.LAST_NAMES.length],
|
||||||
skills: {
|
skills: {
|
||||||
@@ -32,8 +32,8 @@ export default class RowDataFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createRandomPhoneNumber() {
|
createRandomPhoneNumber() {
|
||||||
var result = '+';
|
let result = '+';
|
||||||
for (var i = 0; i < 12; i++) {
|
for (let i = 0; i < 12; i++) {
|
||||||
result += Math.round(Math.random() * 10);
|
result += Math.round(Math.random() * 10);
|
||||||
if (i === 2 || i === 5 || i === 8) {
|
if (i === 2 || i === 5 || i === 8) {
|
||||||
result += ' ';
|
result += ' ';
|
||||||
@@ -1,14 +1,15 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import * as PropTypes from 'prop-types';
|
||||||
import RefData from './RefData';
|
import RefData from './RefData';
|
||||||
|
|
||||||
export default class SkillsCellRenderer extends React.Component {
|
export default class SkillsCellRenderer extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var skills = [];
|
const skills = [];
|
||||||
var rowData = this.props.data;
|
const rowData = this.props.data;
|
||||||
RefData.IT_SKILLS.forEach( (skill) => {
|
RefData.IT_SKILLS.forEach((skill) => {
|
||||||
if (rowData && rowData.skills && 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}/>);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -22,5 +23,5 @@ export default class SkillsCellRenderer extends React.Component {
|
|||||||
// this piece is optional. the grid will always pass the 'params'
|
// this piece is optional. the grid will always pass the 'params'
|
||||||
// props, so little need for adding this validation meta-data.
|
// props, so little need for adding this validation meta-data.
|
||||||
SkillsCellRenderer.propTypes = {
|
SkillsCellRenderer.propTypes = {
|
||||||
params: React.PropTypes.object
|
params: PropTypes.object
|
||||||
};
|
};
|
||||||
@@ -31,21 +31,21 @@ export default class SkillsFilter extends React.Component {
|
|||||||
|
|
||||||
setModel(model) {
|
setModel(model) {
|
||||||
this.setState({
|
this.setState({
|
||||||
android: model.android,
|
android: model ? model.android : null,
|
||||||
css: model.css,
|
css: model ? model.css : null,
|
||||||
html5: model.html5,
|
html5: model ? model.html5 : null,
|
||||||
mac: model.mac,
|
mac: model ? model.mac : null,
|
||||||
windows: model.windows
|
windows: model ? model.windows : null
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// called by agGrid
|
// called by agGrid
|
||||||
doesFilterPass(params) {
|
doesFilterPass(params) {
|
||||||
|
|
||||||
var rowSkills = params.data.skills;
|
const rowSkills = params.data.skills;
|
||||||
var passed = true;
|
let passed = true;
|
||||||
|
|
||||||
RefData.IT_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;
|
||||||
@@ -56,19 +56,23 @@ export default class SkillsFilter extends React.Component {
|
|||||||
return passed;
|
return passed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
getModel() {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
// called by agGrid
|
// called by agGrid
|
||||||
isFilterActive() {
|
isFilterActive() {
|
||||||
var somethingSelected = this.state.android || this.state.css ||
|
const somethingSelected = this.state.android || this.state.css ||
|
||||||
this.state.html5 || this.state.mac || this.state.windows;
|
this.state.html5 || this.state.mac || this.state.windows;
|
||||||
return somethingSelected;
|
return somethingSelected;
|
||||||
};
|
};
|
||||||
|
|
||||||
onSkillChanged(skill, event) {
|
onSkillChanged(skill, event) {
|
||||||
var newValue = event.target.checked;
|
const newValue = event.target.checked;
|
||||||
var newModel = {};
|
const newModel = {};
|
||||||
newModel[skill] = newValue;
|
newModel[skill] = newValue;
|
||||||
// set the state, and once it is done, then call filterChangedCallback
|
// set the state, and once it is done, then call filterChangedCallback
|
||||||
this.setState(newModel, this.props.filterChangedCallback );
|
this.setState(newModel, this.props.filterChangedCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
helloFromSkillsFilter() {
|
helloFromSkillsFilter() {
|
||||||
@@ -77,17 +81,18 @@ export default class SkillsFilter extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
||||||
var skillsTemplates = [];
|
const skillsTemplates = [];
|
||||||
RefData.IT_SKILLS.forEach( (skill, index) => {
|
RefData.IT_SKILLS.forEach((skill, index) => {
|
||||||
|
|
||||||
var skillName = RefData.IT_SKILLS_NAMES[index];
|
const skillName = RefData.IT_SKILLS_NAMES[index];
|
||||||
var template = (
|
const 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>
|
||||||
<div style={{textAlign: 'center'}}>{skillName}</div>
|
<div style={{textAlign: 'center'}}>{skillName}</div>
|
||||||
<div>
|
<div>
|
||||||
<input type="checkbox" onClick={this.onSkillChanged.bind(this, skill)}/>
|
<input type="checkbox" onClick={this.onSkillChanged.bind(this, skill)}/>
|
||||||
<img src={'images/skills/'+skill+'.png'} width={30}/>
|
<img src={'images/skills/' + skill + '.png'} width={30}/>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
@@ -98,7 +103,13 @@ export default class SkillsFilter extends React.Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{width: 380}}>
|
<div style={{width: 380}}>
|
||||||
<div style={{textAlign: 'center', background: 'lightgray', width: '100%', display: 'block', borderBottom: '1px solid grey'}}>
|
<div style={{
|
||||||
|
textAlign: 'center',
|
||||||
|
background: 'lightgray',
|
||||||
|
width: '100%',
|
||||||
|
display: 'block',
|
||||||
|
borderBottom: '1px solid grey'
|
||||||
|
}}>
|
||||||
<b>Custom Skills Filter</b>
|
<b>Custom Skills Filter</b>
|
||||||
</div>
|
</div>
|
||||||
{skillsTemplates}
|
{skillsTemplates}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
import React from "react";
|
||||||
|
import * as PropTypes from "prop-types";
|
||||||
|
|
||||||
|
// Header component to be used as default for all the columns.
|
||||||
|
export default class SortableHeaderComponent extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
// this.sortChanged = this.onSortChanged.bind(this);
|
||||||
|
this.props.column.addEventListener('sortChanged', this.onSortChanged);
|
||||||
|
|
||||||
|
//The state of this component contains the current sort state of this column
|
||||||
|
//The possible values are: 'asc', 'desc' and ''
|
||||||
|
this.state = {
|
||||||
|
sorted: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.props.column.removeEventListener('sortChanged', this.onSortChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let sortElements = [];
|
||||||
|
if (this.props.enableSorting) {
|
||||||
|
let downArrowClass = "customSortDownLabel " + (this.state.sorted === 'desc' ? " active" : "");
|
||||||
|
let upArrowClass = "customSortUpLabel " + (this.state.sorted === 'asc' ? " active" : "");
|
||||||
|
let removeArrowClass = "customSortRemoveLabel " + (this.state.sorted === '' ? " active" : "");
|
||||||
|
|
||||||
|
sortElements.push(<div key={`up${this.props.displayName}`} className={downArrowClass}
|
||||||
|
onClick={this.onSortRequested.bind(this, 'desc')}><i
|
||||||
|
className="fa fa-long-arrow-down"/></div>);
|
||||||
|
sortElements.push(<div key={`down${this.props.displayName}`} className={upArrowClass}
|
||||||
|
onClick={this.onSortRequested.bind(this, 'asc')}><i
|
||||||
|
className="fa fa-long-arrow-up"/></div>);
|
||||||
|
sortElements.push(<div key={`minus${this.props.displayName}`} className={removeArrowClass}
|
||||||
|
onClick={this.onSortRequested.bind(this, '')}><i
|
||||||
|
className="fa fa-times"/></div>)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let menuButton = null;
|
||||||
|
if (this.props.enableMenu) {
|
||||||
|
menuButton =
|
||||||
|
<div ref="menuButton" className="customHeaderMenuButton" onClick={this.onMenuClick.bind(this)}><i
|
||||||
|
className={"fa " + this.props.menuIcon}/></div>
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div>
|
||||||
|
{menuButton}
|
||||||
|
<div className="customHeaderLabel">{this.props.displayName}</div>
|
||||||
|
{sortElements}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
onSortRequested(order, event) {
|
||||||
|
this.props.setSort(order, event.shiftKey);
|
||||||
|
};
|
||||||
|
|
||||||
|
onSortChanged = () => {
|
||||||
|
if (this.props.column.isSortAscending()) {
|
||||||
|
this.setState({
|
||||||
|
sorted: 'asc'
|
||||||
|
})
|
||||||
|
} else if (this.props.column.isSortDescending()) {
|
||||||
|
this.setState({
|
||||||
|
sorted: 'desc'
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
sorted: ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMenuClick() {
|
||||||
|
this.props.showColumnMenu(this.refs.menuButton);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
SortableHeaderComponent.propTypes = {
|
||||||
|
params: PropTypes.object
|
||||||
|
};
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import React, {Component} from "react";
|
||||||
|
|
||||||
|
import {AgGridReact} from "ag-grid-react";
|
||||||
|
import {connect} from "react-redux";
|
||||||
|
|
||||||
|
import PriceRenderer from "./PriceRenderer";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This component serves to display the row data (provided by redux)
|
||||||
|
*/
|
||||||
|
class GridComponent extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
columnDefs: [
|
||||||
|
{
|
||||||
|
field: 'symbol'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'price',
|
||||||
|
cellClass: 'align-right',
|
||||||
|
cellRendererFramework: PriceRenderer
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onGridReady = this.onGridReady.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
onGridReady(params) {
|
||||||
|
this.gridApi = params.api;
|
||||||
|
this.columnApi = params.columnApi;
|
||||||
|
|
||||||
|
this.gridApi.sizeColumnsToFit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// row data will be provided via redux on this.props.rowData
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div style={{height: 400, width: 900, marginTop: 15}}
|
||||||
|
className="ag-fresh">
|
||||||
|
<AgGridReact
|
||||||
|
// properties
|
||||||
|
columnDefs={this.state.columnDefs}
|
||||||
|
rowData={this.props.rowData}
|
||||||
|
|
||||||
|
// events
|
||||||
|
onGridReady={this.onGridReady}>
|
||||||
|
</AgGridReact>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pull off row data changes
|
||||||
|
export default connect(
|
||||||
|
(state) => {
|
||||||
|
return {
|
||||||
|
rowData: state.rowData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)(GridComponent);
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
import React, {Component} from "react";
|
||||||
|
import {connect} from "react-redux";
|
||||||
|
|
||||||
|
// take this line out if you do not want to use ag-Grid-Enterprise
|
||||||
|
import "ag-grid-enterprise";
|
||||||
|
|
||||||
|
import {setCurrency, updateRowData} from "./gridDataActions";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This component serves both to host the demo controls, which in turn will drive row data state changes
|
||||||
|
*/
|
||||||
|
class HeaderComponent extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
// provide the initial data to the store (which in turn will populate the grid)
|
||||||
|
this.props.dispatch(updateRowData(this.createRowData()));
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrency(currencySymbol, exchangeRate) {
|
||||||
|
this.props.dispatch(setCurrency(currencySymbol, exchangeRate));
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div style={{marginTop: 15}}>
|
||||||
|
<button onClick={this.setCurrency.bind(this, '£', 1)}>Set Currency to GBP</button>
|
||||||
|
<button onClick={this.setCurrency.bind(this, '$', 1.29)}>Set Currency to USD</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// the following methods are for creating dummy row data
|
||||||
|
createRowData() {
|
||||||
|
let rowData = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < 14; i++) {
|
||||||
|
let newItem = this.createItem();
|
||||||
|
rowData.push(newItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rowData;
|
||||||
|
}
|
||||||
|
|
||||||
|
createItem() {
|
||||||
|
return {
|
||||||
|
symbol: this.createUniqueRandomSymbol(),
|
||||||
|
price: Math.floor(Math.random() * 100)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates a unique symbol, eg 'ADG' or 'ZJD'
|
||||||
|
createUniqueRandomSymbol() {
|
||||||
|
let symbol;
|
||||||
|
let possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
||||||
|
let isUnique = false;
|
||||||
|
while (!isUnique) {
|
||||||
|
symbol = '';
|
||||||
|
// create symbol
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
symbol += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||||
|
}
|
||||||
|
// check uniqueness
|
||||||
|
isUnique = true;
|
||||||
|
this.props.rowData.forEach(function (oldItem) {
|
||||||
|
if (oldItem.symbol === symbol) {
|
||||||
|
isUnique = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pull off row data
|
||||||
|
export default connect(
|
||||||
|
(state) => {
|
||||||
|
return {
|
||||||
|
rowData: state.rowData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)(HeaderComponent);
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import React, {Component} from "react";
|
||||||
|
import {connect} from "react-redux";
|
||||||
|
|
||||||
|
class PriceRenderer extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
convertedValue: this.applyExchangeRate(props.exchangeRate, props.value)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
this.setState({
|
||||||
|
convertedValue: this.applyExchangeRate(nextProps.exchangeRate, nextProps.value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<span>{this.props.currencySymbol}{this.state.convertedValue}</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
applyExchangeRate = (exchangeRate, value) => {
|
||||||
|
return parseFloat(value * exchangeRate).toFixed(2); // simplified/naive exchange rate implementation!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
(state) => {
|
||||||
|
return {
|
||||||
|
currencySymbol: state.currencySymbol,
|
||||||
|
exchangeRate: state.exchangeRate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)(PriceRenderer);
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import React, {Component} from "react";
|
||||||
|
import {Provider} from "react-redux";
|
||||||
|
import {createStore} from "redux";
|
||||||
|
|
||||||
|
// take this line out if you do not want to use ag-Grid-Enterprise
|
||||||
|
import "ag-grid-enterprise";
|
||||||
|
|
||||||
|
import HeaderComponent from "./HeaderComponent";
|
||||||
|
import GridComponent from "./GridComponent";
|
||||||
|
|
||||||
|
import gridData from "./gridDataReducer";
|
||||||
|
|
||||||
|
let store = createStore(gridData);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This component serves as a container for both the header and grid components. It's primarily here to act as a container
|
||||||
|
* for the redux Provider
|
||||||
|
*/
|
||||||
|
export default class SimpleReduxExample extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Provider store={store}>
|
||||||
|
<div>
|
||||||
|
<h1>Simple Redux Example using Connected React Components</h1>
|
||||||
|
<HeaderComponent />
|
||||||
|
<GridComponent />
|
||||||
|
</div>
|
||||||
|
</Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
export function updateRowData(rowData) {
|
||||||
|
return {
|
||||||
|
type: 'ROW_DATA_CHANGED',
|
||||||
|
rowData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export function setCurrency(currencySymbol, exchangeRate) {
|
||||||
|
return {
|
||||||
|
type: 'CURRENCY_CHANGED',
|
||||||
|
currencySymbol,
|
||||||
|
exchangeRate
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
export default (state = {rowData: [], currencySymbol: '£', exchangeRate: 1}, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case 'ROW_DATA_CHANGED':
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
rowData: action.rowData,
|
||||||
|
};
|
||||||
|
case 'CURRENCY_CHANGED':
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
currencySymbol: action.currencySymbol,
|
||||||
|
exchangeRate: action.exchangeRate
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
import ReactDOM from 'react-dom';
|
|
||||||
import React from 'react';
|
|
||||||
import MyApp from './myApp.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(MyApp),
|
|
||||||
container
|
|
||||||
);
|
|
||||||
});
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
|
|
||||||
.ag-cell {
|
|
||||||
padding-top: 2px !important;
|
|
||||||
padding-bottom: 2px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
font-weight: normal !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.div-percent-bar {
|
|
||||||
display: inline-block;
|
|
||||||
height: 20px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.div-percent-value {
|
|
||||||
position: absolute;
|
|
||||||
padding-left: 4px;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.div-outer-div {
|
|
||||||
display: inline-block;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
@@ -1,356 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import {AgGridReact} from "ag-grid-react";
|
|
||||||
import "./myApp.css";
|
|
||||||
import "ag-grid-enterprise";
|
|
||||||
|
|
||||||
|
|
||||||
export class DetailPanelCellRenderer extends React.Component{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
render (){
|
|
||||||
return <div><div class="full-width-panel">
|
|
||||||
<div class="full-width-details">
|
|
||||||
<div class="full-width-detail"><b>Name: </b>+parentRecord.name+</div>
|
|
||||||
<div class="full-width-detail"><b>Account: </b>+parentRecord.account+</div>
|
|
||||||
</div>
|
|
||||||
<div class="full-width-grid"></div>
|
|
||||||
<div class="full-width-grid-toolbar">
|
|
||||||
<img class="full-width-phone-icon" src="https://www.ag-grid.com/images/phone.png"/>
|
|
||||||
<button><img src="https://www.ag-grid.com/images/fire.png"/></button>
|
|
||||||
<button><img src="https://www.ag-grid.com/images/frost.png"/></button>
|
|
||||||
<button><img src="https://www.ag-grid.com/images/sun.png"/></button>
|
|
||||||
<input class="full-width-search" placeholder="Search..."/>
|
|
||||||
</div>
|
|
||||||
</div></div>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// take this line out if you do not want to use ag-Grid-Enterprise
|
|
||||||
// a list of names we pick from when generating data
|
|
||||||
var firstnames = ['Sophia','Emma','Olivia','Isabella','Mia','Ava','Lily','Zoe','Emily','Chloe','Layla','Madison','Madelyn','Abigail','Aubrey','Charlotte','Amelia','Ella','Kaylee','Avery','Aaliyah','Hailey','Hannah','Addison','Riley','Harper','Aria','Arianna','Mackenzie','Lila','Evelyn','Adalyn','Grace','Brooklyn','Ellie','Anna','Kaitlyn','Isabelle','Sophie','Scarlett','Natalie','Leah','Sarah','Nora','Mila','Elizabeth','Lillian','Kylie','Audrey','Lucy','Maya'];
|
|
||||||
var lastnames = ['Smith','Jones','Williams','Taylor','Brown','Davies','Evans','Wilson','Thomas','Johnson'];
|
|
||||||
|
|
||||||
var images = ['niall','sean','alberto','statue','horse'];
|
|
||||||
// each call gets a unique id, nothing to do with the grid, just help make the sample
|
|
||||||
// data more realistic
|
|
||||||
var callIdSequence = 555;
|
|
||||||
|
|
||||||
// method creates all the data, both the top level grid and the lower level grids
|
|
||||||
function createRowData() {
|
|
||||||
var rowData = [];
|
|
||||||
|
|
||||||
for (var i = 0; i < 20; i++) {
|
|
||||||
var firstName = firstnames[Math.floor(Math.random()*firstnames.length)];
|
|
||||||
var lastName = lastnames[Math.floor(Math.random()*lastnames.length)];
|
|
||||||
|
|
||||||
var image = images[i % images.length];
|
|
||||||
|
|
||||||
var totalDuration = 0;
|
|
||||||
|
|
||||||
var callRecords = [];
|
|
||||||
// call count is random number between 20 and 120
|
|
||||||
var callCount = Math.floor(Math.random() * 100) + 20;
|
|
||||||
for (var j = 0; j<callCount; j++) {
|
|
||||||
// duration is random number between 20 and 120
|
|
||||||
var callDuration = Math.floor(Math.random() * 100) + 20;
|
|
||||||
var callRecord = {
|
|
||||||
callId: callIdSequence++,
|
|
||||||
duration: callDuration,
|
|
||||||
switchCode: 'SW' + Math.floor(Math.random() * 10),
|
|
||||||
// 50% chance of in vs out
|
|
||||||
direction: (Math.random()>.5) ? 'In' : 'Out',
|
|
||||||
// made up number
|
|
||||||
number: '(0' + Math.floor(Math.random() * 10) + ') ' + Math.floor(Math.random() * 100000000)
|
|
||||||
};
|
|
||||||
callRecords.push(callRecord);
|
|
||||||
totalDuration += callDuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
var record = {
|
|
||||||
name: firstName + ' ' + lastName,
|
|
||||||
account: i + 177000,
|
|
||||||
totalCalls: callCount,
|
|
||||||
image: image,
|
|
||||||
// convert from seconds to minutes
|
|
||||||
totalMinutes: totalDuration / 60,
|
|
||||||
callRecords: callRecords
|
|
||||||
};
|
|
||||||
rowData.push(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rowData;
|
|
||||||
}
|
|
||||||
|
|
||||||
var minuteCellFormatter = function (params) {
|
|
||||||
return params.value.toLocaleString() + 'm';
|
|
||||||
};
|
|
||||||
|
|
||||||
var secondCellFormatter= function (params) {
|
|
||||||
return params.value.toLocaleString() + 's';
|
|
||||||
};
|
|
||||||
|
|
||||||
var masterColumnDefs = [
|
|
||||||
{headerName: 'Name', field: 'name',
|
|
||||||
// left column is going to act as group column, with the expand / contract controls
|
|
||||||
cellRenderer: 'group',
|
|
||||||
// we don't want the child count - it would be one each time anyway as each parent
|
|
||||||
// not has exactly one child node
|
|
||||||
cellRendererParams: { suppressCount: true }
|
|
||||||
},
|
|
||||||
{headerName: 'Account', field: 'account'},
|
|
||||||
{headerName: 'Calls', field: 'totalCalls'},
|
|
||||||
{headerName: 'Minutes', field: 'totalMinutes', cellFormatter: minuteCellFormatter}
|
|
||||||
];
|
|
||||||
|
|
||||||
var detailColumnDefs = [
|
|
||||||
{headerName: 'Call ID', field: 'callId', cellClass: 'call-record-cell'},
|
|
||||||
{headerName: 'Direction', field: 'direction', cellClass: 'call-record-cell'},
|
|
||||||
{headerName: 'Number', field: 'number', cellClass: 'call-record-cell'},
|
|
||||||
{headerName: 'Duration', field: 'duration', cellClass: 'call-record-cell', cellFormatter: secondCellFormatter},
|
|
||||||
{headerName: 'Switch', field: 'switchCode', cellClass: 'call-record-cell'}
|
|
||||||
];
|
|
||||||
|
|
||||||
var rowData = createRowData();
|
|
||||||
export default class MyApp extends React.Component {
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
quickFilterText: null,
|
|
||||||
showGrid: true,
|
|
||||||
showToolPanel: false,
|
|
||||||
icons: {
|
|
||||||
columnRemoveFromGroup: '<i class="fa fa-remove"/>',
|
|
||||||
filter: '<i class="fa fa-filter"/>',
|
|
||||||
sortAscending: '<i class="fa fa-long-arrow-down"/>',
|
|
||||||
sortDescending: '<i class="fa fa-long-arrow-up"/>',
|
|
||||||
groupExpanded: '<i class="fa fa-minus-square-o"/>',
|
|
||||||
groupContracted: '<i class="fa fa-plus-square-o"/>',
|
|
||||||
columnGroupOpened: '<i class="fa fa-minus-square-o"/>',
|
|
||||||
columnGroupClosed: '<i class="fa fa-plus-square-o"/>'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// the grid options are optional, because you can provide every property
|
|
||||||
// to the grid via standard React properties. however, the react interface
|
|
||||||
// doesn't block you from using the standard JavaScript interface if you
|
|
||||||
// wish. Maybe you have the gridOptions stored as JSON on your server? If
|
|
||||||
// you do, the providing the gridOptions as a standalone object is just
|
|
||||||
// what you want!
|
|
||||||
this.gridOptions = {
|
|
||||||
columnDefs: masterColumnDefs,
|
|
||||||
rowData: rowData,
|
|
||||||
//We register the react date component that ag-grid will use to render
|
|
||||||
// this is how you listen for events using gridOptions
|
|
||||||
onModelUpdated: function () {
|
|
||||||
console.log('event onModelUpdated received');
|
|
||||||
},
|
|
||||||
defaultColDef : {
|
|
||||||
headerComponentParams : {
|
|
||||||
menuIcon: 'fa-bars'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// this is a simple property
|
|
||||||
rowBuffer: 10 // no need to set this, the default is fine for almost all scenarios
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
onShowGrid(show) {
|
|
||||||
this.setState({
|
|
||||||
showGrid: show
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onToggleToolPanel(event) {
|
|
||||||
this.setState({showToolPanel: event.target.checked});
|
|
||||||
}
|
|
||||||
|
|
||||||
onGridReady(params) {
|
|
||||||
this.api = params.api;
|
|
||||||
this.columnApi = params.columnApi;
|
|
||||||
params.api.sizeColumnsToFit();
|
|
||||||
}
|
|
||||||
|
|
||||||
selectAll() {
|
|
||||||
this.api.selectAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
deselectAll() {
|
|
||||||
this.api.deselectAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
setCountryVisible(visible) {
|
|
||||||
this.columnApi.setColumnVisible('country', visible);
|
|
||||||
}
|
|
||||||
|
|
||||||
onQuickFilterText(event) {
|
|
||||||
this.setState({quickFilterText: event.target.value});
|
|
||||||
}
|
|
||||||
|
|
||||||
onCellClicked(event) {
|
|
||||||
console.log('onCellClicked: ' + event.data.name + ', col ' + event.colIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
onRowSelected(event) {
|
|
||||||
console.log('onRowSelected: ' + event.node.data.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
onRefreshData() {
|
|
||||||
var newRowData = new RowDataFactory().createRowData();
|
|
||||||
this.setState({
|
|
||||||
rowData: newRowData
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
invokeSkillsFilterMethod() {
|
|
||||||
var skillsFilter = this.api.getFilterInstance('skills');
|
|
||||||
var componentInstance = skillsFilter.getFrameworkComponentInstance();
|
|
||||||
componentInstance.helloFromSkillsFilter();
|
|
||||||
}
|
|
||||||
|
|
||||||
dobFilter () {
|
|
||||||
let dateFilterComponent = this.gridOptions.api.getFilterInstance('dob');
|
|
||||||
dateFilterComponent.setFilterType('equals');
|
|
||||||
dateFilterComponent.setDateFrom('2000-01-01');
|
|
||||||
this.gridOptions.api.onFilterChanged();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
onIsFullWidthCell (rowNode) {
|
|
||||||
return rowNode.level === 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
onGetRowHeight (params) {
|
|
||||||
var rowIsDetailRow = params.node.level===1;
|
|
||||||
// return 100 when detail row, otherwise return 25
|
|
||||||
return rowIsDetailRow ? 75 : 25;
|
|
||||||
}
|
|
||||||
|
|
||||||
onGetNodeChildDetails (record) {
|
|
||||||
if (record.callRecords) {
|
|
||||||
return {
|
|
||||||
group: true,
|
|
||||||
// the key is used by the default group cellRenderer
|
|
||||||
key: record.name,
|
|
||||||
// provide ag-Grid with the children of this group
|
|
||||||
children: [record.callRecords],
|
|
||||||
// for demo, expand the third row by default
|
|
||||||
expanded: record.account === 177005
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
var gridTemplate;
|
|
||||||
var bottomHeaderTemplate;
|
|
||||||
var topHeaderTemplate;
|
|
||||||
|
|
||||||
topHeaderTemplate = (
|
|
||||||
<div>
|
|
||||||
<div style={{float: 'right'}}>
|
|
||||||
<input type="text" onChange={this.onQuickFilterText.bind(this)}
|
|
||||||
placeholder="Type text to filter..."/>
|
|
||||||
<button id="btDestroyGrid" disabled={!this.state.showGrid}
|
|
||||||
onClick={this.onShowGrid.bind(this, false)}>Destroy Grid
|
|
||||||
</button>
|
|
||||||
<button id="btCreateGrid" disabled={this.state.showGrid} onClick={this.onShowGrid.bind(this, true)}>
|
|
||||||
Create Grid
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div style={{padding: '4px'}}>
|
|
||||||
<b>Employees Skills and Contact Details</b> <span id="rowCount"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
// showing the bottom header and grid is optional, so we put in a switch
|
|
||||||
if (this.state.showGrid) {
|
|
||||||
bottomHeaderTemplate = (
|
|
||||||
<div>
|
|
||||||
<div style={{padding: 4}} className={'toolbar'}>
|
|
||||||
<span>
|
|
||||||
Grid API:
|
|
||||||
<button onClick={this.selectAll.bind(this)}>Select All</button>
|
|
||||||
<button onClick={this.deselectAll.bind(this)}>Clear Selection</button>
|
|
||||||
</span>
|
|
||||||
<span style={{marginLeft: 20}}>
|
|
||||||
Column API:
|
|
||||||
<button onClick={this.setCountryVisible.bind(this, false)}>Hide Country Column</button>
|
|
||||||
<button onClick={this.setCountryVisible.bind(this, true)}>Show Country Column</button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div style={{clear: 'both'}}></div>
|
|
||||||
<div style={{padding: 4}} className={'toolbar'}>
|
|
||||||
<span>
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" onChange={this.onToggleToolPanel.bind(this)}/>
|
|
||||||
Show Tool Panel
|
|
||||||
</label>
|
|
||||||
<button onClick={this.onRefreshData.bind(this)}>Refresh Data</button>
|
|
||||||
</span>
|
|
||||||
<span style={{marginLeft: 20}}>
|
|
||||||
Filter API:
|
|
||||||
<button onClick={this.invokeSkillsFilterMethod.bind(this, false)}>Invoke Skills Filter Method</button>
|
|
||||||
<button onClick={this.dobFilter.bind(this)}>DOB equals to 01/01/2000</button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div style={{clear: 'both'}}></div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
gridTemplate = (
|
|
||||||
<div style={{height: 400}} className="ag-fresh">
|
|
||||||
<AgGridReact
|
|
||||||
// gridOptions is optional - it's possible to provide
|
|
||||||
// all values as React props
|
|
||||||
gridOptions={this.gridOptions}
|
|
||||||
|
|
||||||
// listening for events
|
|
||||||
onGridReady={this.onGridReady.bind(this)}
|
|
||||||
onRowSelected={this.onRowSelected.bind(this)}
|
|
||||||
onCellClicked={this.onCellClicked.bind(this)}
|
|
||||||
|
|
||||||
// binding to simple properties
|
|
||||||
showToolPanel={this.state.showToolPanel}
|
|
||||||
quickFilterText={this.state.quickFilterText}
|
|
||||||
|
|
||||||
// binding to an object property
|
|
||||||
icons={this.state.icons}
|
|
||||||
|
|
||||||
|
|
||||||
// no binding, just providing hard coded strings for the properties
|
|
||||||
suppressRowClickSelection="true"
|
|
||||||
rowSelection="multiple"
|
|
||||||
enableColResize="true"
|
|
||||||
enableSorting="true"
|
|
||||||
enableFilter="true"
|
|
||||||
groupHeaders="true"
|
|
||||||
rowHeight="22"
|
|
||||||
// we cannot filter on the groups, as filters work on the child nodes, and in this example
|
|
||||||
// the child nodes are not aggregations of the parent.
|
|
||||||
suppressMenuFilterPanel="true"
|
|
||||||
isFullWidthCell = {this.onIsFullWidthCell.bind(this)}
|
|
||||||
// see ag-Grid docs cellRenderer for details on how to build cellRenderers
|
|
||||||
fullWidthCellRendererFramework= {DetailPanelCellRenderer}
|
|
||||||
getRowHeight={this.onGetRowHeight.bind(this)}
|
|
||||||
getNodeChildDetails={this.onGetNodeChildDetails.bind(this)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <div style={{width: '1024px'}}>
|
|
||||||
<div style={{padding: '4px'}}>
|
|
||||||
{topHeaderTemplate}
|
|
||||||
{bottomHeaderTemplate}
|
|
||||||
{gridTemplate}
|
|
||||||
</div>
|
|
||||||
</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
export default class ColDefFactory {
|
|
||||||
createColDefs() {
|
|
||||||
return [
|
|
||||||
{headerName: "Athlete", field: "athlete", width: 200},
|
|
||||||
{headerName: "Age", field: "age", width: 90},
|
|
||||||
{headerName: "Gold", field: "gold", width: 100, aggFunc: 'sum'},
|
|
||||||
{headerName: "Silver", field: "silver", width: 100, aggFunc: 'sum'},
|
|
||||||
{headerName: "Bronze", field: "bronze", width: 100, aggFunc: 'sum'},
|
|
||||||
{headerName: "Total", field: "total", width: 100, aggFunc: 'sum'},
|
|
||||||
{headerName: "Country", field: "country", width: 120, rowGroupIndex: 0},
|
|
||||||
{headerName: "Year", field: "year", width: 90},
|
|
||||||
{headerName: "Date", field: "date", width: 110},
|
|
||||||
{headerName: "Sport", field: "sport", width: 110}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
import ReactDOM from 'react-dom';
|
|
||||||
import React from 'react';
|
|
||||||
import MyApp from './myApp.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(MyApp),
|
|
||||||
container
|
|
||||||
);
|
|
||||||
});
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
|
|
||||||
.ag-cell {
|
|
||||||
padding-top: 2px !important;
|
|
||||||
padding-bottom: 2px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
font-weight: normal !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.div-percent-bar {
|
|
||||||
display: inline-block;
|
|
||||||
height: 20px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.div-percent-value {
|
|
||||||
position: absolute;
|
|
||||||
padding-left: 4px;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.div-outer-div {
|
|
||||||
display: inline-block;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import {AgGridReact} from "ag-grid-react";
|
|
||||||
import ColDefFactory from "./ColDefFactory.jsx";
|
|
||||||
import "./myApp.css";
|
|
||||||
|
|
||||||
// take this line out if you do not want to use ag-Grid-Enterprise
|
|
||||||
import "ag-grid-enterprise";
|
|
||||||
|
|
||||||
|
|
||||||
export default class MyApp extends React.Component {
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
showToolPanel: false,
|
|
||||||
columnDefs: new ColDefFactory().createColDefs(),
|
|
||||||
rowData: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.gridOptions = {
|
|
||||||
groupRowInnerRenderer: function (params) {
|
|
||||||
var FLAG_CODES = {
|
|
||||||
'Ireland': 'ie',
|
|
||||||
'United States': 'us',
|
|
||||||
'Russia': 'ru',
|
|
||||||
'Australia': 'au',
|
|
||||||
'Canada': 'ca',
|
|
||||||
'Norway': 'no',
|
|
||||||
'China': 'cn',
|
|
||||||
'Zimbabwe': 'zw',
|
|
||||||
'Netherlands': 'nl',
|
|
||||||
'South Korea': 'kr',
|
|
||||||
'Croatia': 'hr',
|
|
||||||
'France': 'fr'
|
|
||||||
};
|
|
||||||
|
|
||||||
var flagCode = FLAG_CODES[params.node.key];
|
|
||||||
|
|
||||||
var html = '';
|
|
||||||
if (flagCode) {
|
|
||||||
html += '<img class="flag" border="0" width="20" height="15" src="https://flags.fmcdn.net/data/flags/mini/' + flagCode + '.png">'
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '<span class="groupTitle"> COUNTRY_NAME</span>'.replace('COUNTRY_NAME', params.node.key);
|
|
||||||
html += '<span class="medal gold"> Gold: GOLD_COUNT</span>'.replace('GOLD_COUNT', params.data.gold);
|
|
||||||
html += '<span class="medal silver"> Silver: SILVER_COUNT</span>'.replace('SILVER_COUNT', params.data.silver);
|
|
||||||
html += '<span class="medal bronze"> Bronze: BRONZE_COUNT</span>'.replace('BRONZE_COUNT', params.data.bronze);
|
|
||||||
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
onGridReady(params) {
|
|
||||||
this.api = params.api;
|
|
||||||
this.columnApi = params.columnApi;
|
|
||||||
|
|
||||||
var that = this;
|
|
||||||
var httpRequest = new XMLHttpRequest();
|
|
||||||
httpRequest.open('GET', '/olympicWinners.json');
|
|
||||||
httpRequest.send();
|
|
||||||
httpRequest.onreadystatechange = function() {
|
|
||||||
if (httpRequest.readyState == 4 && httpRequest.status == 200) {
|
|
||||||
var httpResult = JSON.parse(httpRequest.responseText);
|
|
||||||
that.api.setRowData(httpResult);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
var gridTemplate = (
|
|
||||||
<div style={{height: 400}} className="ag-fresh">
|
|
||||||
<AgGridReact
|
|
||||||
// gridOptions is optional - it's possible to provide
|
|
||||||
// all values as React props
|
|
||||||
gridOptions={this.gridOptions}
|
|
||||||
|
|
||||||
// listening for events
|
|
||||||
onGridReady={this.onGridReady.bind(this)}
|
|
||||||
|
|
||||||
// binding to array properties
|
|
||||||
columnDefs={this.state.columnDefs}
|
|
||||||
rowData={this.state.rowData}
|
|
||||||
|
|
||||||
groupUseEntireRow="true"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
return <div style={{width: '800px'}}>
|
|
||||||
<div>
|
|
||||||
{gridTemplate}
|
|
||||||
</div>
|
|
||||||
</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
<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/react-large.js" charset="utf-8"></script>
|
||||||
<!-- Example uses font awesome icons -->
|
<!-- Example uses font awesome icons -->
|
||||||
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
|
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
|
||||||
</head>
|
</head>
|
||||||
@@ -3,9 +3,9 @@
|
|||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import LargeGrid from './largeGrid.jsx';
|
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/dist/styles/ag-grid.css';
|
||||||
import 'ag-grid-root/dist/styles/theme-fresh.css';
|
import 'ag-grid/dist/styles/theme-fresh.css';
|
||||||
|
|
||||||
// waiting for dom to load before booting react. we could alternatively
|
// 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.
|
// put the index.js reference at the end fo the index.html, but i prefer this way.
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import React from 'react';
|
import React, {Component} from 'react';
|
||||||
import {reactCellRendererFactory} from 'ag-grid-react';
|
|
||||||
import SimpleCellRenderer from './simpleCellRenderer.jsx';
|
import SimpleCellRenderer from './simpleCellRenderer.jsx';
|
||||||
|
|
||||||
import {AgGridReact} from 'ag-grid-react';
|
import {AgGridReact} from 'ag-grid-react';
|
||||||
@@ -7,7 +6,7 @@ import {AgGridReact} from 'ag-grid-react';
|
|||||||
// put this line in to use ag-Grid enterprise
|
// put this line in to use ag-Grid enterprise
|
||||||
// import 'ag-grid-enterprise';
|
// import 'ag-grid-enterprise';
|
||||||
|
|
||||||
export default class MyApp extends React.Component {
|
export default class MyApp extends Component {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
@@ -22,22 +21,22 @@ export default class MyApp extends React.Component {
|
|||||||
|
|
||||||
createColumnNames() {
|
createColumnNames() {
|
||||||
// creates column names by iterating the alphabet twice, eg {'aa','ab','ac',.....'zz'}
|
// creates column names by iterating the alphabet twice, eg {'aa','ab','ac',.....'zz'}
|
||||||
var alphabet = 'abcdefghijklmnopqrstuvwxyz'.split('');
|
const alphabet = 'abcdefghijklmnopqrstuvwxyz'.split('');
|
||||||
this.columnNames = [];
|
this.columnNames = [];
|
||||||
alphabet.forEach( letter1 => {
|
alphabet.forEach(letter1 => {
|
||||||
alphabet.forEach( letter2 => {
|
alphabet.forEach(letter2 => {
|
||||||
this.columnNames.push(letter1 + letter2);
|
this.columnNames.push(letter1 + letter2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
createRowData() {
|
createRowData() {
|
||||||
var rowData = [];
|
const rowData = [];
|
||||||
|
|
||||||
for (var i = 0; i<1000; i++) {
|
for (let i = 0; i < 1000; i++) {
|
||||||
var item = {};
|
const item = {};
|
||||||
this.columnNames.forEach( colName => {
|
this.columnNames.forEach(colName => {
|
||||||
item[colName] = '('+colName.toUpperCase()+','+i+')'
|
item[colName] = '(' + colName.toUpperCase() + ',' + i + ')'
|
||||||
});
|
});
|
||||||
rowData.push(item);
|
rowData.push(item);
|
||||||
}
|
}
|
||||||
@@ -46,9 +45,9 @@ export default class MyApp extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createColumnDefs() {
|
createColumnDefs() {
|
||||||
var columnDefs = [];
|
const columnDefs = [];
|
||||||
|
|
||||||
this.columnNames.forEach( colName => {
|
this.columnNames.forEach(colName => {
|
||||||
columnDefs.push({
|
columnDefs.push({
|
||||||
headerName: colName.toUpperCase(),
|
headerName: colName.toUpperCase(),
|
||||||
field: colName,
|
field: colName,
|
||||||
@@ -63,7 +62,7 @@ export default class MyApp extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div style={{height: '100%'}} className="ag-fresh">
|
<div style={{height: '100%'}} className="ag-fresh">
|
||||||
<AgGridReact columnDefs={this.state.columnDefs} rowData={this.state.rowData} />
|
<AgGridReact columnDefs={this.state.columnDefs} rowData={this.state.rowData}/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import * as PropTypes from 'prop-types';
|
||||||
|
|
||||||
export default class SimpleCellRenderer extends React.Component {
|
export default class SimpleCellRenderer extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
@@ -11,5 +12,5 @@ export default class SimpleCellRenderer extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SimpleCellRenderer.propTypes = {
|
SimpleCellRenderer.propTypes = {
|
||||||
params: React.PropTypes.object
|
params: PropTypes.object
|
||||||
};
|
};
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
import SkillsCellRenderer from './SkillsCellRenderer.jsx';
|
|
||||||
import NameCellEditor from './NameCellEditor.jsx';
|
|
||||||
import ProficiencyCellRenderer from './ProficiencyCellRenderer.jsx';
|
|
||||||
import RefData from './RefData';
|
|
||||||
import SkillsFilter from './SkillsFilter.jsx';
|
|
||||||
import ProficiencyFilter from './ProficiencyFilter.jsx';
|
|
||||||
import MyReactHeaderGroupComponent from './MyReactHeaderGroupComponent.jsx';
|
|
||||||
|
|
||||||
export default class ColDefFactory {
|
|
||||||
|
|
||||||
createColDefs() {
|
|
||||||
|
|
||||||
var columnDefs = [
|
|
||||||
{headerName: '#', width: 30, checkboxSelection: true, suppressSorting: true,
|
|
||||||
suppressMenu: true, pinned: true},
|
|
||||||
{
|
|
||||||
headerName: 'Employee',
|
|
||||||
headerGroupComponentFramework: MyReactHeaderGroupComponent,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
headerName: "Name", field: "name", enableRowGroup: true, enablePivot: true,
|
|
||||||
width: 150, pinned: true, editable: true,
|
|
||||||
// use a React cellEditor
|
|
||||||
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,
|
|
||||||
filterParams: {
|
|
||||||
cellRenderer: countryCellRenderer, cellHeight: 20
|
|
||||||
}, columnGroupShow: 'open'
|
|
||||||
}, {
|
|
||||||
headerName: "DOB", field: "dob", width: 110, enableRowGroup: true, enablePivot: true, filter:'date',
|
|
||||||
pinned: true, cellRenderer: function(params) {
|
|
||||||
return pad(params.value.getDate(), 2) + '/' +
|
|
||||||
pad(params.value.getMonth() + 1, 2)+ '/' +
|
|
||||||
params.value.getFullYear();
|
|
||||||
}, columnGroupShow: 'open'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headerName: 'IT Skills',
|
|
||||||
children: [
|
|
||||||
{headerName: "Skills", width: 125, suppressSorting: true, field: 'skills', enableRowGroup: true, enablePivot: true,
|
|
||||||
// supply a React component
|
|
||||||
cellRendererFramework: SkillsCellRenderer,
|
|
||||||
// supply a React component
|
|
||||||
filterFramework: SkillsFilter
|
|
||||||
},
|
|
||||||
{headerName: "Proficiency", field: "proficiency", width: 135, enableValue: true,
|
|
||||||
// supply a React component
|
|
||||||
cellRendererFramework: ProficiencyCellRenderer,
|
|
||||||
// supply a React component
|
|
||||||
filterFramework: ProficiencyFilter
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headerName: 'Contact',
|
|
||||||
children: [
|
|
||||||
{headerName: "Mobile", field: "mobile", width: 150, filter: 'text'},
|
|
||||||
{headerName: "Land-line", field: "landline", width: 150, filter: 'text'},
|
|
||||||
{headerName: "Address", field: "address", width: 500, filter: 'text'}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
return columnDefs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is a simple cell renderer, putting together static html, no
|
|
||||||
// need to use React for it.
|
|
||||||
function countryCellRenderer(params) {
|
|
||||||
if (params.value) {
|
|
||||||
var flag = "<img border='0' width='15' height='10' " +
|
|
||||||
"style='margin-bottom: 2px' src='http://flags.fmcdn.net/data/flags/mini/"
|
|
||||||
+ RefData.COUNTRY_CODES[params.value] + ".png'>";
|
|
||||||
return flag + " " + params.value;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Utility function used to pad the date formatting.
|
|
||||||
function pad(num, totalStringSize) {
|
|
||||||
let asString = num + "";
|
|
||||||
while (asString.length < totalStringSize) asString = "0" + asString;
|
|
||||||
return asString;
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
// Header component to be used as default for all the columns.
|
|
||||||
export default class MyReactHeaderComponent extends React.Component {
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.props.column.addEventListener('sortChanged', this.onSortChanged.bind(this));
|
|
||||||
|
|
||||||
//The state of this component contains the current sort state of this column
|
|
||||||
//The possible values are: 'asc', 'desc' and ''
|
|
||||||
this.state = {
|
|
||||||
sorted: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
render() {
|
|
||||||
let sortElements = [];
|
|
||||||
if (this.props.enableSorting){
|
|
||||||
let downArrowClass = "customSortDownLabel " + (this.state.sorted === 'desc' ? " active" : "");
|
|
||||||
let upArrowClass = "customSortUpLabel " + (this.state.sorted === 'asc' ? " active" : "");
|
|
||||||
let removeArrowClass = "customSortRemoveLabel " + (this.state.sorted === '' ? " active" : "");
|
|
||||||
|
|
||||||
sortElements.push(<div className={downArrowClass} onClick={this.onSortRequested.bind(this, 'desc')}><i className="fa fa-long-arrow-down"/></div>)
|
|
||||||
sortElements.push(<div className={upArrowClass} onClick={this.onSortRequested.bind(this, 'asc')}><i className="fa fa-long-arrow-up"/></div>)
|
|
||||||
sortElements.push(<div className={removeArrowClass} onClick={this.onSortRequested.bind(this, '')}><i className="fa fa-times"/></div>)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
let menuButton = null;
|
|
||||||
if (this.props.enableMenu){
|
|
||||||
menuButton = <div ref="menuButton" className="customHeaderMenuButton" onClick={this.onMenuClick.bind(this)}><i className={"fa " + this.props.menuIcon}/></div>
|
|
||||||
}
|
|
||||||
|
|
||||||
return <div>
|
|
||||||
{menuButton}
|
|
||||||
<div className="customHeaderLabel">{this.props.displayName}</div>
|
|
||||||
{sortElements}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
onSortRequested (order, event) {
|
|
||||||
this.props.setSort (order, event.shiftKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
onSortChanged (){
|
|
||||||
if (this.props.column.isSortAscending()){
|
|
||||||
this.setState({
|
|
||||||
sorted: 'asc'
|
|
||||||
})
|
|
||||||
} else if (this.props.column.isSortDescending()){
|
|
||||||
this.setState({
|
|
||||||
sorted: 'desc'
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
sorted: ''
|
|
||||||
})
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onMenuClick (){
|
|
||||||
this.props.showColumnMenu (this.refs.menuButton);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
MyReactHeaderComponent.propTypes = {
|
|
||||||
params: React.PropTypes.object
|
|
||||||
};
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
export default class RefData {}
|
|
||||||
|
|
||||||
RefData.FIRST_NAMES = [
|
|
||||||
"Sophie", "Isabelle", "Emily", "Olivia", "Lily", "Chloe", "Isabella",
|
|
||||||
"Amelia", "Jessica", "Sophia", "Ava", "Charlotte", "Mia", "Lucy", "Grace", "Ruby",
|
|
||||||
"Ella", "Evie", "Freya", "Isla", "Poppy", "Daisy", "Layla"
|
|
||||||
];
|
|
||||||
|
|
||||||
RefData.LAST_NAMES = [
|
|
||||||
"Beckham", "Black", "Braxton", "Brennan", "Brock", "Bryson", "Cadwell",
|
|
||||||
"Cage", "Carson", "Chandler", "Cohen", "Cole", "Corbin", "Dallas", "Dalton", "Dane",
|
|
||||||
"Donovan", "Easton", "Fisher", "Fletcher", "Grady", "Greyson", "Griffin", "Gunner",
|
|
||||||
"Hayden", "Hudson", "Hunter", "Jacoby", "Jagger", "Jaxon", "Jett", "Kade", "Kane",
|
|
||||||
"Keating", "Keegan", "Kingston", "Kobe"
|
|
||||||
];
|
|
||||||
|
|
||||||
RefData.COUNTRY_CODES = {
|
|
||||||
Ireland: "ie",
|
|
||||||
Spain: "es",
|
|
||||||
"United Kingdom": "gb",
|
|
||||||
France: "fr",
|
|
||||||
Germany: "de",
|
|
||||||
Sweden: "se",
|
|
||||||
Italy: "it",
|
|
||||||
Greece: "gr",
|
|
||||||
Iceland: "is",
|
|
||||||
Portugal: "pt",
|
|
||||||
Malta: "mt",
|
|
||||||
Norway: "no",
|
|
||||||
Brazil: "br",
|
|
||||||
Argentina: "ar",
|
|
||||||
Colombia: "co",
|
|
||||||
Peru: "pe",
|
|
||||||
Venezuela: "ve",
|
|
||||||
Uruguay: "uy"
|
|
||||||
};
|
|
||||||
|
|
||||||
RefData.COUNTRIES = [
|
|
||||||
{country: "Ireland", continent: "Europe", language: "English"},
|
|
||||||
{country: "Spain", continent: "Europe", language: "Spanish"},
|
|
||||||
{country: "United Kingdom", continent: "Europe", language: "English"},
|
|
||||||
{country: "France", continent: "Europe", language: "French"},
|
|
||||||
{country: "Germany", continent: "Europe", language: "(other)"},
|
|
||||||
{country: "Sweden", continent: "Europe", language: "(other)"},
|
|
||||||
{country: "Norway", continent: "Europe", language: "(other)"},
|
|
||||||
{country: "Italy", continent: "Europe", language: "(other)"},
|
|
||||||
{country: "Greece", continent: "Europe", language: "(other)"},
|
|
||||||
{country: "Iceland", continent: "Europe", language: "(other)"},
|
|
||||||
{country: "Portugal", continent: "Europe", language: "Portuguese"},
|
|
||||||
{country: "Malta", continent: "Europe", language: "(other)"},
|
|
||||||
{country: "Brazil", continent: "South America", language: "Portuguese"},
|
|
||||||
{country: "Argentina", continent: "South America", language: "Spanish"},
|
|
||||||
{country: "Colombia", continent: "South America", language: "Spanish"},
|
|
||||||
{country: "Peru", continent: "South America", language: "Spanish"},
|
|
||||||
{country: "Venezuela", continent: "South America", language: "Spanish"},
|
|
||||||
{country: "Uruguay", continent: "South America", language: "Spanish"}
|
|
||||||
];
|
|
||||||
|
|
||||||
RefData.DOB = [
|
|
||||||
new Date(2000, 0, 1 ),
|
|
||||||
new Date(2001, 1, 2 ),
|
|
||||||
new Date(2002, 2, 3 ),
|
|
||||||
new Date(2003, 3, 4 ),
|
|
||||||
new Date(2004, 4, 5 ),
|
|
||||||
new Date(2005, 5, 6 ),
|
|
||||||
new Date(2006, 6, 7 ),
|
|
||||||
new Date(2007, 7, 8 ),
|
|
||||||
new Date(2008, 8, 9 ),
|
|
||||||
new Date(2009, 9, 10 ),
|
|
||||||
new Date(2010, 10, 11 ),
|
|
||||||
new Date(2011, 11, 12 )
|
|
||||||
];
|
|
||||||
|
|
||||||
RefData.ADDRESSES = [
|
|
||||||
'1197 Thunder Wagon Common, Cataract, RI, 02987-1016, US, (401) 747-0763',
|
|
||||||
'3685 Rocky Glade, Showtucket, NU, X1E-9I0, CA, (867) 371-4215',
|
|
||||||
'3235 High Forest, Glen Campbell, MS, 39035-6845, US, (601) 638-8186',
|
|
||||||
'2234 Sleepy Pony Mall , Drain, DC, 20078-4243, US, (202) 948-3634',
|
|
||||||
'2722 Hazy Turnabout, Burnt Cabins, NY, 14120-5642, US, (917) 604-6597',
|
|
||||||
'6686 Lazy Ledge, Two Rock, CA, 92639-3020, US, (619) 901-9911',
|
|
||||||
'2000 Dewy Limits, Wacahoota, NF, A4L-2V9, CA, (709) 065-3959',
|
|
||||||
'7710 Noble Pond Avenue, Bolivia, RI, 02931-1842, US, (401) 865-2160',
|
|
||||||
'3452 Sunny Vale, Pyro, ON, M8V-4Z0, CA, (519) 072-8609',
|
|
||||||
'4402 Dusty Cove, Many Farms, UT, 84853-8223, US, (435) 518-0673',
|
|
||||||
'5198 Silent Parade, Round Bottom, MD, 21542-9798, US, (301) 060-7245',
|
|
||||||
'8550 Shady Moor, Kitty Fork, CO, 80941-6207, US, (303) 502-3767',
|
|
||||||
'2131 Old Dell, Merry Midnight, AK, 99906-8842, US, (907) 369-2206',
|
|
||||||
'7390 Harvest Crest, Mosquito Crossing, RI, 02957-6116, US, (401) 463-6348',
|
|
||||||
'874 Little Point, Hot Coffee, BC, V3U-2P6, CA, (250) 706-9207',
|
|
||||||
'8834 Stony Pioneer Heights, Newlove, OR, 97419-8670, US, (541) 408-2213',
|
|
||||||
'9829 Grand Beach, Flint, UT, 84965-9900, US, (435) 700-5161',
|
|
||||||
'3799 Cozy Blossom Ramp, Ptarmigan, MS, 38715-0313, US, (769) 740-1526',
|
|
||||||
'3254 Silver Island Loop, Maunaloa, DE, 19869-3169, US, (302) 667-7671',
|
|
||||||
'1081 Middle Wood, Taylors Gut Landing, OR, 97266-2873, US, (541) 357-6310',
|
|
||||||
'1137 Umber Trail, Shacktown, NW, X3U-5Y8, CA, (867) 702-6883',
|
|
||||||
'9914 Hidden Bank, Wyoming, MO, 64635-9665, US, (636) 280-4192',
|
|
||||||
'7080 Misty Nectar Townline, Coward, AB, T9U-3N4, CA, (403) 623-2838',
|
|
||||||
'1184 Wishing Grounds, Vibank, NW, X7D-0V9, CA, (867) 531-2730',
|
|
||||||
'126 Easy Pointe, Grandview Beach, KY, 40928-9539, US, (502) 548-0956',
|
|
||||||
'6683 Colonial Street, Swan River, BC, V1A-9I8, CA, (778) 014-4257',
|
|
||||||
'960 Gentle Oak Lane, Shakopee, ND, 58618-6277, US, (701) 327-1219',
|
|
||||||
'6918 Cotton Pine Corner, Kenaston, IA, 52165-3975, US, (515) 906-7427',
|
|
||||||
'2368 Burning Woods, Ernfold, NY, 11879-9186, US, (646) 819-0355',
|
|
||||||
'5646 Quiet Shadow Chase, Tiger Tail, IA, 52283-5537, US, (712) 375-9225',
|
|
||||||
'5466 Foggy Mountain Dale, Sweet Home, MT, 59738-0251, US, (406) 881-1706',
|
|
||||||
'5313 Clear Willow Route, Amazon, BC, V0S-2S6, CA, (604) 340-7596',
|
|
||||||
'7000 Pleasant Autoroute, Spaceport City, UT, 84749-2448, US, (435) 154-3360',
|
|
||||||
'8359 Quaking Anchor Road, Gross, BC, V9O-0H5, CA, (250) 985-3859',
|
|
||||||
'5143 Amber Deer Hollow, New Deal, ND, 58446-0853, US, (701) 927-0322',
|
|
||||||
'6230 Jagged Bear Key, Young, AR, 72337-3811, US, (501) 805-7239',
|
|
||||||
'7207 Heather Vista, Devon, WY, 82520-1771, US, (307) 358-7092',
|
|
||||||
'9416 Red Rise Place, Spraytown, OK, 73809-4766, US, (580) 867-1973',
|
|
||||||
'3770 Golden Horse Diversion, Yelland, IL, 60471-1487, US, (224) 717-9349',
|
|
||||||
'4819 Honey Treasure Park, Alaska, NB, E1U-3I0, CA, (506) 656-9138',
|
|
||||||
'6187 Round Front, Land O Lakes, AK, 99873-6403, US, (907) 853-9063',
|
|
||||||
'9218 Crystal Highway, Pickelville, MT, 59847-9299, US, (406) 076-0024',
|
|
||||||
'6737 Bright Quay, Lazy Mountain, KY, 42390-4772, US, (606) 256-7288',
|
|
||||||
'237 Merry Campus, Twentysix, SC, 29330-4909, US, (864) 945-0157',
|
|
||||||
'446 Fallen Gate Rise, Petrolia, SC, 29959-9527, US, (864) 826-0553',
|
|
||||||
'2347 Indian Boulevard, Frisbee, VA, 23797-6458, US, (703) 656-8445',
|
|
||||||
'365 Emerald Grove Line, Level, NC, 28381-1514, US, (919) 976-7958',
|
|
||||||
'1207 Iron Extension, Klickitat, SC, 29197-8571, US, (803) 535-7888',
|
|
||||||
'6770 Cinder Glen, Caronport, OH, 45053-5002, US, (440) 369-4018',
|
|
||||||
'7619 Tawny Carrefour, Senlac, NV, 89529-9876, US, (775) 901-6433'];
|
|
||||||
|
|
||||||
RefData.IT_SKILLS = ['android', 'css', 'html5', 'mac', 'windows'];
|
|
||||||
|
|
||||||
RefData.IT_SKILLS_NAMES = ['Android', 'CSS', 'HTML 5', 'Mac', 'Windows'];
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
import ReactDOM from 'react-dom';
|
|
||||||
import React from 'react';
|
|
||||||
import MyApp from './myApp.jsx';
|
|
||||||
|
|
||||||
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(MyApp),
|
|
||||||
container
|
|
||||||
);
|
|
||||||
});
|
|
||||||
@@ -1,224 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import {AgGridReact} from "ag-grid-react";
|
|
||||||
import RowDataFactory from "./RowDataFactory";
|
|
||||||
import ColDefFactory from "./ColDefFactory.jsx";
|
|
||||||
import MyReactDateComponent from "./MyReactDateComponent.jsx";
|
|
||||||
import MyReactHeaderComponent from "./MyReactHeaderComponent.jsx";
|
|
||||||
import "./myApp.css";
|
|
||||||
// take this line out if you do not want to use ag-Grid-Enterprise
|
|
||||||
import "ag-grid-enterprise";
|
|
||||||
|
|
||||||
export default class MyApp extends React.Component {
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
quickFilterText: null,
|
|
||||||
showGrid: true,
|
|
||||||
showToolPanel: false,
|
|
||||||
columnDefs: new ColDefFactory().createColDefs(),
|
|
||||||
rowData: new RowDataFactory().createRowData(),
|
|
||||||
icons: {
|
|
||||||
columnRemoveFromGroup: '<i class="fa fa-remove"/>',
|
|
||||||
filter: '<i class="fa fa-filter"/>',
|
|
||||||
sortAscending: '<i class="fa fa-long-arrow-down"/>',
|
|
||||||
sortDescending: '<i class="fa fa-long-arrow-up"/>',
|
|
||||||
groupExpanded: '<i class="fa fa-minus-square-o"/>',
|
|
||||||
groupContracted: '<i class="fa fa-plus-square-o"/>',
|
|
||||||
columnGroupOpened: '<i class="fa fa-minus-square-o"/>',
|
|
||||||
columnGroupClosed: '<i class="fa fa-plus-square-o"/>'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// the grid options are optional, because you can provide every property
|
|
||||||
// to the grid via standard React properties. however, the react interface
|
|
||||||
// doesn't block you from using the standard JavaScript interface if you
|
|
||||||
// wish. Maybe you have the gridOptions stored as JSON on your server? If
|
|
||||||
// you do, the providing the gridOptions as a standalone object is just
|
|
||||||
// what you want!
|
|
||||||
this.gridOptions = {
|
|
||||||
//We register the react date component that ag-grid will use to render
|
|
||||||
dateComponentFramework: MyReactDateComponent,
|
|
||||||
// this is how you listen for events using gridOptions
|
|
||||||
onModelUpdated: function () {
|
|
||||||
console.log('event onModelUpdated received');
|
|
||||||
},
|
|
||||||
defaultColDef: {
|
|
||||||
headerComponentFramework: MyReactHeaderComponent,
|
|
||||||
headerComponentParams: {
|
|
||||||
menuIcon: 'fa-bars'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// this is a simple property
|
|
||||||
rowBuffer: 10 // no need to set this, the default is fine for almost all scenarios
|
|
||||||
};
|
|
||||||
|
|
||||||
this.onGridReady = this.onGridReady.bind(this);
|
|
||||||
this.onRowSelected = this.onRowSelected.bind(this);
|
|
||||||
this.onCellClicked = this.onCellClicked.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
onShowGrid(show) {
|
|
||||||
this.setState({
|
|
||||||
showGrid: show
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onToggleToolPanel(event) {
|
|
||||||
this.setState({showToolPanel: event.target.checked});
|
|
||||||
}
|
|
||||||
|
|
||||||
onGridReady(params) {
|
|
||||||
this.api = params.api;
|
|
||||||
this.columnApi = params.columnApi;
|
|
||||||
}
|
|
||||||
|
|
||||||
selectAll() {
|
|
||||||
this.api.selectAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
deselectAll() {
|
|
||||||
this.api.deselectAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
setCountryVisible(visible) {
|
|
||||||
this.columnApi.setColumnVisible('country', visible);
|
|
||||||
}
|
|
||||||
|
|
||||||
onQuickFilterText(event) {
|
|
||||||
this.setState({quickFilterText: event.target.value});
|
|
||||||
}
|
|
||||||
|
|
||||||
onCellClicked(event) {
|
|
||||||
console.log('onCellClicked: ' + event.data.name + ', col ' + event.colIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
onRowSelected(event) {
|
|
||||||
console.log('onRowSelected: ' + event.node.data.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
onRefreshData() {
|
|
||||||
var newRowData = new RowDataFactory().createRowData();
|
|
||||||
this.setState({
|
|
||||||
rowData: newRowData
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
invokeSkillsFilterMethod() {
|
|
||||||
var skillsFilter = this.api.getFilterInstance('skills');
|
|
||||||
var componentInstance = skillsFilter.getFrameworkComponentInstance();
|
|
||||||
componentInstance.helloFromSkillsFilter();
|
|
||||||
}
|
|
||||||
|
|
||||||
dobFilter() {
|
|
||||||
let dateFilterComponent = this.gridOptions.api.getFilterInstance('dob');
|
|
||||||
dateFilterComponent.setFilterType('equals');
|
|
||||||
dateFilterComponent.setDateFrom('2000-01-01');
|
|
||||||
this.gridOptions.api.onFilterChanged();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
var gridTemplate;
|
|
||||||
var bottomHeaderTemplate;
|
|
||||||
var topHeaderTemplate;
|
|
||||||
|
|
||||||
topHeaderTemplate = (
|
|
||||||
<div>
|
|
||||||
<div style={{float: 'right'}}>
|
|
||||||
<input type="text" onChange={this.onQuickFilterText.bind(this)}
|
|
||||||
placeholder="Type text to filter..."/>
|
|
||||||
<button id="btDestroyGrid" disabled={!this.state.showGrid}
|
|
||||||
onClick={this.onShowGrid.bind(this, false)}>Destroy Grid
|
|
||||||
</button>
|
|
||||||
<button id="btCreateGrid" disabled={this.state.showGrid} onClick={this.onShowGrid.bind(this, true)}>
|
|
||||||
Create Grid
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div style={{padding: '4px'}}>
|
|
||||||
<b>Employees Skills and Contact Details</b> <span id="rowCount"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
// showing the bottom header and grid is optional, so we put in a switch
|
|
||||||
if (this.state.showGrid) {
|
|
||||||
bottomHeaderTemplate = (
|
|
||||||
<div>
|
|
||||||
<div style={{padding: 4}} className={'toolbar'}>
|
|
||||||
<span>
|
|
||||||
Grid API:
|
|
||||||
<button onClick={this.selectAll.bind(this)}>Select All</button>
|
|
||||||
<button onClick={this.deselectAll.bind(this)}>Clear Selection</button>
|
|
||||||
</span>
|
|
||||||
<span style={{marginLeft: 20}}>
|
|
||||||
Column API:
|
|
||||||
<button onClick={this.setCountryVisible.bind(this, false)}>Hide Country Column</button>
|
|
||||||
<button onClick={this.setCountryVisible.bind(this, true)}>Show Country Column</button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div style={{clear: 'both'}}></div>
|
|
||||||
<div style={{padding: 4}} className={'toolbar'}>
|
|
||||||
<span>
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" onChange={this.onToggleToolPanel.bind(this)}/>
|
|
||||||
Show Tool Panel
|
|
||||||
</label>
|
|
||||||
<button onClick={this.onRefreshData.bind(this)}>Refresh Data</button>
|
|
||||||
</span>
|
|
||||||
<span style={{marginLeft: 20}}>
|
|
||||||
Filter API:
|
|
||||||
<button onClick={this.invokeSkillsFilterMethod.bind(this, false)}>Invoke Skills Filter Method</button>
|
|
||||||
<button onClick={this.dobFilter.bind(this)}>DOB equals to 01/01/2000</button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div style={{clear: 'both'}}></div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
gridTemplate = (
|
|
||||||
<div style={{height: 400}} className="ag-fresh">
|
|
||||||
<AgGridReact
|
|
||||||
// gridOptions is optional - it's possible to provide
|
|
||||||
// all values as React props
|
|
||||||
gridOptions={this.gridOptions}
|
|
||||||
|
|
||||||
// listening for events
|
|
||||||
onGridReady={this.onGridReady}
|
|
||||||
onRowSelected={this.onRowSelected}
|
|
||||||
onCellClicked={this.onCellClicked}
|
|
||||||
|
|
||||||
// binding to simple properties
|
|
||||||
showToolPanel={this.state.showToolPanel}
|
|
||||||
quickFilterText={this.state.quickFilterText}
|
|
||||||
|
|
||||||
// binding to an object property
|
|
||||||
icons={this.state.icons}
|
|
||||||
|
|
||||||
// binding to array properties
|
|
||||||
columnDefs={this.state.columnDefs}
|
|
||||||
rowData={this.state.rowData}
|
|
||||||
|
|
||||||
// no binding, just providing hard coded strings for the properties
|
|
||||||
suppressRowClickSelection="true"
|
|
||||||
rowSelection="multiple"
|
|
||||||
enableColResize="true"
|
|
||||||
enableSorting="true"
|
|
||||||
enableFilter="true"
|
|
||||||
groupHeaders="true"
|
|
||||||
rowHeight="22"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <div style={{width: '1024px'}}>
|
|
||||||
<div style={{padding: '4px'}}>
|
|
||||||
{topHeaderTemplate}
|
|
||||||
{bottomHeaderTemplate}
|
|
||||||
{gridTemplate}
|
|
||||||
</div>
|
|
||||||
</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
16
src-trader-dashboard/actions/fxDataActions.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import cloneDeep from "lodash/cloneDeep";
|
||||||
|
|
||||||
|
export function fxDataUpdated(fxData) {
|
||||||
|
return {
|
||||||
|
type: 'FX_DATA_CHANGED',
|
||||||
|
fxData: cloneDeep(fxData)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fxTopMoversUpdated(fxTopMovers) {
|
||||||
|
return {
|
||||||
|
type: 'FX_TOP_MOVERS_CHANGED',
|
||||||
|
fxTopMovers: cloneDeep(fxTopMovers)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { Component } from 'react';
|
import React, {Component} from "react";
|
||||||
|
|
||||||
export default class extends Component {
|
export default class extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
|||||||
26
src-trader-dashboard/components/FxPanel.jsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import React, {Component} from "react";
|
||||||
|
|
||||||
|
import FxDataService from "../services/FxDataService.jsx";
|
||||||
|
import FxQuoteMatrix from "./FxQuoteMatrix.jsx";
|
||||||
|
import TopMoversGrid from "./TopMoversGrid.jsx";
|
||||||
|
|
||||||
|
export default class extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.fxDataService = new FxDataService();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div style={{float: "left", marginRight: 25}}>
|
||||||
|
<FxQuoteMatrix fxDataService={this.fxDataService}/>
|
||||||
|
</div>
|
||||||
|
<div style={{float: "left"}}>
|
||||||
|
<TopMoversGrid fxDataService={this.fxDataService}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,82 +1,75 @@
|
|||||||
import React, {Component} from "react";
|
import React, {Component} from "react";
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
|
|
||||||
import {AgGridReact} from "ag-grid-react";
|
import {AgGridReact} from "ag-grid-react";
|
||||||
|
|
||||||
import ExchangeService from "../services/ExchangeService.jsx";
|
import assign from "lodash/assign";
|
||||||
|
import uniq from "lodash/uniq";
|
||||||
|
|
||||||
class FxQuoteMatrix extends Component {
|
class FxQuoteMatrix extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.exchangeService = new ExchangeService();
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
columnDefs: this.exchangeService.getFxMatrixHeaderNames(),
|
columnDefs: this.props.fxDataService.getFxMatrixHeaderNames()
|
||||||
// rowData: this.exchangeService.getFxMatrixSnapshot()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// grid events
|
// grid events
|
||||||
this.onGridReady = this.onGridReady.bind(this);
|
this.onGridReady = this.onGridReady.bind(this);
|
||||||
|
|
||||||
|
// grid callbacks
|
||||||
|
this.getRowNodeId = this.getRowNodeId.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
onGridReady(params) {
|
onGridReady(params) {
|
||||||
this.gridApi = params.api;
|
this.gridApi = params.api;
|
||||||
this.columnApi = params.columnApi;
|
this.columnApi = params.columnApi;
|
||||||
|
|
||||||
|
if (this.props.rowData) {
|
||||||
|
this.gridApi.setRowData(this.props.rowData)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getRowNodeId(data) {
|
||||||
// componentWillUnmount() {
|
return data.symbol;
|
||||||
// this.exchangeService.removeSubscribers();
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
console.log(props);
|
const newRowData = nextProps.rowData;
|
||||||
// if (nextProps.selectedExchange.supportedStocks !== this.props.selectedExchange.supportedStocks) {
|
|
||||||
// if (!this.gridApi) {
|
const updatedRows = [];
|
||||||
// return;
|
|
||||||
// }
|
for (let i = 0; i < newRowData.length; i++) {
|
||||||
//
|
let newRow = newRowData[i];
|
||||||
// const currentSymbols = this.props.selectedExchange.supportedStocks;
|
let currentRowNode = this.gridApi.getRowNode(newRow.symbol);
|
||||||
// const nextSymbols = nextProps.selectedExchange.supportedStocks;
|
|
||||||
//
|
const {data} = currentRowNode;
|
||||||
// // Unsubscribe to current ones that will be removed
|
for (const def of this.state.columnDefs) {
|
||||||
// const symbolsRemoved = difference(currentSymbols, nextSymbols);
|
if (data[def.field] !== newRow[def.field]) {
|
||||||
// forEach(symbolsRemoved, symbol => {
|
updatedRows.push(newRow);
|
||||||
// this.exchangeService.removeSubscriber(this.updateQuote, symbol);
|
break;
|
||||||
// });
|
}
|
||||||
//
|
}
|
||||||
// // Subscribe to new ones that need to be added
|
}
|
||||||
// const symbolsAdded = difference(nextSymbols, currentSymbols);
|
|
||||||
// forEach(symbolsAdded, symbol => {
|
|
||||||
// this.exchangeService.addSubscriber(this.updateQuote, symbol);
|
this.gridApi.updateRowData({update: updatedRows});
|
||||||
// });
|
|
||||||
//
|
|
||||||
// // Remove ag-grid nodes as necessary
|
|
||||||
// const nodesToRemove = [];
|
|
||||||
// this.gridApi.forEachNode(node => {
|
|
||||||
// const {data} = node;
|
|
||||||
// if (includes(symbolsRemoved, data.symbol)) {
|
|
||||||
// nodesToRemove.push(node);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// this.gridApi.removeItems(nodesToRemove);
|
|
||||||
//
|
|
||||||
// // Insert new ag-grid nodes as necessary
|
|
||||||
// this.gridApi.addItems(map(symbolsAdded, symbol => this.exchangeService.getTicker(symbol)));
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div style={{height: 500, width: "100%"}}
|
<div style={{height: 410, width: 800}}
|
||||||
className="ag-fresh">
|
className="ag-fresh">
|
||||||
<AgGridReact
|
<AgGridReact
|
||||||
// properties
|
// properties
|
||||||
columnDefs={this.state.columnDefs}
|
columnDefs={this.state.columnDefs}
|
||||||
rowData={this.state.rowData}
|
|
||||||
enableSorting="false"
|
enableSorting="false"
|
||||||
enableFilter="false"
|
enableFilter="false"
|
||||||
|
|
||||||
|
// callbacks
|
||||||
|
getRowNodeId={this.getRowNodeId}
|
||||||
|
|
||||||
// events
|
// events
|
||||||
onGridReady={this.onGridReady}>
|
onGridReady={this.onGridReady}>
|
||||||
</AgGridReact>
|
</AgGridReact>
|
||||||
@@ -88,7 +81,7 @@ class FxQuoteMatrix extends Component {
|
|||||||
export default connect(
|
export default connect(
|
||||||
(state) => {
|
(state) => {
|
||||||
return {
|
return {
|
||||||
rowData: state.fxRowData
|
rowData: state.fxData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)(FxQuoteMatrix);
|
)(FxQuoteMatrix);
|
||||||
@@ -1,15 +1,11 @@
|
|||||||
import React, {Component} from "react";
|
import React, {Component} from "react";
|
||||||
|
|
||||||
// take this line out if you do not want to use ag-Grid-Enterprise
|
|
||||||
import "ag-grid-enterprise";
|
|
||||||
|
|
||||||
import {AgGridReact} from "ag-grid-react";
|
import {AgGridReact} from "ag-grid-react";
|
||||||
|
|
||||||
import map from "lodash/map";
|
import map from "lodash/map";
|
||||||
import difference from "lodash/difference";
|
import difference from "lodash/difference";
|
||||||
import forEach from "lodash/forEach";
|
import forEach from "lodash/forEach";
|
||||||
import includes from "lodash/includes";
|
import includes from "lodash/includes";
|
||||||
import assign from "lodash/assign";
|
|
||||||
|
|
||||||
import ExchangeService from "../services/ExchangeService.jsx";
|
import ExchangeService from "../services/ExchangeService.jsx";
|
||||||
|
|
||||||
@@ -27,32 +23,23 @@ export default class extends Component {
|
|||||||
{
|
{
|
||||||
field: 'price',
|
field: 'price',
|
||||||
headerName: 'Price',
|
headerName: 'Price',
|
||||||
cellFormatter: this.numberFormatter,
|
valueFormatter: this.numberFormatter,
|
||||||
cellRenderer: 'animateShowChange',
|
cellRenderer: 'animateShowChange',
|
||||||
cellStyle: {'text-align': 'right'}
|
cellStyle: {'text-align': 'right'}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'bid',
|
field: 'bid',
|
||||||
headerName: 'Bid',
|
headerName: 'Bid',
|
||||||
cellFormatter: this.numberFormatter,
|
valueFormatter: this.numberFormatter,
|
||||||
cellRenderer: 'animateShowChange',
|
cellRenderer: 'animateShowChange',
|
||||||
cellStyle: {'text-align': 'right'}
|
cellStyle: {'text-align': 'right'}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'ask',
|
field: 'ask',
|
||||||
headerName: 'Ask',
|
headerName: 'Ask',
|
||||||
cellFormatter: this.numberFormatter,
|
valueFormatter: this.numberFormatter,
|
||||||
cellRenderer: 'animateShowChange',
|
cellRenderer: 'animateShowChange',
|
||||||
cellStyle: {'text-align': 'right'}
|
cellStyle: {'text-align': 'right'}
|
||||||
},
|
|
||||||
{
|
|
||||||
headerName: 'Recommendation',
|
|
||||||
field: 'recommendation',
|
|
||||||
cellEditor: 'richSelect',
|
|
||||||
cellEditorParams: {
|
|
||||||
values: ['Buy', 'Hold', 'Sell']
|
|
||||||
},
|
|
||||||
editable: true
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
@@ -61,10 +48,13 @@ export default class extends Component {
|
|||||||
|
|
||||||
// grid events
|
// grid events
|
||||||
this.onGridReady = this.onGridReady.bind(this);
|
this.onGridReady = this.onGridReady.bind(this);
|
||||||
this.onRowClicked = this.onRowClicked.bind(this);
|
this.onSelectionChanged = this.onSelectionChanged.bind(this);
|
||||||
|
|
||||||
|
// grid callbacks
|
||||||
|
this.getRowNodeId = this.getRowNodeId.bind(this);
|
||||||
|
|
||||||
// component events
|
// component events
|
||||||
this.updateQuote = this.updateQuote.bind(this);
|
this.updateSymbol = this.updateSymbol.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
numberFormatter(params) {
|
numberFormatter(params) {
|
||||||
@@ -81,18 +71,26 @@ export default class extends Component {
|
|||||||
|
|
||||||
// make realistic - call in a batch
|
// make realistic - call in a batch
|
||||||
let rowData = map(this.props.selectedExchange.supportedStocks, symbol => this.exchangeService.getTicker(symbol));
|
let rowData = map(this.props.selectedExchange.supportedStocks, symbol => this.exchangeService.getTicker(symbol));
|
||||||
this.gridApi.addItems(rowData);
|
this.gridApi.updateRowData({add: rowData});
|
||||||
|
|
||||||
|
// select the first symbol to show the chart
|
||||||
|
this.gridApi.getModel().getRow(0).setSelected(true);
|
||||||
|
|
||||||
this.gridApi.sizeColumnsToFit();
|
this.gridApi.sizeColumnsToFit();
|
||||||
}
|
}
|
||||||
|
|
||||||
onRowClicked(params) {
|
getRowNodeId(data) {
|
||||||
this.props.onRowClicked(params.data.symbol);
|
return data.symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelectionChanged() {
|
||||||
|
let selectedNode = this.gridApi.getSelectedNodes()[0];
|
||||||
|
this.props.onSelectionChanged(selectedNode ? selectedNode.data.symbol : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this.props.selectedExchange.supportedStocks.forEach(symbol => {
|
this.props.selectedExchange.supportedStocks.forEach(symbol => {
|
||||||
this.exchangeService.addSubscriber(this.updateQuote, symbol);
|
this.exchangeService.addSubscriber(this.updateSymbol, symbol);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,6 +103,7 @@ export default class extends Component {
|
|||||||
if (!this.gridApi) {
|
if (!this.gridApi) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.gridApi.deselectAll();
|
||||||
|
|
||||||
const currentSymbols = this.props.selectedExchange.supportedStocks;
|
const currentSymbols = this.props.selectedExchange.supportedStocks;
|
||||||
const nextSymbols = nextProps.selectedExchange.supportedStocks;
|
const nextSymbols = nextProps.selectedExchange.supportedStocks;
|
||||||
@@ -112,67 +111,59 @@ export default class extends Component {
|
|||||||
// Unsubscribe to current ones that will be removed
|
// Unsubscribe to current ones that will be removed
|
||||||
const symbolsRemoved = difference(currentSymbols, nextSymbols);
|
const symbolsRemoved = difference(currentSymbols, nextSymbols);
|
||||||
forEach(symbolsRemoved, symbol => {
|
forEach(symbolsRemoved, symbol => {
|
||||||
this.exchangeService.removeSubscriber(this.updateQuote, symbol);
|
this.exchangeService.removeSubscriber(this.updateSymbol, symbol);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Remove ag-grid nodes as necessary
|
||||||
|
const rowsToRemove = [];
|
||||||
|
this.gridApi.forEachNode(node => {
|
||||||
|
const {data} = node;
|
||||||
|
if (includes(symbolsRemoved, data.symbol)) {
|
||||||
|
rowsToRemove.push(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.gridApi.updateRowData({remove: rowsToRemove});
|
||||||
|
|
||||||
// Subscribe to new ones that need to be added
|
// Subscribe to new ones that need to be added
|
||||||
const symbolsAdded = difference(nextSymbols, currentSymbols);
|
const symbolsAdded = difference(nextSymbols, currentSymbols);
|
||||||
forEach(symbolsAdded, symbol => {
|
forEach(symbolsAdded, symbol => {
|
||||||
this.exchangeService.addSubscriber(this.updateQuote, symbol);
|
this.exchangeService.addSubscriber(this.updateSymbol, symbol);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remove ag-grid nodes as necessary
|
|
||||||
const nodesToRemove = [];
|
|
||||||
this.gridApi.forEachNode(node => {
|
|
||||||
const {data} = node;
|
|
||||||
if (includes(symbolsRemoved, data.symbol)) {
|
|
||||||
nodesToRemove.push(node);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.gridApi.removeItems(nodesToRemove);
|
|
||||||
|
|
||||||
// Insert new ag-grid nodes as necessary
|
// Insert new ag-grid nodes as necessary
|
||||||
this.gridApi.addItems(map(symbolsAdded, symbol => this.exchangeService.getTicker(symbol)));
|
let rowData = map(symbolsAdded, symbol => this.exchangeService.getTicker(symbol));
|
||||||
|
this.gridApi.updateRowData({add: rowData});
|
||||||
|
|
||||||
|
// select the first symbol to show the chart
|
||||||
|
this.gridApi.getModel().getRow(0).setSelected(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateQuote(quote) {
|
updateSymbol(symbol) {
|
||||||
if (!this.gridApi) {
|
if (!this.gridApi) {
|
||||||
// the grid isn't ready yet
|
// the grid isn't ready yet
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedNodes = [];
|
this.gridApi.updateRowData({update: [symbol]});
|
||||||
const updatedCols = [];
|
}
|
||||||
|
|
||||||
this.gridApi.forEachNode(node => {
|
|
||||||
const {data} = node;
|
|
||||||
if (data.symbol === quote.symbol) {
|
|
||||||
for (const def of this.state.columnDefs) {
|
|
||||||
if (data[def.field] !== quote[def.field]) {
|
|
||||||
updatedCols.push(def.field);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assign(data, quote);
|
|
||||||
updatedNodes.push(node);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.gridApi.refreshCells(updatedNodes, updatedCols);
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div style={{height: 500, width: 800}}
|
<div style={{height: 410, width: 800}}
|
||||||
className="ag-fresh">
|
className="ag-fresh">
|
||||||
<AgGridReact
|
<AgGridReact
|
||||||
// properties
|
// properties
|
||||||
columnDefs={this.state.columnDefs}
|
columnDefs={this.state.columnDefs}
|
||||||
enableSorting="true"
|
enableSorting="true"
|
||||||
|
rowSelection="single"
|
||||||
|
|
||||||
|
// callbacks
|
||||||
|
getRowNodeId={this.getRowNodeId}
|
||||||
|
|
||||||
// events
|
// events
|
||||||
onGridReady={this.onGridReady}
|
onGridReady={this.onGridReady}
|
||||||
onRowClicked={this.onRowClicked}>
|
onSelectionChanged={this.onSelectionChanged}>
|
||||||
</AgGridReact>
|
</AgGridReact>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export default class extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps, nextState) {
|
componentWillReceiveProps(nextProps) {
|
||||||
if (nextProps.selectedSymbol &&
|
if (nextProps.selectedSymbol &&
|
||||||
nextProps.selectedSymbol !== this.props.selectedSymbol) {
|
nextProps.selectedSymbol !== this.props.selectedSymbol) {
|
||||||
let stockDetail = this.exchangeService.getTickerDetail(nextProps.selectedSymbol);
|
let stockDetail = this.exchangeService.getTickerDetail(nextProps.selectedSymbol);
|
||||||
@@ -35,7 +35,7 @@ export default class extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
shouldComponentUpdate(nextProps) {
|
||||||
return nextProps.selectedSymbol !== this.props.selectedSymbol;
|
return nextProps.selectedSymbol !== this.props.selectedSymbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export default class extends Component {
|
|||||||
|
|
||||||
static get defaultProps() {
|
static get defaultProps() {
|
||||||
return {
|
return {
|
||||||
graphHeight: 320,
|
graphHeight: 230,
|
||||||
graphWidth: 400
|
graphWidth: 400
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React, {Component} from "react";
|
|||||||
|
|
||||||
import PriceChangesGrid from "./PriceChangesGrid.jsx";
|
import PriceChangesGrid from "./PriceChangesGrid.jsx";
|
||||||
import StockDetailPanel from "./StockDetailPanel.jsx";
|
import StockDetailPanel from "./StockDetailPanel.jsx";
|
||||||
import FxQuoteMatrix from "./FxQuoteMatrix.jsx";
|
import FxPanel from "./FxPanel.jsx";
|
||||||
|
|
||||||
export default class extends Component {
|
export default class extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -12,7 +12,7 @@ export default class extends Component {
|
|||||||
selectedSymbol: null
|
selectedSymbol: null
|
||||||
};
|
};
|
||||||
|
|
||||||
this.onRowClicked = this.onRowClicked.bind(this);
|
this.onSelectionChanged = this.onSelectionChanged.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
@@ -28,7 +28,7 @@ export default class extends Component {
|
|||||||
nextState.selectedSymbol !== this.state.selectedSymbol;
|
nextState.selectedSymbol !== this.state.selectedSymbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
onRowClicked(selectedSymbol) {
|
onSelectionChanged(selectedSymbol) {
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedSymbol
|
selectedSymbol
|
||||||
})
|
})
|
||||||
@@ -37,18 +37,18 @@ export default class extends Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div style={{width: 1250}}>
|
<div style={{width: 1250}}>
|
||||||
{/*<div>*/}
|
<div>
|
||||||
{/*<div style={{float: "left", marginRight: 25}}>*/}
|
<div style={{float: "left", marginRight: 25}}>
|
||||||
{/*<PriceChangesGrid selectedExchange={this.props.selectedExchange}*/}
|
<PriceChangesGrid selectedExchange={this.props.selectedExchange}
|
||||||
{/*onRowClicked={this.onRowClicked}/>*/}
|
onSelectionChanged={this.onSelectionChanged}/>
|
||||||
{/*</div>*/}
|
</div>
|
||||||
{/*<div style={{float: "left"}}>*/}
|
<div style={{float: "left"}}>
|
||||||
{/*<StockDetailPanel selectedSymbol={this.state.selectedSymbol}*/}
|
<StockDetailPanel selectedSymbol={this.state.selectedSymbol}
|
||||||
{/*exchangeName={this.props.selectedExchange.name}/>*/}
|
exchangeName={this.props.selectedExchange.name}/>
|
||||||
{/*</div>*/}
|
</div>
|
||||||
{/*</div>*/}
|
</div>
|
||||||
<div style={{width: "100%", clear: "both", paddingTop: 25}}>
|
<div style={{width: "100%", clear: "both", paddingTop: 25}}>
|
||||||
<FxQuoteMatrix/>
|
<FxPanel/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export default class extends Component {
|
|||||||
this.updatePriceDelta(this.props.pricingDelta);
|
this.updatePriceDelta(this.props.pricingDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps, nextState) {
|
componentWillReceiveProps(nextProps) {
|
||||||
if (!isEqual(this.props.pricingDelta, nextProps.pricingDelta)) {
|
if (!isEqual(this.props.pricingDelta, nextProps.pricingDelta)) {
|
||||||
this.updatePriceDelta(nextProps.pricingDelta);
|
this.updatePriceDelta(nextProps.pricingDelta);
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,7 @@ export default class extends Component {
|
|||||||
|
|
||||||
let swingStyle = this.state.delta >= 0 ? positiveSwingStyle : negativeSwingStyle;
|
let swingStyle = this.state.delta >= 0 ? positiveSwingStyle : negativeSwingStyle;
|
||||||
|
|
||||||
if(!this.props.pricingDelta) {
|
if (!this.props.pricingDelta) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
|
|||||||
90
src-trader-dashboard/components/TopMoversGrid.jsx
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
import React, {Component} from "react";
|
||||||
|
import {connect} from "react-redux";
|
||||||
|
|
||||||
|
import {AgGridReact} from "ag-grid-react";
|
||||||
|
|
||||||
|
class TopMoversGrid extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
columnDefs: [
|
||||||
|
{
|
||||||
|
field: 'symbol',
|
||||||
|
headerName: 'Symbol'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'last',
|
||||||
|
headerName: 'Last',
|
||||||
|
headerClass: 'align-right',
|
||||||
|
cellRenderer: 'animateShowChange',
|
||||||
|
cellClass: 'align-right'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'net',
|
||||||
|
headerName: 'Net',
|
||||||
|
headerClass: 'align-right',
|
||||||
|
cellRenderer: 'animateShowChange',
|
||||||
|
cellClass: 'align-right'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'pct_net_change',
|
||||||
|
headerName: '% NC',
|
||||||
|
headerClass: 'align-right',
|
||||||
|
cellRenderer: 'animateShowChange',
|
||||||
|
cellClass: 'align-right',
|
||||||
|
sort: 'desc',
|
||||||
|
valueFormatter(params) {
|
||||||
|
return params.value.toFixed(2)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
// grid events
|
||||||
|
this.onGridReady = this.onGridReady.bind(this);
|
||||||
|
|
||||||
|
// grid callbacks
|
||||||
|
this.getRowNodeId = this.getRowNodeId.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
getRowNodeId(data) {
|
||||||
|
return data.symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
onGridReady(params) {
|
||||||
|
this.gridApi = params.api;
|
||||||
|
this.columnApi = params.columnApi;
|
||||||
|
|
||||||
|
this.gridApi.sizeColumnsToFit();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div style={{height: 410, width: 400}}
|
||||||
|
className="ag-fresh">
|
||||||
|
<AgGridReact
|
||||||
|
// properties
|
||||||
|
columnDefs={this.state.columnDefs}
|
||||||
|
rowData={this.props.rowData}
|
||||||
|
enableSorting
|
||||||
|
enableFilter="false"
|
||||||
|
animateRows
|
||||||
|
deltaRowDataMode
|
||||||
|
getRowNodeId={this.getRowNodeId}
|
||||||
|
|
||||||
|
// events
|
||||||
|
onGridReady={this.onGridReady}>
|
||||||
|
</AgGridReact>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
(state) => {
|
||||||
|
return {
|
||||||
|
rowData: state.fxTopMovers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)(TopMoversGrid);
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import React, {Component} from "react";
|
||||||
|
import * as PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
export default class HorizontalBarComponent extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
value: this.props.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let positiveChange = {
|
||||||
|
fill: "green"
|
||||||
|
};
|
||||||
|
|
||||||
|
let negativeChange = {
|
||||||
|
fill: "red"
|
||||||
|
};
|
||||||
|
|
||||||
|
let text = {
|
||||||
|
position: "absolute",
|
||||||
|
top: 0,
|
||||||
|
width: "100%",
|
||||||
|
textAlign: "right"
|
||||||
|
};
|
||||||
|
|
||||||
|
let pctNetChange = this.state.value;
|
||||||
|
let pctNetChangeBar = Math.min(Math.abs(pctNetChange) * 100, 100) / 2;
|
||||||
|
|
||||||
|
let barWidth = `${pctNetChangeBar}%`;
|
||||||
|
let barStyle = pctNetChange >= 0 ? positiveChange : negativeChange;
|
||||||
|
let barX = `${pctNetChange >= 0 ? '50' : 50 - pctNetChangeBar}%`;
|
||||||
|
return (
|
||||||
|
<div style={{position: 'relative'}}>
|
||||||
|
<div style={{width: "50%"}}>
|
||||||
|
<svg width="100%" preserveAspectRatio="none">
|
||||||
|
<rect x={barX} y="0" width={barWidth} height="20px" rx="4" ry="4" style={barStyle}/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div style={text}>{pctNetChange}</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh(params) {
|
||||||
|
this.setState({
|
||||||
|
value: params.value
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HorizontalBarComponent.propTypes = {
|
||||||
|
params: PropTypes.object
|
||||||
|
};
|
||||||
@@ -3,13 +3,17 @@
|
|||||||
|
|
||||||
<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/react-trader.js" charset="utf-8"></script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
html, body {
|
html, body {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ag-fresh .ag-value-change-value-highlight {
|
||||||
|
background-color: #afbcff;
|
||||||
|
}
|
||||||
|
|
||||||
.align-right {
|
.align-right {
|
||||||
text-align: right
|
text-align: right
|
||||||
}
|
}
|
||||||
@@ -44,7 +48,7 @@
|
|||||||
background-image: linear-gradient(to bottom, #afbcff 0%, #c1d5c9 100%), linear-gradient(to bottom, #afbcff 0%, #c1d5c9 100%);
|
background-image: linear-gradient(to bottom, #afbcff 0%, #c1d5c9 100%), linear-gradient(to bottom, #afbcff 0%, #c1d5c9 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.fx-postive {
|
.fx-positive {
|
||||||
border-top: 20px solid #3ACFD5;
|
border-top: 20px solid #3ACFD5;
|
||||||
border-right: 20px solid #3a4ed5;
|
border-right: 20px solid #3a4ed5;
|
||||||
-webkit-box-sizing: border-box;
|
-webkit-box-sizing: border-box;
|
||||||
|
|||||||
@@ -4,16 +4,14 @@ import React from "react";
|
|||||||
import {render} from "react-dom";
|
import {render} from "react-dom";
|
||||||
|
|
||||||
import {Provider} from "react-redux";
|
import {Provider} from "react-redux";
|
||||||
import {createStore} from "redux";
|
|
||||||
|
|
||||||
|
import "ag-grid/dist/styles/ag-grid.css";
|
||||||
|
import "ag-grid/dist/styles/theme-fresh.css";
|
||||||
|
|
||||||
|
import StoreService from './services/StoreService';
|
||||||
import TraderDashboard from "./components/TraderDashboard.jsx";
|
import TraderDashboard from "./components/TraderDashboard.jsx";
|
||||||
|
|
||||||
import "ag-grid-root/dist/styles/ag-grid.css";
|
let store = StoreService.STORE;
|
||||||
import "ag-grid-root/dist/styles/theme-fresh.css";
|
|
||||||
|
|
||||||
import fxData from "./reducers/fxData";
|
|
||||||
|
|
||||||
let store = createStore(fxData);
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
render(
|
render(
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
export default (state = {fxRowData: []}, action) => {
|
|
||||||
return state;
|
|
||||||
};
|
|
||||||
16
src-trader-dashboard/reducers/fxDataReducer.jsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
export default (state = {fxData: [], fxTopMovers: []}, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case 'FX_DATA_CHANGED':
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
fxData: action.fxData.slice(0),
|
||||||
|
};
|
||||||
|
case 'FX_TOP_MOVERS_CHANGED':
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
fxTopMovers: action.fxTopMovers.slice(0),
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return action.state;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import concat from "lodash/concat";
|
import concat from "lodash/concat";
|
||||||
import remove from "lodash/remove";
|
|
||||||
import uniq from "lodash/uniq";
|
import uniq from "lodash/uniq";
|
||||||
import find from "lodash/find";
|
import find from "lodash/find";
|
||||||
import sampleSize from "lodash/sampleSize";
|
import sampleSize from "lodash/sampleSize";
|
||||||
@@ -8,19 +7,54 @@ import keys from "lodash/keys";
|
|||||||
export default class {
|
export default class {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.subscribers = {};
|
this.subscribers = {};
|
||||||
|
|
||||||
this.exchanges = [
|
|
||||||
{name: 'Nasdaq Stock Market', symbol: 'NASDAQ', supportedStocks: NASDAQ_SYMBOLS},
|
|
||||||
{name: 'London Stock Exchange', symbol: 'LSE', supportedStocks: LSE_SYMBOLS},
|
|
||||||
{name: 'Japan Exchange Group', symbol: 'JSE', supportedStocks: JSE_SYMBOLS},
|
|
||||||
{name: 'Deutsche Börse', symbol: 'DE', supportedStocks: DE_SYMBOLS}
|
|
||||||
];
|
|
||||||
|
|
||||||
this.initialiseTickerData();
|
|
||||||
|
|
||||||
this.timestamp = new Date();
|
this.timestamp = new Date();
|
||||||
|
|
||||||
|
// create the initial state of data
|
||||||
|
this.initialiseTickerData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addSubscriber(subscriber, symbol) {
|
||||||
|
if (!this.subscribers[symbol]) {
|
||||||
|
this.subscribers[symbol] = [];
|
||||||
|
}
|
||||||
|
this.subscribers[symbol].push(subscriber);
|
||||||
|
|
||||||
|
if (!this.updateInterval) {
|
||||||
|
this.updateInterval = setInterval(this.applyDeltasToTickerData.bind(this), 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeSubscriber(subscriber, symbol) {
|
||||||
|
let subscribers = this.subscribers[symbol];
|
||||||
|
subscribers.splice(subscribers.indexOf(subscriber), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeSubscribers() {
|
||||||
|
this.subscribers = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
getTicker(symbol) {
|
||||||
|
return this.tickerData[symbol];
|
||||||
|
}
|
||||||
|
|
||||||
|
getExchanges() {
|
||||||
|
return EXCHANGES;
|
||||||
|
}
|
||||||
|
|
||||||
|
getExchangeInformation(exchangeName) {
|
||||||
|
return find(EXCHANGES, (exchange) => {
|
||||||
|
return exchange.symbol === exchangeName;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getTickerDetail(symbol) {
|
||||||
|
return this.createTickerDetail(symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the rest of this class exists primarily to create mock data - it can safely be ignored
|
||||||
|
* as it is secondary to the main ideas being demonstrated by the rest of the application
|
||||||
|
*/
|
||||||
initialiseTickerData() {
|
initialiseTickerData() {
|
||||||
this.tickerData = {};
|
this.tickerData = {};
|
||||||
|
|
||||||
@@ -37,7 +71,7 @@ export default class {
|
|||||||
price,
|
price,
|
||||||
bid: price - this.random(1, 3),
|
bid: price - this.random(1, 3),
|
||||||
ask: price + this.random(1, 3),
|
ask: price + this.random(1, 3),
|
||||||
recommendation: ['Buy','Hold','Sell'][Math.floor(this.random(0, 2))]
|
recommendation: ['Buy', 'Hold', 'Sell'][Math.floor(this.random(0, 2))]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,17 +79,6 @@ export default class {
|
|||||||
return parseFloat((Math.random() * (max - min + 1) + min))
|
return parseFloat((Math.random() * (max - min + 1) + min))
|
||||||
}
|
}
|
||||||
|
|
||||||
addSubscriber(subscriber, symbol) {
|
|
||||||
if (!this.subscribers[symbol]) {
|
|
||||||
this.subscribers[symbol] = [];
|
|
||||||
}
|
|
||||||
this.subscribers[symbol].push(subscriber);
|
|
||||||
|
|
||||||
if (!this.updateInterval) {
|
|
||||||
this.updateInterval = setInterval(this.applyDeltasToTickerData.bind(this), 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
applyDeltasToTickerData() {
|
applyDeltasToTickerData() {
|
||||||
let symbols = keys(this.subscribers);
|
let symbols = keys(this.subscribers);
|
||||||
let properties = ['price', 'bid', 'ask'];
|
let properties = ['price', 'bid', 'ask'];
|
||||||
@@ -81,24 +104,6 @@ export default class {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
removeSubscriber(subscriber, symbol) {
|
|
||||||
remove(this.subscribers[symbol], subscriber);
|
|
||||||
}
|
|
||||||
|
|
||||||
getTicker(symbol) {
|
|
||||||
return this.tickerData[symbol];
|
|
||||||
}
|
|
||||||
|
|
||||||
getExchanges() {
|
|
||||||
return this.exchanges;
|
|
||||||
}
|
|
||||||
|
|
||||||
getExchangeInformation(exchangeName) {
|
|
||||||
return find(this.exchanges, (exchange) => {
|
|
||||||
return exchange.symbol === exchangeName;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
formatNumber(input) {
|
formatNumber(input) {
|
||||||
return input.toFixed(2);
|
return input.toFixed(2);
|
||||||
}
|
}
|
||||||
@@ -107,7 +112,7 @@ export default class {
|
|||||||
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||||
}
|
}
|
||||||
|
|
||||||
getTickerDetail(symbol) {
|
createTickerDetail(symbol) {
|
||||||
let ticker = this.getTicker(symbol);
|
let ticker = this.getTicker(symbol);
|
||||||
let currentPrice = ticker.price;
|
let currentPrice = ticker.price;
|
||||||
let tenthOfCurrentPrice = currentPrice / 10;
|
let tenthOfCurrentPrice = currentPrice / 10;
|
||||||
@@ -190,33 +195,6 @@ export default class {
|
|||||||
|
|
||||||
return historicalData;
|
return historicalData;
|
||||||
}
|
}
|
||||||
|
|
||||||
getFxMatrixHeaderNames() {
|
|
||||||
return FX_DELTA_HEADERS;
|
|
||||||
}
|
|
||||||
|
|
||||||
getFxMatrixSnapshot() {
|
|
||||||
let columns = FX_CURRENCY_MATRIX[0];
|
|
||||||
let data = FX_CURRENCY_MATRIX.slice(1);
|
|
||||||
|
|
||||||
let rowData = [];
|
|
||||||
for (let i = 0; i < data.length; i++) {
|
|
||||||
let currentRow = data[i];
|
|
||||||
|
|
||||||
let row = {};
|
|
||||||
for (let j = 0; j < columns.length; j++) {
|
|
||||||
row[columns[j]] = currentRow[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
// last, net and % change are different
|
|
||||||
row['last'] = Math.floor(this.random(7000, 170000));
|
|
||||||
row['net'] = this.random(-500, 500).toFixed(2);
|
|
||||||
row['pct_net_change'] = this.random(-1, 1).toFixed(2);
|
|
||||||
|
|
||||||
rowData.push(row);
|
|
||||||
}
|
|
||||||
return rowData;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const NASDAQ_SYMBOLS = [
|
const NASDAQ_SYMBOLS = [
|
||||||
@@ -355,348 +333,9 @@ const DE_SYMBOLS = [
|
|||||||
"AFMF.L",
|
"AFMF.L",
|
||||||
];
|
];
|
||||||
|
|
||||||
const FX_CURRENCY_SYMBOLS = ["USDGBP", "USDEUR", "USDAED", "USDJPY", "USDCAD", "USDCHF", "GBPUSD", "GBPEUR", "GBPAED", "GBPJPY", "GBPCAD", "GBPCHF", "EURUSD", "EURGBP", "EURAED", "EURJPY", "EURCAD", "EURCHF", "AEDUSD", "AEDGBP", "AEDEUR", "AEDJPY", "AEDCAD", "AEDCHF", "JPYUSD", "JPYGBP", "JPYEUR", "JPYAED", "JPYCAD", "JPYCHF", "CADUSD", "CADGBP", "CADEUR", "CADAED", "CADJPY", "CADCHF", "CHFUSD", "CHFGBP", "CHFEUR", "CHFAED", "CHFJPY", "CHFCAD"];
|
const EXCHANGES = [
|
||||||
const FX_DELTA_HEADERS = [
|
{name: 'Nasdaq Stock Market', symbol: 'NASDAQ', supportedStocks: NASDAQ_SYMBOLS},
|
||||||
{
|
{name: 'London Stock Exchange', symbol: 'LSE', supportedStocks: LSE_SYMBOLS},
|
||||||
field: 'symbol',
|
{name: 'Japan Exchange Group', symbol: 'JSE', supportedStocks: JSE_SYMBOLS},
|
||||||
headerName: 'Symbol',
|
{name: 'Deutsche Börse', symbol: 'DE', supportedStocks: DE_SYMBOLS}
|
||||||
width: 80
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'last',
|
|
||||||
headerName: 'Last',
|
|
||||||
headerClass: 'align-right',
|
|
||||||
cellRenderer: 'animateShowChange',
|
|
||||||
cellClass: 'align-right',
|
|
||||||
width: 70
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'net',
|
|
||||||
headerName: 'Net',
|
|
||||||
headerClass: 'align-right',
|
|
||||||
cellRenderer: 'animateShowChange',
|
|
||||||
cellStyle: {'text-align': 'right'},
|
|
||||||
width: 60
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'pct_net_change',
|
|
||||||
headerName: '% NC',
|
|
||||||
headerClass: 'align-right',
|
|
||||||
cellStyle: {'text-align': 'right'}, // to be removed once the component is in place
|
|
||||||
// cellRendererFramework: HorizontalBarComponent,
|
|
||||||
width: 67,
|
|
||||||
cellClassRules: {
|
|
||||||
'pct-change-green': 'x > 0',
|
|
||||||
'pct-change-amber': 'x <= 0 && x >= -0.10',
|
|
||||||
'pct-change-red': 'x < -0.10'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
].concat(FX_CURRENCY_SYMBOLS.map((symbol) => {
|
|
||||||
"use strict";
|
|
||||||
return {
|
|
||||||
field: symbol,
|
|
||||||
headerName: symbol,
|
|
||||||
headerClass: 'align-right',
|
|
||||||
width: 87,
|
|
||||||
cellStyle: {'text-align': 'right'},
|
|
||||||
cellClassRules: {
|
|
||||||
'fx-postive': 'x > 0.8',
|
|
||||||
'fx-null': 'x === null',
|
|
||||||
'fx-negative': 'x < -0.8'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
const FX_CURRENCY_MATRIX = [
|
|
||||||
["symbol", ...FX_CURRENCY_SYMBOLS],
|
|
||||||
["USDGBP", null, "0.89", "-0.01", "0.29", "0.28", "-0.04", "0.47", "0.17", "0.20", "0.11", "0.97", "0.07", "-0.20", "0.57", "0.54", "0.26", "0.33", "0.86", "0.95", "0.39", "0.21", "-0.49", "0.63", "-0.13", "-0.86", "0.18", "-0.84", "-0.89", "0.05", "-0.29", "0.34", "0.93", "0.41", "0.13", "-0.17", "0.70", "-0.17", "0.60", "0.00", "0.09", "-0.15", "0.10"],
|
|
||||||
["USDEUR", "0.89", null, "0.25", "0.29", "0.86", "-0.93", "0.09", "0.63", "0.76", "0.10", "0.51", "-0.31", "-0.51", "0.20", "0.48", "-0.42", "0.73", "0.57", "0.65", "0.40", "0.12", "0.24", "0.42", "0.75", "0.13", "0.75", "0.42", "-0.80", "-0.26", "0.68", "0.68", "0.98", "0.87", "0.48", "0.52", "0.23", "0.61", "0.71", "-0.61", "0.40", "-0.80", "-0.89"],
|
|
||||||
["USDAED", "0.90", "0.95", null, "0.71", "0.49", "0.50", "0.51", "0.07", "0.80", "-0.74", "0.54", "0.46", "-0.90", "-0.33", "0.75", "0.91", "0.84", "0.86", "0.89", "0.68", "0.71", "0.74", "0.58", "-0.24", "0.31", "0.85", "0.28", "0.44", "0.51", "-0.19", "0.71", "0.81", "0.85", "0.23", "0.09", "0.65", "-0.48", "0.43", "0.97", "0.11", "-0.81", "-0.69"],
|
|
||||||
["USDJPY", "0.84", "0.92", "0.36", null, "0.79", "0.90", "0.86", "0.42", "0.14", "0.98", "0.47", "0.76", "0.60", "0.15", "0.04", "0.58", "0.13", "-0.16", "0.63", "0.86", "-0.63", "-0.95", "0.42", "0.08", "0.90", "-0.39", "-0.16", "0.66", "0.95", "0.31", "0.66", "-0.84", "0.06", "-0.60", "0.08", "0.57", "0.93", "0.78", "0.15", "0.36", "0.78", "0.34"],
|
|
||||||
["USDCAD", "0.79", "-0.87", "0.93", "0.83", null, "0.10", "0.60", "0.34", "0.98", "0.70", "0.09", "0.46", "0.80", "0.10", "0.26", "-0.90", "0.69", "-0.22", "0.51", "-0.75", "-0.08", "0.07", "0.24", "0.68", "0.60", "0.37", "0.92", "0.02", "0.66", "0.16", "0.24", "-0.79", "0.19", "0.19", "0.08", "-0.97", "-0.93", "0.04", "-0.92", "0.86", "-0.36", "0.04"],
|
|
||||||
["USDCHF", "0.94", "-0.02", "0.70", "0.82", "0.41", null, "0.76", "0.06", "0.46", "0.99", "0.07", "0.72", "0.14", "0.90", "0.23", "-0.54", "0.64", "0.80", "0.16", "0.23", "0.66", "-0.89", "-0.54", "-0.95", "0.27", "0.56", "0.42", "0.41", "0.88", "0.81", "0.37", "0.75", "0.06", "-0.75", "0.98", "0.21", "0.01", "0.03", "0.35", "-0.42", "0.55", "0.19"],
|
|
||||||
["GBPUSD", "0.05", "-0.64", "0.47", "0.56", "0.51", "-0.47", null, "-0.15", "0.13", "0.55", "0.58", "0.57", "-0.49", "0.28", "0.86", "0.49", "0.12", "-0.91", "0.06", "0.12", "0.18", "-0.02", "-0.55", "0.18", "0.29", "0.76", "0.11", "0.04", "0.55", "0.16", "0.84", "0.83", "-0.94", "0.32", "0.07", "-0.33", "-0.29", "0.01", "-0.19", "0.01", "-0.60", "0.66"],
|
|
||||||
["GBPEUR", "-0.32", "0.17", "0.60", "-0.52", "-0.52", "0.39", "-0.42", null, "0.07", "0.69", "0.67", "0.01", "0.72", "0.35", "0.66", "-0.66", "0.21", "0.12", "0.42", "-0.57", "-0.04", "0.48", "0.91", "0.72", "-0.16", "0.79", "0.03", "0.44", "0.17", "0.87", "-0.82", "0.20", "0.88", "0.48", "0.59", "-0.70", "0.12", "0.56", "-0.69", "0.10", "0.90", "1.00"],
|
|
||||||
["GBPAED", "0.76", "0.05", "0.72", "-0.40", "0.93", "0.64", "0.90", "0.21", null, "0.91", "0.33", "-0.36", "0.28", "0.87", "0.25", "0.33", "0.44", "0.89", "0.17", "0.96", "0.86", "0.88", "0.03", "-0.25", "0.21", "0.98", "-0.60", "0.07", "0.90", "0.23", "0.41", "0.77", "0.83", "0.94", "0.12", "0.37", "0.58", "0.35", "-0.53", "0.49", "0.96", "-0.06"],
|
|
||||||
["GBPJPY", "0.63", "0.72", "0.59", "0.89", "-0.54", "0.97", "0.61", "0.64", "0.85", null, "0.35", "0.57", "0.25", "0.85", "0.27", "-0.70", "-0.30", "-0.36", "0.29", "0.82", "0.26", "0.69", "0.46", "0.01", "0.09", "0.78", "0.95", "0.16", "0.07", "0.41", "0.99", "0.67", "0.34", "-0.89", "0.83", "0.32", "0.21", "-0.48", "-0.64", "0.65", "0.58", "0.69"],
|
|
||||||
["GBPCAD", "0.78", "0.09", "0.33", "0.11", "0.95", "0.01", "0.96", "0.72", "0.13", "0.02", null, "0.44", "0.63", "-0.52", "0.08", "-0.85", "0.74", "0.41", "0.52", "0.15", "-0.97", "0.61", "0.58", "0.47", "0.56", "0.37", "0.54", "-0.65", "0.98", "0.44", "0.28", "0.70", "0.44", "0.34", "0.95", "0.82", "-0.09", "0.62", "0.87", "0.25", "-1.00", "0.99"],
|
|
||||||
["GBPCHF", "-0.87", "0.68", "0.84", "0.83", "0.50", "0.74", "0.02", "0.11", "-0.12", "0.36", "0.71", null, "0.45", "0.02", "0.51", "0.50", "-0.03", "-0.94", "0.23", "0.38", "0.09", "0.26", "0.14", "0.39", "0.36", "0.01", "0.76", "0.21", "0.03", "0.97", "-0.89", "0.68", "0.43", "0.43", "0.26", "0.01", "0.60", "0.15", "0.77", "0.51", "-0.31", "0.37"],
|
|
||||||
["EURUSD", "-0.45", "-0.05", "0.14", "-0.11", "0.36", "0.12", "0.76", "0.66", "0.50", "0.31", "0.28", "0.90", null, "-0.04", "0.73", "0.33", "0.27", "0.22", "0.86", "0.79", "-0.29", "0.30", "0.89", "0.73", "0.94", "0.24", "0.19", "0.81", "0.88", "0.46", "0.19", "0.79", "-0.16", "0.85", "0.84", "-0.57", "-0.87", "0.86", "0.69", "0.12", "0.64", "0.13"],
|
|
||||||
["EURGBP", "0.06", "0.81", "0.54", "0.57", "0.57", "0.81", "0.38", "0.70", "0.37", "0.58", "-0.56", "0.77", "0.59", null, "0.98", "-0.48", "0.60", "0.78", "0.22", "0.20", "-0.62", "-0.97", "-0.55", "0.39", "0.88", "0.96", "0.32", "0.84", "0.26", "-0.47", "0.04", "0.34", "-0.24", "0.53", "-0.75", "-0.97", "0.47", "0.81", "0.49", "-0.84", "0.94", "0.09"],
|
|
||||||
["EURAED", "0.61", "0.59", "0.11", "0.21", "0.41", "-0.45", "0.32", "0.90", "-0.98", "0.38", "0.27", "0.62", "0.67", "0.89", null, "0.27", "0.65", "0.72", "0.69", "0.66", "0.12", "0.32", "0.11", "-0.73", "-0.17", "0.74", "0.03", "0.96", "0.59", "-0.92", "-0.91", "-0.41", "0.09", "0.45", "0.90", "0.88", "0.96", "0.47", "0.95", "0.27", "-0.48", "0.71"],
|
|
||||||
["EURJPY", "-0.01", "0.36", "0.28", "0.68", "0.50", "0.25", "0.81", "0.64", "0.12", "-0.73", "-0.47", "0.96", "-0.98", "-0.41", "0.78", null, "0.19", "-0.37", "0.24", "0.63", "0.74", "-0.24", "0.46", "0.63", "0.99", "0.65", "0.52", "0.11", "0.52", "0.39", "0.41", "0.51", "0.78", "1.00", "0.80", "-0.11", "0.90", "0.96", "0.66", "0.32", "0.02", "0.19"],
|
|
||||||
["EURCAD", "-0.80", "0.40", "0.35", "0.45", "0.66", "0.21", "0.77", "0.58", "0.09", "1.00", "0.02", "-0.85", "0.89", "0.63", "-0.05", "0.46", null, "0.87", "0.96", "-0.48", "0.40", "0.18", "0.37", "0.81", "0.50", "-0.06", "-0.56", "0.38", "0.02", "0.83", "-0.93", "0.80", "0.31", "0.10", "0.70", "0.55", "0.47", "0.77", "0.98", "0.88", "0.19", "0.91"],
|
|
||||||
["EURCHF", "-0.93", "0.01", "-0.29", "0.46", "-0.59", "-0.15", "0.58", "0.00", "-0.62", "0.36", "0.27", "-0.10", "-0.10", "0.57", "0.57", "0.75", "-0.10", null, "0.88", "0.21", "0.89", "0.85", "0.16", "0.93", "0.60", "0.59", "0.42", "0.70", "0.66", "0.80", "0.83", "0.52", "0.01", "0.41", "0.68", "0.94", "0.81", "0.40", "0.69", "0.04", "0.70", "0.61"],
|
|
||||||
["AEDUSD", "0.10", "0.45", "0.06", "-0.37", "-0.14", "0.63", "0.10", "0.77", "0.95", "-0.12", "1.00", "-0.19", "-0.59", "0.78", "0.10", "0.76", "-0.45", "-0.99", null, "-0.46", "0.28", "0.31", "0.32", "0.42", "-0.00", "0.66", "0.24", "0.31", "0.10", "0.73", "0.02", "0.78", "0.07", "1.00", "0.43", "0.61", "0.53", "0.53", "0.41", "0.37", "0.97", "-0.19"],
|
|
||||||
["AEDGBP", "0.70", "0.73", "0.34", "0.97", "0.84", "0.05", "0.21", "0.14", "0.45", "0.69", "0.41", "-0.53", "0.28", "0.13", "0.99", "0.97", "0.93", "0.62", "0.35", null, "0.18", "0.96", "0.58", "0.04", "0.00", "0.58", "-0.54", "0.35", "0.84", "0.83", "-0.20", "0.51", "0.32", "0.01", "0.95", "0.69", "-0.73", "0.36", "0.78", "0.02", "0.22", "0.39"],
|
|
||||||
["AEDEUR", "0.18", "0.84", "-0.89", "0.90", "-0.25", "0.53", "0.71", "0.80", "0.60", "-0.98", "-0.81", "0.57", "0.72", "0.32", "-0.23", "0.98", "0.50", "0.93", "0.56", "0.26", null, "0.61", "0.47", "0.72", "0.58", "0.19", "0.94", "0.21", "0.47", "0.70", "0.67", "0.85", "0.98", "0.15", "0.21", "0.43", "0.03", "0.92", "0.91", "0.35", "0.70", "0.85"],
|
|
||||||
["AEDJPY", "0.88", "0.62", "0.50", "0.27", "0.56", "0.61", "0.06", "-0.02", "0.42", "0.26", "0.23", "0.83", "-0.55", "0.94", "0.01", "0.72", "-0.43", "0.10", "0.01", "-0.20", "0.13", null, "0.70", "0.10", "0.05", "0.43", "-0.14", "-0.64", "0.80", "0.79", "0.57", "0.14", "0.14", "0.04", "-0.96", "0.59", "0.14", "0.51", "0.23", "0.57", "0.94", "0.88"],
|
|
||||||
["AEDCAD", "0.75", "-0.99", "0.82", "-0.87", "0.79", "1.00", "0.21", "0.30", "-0.40", "0.34", "-0.85", "0.41", "0.79", "0.17", "0.58", "-0.24", "0.18", "0.15", "0.18", "0.44", "0.34", "0.90", null, "0.10", "0.34", "0.31", "0.34", "0.79", "-0.05", "0.19", "-0.86", "0.61", "-0.65", "0.23", "0.59", "0.69", "-0.65", "0.89", "0.97", "0.12", "0.63", "-0.24"],
|
|
||||||
["AEDCHF", "0.67", "0.46", "0.92", "0.22", "0.91", "0.67", "0.81", "0.04", "0.29", "0.13", "0.80", "0.95", "0.29", "0.99", "-0.17", "0.58", "0.64", "0.68", "0.41", "0.69", "0.84", "0.01", "0.04", null, "0.07", "0.16", "0.26", "-0.43", "0.08", "0.58", "0.33", "-0.28", "0.03", "-0.08", "0.54", "-0.91", "0.78", "-0.10", "-0.13", "0.15", "0.62", "-0.13"],
|
|
||||||
["JPYUSD", "-0.67", "0.90", "0.84", "0.10", "0.77", "0.43", "0.59", "0.69", "0.63", "0.82", "-0.61", "0.41", "0.07", "0.48", "1.00", "-0.52", "0.22", "0.89", "0.43", "0.54", "0.56", "-0.43", "0.78", "0.67", null, "0.06", "0.28", "0.04", "0.62", "0.18", "0.77", "0.63", "0.05", "0.87", "0.22", "0.21", "0.07", "0.25", "-0.55", "0.67", "0.10", "-0.67"],
|
|
||||||
["JPYGBP", "0.21", "0.46", "0.23", "0.53", "-0.97", "0.78", "0.43", "0.74", "-0.95", "0.98", "0.49", "0.66", "0.18", "0.55", "-0.33", "0.67", "0.65", "0.23", "-0.07", "-0.67", "0.56", "0.74", "-0.38", "-0.83", "-0.51", null, "-0.26", "-0.79", "0.73", "-0.78", "-0.09", "0.19", "0.48", "0.97", "0.11", "0.19", "0.51", "0.32", "0.81", "-0.02", "0.17", "0.48"],
|
|
||||||
["JPYEUR", "0.83", "0.86", "0.62", "-0.92", "0.64", "0.58", "0.55", "0.07", "0.81", "0.32", "0.33", "0.96", "0.48", "0.57", "0.25", "0.56", "0.33", "0.02", "-0.79", "0.44", "0.95", "0.35", "0.41", "0.06", "0.28", "0.77", null, "0.64", "0.79", "0.74", "0.67", "-0.97", "0.47", "-0.11", "0.03", "0.39", "-0.37", "0.06", "0.09", "0.13", "0.20", "0.87"],
|
|
||||||
["JPYAED", "0.69", "0.80", "0.90", "0.06", "0.55", "0.90", "-0.09", "0.05", "-0.10", "0.31", "0.57", "0.69", "-0.78", "0.42", "0.64", "0.96", "0.08", "-0.76", "0.59", "0.00", "0.40", "-0.88", "0.69", "0.17", "-0.16", "0.57", "0.86", null, "-0.61", "-0.14", "0.41", "-0.16", "0.36", "0.95", "0.44", "0.41", "0.35", "-0.56", "0.25", "0.66", "0.90", "0.82"],
|
|
||||||
["JPYCAD", "0.33", "0.27", "0.61", "0.01", "-0.16", "0.21", "0.57", "-0.41", "-0.56", "0.55", "0.13", "-0.87", "0.19", "0.64", "-0.38", "-0.80", "-0.10", "0.44", "0.72", "-0.72", "0.48", "0.42", "0.84", "0.73", "0.35", "0.68", "0.01", "0.09", null, "0.87", "0.17", "0.45", "0.02", "0.01", "0.77", "0.24", "0.62", "0.39", "-0.73", "0.21", "-0.08", "0.42"],
|
|
||||||
["JPYCHF", "-0.45", "0.52", "0.34", "0.85", "0.16", "0.96", "0.53", "0.62", "0.46", "0.94", "0.08", "-0.68", "0.81", "0.44", "0.27", "0.75", "-0.84", "0.69", "-0.99", "0.41", "0.66", "-0.94", "0.21", "0.85", "-0.08", "0.36", "0.62", "0.25", "-0.48", null, "0.51", "-0.39", "0.60", "0.63", "0.68", "0.10", "0.62", "0.68", "0.00", "0.24", "0.61", "0.23"],
|
|
||||||
["CADUSD", "-0.65", "0.73", "0.93", "0.27", "-0.00", "-0.46", "0.53", "0.36", "0.83", "0.58", "0.40", "0.03", "0.32", "0.38", "-0.53", "0.86", "0.42", "0.90", "0.83", "0.94", "0.34", "-0.56", "0.46", "-0.72", "0.13", "0.08", "0.25", "0.59", "0.75", "0.72", null, "0.62", "0.73", "0.52", "0.28", "0.03", "-0.54", "0.50", "0.76", "-0.28", "0.89", "0.97"],
|
|
||||||
["CADGBP", "0.74", "0.58", "0.55", "0.01", "0.33", "0.61", "0.75", "0.86", "-0.87", "0.50", "0.57", "0.84", "-0.34", "1.00", "0.77", "0.75", "0.40", "0.12", "-0.57", "-0.16", "-0.91", "0.06", "0.67", "-0.55", "0.02", "0.78", "0.57", "0.70", "0.21", "0.95", "-0.91", null, "-0.82", "0.71", "0.36", "0.46", "0.46", "0.24", "0.15", "0.54", "0.15", "0.83"],
|
|
||||||
["CADEUR", "-0.58", "0.29", "0.03", "0.70", "0.77", "0.80", "0.52", "0.04", "0.11", "0.86", "-0.98", "0.02", "0.01", "-0.19", "-0.48", "0.80", "0.90", "0.10", "0.28", "0.88", "0.98", "0.43", "0.47", "-0.41", "-0.92", "0.49", "0.64", "-0.60", "0.11", "0.61", "0.19", "-0.39", null, "-0.21", "0.56", "-0.45", "-0.48", "0.51", "0.04", "-0.44", "-0.22", "-0.29"],
|
|
||||||
["CADAED", "0.07", "0.55", "0.99", "-0.41", "0.65", "0.75", "0.97", "0.74", "0.65", "0.37", "-0.04", "0.85", "0.83", "0.25", "0.14", "-0.00", "0.80", "0.78", "-0.42", "0.54", "-0.42", "-0.07", "-0.62", "0.56", "0.89", "0.92", "0.19", "0.64", "0.45", "0.24", "0.97", "0.41", "0.36", null, "-0.54", "-0.85", "-0.68", "0.48", "0.13", "0.61", "0.75", "0.21"],
|
|
||||||
["CADJPY", "-0.84", "0.71", "0.59", "-0.78", "0.92", "0.93", "0.03", "0.27", "0.22", "0.71", "-0.79", "0.72", "0.27", "0.29", "0.40", "0.66", "0.44", "-0.33", "0.24", "0.99", "-0.95", "0.74", "0.42", "0.45", "0.08", "0.46", "0.22", "0.70", "0.80", "0.36", "0.36", "0.94", "0.75", "0.51", null, "0.10", "0.31", "0.54", "1.00", "0.78", "0.17", "0.32"],
|
|
||||||
["CADCHF", "0.19", "0.00", "0.62", "-0.63", "0.75", "0.57", "0.28", "-0.98", "0.17", "-0.63", "0.09", "0.10", "-0.09", "0.22", "0.65", "0.20", "0.27", "-0.66", "-0.70", "0.72", "0.40", "0.96", "0.52", "0.38", "0.96", "0.90", "0.35", "-0.70", "0.37", "0.94", "0.20", "0.78", "0.34", "0.24", "-0.18", null, "0.05", "0.71", "0.05", "0.38", "0.02", "0.60"],
|
|
||||||
["CHFUSD", "0.42", "0.61", "-0.30", "-0.27", "0.46", "0.63", "0.64", "0.33", "0.18", "0.88", "0.99", "0.73", "0.85", "0.07", "0.53", "0.31", "-0.63", "0.56", "-0.04", "-0.68", "0.43", "-0.96", "0.45", "0.45", "0.50", "0.17", "0.82", "0.34", "0.26", "0.16", "0.71", "0.35", "0.57", "0.79", "0.56", "0.55", null, "0.02", "-0.90", "0.84", "0.33", "0.18"],
|
|
||||||
["CHFGBP", "-0.38", "0.73", "0.25", "0.64", "0.41", "-0.48", "0.75", "-0.40", "0.37", "0.62", "0.30", "0.06", "0.54", "0.15", "0.51", "0.33", "-0.79", "-0.05", "-0.54", "0.21", "0.40", "0.86", "0.96", "0.94", "0.52", "0.07", "0.71", "-0.80", "-0.40", "0.71", "0.71", "0.89", "0.43", "-0.68", "0.93", "0.05", "0.42", null, "0.59", "-0.67", "0.03", "0.17"],
|
|
||||||
["CHFEUR", "-0.64", "0.96", "-0.34", "0.71", "0.53", "0.44", "0.27", "0.56", "0.96", "0.40", "0.86", "0.65", "0.82", "0.89", "-0.75", "0.29", "0.06", "0.70", "0.23", "0.68", "0.79", "0.21", "0.50", "0.14", "-0.27", "-0.83", "-0.22", "0.59", "0.40", "0.10", "0.88", "0.99", "0.21", "-0.36", "0.00", "0.53", "0.08", "0.08", null, "0.53", "-0.51", "0.03"],
|
|
||||||
["CHFAED", "-0.99", "0.71", "0.51", "0.58", "0.57", "0.73", "0.60", "0.23", "0.02", "0.84", "0.90", "0.56", "0.03", "-0.93", "0.59", "0.24", "-0.67", "0.13", "0.99", "0.28", "0.72", "0.79", "-0.83", "-0.30", "0.73", "0.08", "-0.02", "0.85", "0.33", "0.57", "0.09", "0.26", "0.16", "0.80", "0.65", "-0.19", "-0.38", "-0.61", "-0.98", null, "0.57", "-0.81"],
|
|
||||||
["CHFJPY", "0.60", "0.96", "0.22", "0.52", "0.63", "0.24", "0.76", "0.91", "0.80", "-0.14", "0.59", "-0.01", "0.60", "-0.08", "0.63", "0.39", "0.30", "-0.71", "0.18", "0.94", "-0.30", "0.28", "0.87", "0.92", "-0.19", "0.18", "-0.40", "0.44", "0.88", "0.52", "0.50", "0.44", "0.84", "0.24", "0.09", "0.15", "0.10", "0.30", "-0.05", "0.79", null, "0.99"],
|
|
||||||
["CHFCAD", "0.93", "0.24", "0.05", "0.40", "0.75", "0.12", "0.90", "0.56", "0.46", "0.62", "0.71", "0.01", "0.04", "0.02", "0.49", "0.51", "-0.94", "0.93", "0.80", "-0.40", "0.79", "0.82", "-0.04", "0.38", "-0.24", "-0.17", "0.78", "-0.42", "0.92", "-0.83", "-0.01", "0.54", "0.73", "0.52", "0.95", "0.44", "0.90", "0.81", "0.42", "0.26", "0.36", null]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// for (i = 0; i < MAJOR_CURRENCIES.length; i++) {
|
|
||||||
// for (j = 0; j < MAJOR_CURRENCIES.length; j++) {
|
|
||||||
// if (i === j) {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// console.log(`${MAJOR_CURRENCIES[i] + MAJOR_CURRENCIES[j]}`);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let rows = [];
|
|
||||||
// let row = ['Symbol'];
|
|
||||||
//
|
|
||||||
// rows = [];
|
|
||||||
// for (j = 0; j < FX_CURRENCY_CODE.length; j++) {
|
|
||||||
// row.push(FX_CURRENCY_CODE[j]);
|
|
||||||
// }
|
|
||||||
// rows.push(row);
|
|
||||||
//
|
|
||||||
// for (i = 0; i < FX_CURRENCY_CODE.length; i++) {
|
|
||||||
// let row = [];
|
|
||||||
// row.push(FX_CURRENCY_CODE[i]);
|
|
||||||
//
|
|
||||||
// for (j = 0; j < FX_CURRENCY_CODE.length; j++) {
|
|
||||||
// if (i === j) {
|
|
||||||
// row.push(null);
|
|
||||||
// } else {
|
|
||||||
// var mutliplier = ((Math.random() * 10) > 8) ? -1 : 1;
|
|
||||||
// row.push((mutliplier * Math.random()).toFixed(2))
|
|
||||||
// // row.push(`${FX_CURRENCY_CODE[j]} value`)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// rows.push(row);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// JSON.stringify(rows);
|
|
||||||
|
|
||||||
const FX_CURRENCY_CODE = [
|
|
||||||
'USDGBP',
|
|
||||||
'USDEUR',
|
|
||||||
'USDAED',
|
|
||||||
'USDJPY',
|
|
||||||
'USDCAD',
|
|
||||||
'USDCHF',
|
|
||||||
'GBPUSD',
|
|
||||||
'GBPEUR',
|
|
||||||
'GBPAED',
|
|
||||||
'GBPJPY',
|
|
||||||
'GBPCAD',
|
|
||||||
'GBPCHF',
|
|
||||||
'EURUSD',
|
|
||||||
'EURGBP',
|
|
||||||
'EURAED',
|
|
||||||
'EURJPY',
|
|
||||||
'EURCAD',
|
|
||||||
'EURCHF',
|
|
||||||
'AEDUSD',
|
|
||||||
'AEDGBP',
|
|
||||||
'AEDEUR',
|
|
||||||
'AEDJPY',
|
|
||||||
'AEDCAD',
|
|
||||||
'AEDCHF',
|
|
||||||
'JPYUSD',
|
|
||||||
'JPYGBP',
|
|
||||||
'JPYEUR',
|
|
||||||
'JPYAED',
|
|
||||||
'JPYCAD',
|
|
||||||
'JPYCHF',
|
|
||||||
'CADUSD',
|
|
||||||
'CADGBP',
|
|
||||||
'CADEUR',
|
|
||||||
'CADAED',
|
|
||||||
'CADJPY',
|
|
||||||
'CADCHF',
|
|
||||||
'CHFUSD',
|
|
||||||
'CHFGBP',
|
|
||||||
'CHFEUR',
|
|
||||||
'CHFAED',
|
|
||||||
'CHFJPY',
|
|
||||||
'CHFCAD'
|
|
||||||
];
|
|
||||||
|
|
||||||
const MAJOR_CURRENCIES = [
|
|
||||||
'USD',
|
|
||||||
'GBP',
|
|
||||||
'EUR',
|
|
||||||
'AED',
|
|
||||||
'JPY',
|
|
||||||
'CAD',
|
|
||||||
'CHF'];
|
|
||||||
|
|
||||||
const SECONDARY_CURRENCIES = [
|
|
||||||
'AFN',
|
|
||||||
'ALL',
|
|
||||||
'AMD',
|
|
||||||
'ANG',
|
|
||||||
'AOA',
|
|
||||||
'ARS',
|
|
||||||
'AUD',
|
|
||||||
'AWG',
|
|
||||||
'AZN',
|
|
||||||
'BAM',
|
|
||||||
'BBD',
|
|
||||||
'BDT',
|
|
||||||
'BGN',
|
|
||||||
'BHD',
|
|
||||||
'BIF',
|
|
||||||
'BMD',
|
|
||||||
'BND',
|
|
||||||
'BOB',
|
|
||||||
'BRL',
|
|
||||||
'BSD',
|
|
||||||
'BTN',
|
|
||||||
'BWP',
|
|
||||||
'BYN',
|
|
||||||
'BZD',
|
|
||||||
'CDF',
|
|
||||||
'CLP',
|
|
||||||
'CNY',
|
|
||||||
'COP',
|
|
||||||
'CRC',
|
|
||||||
'CUC',
|
|
||||||
'CUP',
|
|
||||||
'CVE',
|
|
||||||
'CZK',
|
|
||||||
'DJF',
|
|
||||||
'DKK',
|
|
||||||
'DOP',
|
|
||||||
'DZD',
|
|
||||||
'EGP',
|
|
||||||
'ERN',
|
|
||||||
'ETB',
|
|
||||||
'FJD',
|
|
||||||
'FKP',
|
|
||||||
'GEL',
|
|
||||||
'GGP',
|
|
||||||
'GHS',
|
|
||||||
'GIP',
|
|
||||||
'GMD',
|
|
||||||
'GNF',
|
|
||||||
'GTQ',
|
|
||||||
'GYD',
|
|
||||||
'HKD',
|
|
||||||
'HNL',
|
|
||||||
'HRK',
|
|
||||||
'HTG',
|
|
||||||
'HUF',
|
|
||||||
'IDR',
|
|
||||||
'ILS',
|
|
||||||
'IMP',
|
|
||||||
'INR',
|
|
||||||
'IQD',
|
|
||||||
'IRR',
|
|
||||||
'ISK',
|
|
||||||
'JEP',
|
|
||||||
'JMD',
|
|
||||||
'JOD',
|
|
||||||
'KES',
|
|
||||||
'KGS',
|
|
||||||
'KHR',
|
|
||||||
'KMF',
|
|
||||||
'KPW',
|
|
||||||
'KRW',
|
|
||||||
'KWD',
|
|
||||||
'KYD',
|
|
||||||
'KZT',
|
|
||||||
'LAK',
|
|
||||||
'LBP',
|
|
||||||
'LKR',
|
|
||||||
'LRD',
|
|
||||||
'LSL',
|
|
||||||
'LYD',
|
|
||||||
'MAD',
|
|
||||||
'MDL',
|
|
||||||
'MGA',
|
|
||||||
'MKD',
|
|
||||||
'MMK',
|
|
||||||
'MNT',
|
|
||||||
'MOP',
|
|
||||||
'MRO',
|
|
||||||
'MUR',
|
|
||||||
'MVR',
|
|
||||||
'MWK',
|
|
||||||
'MXN',
|
|
||||||
'MYR',
|
|
||||||
'MZN',
|
|
||||||
'NAD',
|
|
||||||
'NGN',
|
|
||||||
'NIO',
|
|
||||||
'NOK',
|
|
||||||
'NPR',
|
|
||||||
'NZD',
|
|
||||||
'OMR',
|
|
||||||
'PAB',
|
|
||||||
'PEN',
|
|
||||||
'PGK',
|
|
||||||
'PHP',
|
|
||||||
'PKR',
|
|
||||||
'PLN',
|
|
||||||
'PYG',
|
|
||||||
'QAR',
|
|
||||||
'RON',
|
|
||||||
'RSD',
|
|
||||||
'RUB',
|
|
||||||
'RWF',
|
|
||||||
'SAR',
|
|
||||||
'SBD',
|
|
||||||
'SCR',
|
|
||||||
'SDG',
|
|
||||||
'SEK',
|
|
||||||
'SGD',
|
|
||||||
'SHP',
|
|
||||||
'SLL',
|
|
||||||
'SOS',
|
|
||||||
'SPL',
|
|
||||||
'SRD',
|
|
||||||
'STD',
|
|
||||||
'SVC',
|
|
||||||
'SYP',
|
|
||||||
'SZL',
|
|
||||||
'THB',
|
|
||||||
'TJS',
|
|
||||||
'TMT',
|
|
||||||
'TND',
|
|
||||||
'TOP',
|
|
||||||
'TRY',
|
|
||||||
'TTD',
|
|
||||||
'TVD',
|
|
||||||
'TWD',
|
|
||||||
'TZS',
|
|
||||||
'UAH',
|
|
||||||
'UGX',
|
|
||||||
'UYU',
|
|
||||||
'UZS',
|
|
||||||
'VEF',
|
|
||||||
'VND',
|
|
||||||
'VUV',
|
|
||||||
'WST',
|
|
||||||
'XAF',
|
|
||||||
'XCD',
|
|
||||||
'XDR',
|
|
||||||
'XOF',
|
|
||||||
'XPF',
|
|
||||||
'YER',
|
|
||||||
'ZMW',
|
|
||||||
'ZWD',
|
|
||||||
'ZAR'];
|
|
||||||
|
|||||||
201
src-trader-dashboard/services/FxDataService.jsx
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
import sampleSize from "lodash/sampleSize";
|
||||||
|
import cloneDeep from "lodash/cloneDeep";
|
||||||
|
|
||||||
|
import StoreService from "./StoreService";
|
||||||
|
import {fxDataUpdated, fxTopMoversUpdated} from "../actions/fxDataActions";
|
||||||
|
|
||||||
|
import HorizontalBarComponent from "../components/renderers/HorizontalBarComponent.jsx";
|
||||||
|
|
||||||
|
export default class {
|
||||||
|
constructor() {
|
||||||
|
this.store = StoreService.STORE;
|
||||||
|
|
||||||
|
// create the initial state of the fx data
|
||||||
|
this.createFxMatrixSnapshot();
|
||||||
|
this.calculateTopMovers();
|
||||||
|
|
||||||
|
// and dispatch it
|
||||||
|
this.store.dispatch(fxDataUpdated(this.fxData));
|
||||||
|
this.store.dispatch(fxTopMoversUpdated(this.fxTopMovers));
|
||||||
|
|
||||||
|
// periodically update the fx and top mover information
|
||||||
|
this.kickOffPeriodicUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
|
kickOffPeriodicUpdates() {
|
||||||
|
setInterval(() => {
|
||||||
|
this.applyDeltasToFxData();
|
||||||
|
|
||||||
|
this.store.dispatch(fxDataUpdated(this.fxData));
|
||||||
|
}, 1500);
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
this.calculateTopMovers();
|
||||||
|
|
||||||
|
this.store.dispatch(fxTopMoversUpdated(this.fxTopMovers));
|
||||||
|
}, 2500);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the rest of this class exists primarily to create mock data - it can safely be ignored
|
||||||
|
* as it is secondary to the main ideas being demonstrated by the rest of the application
|
||||||
|
*/
|
||||||
|
calculateTopMovers() {
|
||||||
|
let fxData = cloneDeep(this.fxData);
|
||||||
|
fxData.sort((a, b) => {
|
||||||
|
return Math.abs(b.pct_net_change) - Math.abs(a.pct_net_change);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.fxTopMovers = fxData.slice(0, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
applyDeltasToFxData() {
|
||||||
|
let fxSymbolsToUpdate = sampleSize(FX_CURRENCY_SYMBOLS, FX_CURRENCY_SYMBOLS.length / 5);
|
||||||
|
let rowsToUpdate = sampleSize(this.fxData, this.fxData.length / 5);
|
||||||
|
for (let i = 0; i < rowsToUpdate.length; i++) {
|
||||||
|
let row = rowsToUpdate[i];
|
||||||
|
|
||||||
|
let maxSwing = row.last * 0.05; // max 5% swing
|
||||||
|
let swing = Math.floor(this.random(-maxSwing, maxSwing));
|
||||||
|
row.last = row.last + swing;
|
||||||
|
row.net = swing;
|
||||||
|
|
||||||
|
let multiplier = ((Math.random() * 10) > 5) ? -1 : 1;
|
||||||
|
row['pct_net_change'] = multiplier * (this.random(30, 100) / 100).toFixed(2);
|
||||||
|
|
||||||
|
for (let symbolToUpdate of fxSymbolsToUpdate) {
|
||||||
|
if (row[symbolToUpdate] === null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let multiplier = ((Math.random() * 10) > 8) ? -1 : 1;
|
||||||
|
row[symbolToUpdate] = (multiplier * Math.random()).toFixed(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
random(min, max) {
|
||||||
|
return parseFloat((Math.random() * (max - min + 1) + min))
|
||||||
|
}
|
||||||
|
|
||||||
|
getFxMatrixHeaderNames() {
|
||||||
|
return FX_DELTA_HEADERS;
|
||||||
|
}
|
||||||
|
|
||||||
|
createFxMatrixSnapshot() {
|
||||||
|
let columns = FX_CURRENCY_MATRIX[0];
|
||||||
|
let data = FX_CURRENCY_MATRIX.slice(1);
|
||||||
|
|
||||||
|
let rowData = [];
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
let currentRow = data[i];
|
||||||
|
|
||||||
|
let row = {};
|
||||||
|
for (let j = 0; j < columns.length; j++) {
|
||||||
|
row[columns[j]] = currentRow[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
// last, net and % change are different
|
||||||
|
row['last'] = Math.floor(this.random(7000, 170000));
|
||||||
|
row['net'] = Math.floor(this.random(-500, 500));
|
||||||
|
|
||||||
|
let multiplier = ((Math.random() * 10) > 5) ? -1 : 1;
|
||||||
|
row['pct_net_change'] = multiplier * (this.random(30, 100) / 100).toFixed(2);
|
||||||
|
|
||||||
|
rowData.push(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fxData = rowData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const FX_CURRENCY_SYMBOLS = ["USDGBP", "USDEUR", "USDAED", "USDJPY", "USDCAD", "USDCHF", "GBPUSD", "GBPEUR", "GBPAED", "GBPJPY", "GBPCAD", "GBPCHF", "EURUSD", "EURGBP", "EURAED", "EURJPY", "EURCAD", "EURCHF", "AEDUSD", "AEDGBP", "AEDEUR", "AEDJPY", "AEDCAD", "AEDCHF", "JPYUSD", "JPYGBP", "JPYEUR", "JPYAED", "JPYCAD", "JPYCHF", "CADUSD", "CADGBP", "CADEUR", "CADAED", "CADJPY", "CADCHF", "CHFUSD", "CHFGBP", "CHFEUR", "CHFAED", "CHFJPY", "CHFCAD"];
|
||||||
|
const FX_DELTA_HEADERS = [
|
||||||
|
{
|
||||||
|
field: 'symbol',
|
||||||
|
headerName: 'Symbol',
|
||||||
|
width: 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'last',
|
||||||
|
headerName: 'Last',
|
||||||
|
headerClass: 'align-right',
|
||||||
|
cellRenderer: 'animateShowChange',
|
||||||
|
cellClass: 'align-right',
|
||||||
|
width: 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'net',
|
||||||
|
headerName: 'Net',
|
||||||
|
headerClass: 'align-right',
|
||||||
|
cellRenderer: 'animateShowChange',
|
||||||
|
cellClass: 'align-right',
|
||||||
|
width: 90
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'pct_net_change',
|
||||||
|
headerName: '% NC',
|
||||||
|
cellRendererFramework: HorizontalBarComponent,
|
||||||
|
width: 85
|
||||||
|
},
|
||||||
|
].concat(FX_CURRENCY_SYMBOLS.map((symbol) => {
|
||||||
|
"use strict";
|
||||||
|
return {
|
||||||
|
field: symbol,
|
||||||
|
headerName: symbol,
|
||||||
|
width: 67,
|
||||||
|
cellClass: 'align-right',
|
||||||
|
cellRenderer: 'animateShowChange',
|
||||||
|
cellClassRules: {
|
||||||
|
'fx-positive': 'x > 0.8',
|
||||||
|
'fx-null': 'x === null',
|
||||||
|
'fx-negative': 'x < -0.8'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
const FX_CURRENCY_MATRIX = [
|
||||||
|
["symbol", ...FX_CURRENCY_SYMBOLS],
|
||||||
|
["USDGBP", null, "0.89", "-0.01", "0.29", "0.28", "-0.04", "0.47", "0.17", "0.20", "0.11", "0.97", "0.07", "-0.20", "0.57", "0.54", "0.26", "0.33", "0.86", "0.95", "0.39", "0.21", "-0.49", "0.63", "-0.13", "-0.86", "0.18", "-0.84", "-0.89", "0.05", "-0.29", "0.34", "0.93", "0.41", "0.13", "-0.17", "0.70", "-0.17", "0.60", "0.00", "0.09", "-0.15", "0.10"],
|
||||||
|
["USDEUR", "0.89", null, "0.25", "0.29", "0.86", "-0.93", "0.09", "0.63", "0.76", "0.10", "0.51", "-0.31", "-0.51", "0.20", "0.48", "-0.42", "0.73", "0.57", "0.65", "0.40", "0.12", "0.24", "0.42", "0.75", "0.13", "0.75", "0.42", "-0.80", "-0.26", "0.68", "0.68", "0.98", "0.87", "0.48", "0.52", "0.23", "0.61", "0.71", "-0.61", "0.40", "-0.80", "-0.89"],
|
||||||
|
["USDAED", "0.90", "0.95", null, "0.71", "0.49", "0.50", "0.51", "0.07", "0.80", "-0.74", "0.54", "0.46", "-0.90", "-0.33", "0.75", "0.91", "0.84", "0.86", "0.89", "0.68", "0.71", "0.74", "0.58", "-0.24", "0.31", "0.85", "0.28", "0.44", "0.51", "-0.19", "0.71", "0.81", "0.85", "0.23", "0.09", "0.65", "-0.48", "0.43", "0.97", "0.11", "-0.81", "-0.69"],
|
||||||
|
["USDJPY", "0.84", "0.92", "0.36", null, "0.79", "0.90", "0.86", "0.42", "0.14", "0.98", "0.47", "0.76", "0.60", "0.15", "0.04", "0.58", "0.13", "-0.16", "0.63", "0.86", "-0.63", "-0.95", "0.42", "0.08", "0.90", "-0.39", "-0.16", "0.66", "0.95", "0.31", "0.66", "-0.84", "0.06", "-0.60", "0.08", "0.57", "0.93", "0.78", "0.15", "0.36", "0.78", "0.34"],
|
||||||
|
["USDCAD", "0.79", "-0.87", "0.93", "0.83", null, "0.10", "0.60", "0.34", "0.98", "0.70", "0.09", "0.46", "0.80", "0.10", "0.26", "-0.90", "0.69", "-0.22", "0.51", "-0.75", "-0.08", "0.07", "0.24", "0.68", "0.60", "0.37", "0.92", "0.02", "0.66", "0.16", "0.24", "-0.79", "0.19", "0.19", "0.08", "-0.97", "-0.93", "0.04", "-0.92", "0.86", "-0.36", "0.04"],
|
||||||
|
["USDCHF", "0.94", "-0.02", "0.70", "0.82", "0.41", null, "0.76", "0.06", "0.46", "0.99", "0.07", "0.72", "0.14", "0.90", "0.23", "-0.54", "0.64", "0.80", "0.16", "0.23", "0.66", "-0.89", "-0.54", "-0.95", "0.27", "0.56", "0.42", "0.41", "0.88", "0.81", "0.37", "0.75", "0.06", "-0.75", "0.98", "0.21", "0.01", "0.03", "0.35", "-0.42", "0.55", "0.19"],
|
||||||
|
["GBPUSD", "0.05", "-0.64", "0.47", "0.56", "0.51", "-0.47", null, "-0.15", "0.13", "0.55", "0.58", "0.57", "-0.49", "0.28", "0.86", "0.49", "0.12", "-0.91", "0.06", "0.12", "0.18", "-0.02", "-0.55", "0.18", "0.29", "0.76", "0.11", "0.04", "0.55", "0.16", "0.84", "0.83", "-0.94", "0.32", "0.07", "-0.33", "-0.29", "0.01", "-0.19", "0.01", "-0.60", "0.66"],
|
||||||
|
["GBPEUR", "-0.32", "0.17", "0.60", "-0.52", "-0.52", "0.39", "-0.42", null, "0.07", "0.69", "0.67", "0.01", "0.72", "0.35", "0.66", "-0.66", "0.21", "0.12", "0.42", "-0.57", "-0.04", "0.48", "0.91", "0.72", "-0.16", "0.79", "0.03", "0.44", "0.17", "0.87", "-0.82", "0.20", "0.88", "0.48", "0.59", "-0.70", "0.12", "0.56", "-0.69", "0.10", "0.90", "1.00"],
|
||||||
|
["GBPAED", "0.76", "0.05", "0.72", "-0.40", "0.93", "0.64", "0.90", "0.21", null, "0.91", "0.33", "-0.36", "0.28", "0.87", "0.25", "0.33", "0.44", "0.89", "0.17", "0.96", "0.86", "0.88", "0.03", "-0.25", "0.21", "0.98", "-0.60", "0.07", "0.90", "0.23", "0.41", "0.77", "0.83", "0.94", "0.12", "0.37", "0.58", "0.35", "-0.53", "0.49", "0.96", "-0.06"],
|
||||||
|
["GBPJPY", "0.63", "0.72", "0.59", "0.89", "-0.54", "0.97", "0.61", "0.64", "0.85", null, "0.35", "0.57", "0.25", "0.85", "0.27", "-0.70", "-0.30", "-0.36", "0.29", "0.82", "0.26", "0.69", "0.46", "0.01", "0.09", "0.78", "0.95", "0.16", "0.07", "0.41", "0.99", "0.67", "0.34", "-0.89", "0.83", "0.32", "0.21", "-0.48", "-0.64", "0.65", "0.58", "0.69"],
|
||||||
|
["GBPCAD", "0.78", "0.09", "0.33", "0.11", "0.95", "0.01", "0.96", "0.72", "0.13", "0.02", null, "0.44", "0.63", "-0.52", "0.08", "-0.85", "0.74", "0.41", "0.52", "0.15", "-0.97", "0.61", "0.58", "0.47", "0.56", "0.37", "0.54", "-0.65", "0.98", "0.44", "0.28", "0.70", "0.44", "0.34", "0.95", "0.82", "-0.09", "0.62", "0.87", "0.25", "-1.00", "0.99"],
|
||||||
|
["GBPCHF", "-0.87", "0.68", "0.84", "0.83", "0.50", "0.74", "0.02", "0.11", "-0.12", "0.36", "0.71", null, "0.45", "0.02", "0.51", "0.50", "-0.03", "-0.94", "0.23", "0.38", "0.09", "0.26", "0.14", "0.39", "0.36", "0.01", "0.76", "0.21", "0.03", "0.97", "-0.89", "0.68", "0.43", "0.43", "0.26", "0.01", "0.60", "0.15", "0.77", "0.51", "-0.31", "0.37"],
|
||||||
|
["EURUSD", "-0.45", "-0.05", "0.14", "-0.11", "0.36", "0.12", "0.76", "0.66", "0.50", "0.31", "0.28", "0.90", null, "-0.04", "0.73", "0.33", "0.27", "0.22", "0.86", "0.79", "-0.29", "0.30", "0.89", "0.73", "0.94", "0.24", "0.19", "0.81", "0.88", "0.46", "0.19", "0.79", "-0.16", "0.85", "0.84", "-0.57", "-0.87", "0.86", "0.69", "0.12", "0.64", "0.13"],
|
||||||
|
["EURGBP", "0.06", "0.81", "0.54", "0.57", "0.57", "0.81", "0.38", "0.70", "0.37", "0.58", "-0.56", "0.77", "0.59", null, "0.98", "-0.48", "0.60", "0.78", "0.22", "0.20", "-0.62", "-0.97", "-0.55", "0.39", "0.88", "0.96", "0.32", "0.84", "0.26", "-0.47", "0.04", "0.34", "-0.24", "0.53", "-0.75", "-0.97", "0.47", "0.81", "0.49", "-0.84", "0.94", "0.09"],
|
||||||
|
["EURAED", "0.61", "0.59", "0.11", "0.21", "0.41", "-0.45", "0.32", "0.90", "-0.98", "0.38", "0.27", "0.62", "0.67", "0.89", null, "0.27", "0.65", "0.72", "0.69", "0.66", "0.12", "0.32", "0.11", "-0.73", "-0.17", "0.74", "0.03", "0.96", "0.59", "-0.92", "-0.91", "-0.41", "0.09", "0.45", "0.90", "0.88", "0.96", "0.47", "0.95", "0.27", "-0.48", "0.71"],
|
||||||
|
["EURJPY", "-0.01", "0.36", "0.28", "0.68", "0.50", "0.25", "0.81", "0.64", "0.12", "-0.73", "-0.47", "0.96", "-0.98", "-0.41", "0.78", null, "0.19", "-0.37", "0.24", "0.63", "0.74", "-0.24", "0.46", "0.63", "0.99", "0.65", "0.52", "0.11", "0.52", "0.39", "0.41", "0.51", "0.78", "1.00", "0.80", "-0.11", "0.90", "0.96", "0.66", "0.32", "0.02", "0.19"],
|
||||||
|
["EURCAD", "-0.80", "0.40", "0.35", "0.45", "0.66", "0.21", "0.77", "0.58", "0.09", "1.00", "0.02", "-0.85", "0.89", "0.63", "-0.05", "0.46", null, "0.87", "0.96", "-0.48", "0.40", "0.18", "0.37", "0.81", "0.50", "-0.06", "-0.56", "0.38", "0.02", "0.83", "-0.93", "0.80", "0.31", "0.10", "0.70", "0.55", "0.47", "0.77", "0.98", "0.88", "0.19", "0.91"],
|
||||||
|
["EURCHF", "-0.93", "0.01", "-0.29", "0.46", "-0.59", "-0.15", "0.58", "0.00", "-0.62", "0.36", "0.27", "-0.10", "-0.10", "0.57", "0.57", "0.75", "-0.10", null, "0.88", "0.21", "0.89", "0.85", "0.16", "0.93", "0.60", "0.59", "0.42", "0.70", "0.66", "0.80", "0.83", "0.52", "0.01", "0.41", "0.68", "0.94", "0.81", "0.40", "0.69", "0.04", "0.70", "0.61"],
|
||||||
|
["AEDUSD", "0.10", "0.45", "0.06", "-0.37", "-0.14", "0.63", "0.10", "0.77", "0.95", "-0.12", "1.00", "-0.19", "-0.59", "0.78", "0.10", "0.76", "-0.45", "-0.99", null, "-0.46", "0.28", "0.31", "0.32", "0.42", "-0.00", "0.66", "0.24", "0.31", "0.10", "0.73", "0.02", "0.78", "0.07", "1.00", "0.43", "0.61", "0.53", "0.53", "0.41", "0.37", "0.97", "-0.19"],
|
||||||
|
["AEDGBP", "0.70", "0.73", "0.34", "0.97", "0.84", "0.05", "0.21", "0.14", "0.45", "0.69", "0.41", "-0.53", "0.28", "0.13", "0.99", "0.97", "0.93", "0.62", "0.35", null, "0.18", "0.96", "0.58", "0.04", "0.00", "0.58", "-0.54", "0.35", "0.84", "0.83", "-0.20", "0.51", "0.32", "0.01", "0.95", "0.69", "-0.73", "0.36", "0.78", "0.02", "0.22", "0.39"],
|
||||||
|
["AEDEUR", "0.18", "0.84", "-0.89", "0.90", "-0.25", "0.53", "0.71", "0.80", "0.60", "-0.98", "-0.81", "0.57", "0.72", "0.32", "-0.23", "0.98", "0.50", "0.93", "0.56", "0.26", null, "0.61", "0.47", "0.72", "0.58", "0.19", "0.94", "0.21", "0.47", "0.70", "0.67", "0.85", "0.98", "0.15", "0.21", "0.43", "0.03", "0.92", "0.91", "0.35", "0.70", "0.85"],
|
||||||
|
["AEDJPY", "0.88", "0.62", "0.50", "0.27", "0.56", "0.61", "0.06", "-0.02", "0.42", "0.26", "0.23", "0.83", "-0.55", "0.94", "0.01", "0.72", "-0.43", "0.10", "0.01", "-0.20", "0.13", null, "0.70", "0.10", "0.05", "0.43", "-0.14", "-0.64", "0.80", "0.79", "0.57", "0.14", "0.14", "0.04", "-0.96", "0.59", "0.14", "0.51", "0.23", "0.57", "0.94", "0.88"],
|
||||||
|
["AEDCAD", "0.75", "-0.99", "0.82", "-0.87", "0.79", "1.00", "0.21", "0.30", "-0.40", "0.34", "-0.85", "0.41", "0.79", "0.17", "0.58", "-0.24", "0.18", "0.15", "0.18", "0.44", "0.34", "0.90", null, "0.10", "0.34", "0.31", "0.34", "0.79", "-0.05", "0.19", "-0.86", "0.61", "-0.65", "0.23", "0.59", "0.69", "-0.65", "0.89", "0.97", "0.12", "0.63", "-0.24"],
|
||||||
|
["AEDCHF", "0.67", "0.46", "0.92", "0.22", "0.91", "0.67", "0.81", "0.04", "0.29", "0.13", "0.80", "0.95", "0.29", "0.99", "-0.17", "0.58", "0.64", "0.68", "0.41", "0.69", "0.84", "0.01", "0.04", null, "0.07", "0.16", "0.26", "-0.43", "0.08", "0.58", "0.33", "-0.28", "0.03", "-0.08", "0.54", "-0.91", "0.78", "-0.10", "-0.13", "0.15", "0.62", "-0.13"],
|
||||||
|
["JPYUSD", "-0.67", "0.90", "0.84", "0.10", "0.77", "0.43", "0.59", "0.69", "0.63", "0.82", "-0.61", "0.41", "0.07", "0.48", "1.00", "-0.52", "0.22", "0.89", "0.43", "0.54", "0.56", "-0.43", "0.78", "0.67", null, "0.06", "0.28", "0.04", "0.62", "0.18", "0.77", "0.63", "0.05", "0.87", "0.22", "0.21", "0.07", "0.25", "-0.55", "0.67", "0.10", "-0.67"],
|
||||||
|
["JPYGBP", "0.21", "0.46", "0.23", "0.53", "-0.97", "0.78", "0.43", "0.74", "-0.95", "0.98", "0.49", "0.66", "0.18", "0.55", "-0.33", "0.67", "0.65", "0.23", "-0.07", "-0.67", "0.56", "0.74", "-0.38", "-0.83", "-0.51", null, "-0.26", "-0.79", "0.73", "-0.78", "-0.09", "0.19", "0.48", "0.97", "0.11", "0.19", "0.51", "0.32", "0.81", "-0.02", "0.17", "0.48"],
|
||||||
|
["JPYEUR", "0.83", "0.86", "0.62", "-0.92", "0.64", "0.58", "0.55", "0.07", "0.81", "0.32", "0.33", "0.96", "0.48", "0.57", "0.25", "0.56", "0.33", "0.02", "-0.79", "0.44", "0.95", "0.35", "0.41", "0.06", "0.28", "0.77", null, "0.64", "0.79", "0.74", "0.67", "-0.97", "0.47", "-0.11", "0.03", "0.39", "-0.37", "0.06", "0.09", "0.13", "0.20", "0.87"],
|
||||||
|
["JPYAED", "0.69", "0.80", "0.90", "0.06", "0.55", "0.90", "-0.09", "0.05", "-0.10", "0.31", "0.57", "0.69", "-0.78", "0.42", "0.64", "0.96", "0.08", "-0.76", "0.59", "0.00", "0.40", "-0.88", "0.69", "0.17", "-0.16", "0.57", "0.86", null, "-0.61", "-0.14", "0.41", "-0.16", "0.36", "0.95", "0.44", "0.41", "0.35", "-0.56", "0.25", "0.66", "0.90", "0.82"],
|
||||||
|
["JPYCAD", "0.33", "0.27", "0.61", "0.01", "-0.16", "0.21", "0.57", "-0.41", "-0.56", "0.55", "0.13", "-0.87", "0.19", "0.64", "-0.38", "-0.80", "-0.10", "0.44", "0.72", "-0.72", "0.48", "0.42", "0.84", "0.73", "0.35", "0.68", "0.01", "0.09", null, "0.87", "0.17", "0.45", "0.02", "0.01", "0.77", "0.24", "0.62", "0.39", "-0.73", "0.21", "-0.08", "0.42"],
|
||||||
|
["JPYCHF", "-0.45", "0.52", "0.34", "0.85", "0.16", "0.96", "0.53", "0.62", "0.46", "0.94", "0.08", "-0.68", "0.81", "0.44", "0.27", "0.75", "-0.84", "0.69", "-0.99", "0.41", "0.66", "-0.94", "0.21", "0.85", "-0.08", "0.36", "0.62", "0.25", "-0.48", null, "0.51", "-0.39", "0.60", "0.63", "0.68", "0.10", "0.62", "0.68", "0.00", "0.24", "0.61", "0.23"],
|
||||||
|
["CADUSD", "-0.65", "0.73", "0.93", "0.27", "-0.00", "-0.46", "0.53", "0.36", "0.83", "0.58", "0.40", "0.03", "0.32", "0.38", "-0.53", "0.86", "0.42", "0.90", "0.83", "0.94", "0.34", "-0.56", "0.46", "-0.72", "0.13", "0.08", "0.25", "0.59", "0.75", "0.72", null, "0.62", "0.73", "0.52", "0.28", "0.03", "-0.54", "0.50", "0.76", "-0.28", "0.89", "0.97"],
|
||||||
|
["CADGBP", "0.74", "0.58", "0.55", "0.01", "0.33", "0.61", "0.75", "0.86", "-0.87", "0.50", "0.57", "0.84", "-0.34", "1.00", "0.77", "0.75", "0.40", "0.12", "-0.57", "-0.16", "-0.91", "0.06", "0.67", "-0.55", "0.02", "0.78", "0.57", "0.70", "0.21", "0.95", "-0.91", null, "-0.82", "0.71", "0.36", "0.46", "0.46", "0.24", "0.15", "0.54", "0.15", "0.83"],
|
||||||
|
["CADEUR", "-0.58", "0.29", "0.03", "0.70", "0.77", "0.80", "0.52", "0.04", "0.11", "0.86", "-0.98", "0.02", "0.01", "-0.19", "-0.48", "0.80", "0.90", "0.10", "0.28", "0.88", "0.98", "0.43", "0.47", "-0.41", "-0.92", "0.49", "0.64", "-0.60", "0.11", "0.61", "0.19", "-0.39", null, "-0.21", "0.56", "-0.45", "-0.48", "0.51", "0.04", "-0.44", "-0.22", "-0.29"],
|
||||||
|
["CADAED", "0.07", "0.55", "0.99", "-0.41", "0.65", "0.75", "0.97", "0.74", "0.65", "0.37", "-0.04", "0.85", "0.83", "0.25", "0.14", "-0.00", "0.80", "0.78", "-0.42", "0.54", "-0.42", "-0.07", "-0.62", "0.56", "0.89", "0.92", "0.19", "0.64", "0.45", "0.24", "0.97", "0.41", "0.36", null, "-0.54", "-0.85", "-0.68", "0.48", "0.13", "0.61", "0.75", "0.21"],
|
||||||
|
["CADJPY", "-0.84", "0.71", "0.59", "-0.78", "0.92", "0.93", "0.03", "0.27", "0.22", "0.71", "-0.79", "0.72", "0.27", "0.29", "0.40", "0.66", "0.44", "-0.33", "0.24", "0.99", "-0.95", "0.74", "0.42", "0.45", "0.08", "0.46", "0.22", "0.70", "0.80", "0.36", "0.36", "0.94", "0.75", "0.51", null, "0.10", "0.31", "0.54", "1.00", "0.78", "0.17", "0.32"],
|
||||||
|
["CADCHF", "0.19", "0.00", "0.62", "-0.63", "0.75", "0.57", "0.28", "-0.98", "0.17", "-0.63", "0.09", "0.10", "-0.09", "0.22", "0.65", "0.20", "0.27", "-0.66", "-0.70", "0.72", "0.40", "0.96", "0.52", "0.38", "0.96", "0.90", "0.35", "-0.70", "0.37", "0.94", "0.20", "0.78", "0.34", "0.24", "-0.18", null, "0.05", "0.71", "0.05", "0.38", "0.02", "0.60"],
|
||||||
|
["CHFUSD", "0.42", "0.61", "-0.30", "-0.27", "0.46", "0.63", "0.64", "0.33", "0.18", "0.88", "0.99", "0.73", "0.85", "0.07", "0.53", "0.31", "-0.63", "0.56", "-0.04", "-0.68", "0.43", "-0.96", "0.45", "0.45", "0.50", "0.17", "0.82", "0.34", "0.26", "0.16", "0.71", "0.35", "0.57", "0.79", "0.56", "0.55", null, "0.02", "-0.90", "0.84", "0.33", "0.18"],
|
||||||
|
["CHFGBP", "-0.38", "0.73", "0.25", "0.64", "0.41", "-0.48", "0.75", "-0.40", "0.37", "0.62", "0.30", "0.06", "0.54", "0.15", "0.51", "0.33", "-0.79", "-0.05", "-0.54", "0.21", "0.40", "0.86", "0.96", "0.94", "0.52", "0.07", "0.71", "-0.80", "-0.40", "0.71", "0.71", "0.89", "0.43", "-0.68", "0.93", "0.05", "0.42", null, "0.59", "-0.67", "0.03", "0.17"],
|
||||||
|
["CHFEUR", "-0.64", "0.96", "-0.34", "0.71", "0.53", "0.44", "0.27", "0.56", "0.96", "0.40", "0.86", "0.65", "0.82", "0.89", "-0.75", "0.29", "0.06", "0.70", "0.23", "0.68", "0.79", "0.21", "0.50", "0.14", "-0.27", "-0.83", "-0.22", "0.59", "0.40", "0.10", "0.88", "0.99", "0.21", "-0.36", "0.00", "0.53", "0.08", "0.08", null, "0.53", "-0.51", "0.03"],
|
||||||
|
["CHFAED", "-0.99", "0.71", "0.51", "0.58", "0.57", "0.73", "0.60", "0.23", "0.02", "0.84", "0.90", "0.56", "0.03", "-0.93", "0.59", "0.24", "-0.67", "0.13", "0.99", "0.28", "0.72", "0.79", "-0.83", "-0.30", "0.73", "0.08", "-0.02", "0.85", "0.33", "0.57", "0.09", "0.26", "0.16", "0.80", "0.65", "-0.19", "-0.38", "-0.61", "-0.98", null, "0.57", "-0.81"],
|
||||||
|
["CHFJPY", "0.60", "0.96", "0.22", "0.52", "0.63", "0.24", "0.76", "0.91", "0.80", "-0.14", "0.59", "-0.01", "0.60", "-0.08", "0.63", "0.39", "0.30", "-0.71", "0.18", "0.94", "-0.30", "0.28", "0.87", "0.92", "-0.19", "0.18", "-0.40", "0.44", "0.88", "0.52", "0.50", "0.44", "0.84", "0.24", "0.09", "0.15", "0.10", "0.30", "-0.05", "0.79", null, "0.99"],
|
||||||
|
["CHFCAD", "0.93", "0.24", "0.05", "0.40", "0.75", "0.12", "0.90", "0.56", "0.46", "0.62", "0.71", "0.01", "0.04", "0.02", "0.49", "0.51", "-0.94", "0.93", "0.80", "-0.40", "0.79", "0.82", "-0.04", "0.38", "-0.24", "-0.17", "0.78", "-0.42", "0.92", "-0.83", "-0.01", "0.54", "0.73", "0.52", "0.95", "0.44", "0.90", "0.81", "0.42", "0.26", "0.36", null]
|
||||||
|
];
|
||||||
8
src-trader-dashboard/services/StoreService.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import {createStore} from "redux";
|
||||||
|
|
||||||
|
import fxData from "../reducers/fxDataReducer.jsx";
|
||||||
|
|
||||||
|
class StoreService {
|
||||||
|
}
|
||||||
|
StoreService.STORE = createStore(fxData);
|
||||||
|
export default StoreService;
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
entry: "./src-full-width/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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
entry: "./src-grouped/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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||