-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #21 from BadIdeaFactory/13-react-sentence-demo
Initial full stack demonstration
- Loading branch information
Showing
38 changed files
with
5,300 additions
and
1,649 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,9 @@ | ||
{ | ||
"presets": ["es2015", "stage-2"] | ||
"presets": [ | ||
"@babel/preset-env", | ||
"@babel/react" | ||
], | ||
"plugins": [ | ||
"@babel/plugin-proposal-class-properties" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -70,3 +70,9 @@ __pycache__/ | |
|
||
# don't store objects | ||
*.obj | ||
|
||
# I guess react made this? | ||
.cache | ||
|
||
# parcel dists to dist | ||
dist/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,33 +7,55 @@ | |
"author": "Dan Schultz <[email protected]>", | ||
"license": "Apache-2.0", | ||
"dependencies": { | ||
"apollo-boost": "^0.1.22", | ||
"apollo-client": "^2.4.7", | ||
"cors": "^2.8.5", | ||
"d3-array": "^2.0.3", | ||
"d3-scale": "^2.1.2", | ||
"d3-selection": "^1.3.2", | ||
"date-fns": "^1.29.0", | ||
"dotenv": "^6.0.0", | ||
"express": "^4.16.3", | ||
"express-graphql": "^0.6.12", | ||
"graphql": "^14.0.2", | ||
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0", | ||
"graphql-tag": "^2.10.0", | ||
"node-schedule": "^1.3.0", | ||
"opened-captions": "^1.0.3", | ||
"opened-captions": "^1.0.4", | ||
"parcel": "^1.10.3", | ||
"pg": "^7.4.3", | ||
"react": "^16.4.1", | ||
"react-dom": "^16.4.1", | ||
"prop-types": "^15.6.2", | ||
"query-string": "^6.2.0", | ||
"react": "^16.0.0", | ||
"react-apollo": "^2.3.1", | ||
"react-datepicker": "^2.0.0", | ||
"react-dom": "^16.0.0", | ||
"react-redux": "^5.1.0", | ||
"react-router-dom": "^4.3.1", | ||
"request": "^2.88.0", | ||
"request-promise": "^4.2.2", | ||
"sequelize": "^4.38.1", | ||
"wait-on": "^3.1.0" | ||
}, | ||
"scripts": { | ||
"parcel:dev": "./node_modules/.bin/parcel src/client/index.html", | ||
"parcel:watch": "./node_modules/.bin/parcel watch src/client/index.html", | ||
"parcel:build": "./node_modules/.bin/parcel build src/client/index.html", | ||
"start-nlp": "nodemon --watch nlp/app.py --exec 'source .venv/bin/activate && python3 nlp/app.py'", | ||
"start-node": "nodemon --watch src --exec yarn babel-node -- src/server/index.js", | ||
"start": "concurrently 'yarn start-nlp' 'yarn start-node'", | ||
"start": "concurrently 'yarn start-nlp' 'yarn start-node' 'yarn parcel:dev'", | ||
"build": "babel src -d lib", | ||
"lint": "./node_modules/.bin/eslint 'src/**'", | ||
"test": "" | ||
"lint": "./node_modules/.bin/eslint 'src/**/*.js'", | ||
"test": "", | ||
"migrate": "sequelize db:migrate" | ||
}, | ||
"devDependencies": { | ||
"babel-cli": "^6.26.0", | ||
"@babel/core": "7.1.2", | ||
"@babel/node": "7.0.0", | ||
"@babel/plugin-proposal-class-properties": "^7.1.0", | ||
"@babel/preset-env": "7.1.0", | ||
"@babel/preset-react": "^7.0.0", | ||
"babel-eslint": "^9.0.0", | ||
"babel-preset-es2015": "^6.24.1", | ||
"babel-preset-stage-2": "^6.24.1", | ||
"babel-plugin-transform-do-expressions": "^6.22.0", | ||
"concurrently": "^4.0.1", | ||
"eslint": "^5.6.0", | ||
"eslint-config-airbnb": "^17.1.0", | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import ApolloClient from 'apollo-boost' | ||
|
||
const client = new ApolloClient({ | ||
uri: 'http://localhost:3000/graphql', | ||
}) | ||
|
||
export default client |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// Imports | ||
import React from 'react' | ||
import { ApolloProvider } from 'react-apollo' | ||
import { Route, BrowserRouter as Router } from 'react-router-dom' | ||
|
||
// App Imports | ||
import Dashboard from './Dashboard' | ||
import EntityDetail from './EntityDetail' | ||
import Header from './Header' | ||
import client from '../ApolloClient' | ||
|
||
// Component | ||
class App extends React.Component { | ||
state = {} | ||
|
||
setStartTime = (startTime) => { | ||
this.setState({ startTime }) | ||
} | ||
|
||
setEndTime = (endTime) => { | ||
this.setState({ endTime }) | ||
} | ||
|
||
render() { | ||
const { startTime, endTime } = this.state | ||
return ( | ||
<> | ||
<div className="container"> | ||
<Router> | ||
<ApolloProvider client={client}> | ||
<Header | ||
startTime={startTime} | ||
setStartTime={this.setStartTime} | ||
endTime={endTime} | ||
setEndTime={this.setEndTime} | ||
/> | ||
<Route | ||
exact | ||
path="/" | ||
render={props => ( | ||
<Dashboard | ||
{...props} | ||
startTime={startTime} | ||
endTime={endTime} | ||
/> | ||
) | ||
} | ||
/> | ||
<Route | ||
path="/detail" | ||
render={props => ( | ||
<EntityDetail | ||
{...props} | ||
startTime={startTime} | ||
endTime={endTime} | ||
/> | ||
) | ||
} | ||
/> | ||
</ApolloProvider> | ||
</Router> | ||
</div> | ||
</> | ||
) | ||
} | ||
} | ||
|
||
export default App |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
import React from 'react' | ||
import PropTypes from 'prop-types' | ||
|
||
import { Query } from 'react-apollo' | ||
import gql from 'graphql-tag' | ||
|
||
import FrequencyChart from './FrequencyChart' | ||
import SentenceViewer from './SentenceViewer' | ||
|
||
const ALL_ENTITIES_QUERY = gql` | ||
query ALL_ENTITIES_QUERY( | ||
$after: String, | ||
$before: String) { | ||
namedEntities ( | ||
after: $after, | ||
before: $before | ||
) { | ||
entity | ||
type | ||
createdAt | ||
} | ||
} | ||
` | ||
|
||
const RECENT_SENTENCES_QUERY = gql` | ||
query RECENT_SENTENCES_QUERY($after: String!) { | ||
sentences ( | ||
after: $after | ||
) { | ||
content | ||
createdAt | ||
} | ||
} | ||
` | ||
|
||
class Dashboard extends React.Component { | ||
static propTypes = { | ||
startTime: PropTypes.number, | ||
endTime: PropTypes.number, | ||
} | ||
|
||
static defaultProps = { | ||
startTime: null, | ||
endTime: null, | ||
} | ||
|
||
render() { | ||
const { startTime, endTime } = this.props | ||
const currentDate = new Date() | ||
return ( | ||
<> | ||
<div className="row no-gutters"> | ||
<div className="col-sm-7 col-12"> | ||
<div id="dashboardEntityChart" className="elementContainer"> | ||
<h2>Keyword Counts</h2> | ||
<Query | ||
query={ALL_ENTITIES_QUERY} | ||
variables={{ | ||
after: startTime, | ||
before: endTime, | ||
}} | ||
> | ||
{({ data, error, loading }) => { | ||
if (loading) { | ||
return <p>Loading...</p> | ||
} | ||
if (error) { | ||
return ( | ||
<p> | ||
Error: | ||
{error.message} | ||
</p> | ||
) | ||
} | ||
|
||
const aggregatedData = data.namedEntities.reduce((accumulator, currentValue) => { | ||
if (!(currentValue.entity in accumulator)) { | ||
accumulator[currentValue.entity] = 0 | ||
} | ||
accumulator[currentValue.entity] += 1 | ||
return accumulator | ||
}, {}) | ||
|
||
const masterList = Object.keys(aggregatedData).map(key => ({ | ||
key, | ||
val: aggregatedData[key], | ||
})) | ||
|
||
const sortedList = masterList.sort((a, b) => a.val < b.val) | ||
|
||
const labels = sortedList.map(x => x.key) | ||
const values = sortedList.map(x => x.val) | ||
|
||
return ( | ||
<FrequencyChart | ||
data={values} | ||
labels={labels} | ||
/> | ||
) | ||
}} | ||
</Query> | ||
</div> | ||
</div> | ||
<div className="col-sm-5 col-12"> | ||
<div id="dashboardSentences" className="elementContainer"> | ||
<h2>Recent Transcript</h2> | ||
<Query | ||
query={RECENT_SENTENCES_QUERY} | ||
variables={{ after: currentDate.toISOString() }} | ||
> | ||
{({ data, error, loading }) => { | ||
if (loading) { | ||
return <p>Loading...</p> | ||
} | ||
if (error) { | ||
return ( | ||
<p> | ||
Error: | ||
{error.message} | ||
</p> | ||
) | ||
} | ||
return ( | ||
<SentenceViewer | ||
sentences={data.sentences} | ||
/> | ||
) | ||
}} | ||
</Query> | ||
</div> | ||
<div id="dashboardRecentEntities" className="elementContainer"> | ||
<h2>Recent Entities</h2> | ||
</div> | ||
</div> | ||
</div> | ||
</> | ||
) | ||
} | ||
} | ||
|
||
export default Dashboard |
Oops, something went wrong.