Skip to content

Commit

Permalink
Merge pull request #21 from BadIdeaFactory/13-react-sentence-demo
Browse files Browse the repository at this point in the history
Initial full stack demonstration
  • Loading branch information
slifty authored Jan 24, 2019
2 parents 6b2891f + 75e2f3c commit 769035f
Show file tree
Hide file tree
Showing 38 changed files with 5,300 additions and 1,649 deletions.
8 changes: 7 additions & 1 deletion .babelrc
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"
]
}
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"extends": "airbnb",
"parser": "babel-eslint",
"rules": {
"semi": [2, "never"]
"semi": [2, "never"],
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }]
},
"env": {
"es6": true,
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,9 @@ __pycache__/

# don't store objects
*.obj

# I guess react made this?
.cache

# parcel dists to dist
dist/
42 changes: 32 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
7 changes: 7 additions & 0 deletions src/client/ApolloClient.js
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
68 changes: 68 additions & 0 deletions src/client/components/App.js
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
141 changes: 141 additions & 0 deletions src/client/components/Dashboard.js
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
Loading

0 comments on commit 769035f

Please sign in to comment.