Skip to content

Commit

Permalink
Merge pull request #44 from BadIdeaFactory/30-31-layout-and-stubs
Browse files Browse the repository at this point in the history
Add basic layout and stub out components
  • Loading branch information
slifty authored Mar 7, 2019
2 parents 69cc1d1 + c532075 commit 3538b8c
Show file tree
Hide file tree
Showing 34 changed files with 2,311 additions and 1,703 deletions.
3 changes: 2 additions & 1 deletion .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"@babel/react"
],
"plugins": [
"@babel/plugin-proposal-class-properties"
"@babel/plugin-proposal-class-properties",
"babel-plugin-styled-components"
]
}
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"express-graphql": "^0.6.12",
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0",
"graphql-tag": "^2.10.0",
"moment": "^2.24.0",
"node-schedule": "^1.3.0",
"opened-captions": "^1.0.4",
"parcel": "^1.10.3",
Expand All @@ -34,6 +35,7 @@
"request": "^2.88.0",
"request-promise": "^4.2.2",
"sequelize": "^4.38.1",
"styled-components": "^4.1.3",
"wait-on": "^3.1.0"
},
"scripts": {
Expand All @@ -55,6 +57,7 @@
"@babel/preset-env": "7.1.0",
"@babel/preset-react": "^7.0.0",
"babel-eslint": "^9.0.0",
"babel-plugin-styled-components": "^1.10.0",
"babel-plugin-transform-do-expressions": "^6.22.0",
"concurrently": "^4.0.1",
"eslint": "^5.6.0",
Expand Down
25 changes: 4 additions & 21 deletions src/client/components/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,32 @@ 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 Dashboard from './Dashboard'
import client from '../ApolloClient'

// Component
class App extends React.Component {
state = {}

setStartTime = (startTime) => {
setIntervalScope = (startTime, endTime) => {
this.setState({ startTime })
}

setEndTime = (endTime) => {
this.setState({ endTime })
}

render() {
const { startTime, endTime } = this.state
return (
<>
<div className="container">
<div id="mainframe">
<Router>
<ApolloProvider client={client}>
<Header
setIntervalScope={this.setIntervalScope}
startTime={startTime}
setStartTime={this.setStartTime}
endTime={endTime}
setEndTime={this.setEndTime}
/>
<Route
exact
path="/"
render={props => (
<Dashboard
Expand All @@ -46,17 +40,6 @@ class App extends React.Component {
)
}
/>
<Route
path="/detail"
render={props => (
<EntityDetail
{...props}
startTime={startTime}
endTime={endTime}
/>
)
}
/>
</ApolloProvider>
</Router>
</div>
Expand Down
202 changes: 111 additions & 91 deletions src/client/components/Dashboard.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import React from 'react'
import PropTypes from 'prop-types'

import styled from 'styled-components'
import { Query } from 'react-apollo'
import gql from 'graphql-tag'
import moment from 'moment'

import FrequencyChart from './FrequencyChart'
import SentenceViewer from './SentenceViewer'
import LiveTranscript from './Transcripts/LiveTranscript'
import EntityFrequencyTable from './EntityFrequency/Table'
import graph from '../images/fake-graph.jpg'

const ALL_ENTITIES_QUERY = gql`
query ALL_ENTITIES_QUERY(
Expand Down Expand Up @@ -35,107 +38,124 @@ const RECENT_SENTENCES_QUERY = gql`

class Dashboard extends React.Component {
static propTypes = {
startTime: PropTypes.number,
endTime: PropTypes.number,
startTime: PropTypes.string,
endTime: PropTypes.string,
}

static defaultProps = {
startTime: null,
endTime: null,
startTime: moment().subtract(4, 'hours').toISOString(),
endTime: moment().toISOString(),
}

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>
<StyledEntityFrequencyTableWrapper>
<Query
query={ALL_ENTITIES_QUERY}
variables={{
after: startTime,
before: endTime,
}}
>
{({ data, error, loading }) => {
if (loading) {
return <p>Loading...</p>
}
if (error) {
return <p>{error.message}</p>
}

// TODO: Aggregate this via a query instead of th'frontend
const aggregatedData = data.namedEntities.reduce((accumulator, currentValue) => {
if (!(currentValue.entity in accumulator)) {
accumulator[currentValue.entity] = 0
}
accumulator[currentValue.entity] += 1
return accumulator
}, {})

const frequencyTotals = Object.keys(aggregatedData).map(key => ({
key,
total: aggregatedData[key],
}))

// TODO: Which column we sort by will be determined by state
frequencyTotals.sort((a, b) => b.total - a.total)

const labels = frequencyTotals.map(x => x.key)
const totals = frequencyTotals.map(x => x.total)

return (
<EntityFrequencyTable
data={totals}
labels={labels}
/>
)
}}
</Query>
</StyledEntityFrequencyTableWrapper>
<StyledEntityFrequencyGraphWrapper>
<img alt="Graph" src={graph} width="686" height="772" />
</StyledEntityFrequencyGraphWrapper>
<StyledTranscriptAreaWrapper>
<Query
query={RECENT_SENTENCES_QUERY}
variables={{ after: moment().subtract(5, 'minutes').toISOString() }}
>
{({ data, error, loading }) => {
if (loading) {
return <p>Loading...</p>
}
if (error) {
return <p>{error.message}</p>
}

return (
<>
<LiveTranscript
sentences={data.sentences}
/>
</>
)
}}
</Query>
</StyledTranscriptAreaWrapper>
</>
)
}
}

const StyledEntityFrequencyTableWrapper = styled.div`
grid-area: entity-list;
position: relative;
overflow: hidden;
padding: 1rem;
max-width: 300px;
border-bottom: 3px solid red;
`

const StyledEntityFrequencyGraphWrapper = styled.div`
grid-area: entity-graph;
position: relative;
overflow: hidden;
padding: 1rem;
border-bottom: 3px solid yellow;
img {
width: 100%;
height: auto;
max-height: 100%
}
`

const StyledTranscriptAreaWrapper = styled.div`
grid-area: transcripts;
position: relative;
overflow: hidden;
padding: 1rem;
max-width: 500px;
border-bottom: 3px solid green;
`

export default Dashboard
1 change: 1 addition & 0 deletions src/client/components/EntityFrequency/Graph.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// Will describe the line graph of entity frequency.
44 changes: 44 additions & 0 deletions src/client/components/EntityFrequency/Row.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react'
import PropTypes from 'prop-types'
import { withRouter } from 'react-router-dom'
import styled from 'styled-components'

const EntityFrequencyRow = (props) => {
const {
history, label, total, recent,
} = props

const selectEntity = () => {
history.push(`/detail?entity=${label}`)
}

return (
<StyledEntityFrequencyRow onClick={selectEntity}>
<td className="label">{label}</td>
<td className="total">{total}</td>
<td className="recent">{recent}</td>
</StyledEntityFrequencyRow>
)
}
EntityFrequencyRow.propTypes = {
label: PropTypes.string.isRequired,
total: PropTypes.number.isRequired,
recent: PropTypes.number.isRequired,
history: PropTypes.shape({
push: PropTypes.func,
}).isRequired,
}

const StyledEntityFrequencyRow = styled.tr`
&:hover > td {
cursor: pointer;
color: white;
background-color: #eb5757;
}
.recent {
background-color: #fefaee;
}
`

export default withRouter(EntityFrequencyRow)
Loading

0 comments on commit 3538b8c

Please sign in to comment.