diff --git a/frontend/src/Metamaps/GlobalUI/ImportDialog.js b/frontend/src/Metamaps/GlobalUI/ImportDialog.js
index c253512d..391a9213 100644
--- a/frontend/src/Metamaps/GlobalUI/ImportDialog.js
+++ b/frontend/src/Metamaps/GlobalUI/ImportDialog.js
@@ -4,7 +4,7 @@ import React from 'react'
import ReactDOM from 'react-dom'
import outdent from 'outdent'
-import ImportDialogBox from '../../routes/MapView/ImportDialogBox'
+import ImportDialogBox from '../../components/ImportDialogBox'
import PasteInput from '../PasteInput'
import Map from '../Map'
diff --git a/frontend/src/Metamaps/GlobalUI/ReactApp.js b/frontend/src/Metamaps/GlobalUI/ReactApp.js
index 6237f08a..62b5c441 100644
--- a/frontend/src/Metamaps/GlobalUI/ReactApp.js
+++ b/frontend/src/Metamaps/GlobalUI/ReactApp.js
@@ -2,10 +2,13 @@
import React from 'react'
import ReactDOM from 'react-dom'
+import { createStore } from 'redux'
+import { Provider } from 'react-redux'
import { Router, browserHistory } from 'react-router'
import { merge } from 'lodash'
import apply from 'async/apply'
+import reducers from '../../reducers'
import { notifyUser } from './index.js'
import ImportDialog from './ImportDialog'
import Notifications from './Notifications'
@@ -21,6 +24,11 @@ import Visualize from '../Visualize'
import makeRoutes from '../../routes/makeRoutes'
let routes
+let store = createStore(
+ reducers,
+ window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
+)
+
// 220 wide + 16 padding on both sides
const MAP_WIDTH = 252
const MOBILE_VIEW_BREAKPOINT = 504
@@ -92,12 +100,15 @@ const ReactApp = {
render: function() {
const self = ReactApp
const createElement = (Component, props) =>
- const app =
+ const app =
+
+
ReactDOM.render(app, document.getElementById('react-app'))
},
getProps: function() {
const self = ReactApp
return merge({
+ DataModel: DataModel,
unreadNotificationsCount: Notifications.unreadNotificationsCount,
currentUser: Active.Mapper,
toast: self.toast,
diff --git a/frontend/src/Metamaps/JIT.js b/frontend/src/Metamaps/JIT.js
index 1c50256c..02162d15 100644
--- a/frontend/src/Metamaps/JIT.js
+++ b/frontend/src/Metamaps/JIT.js
@@ -38,7 +38,6 @@ const JIT = {
zoom: 'Metamaps:JIT:events:zoom',
animationDone: 'Metamaps:JIT:events:animationDone'
},
- vizData: [], // contains the visualization-compatible graph
/**
* This method will bind the event handlers it is interested and initialize the class.
*/
@@ -55,8 +54,6 @@ const JIT = {
*/
convertModelsToJIT: function(topics, synapses) {
const jitReady = []
-
- const synapsesToRemove = []
let mapping
let node
const nodes = {}
@@ -70,11 +67,7 @@ const JIT = {
})
synapses.each(function(s) {
edge = s.createEdge()
-
- if (topics.get(s.get('topic1_id')) === undefined || topics.get(s.get('topic2_id')) === undefined) {
- // this means it's an invalid synapse
- synapsesToRemove.push(s)
- } else if (nodes[edge.nodeFrom] && nodes[edge.nodeTo]) {
+ if (nodes[edge.nodeFrom] && nodes[edge.nodeTo]) {
existingEdge = _.find(edges, {
nodeFrom: edge.nodeFrom,
nodeTo: edge.nodeTo
@@ -103,29 +96,8 @@ const JIT = {
jitReady.push(node)
})
- return [jitReady, synapsesToRemove]
+ return jitReady
},
- prepareVizData: function() {
- const self = JIT
- let mapping
- self.vizData = []
- Visualize.loadLater = false
- const results = self.convertModelsToJIT(DataModel.Topics, DataModel.Synapses)
- self.vizData = results[0]
- // clean up the synapses array in case of any faulty data
- _.each(results[1], function(synapse) {
- mapping = synapse.getMapping()
- DataModel.Synapses.remove(synapse)
- if (DataModel.Mappings) DataModel.Mappings.remove(mapping)
- })
- if (self.vizData.length === 0) {
- Map.setHasLearnedTopicCreation(false)
- Visualize.loadLater = true
- } else {
- Map.setHasLearnedTopicCreation(true)
- }
- Visualize.render()
- }, // prepareVizData
edgeRender: function(adj, canvas) {
// get nodes cartesian coordinates
const pos = adj.nodeFrom.pos.getc(true)
diff --git a/frontend/src/Metamaps/Map/index.js b/frontend/src/Metamaps/Map/index.js
index f337d1d0..52271250 100644
--- a/frontend/src/Metamaps/Map/index.js
+++ b/frontend/src/Metamaps/Map/index.js
@@ -1,7 +1,7 @@
/* global $ */
import outdent from 'outdent'
-import { find as _find } from 'lodash'
+import _, { find as _find } from 'lodash'
import { browserHistory } from 'react-router'
import Active from '../Active'
@@ -89,12 +89,31 @@ const Map = {
}
ReactApp.render()
},
+ cleanUpSynapses: function () {
+ const synapsesToRemove = []
+ const topics = DataModel.Topics
+ DataModel.Synapses.each(function(s) {
+ if (topics.get(s.get('topic1_id')) === undefined || topics.get(s.get('topic2_id')) === undefined) {
+ // this means it's an invalid synapse
+ synapsesToRemove.push(s)
+ }
+ })
+ // clean up the synapses array in case of any faulty data
+ _.each(synapsesToRemove, function(synapse) {
+ mapping = synapse.getMapping()
+ DataModel.Synapses.remove(synapse)
+ if (DataModel.Mappings) DataModel.Mappings.remove(mapping)
+ })
+ },
launch: function(id) {
const self = Map
var dataIsReadySetupMap = function() {
+ if (DataModel.Topics.length === 0) {
+ Map.setHasLearnedTopicCreation(false)
+ } else {
+ Map.setHasLearnedTopicCreation(true)
+ }
Map.setAccessRequest()
- Visualize.type = 'ForceDirected'
- JIT.prepareVizData()
Selected.reset()
InfoBox.load()
Filter.reset()
@@ -127,6 +146,7 @@ const Map = {
DataModel.Mappings = new DataModel.MappingCollection(data.mappings)
DataModel.Messages = data.messages
DataModel.Stars = data.stars
+ Map.cleanUpSynapses()
DataModel.attachCollectionEvents()
self.requests = data.requests
isLoaded()
diff --git a/frontend/src/Metamaps/Visualize.js b/frontend/src/Metamaps/Visualize.js
index d8d10aa9..bc93c2ec 100644
--- a/frontend/src/Metamaps/Visualize.js
+++ b/frontend/src/Metamaps/Visualize.js
@@ -11,13 +11,12 @@ import Loading from './Loading'
import TopicCard from './Views/TopicCard'
const Visualize = {
- mGraph: null, // a reference to the graph object.
- type: 'ForceDirected', // the type of graph we're building, could be "RGraph", "ForceDirected"
- loadLater: false, // indicates whether there is JSON that should be loaded right in the offset, or whether to wait till the first topic is created
init: function(serverData) {
var self = Visualize
- if (serverData.VisualizeType) self.type = serverData.VisualizeType
+ $jit.RGraph.Plot.NodeTypes.implement(JIT.ForceDirected.nodeSettings)
+ $jit.RGraph.Plot.EdgeTypes.implement(JIT.ForceDirected.edgeSettings)
+
// disable awkward dragging of the canvas element that would sometimes happen
$('#infovis-canvas').on('dragstart', function(event) {
@@ -39,58 +38,32 @@ const Visualize = {
computePositions: function() {
const self = Visualize
- if (self.type === 'RGraph') {
- let i
- let l
+ // for RGraph
+ let i
+ let l
- self.mGraph.graph.eachNode(function(n) {
- const topic = DataModel.Topics.get(n.id)
- topic.set({ node: n }, { silent: true })
- topic.updateNode()
+ self.mGraph.graph.eachNode(function(n) {
+ const topic = DataModel.Topics.get(n.id)
+ topic.set({ node: n }, { silent: true })
+ topic.updateNode()
- n.eachAdjacency(function(edge) {
- if (!edge.getData('init')) {
- edge.setData('init', true)
+ n.eachAdjacency(function(edge) {
+ if (!edge.getData('init')) {
+ edge.setData('init', true)
- l = edge.getData('synapseIDs').length
- for (i = 0; i < l; i++) {
- const synapse = DataModel.Synapses.get(edge.getData('synapseIDs')[i])
- synapse.set({ edge: edge }, { silent: true })
- synapse.updateEdge()
- }
+ l = edge.getData('synapseIDs').length
+ for (i = 0; i < l; i++) {
+ const synapse = DataModel.Synapses.get(edge.getData('synapseIDs')[i])
+ synapse.set({ edge: edge }, { silent: true })
+ synapse.updateEdge()
}
- })
-
- var pos = n.getPos()
- pos.setc(-200, -200)
+ }
})
- self.mGraph.compute('end')
- } else if (self.type === 'ForceDirected') {
- self.mGraph.graph.eachNode(function(n) {
- const topic = DataModel.Topics.get(n.id)
- topic.set({ node: n }, { silent: true })
- topic.updateNode()
- const mapping = topic.getMapping()
- n.eachAdjacency(function(edge) {
- if (!edge.getData('init')) {
- edge.setData('init', true)
-
- const l = edge.getData('synapseIDs').length
- for (let i = 0; i < l; i++) {
- const synapse = DataModel.Synapses.get(edge.getData('synapseIDs')[i])
- synapse.set({ edge: edge }, { silent: true })
- synapse.updateEdge()
- }
- }
- })
-
- const startPos = new $jit.Complex(0, 0)
- const endPos = new $jit.Complex(mapping.get('xloc'), mapping.get('yloc'))
- n.setPos(startPos, 'start')
- n.setPos(endPos, 'end')
- })
- }
+ var pos = n.getPos()
+ pos.setc(-200, -200)
+ })
+ self.mGraph.compute('end')
},
/**
* render does the heavy lifting of creating the engine that renders the graph with the properties we desire
@@ -98,92 +71,12 @@ const Visualize = {
*/
render: function() {
const self = Visualize
-
- if (self.type === 'RGraph') {
- // clear the previous canvas from #infovis
- $('#infovis').empty()
-
- const RGraphSettings = $.extend(true, {}, JIT.ForceDirected.graphSettings)
-
- $jit.RGraph.Plot.NodeTypes.implement(JIT.ForceDirected.nodeSettings)
- $jit.RGraph.Plot.EdgeTypes.implement(JIT.ForceDirected.edgeSettings)
-
- RGraphSettings.width = $(document).width()
- RGraphSettings.height = $(document).height()
- RGraphSettings.background = JIT.RGraph.background
- RGraphSettings.levelDistance = JIT.RGraph.levelDistance
-
- self.mGraph = new $jit.RGraph(RGraphSettings)
- } else if (self.type === 'ForceDirected') {
- // clear the previous canvas from #infovis
- $('#infovis').empty()
-
- const FDSettings = $.extend(true, {}, JIT.ForceDirected.graphSettings)
-
- $jit.ForceDirected.Plot.NodeTypes.implement(JIT.ForceDirected.nodeSettings)
- $jit.ForceDirected.Plot.EdgeTypes.implement(JIT.ForceDirected.edgeSettings)
-
- FDSettings.width = $('body').width()
- FDSettings.height = $('body').height()
-
- self.mGraph = new $jit.ForceDirected(FDSettings)
- } else {
- self.mGraph.graph.empty()
- }
-
- function runAnimation() {
- Loading.hide()
- // load JSON data, if it's not empty
- if (!self.loadLater) {
- // load JSON data.
- var rootIndex = 0
- if (Active.Topic) {
- var node = _.find(JIT.vizData, function(node) {
- return node.id === Active.Topic.id
- })
- rootIndex = _.indexOf(JIT.vizData, node)
- }
- self.mGraph.loadJSON(JIT.vizData, rootIndex)
- // compute positions and plot.
- self.computePositions()
- self.mGraph.busy = true
- if (self.type === 'RGraph') {
- self.mGraph.fx.animate(JIT.RGraph.animate)
- } else if (self.type === 'ForceDirected') {
- self.mGraph.animate(JIT.ForceDirected.animateSavedLayout)
- }
- }
- }
- // hold until all the needed metacode images are loaded
- // hold for a maximum of 80 passes, or 4 seconds of waiting time
- var tries = 0
- function hold() {
- const unique = _.uniq(DataModel.Topics.models, function(metacode) { return metacode.get('metacode_id') })
- const requiredMetacodes = _.map(unique, function(metacode) { return metacode.get('metacode_id') })
- let loadedCount = 0
-
- _.each(requiredMetacodes, function(metacodeId) {
- const metacode = DataModel.Metacodes.get(metacodeId)
- const img = metacode ? metacode.get('image') : false
-
- if (img && (img.complete || (typeof img.naturalWidth !== 'undefined' && img.naturalWidth !== 0))) {
- loadedCount += 1
- }
- })
-
- if (loadedCount === requiredMetacodes.length || tries > 80) {
- runAnimation()
- } else {
- setTimeout(function() { tries++; hold() }, 50)
- }
- }
- hold()
- },
- clearVisualization: function() {
- Visualize.mGraph.graph.empty()
- Visualize.mGraph.plot()
- JIT.centerMap(Visualize.mGraph.canvas)
- $('#infovis').empty()
+ const RGraphSettings = $.extend(true, {}, JIT.ForceDirected.graphSettings)
+ RGraphSettings.width = $(document).width()
+ RGraphSettings.height = $(document).height()
+ RGraphSettings.background = JIT.RGraph.background
+ RGraphSettings.levelDistance = JIT.RGraph.levelDistance
+ self.mGraph = new $jit.RGraph(RGraphSettings)
}
}
diff --git a/frontend/src/actions/constants.js b/frontend/src/actions/constants.js
new file mode 100644
index 00000000..2a2978cc
--- /dev/null
+++ b/frontend/src/actions/constants.js
@@ -0,0 +1,96 @@
+export const OPEN_CHAT = 'OPEN_CHAT'
+export const CLOSE_CHAT = 'CLOSE_CHAT'
+export const CREATE_MESSAGE = 'CREATE_MESSAGE'
+
+export const OPEN_NOTIFICATIONS = 'OPEN_NOTIFICATIONS'
+export const CLOSE_NOTIFICATIONS = 'CLOSE_NOTIFICATIONS'
+export const MARK_NOTIFICATION_READ = 'MARK_NOTIFICATION_READ'
+export const MARK_NOTIFICATION_UNREAD = 'MARK_NOTIFICATION_UNREAD'
+
+export const OPEN_ACCOUNT_MENU = 'OPEN_ACCOUNT_MENU'
+export const CLOSE_ACCOUNT_MENU = 'CLOSE_ACCOUNT_MENU'
+export const STAR_MAP = 'STAR_MAP'
+export const UNSTAR_MAP = 'UNSTAR_MAP'
+export const FOLLOW_MAP = 'FOLLOW_MAP'
+export const UNFOLLOW_MAP = 'UNFOLLOW_MAP'
+export const FOLLOW_TOPIC = 'FOLLOW_TOPIC'
+export const UNFOLLOW_TOPIC = 'UNFOLLOW_TOPIC'
+
+export const PIN_CREATE_TOPIC = 'PIN_CREATE_TOPIC_OPEN'
+export const UNPIN_CREATE_TOPIC = 'UNPIN_CREATE_TOPIC'
+export const OPEN_CREATE_TOPIC = 'OPEN_CREATE_TOPIC'
+export const CLOSE_CREATE_TOPIC = 'CLOSE_CREATE_TOPIC'
+export const CREATE_TOPIC = 'CREATE_TOPIC'
+export const UPDATE_TOPIC = 'UPDATE_TOPIC'
+
+export const OPEN_CREATE_SYNAPSE = 'OPEN_CREATE_SYNAPSE'
+export const CLOSE_CREATE_SYNAPSE = 'CLOSE_CREATE_SYNAPSE'
+export const CREATE_SYNAPSE = 'CREATE_SYNAPSE'
+export const UPDATE_SYNAPSE = 'UPDATE_SYNAPSE'
+
+export const UPDATE_METACODE_SET = 'UPDATE_METACODE_SET'
+export const MAKE_SELECTION = 'MAKE_SELECTION'
+export const HIDE_SELECTED = 'HIDE_SELECTED'
+export const REMOVE_SELECTED = 'REMOVE_SELECTED'
+export const DELETE_SELECTED = 'DELETE_SELECTED'
+export const CHANGE_PERMISSION_SELECTED = 'CHANGE_PERMISSION_SELECTED'
+export const CHANGE_METACODE_SELECTED = 'CHANGE_METACODE_SELECTED'
+
+export const OPEN_TOPIC_CARD = 'OPEN_TOPIC_CARD'
+export const CLOSE_TOPIC_CARD = 'CLOSE_TOPIC_CARD'
+
+export const OPEN_SYNAPSE_CARD = 'OPEN_SYNAPSE_CARD'
+export const CLOSE_SYNAPSE_CARD = 'CLOSE_SYNAPSE_CARD'
+
+export const OPEN_METACODE_SET_SELECT = 'OPEN_METACODE_SET_SELECT'
+export const CLOSE_METACODE_SET_SELECT = 'CLOSE_METACODE_SET_SELECT'
+export const SELECT_METACODE_SET = 'SELECT_METACODE_SET'
+
+export const OPEN_MAP_INFO_BOX = 'OPEN_MAP_INFO_BOX'
+export const CLOSE_MAP_INFO_BOX = 'CLOSE_MAP_INFO_BOX'
+export const UPDATE_MAP = 'UPDATE_MAP'
+
+export const OPEN_HELP = 'OPEN_HELP'
+export const CLOSE_HELP = 'CLOSE_HELP'
+
+export const MAP_CENTER_VIEW = 'MAP_CENTER_VIEW'
+export const MAP_ZOOM_IN = 'MAP_ZOOM_IN'
+export const MAP_ZOOM_OUT = 'MAP_ZOOM_OUT'
+
+export const MAP_DISABLE_SOUND = 'MAP_DISABLE_SOUND'
+export const MAP_ENABLE_SOUND = 'MAP_ENABLE_SOUND'
+
+export const MAP_DISABLE_CURSOR = 'MAP_DISABLE_CURSOR'
+export const MAP_ENABLE_CURSOR = 'MAP_ENABLE_CURSOR'
+
+export const MAP_HIDE_VIDEOS = 'MAP_HIDE_VIDEOS'
+export const MAP_UNHIDE_VIDEOS = 'MAP_UNHIDE_VIDEOS'
+
+export const OPEN_IMPORT_DIALOGUE = 'OPEN_IMPORT_DIALOGUE'
+export const CLOSE_IMPORT_DIALOGUE = 'CLOSE_IMPORT_DIALOGUE'
+
+export const OPEN_FILTERS = 'OPEN_FILTERS'
+export const CLOSE_FILTERS = 'CLOSE_FILTERS'
+
+export const FILTER_ALL_PEOPLE = 'FILTER_ALL_PEOPLE'
+export const FILTER_NO_PEOPLE = 'FILTER_NO_PEOPLE'
+export const FILTER_HIDE_PERSON = 'FILTER_HIDE_PERSON'
+export const FILTER_SHOW_PERSON = 'FILTER_SHOW_PERSON'
+
+export const FILTER_ALL_METACODES = 'FILTER_ALL_METACODES'
+export const FILTER_NO_METACODES = 'FILTER_NO_METACODES'
+export const FILTER_HIDE_METACODE = 'FILTER_HIDE_METACODE'
+export const FILTER_SHOW_METACODE = 'FILTER_SHOW_METACODE'
+
+export const FILTER_ALL_SYNAPSES = 'FILTER_ALL_SYNAPSES'
+export const FILTER_NO_SYNAPSES = 'FILTER_NO_SYNAPSES'
+export const FILTER_HIDE_SYNAPSE = 'FILTER_HIDE_SYNAPSE'
+export const FILTER_SHOW_SYNAPSE = 'FILTER_SHOW_SYNAPSE'
+
+export const OPEN_FORK_MAP = 'OPEN_FORK_MAP'
+export const CLOSE_FORK_MAP = 'CLOSE_FORK_MAP'
+
+export const RIGHT_CLICK_ON_NODE = 'RIGHT_CLICK_ON_NODE'
+export const RIGHT_CLICK_ON_EDGE = 'RIGHT_CLICK_ON_EDGE'
+
+export const MAP_REQUEST_ACCESS = 'MAP_REQUEST_ACCESS'
diff --git a/frontend/src/actions/index.js b/frontend/src/actions/index.js
new file mode 100644
index 00000000..f834b0f3
--- /dev/null
+++ b/frontend/src/actions/index.js
@@ -0,0 +1,13 @@
+import * as c from './constants'
+
+export const openChat = () => {
+ return {
+ type: c.OPEN_CHAT
+ }
+}
+
+export const closeChat = () => {
+ return {
+ type: c.CLOSE_CHAT
+ }
+}
diff --git a/frontend/src/components/DataVis.js b/frontend/src/components/DataVis.js
deleted file mode 100644
index f39bdd7f..00000000
--- a/frontend/src/components/DataVis.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import React, { Component } from 'react'
-import PropTypes from 'prop-types'
-
-class DataVis extends Component {
- static propTypes = {
- }
-
- render () {
- return
- }
-}
-
-export default DataVis
diff --git a/frontend/src/routes/MapView/ImportDialogBox.js b/frontend/src/components/ImportDialogBox.js
similarity index 100%
rename from frontend/src/routes/MapView/ImportDialogBox.js
rename to frontend/src/components/ImportDialogBox.js
diff --git a/frontend/src/components/InfoAndHelp.js b/frontend/src/components/InfoAndHelp.js
index e6bc01d8..d7202dcb 100644
--- a/frontend/src/components/InfoAndHelp.js
+++ b/frontend/src/components/InfoAndHelp.js
@@ -1,7 +1,7 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
-import MapInfoBox from '../routes/MapView/MapInfoBox'
+import MapInfoBox from './MapInfoBox'
class InfoAndHelp extends Component {
static propTypes = {
diff --git a/frontend/src/routes/MapView/Instructions.js b/frontend/src/components/Instructions.js
similarity index 100%
rename from frontend/src/routes/MapView/Instructions.js
rename to frontend/src/components/Instructions.js
diff --git a/frontend/src/routes/MapView/MapChat/Message.js b/frontend/src/components/MapChat/Message.js
similarity index 96%
rename from frontend/src/routes/MapView/MapChat/Message.js
rename to frontend/src/components/MapChat/Message.js
index e4caf3ce..7cfe9ff2 100644
--- a/frontend/src/routes/MapView/MapChat/Message.js
+++ b/frontend/src/components/MapChat/Message.js
@@ -1,6 +1,6 @@
import React from 'react'
import Autolinker from 'autolinker'
-import Util from '../../../Metamaps/Util'
+import Util from '../../Metamaps/Util'
const linker = new Autolinker({ newWindow: true, truncate: 50, email: false, phone: false })
diff --git a/frontend/src/routes/MapView/MapChat/NewMessage.js b/frontend/src/components/MapChat/NewMessage.js
similarity index 100%
rename from frontend/src/routes/MapView/MapChat/NewMessage.js
rename to frontend/src/components/MapChat/NewMessage.js
diff --git a/frontend/src/routes/MapView/MapChat/Participant.js b/frontend/src/components/MapChat/Participant.js
similarity index 100%
rename from frontend/src/routes/MapView/MapChat/Participant.js
rename to frontend/src/components/MapChat/Participant.js
diff --git a/frontend/src/routes/MapView/MapChat/Unread.js b/frontend/src/components/MapChat/Unread.js
similarity index 100%
rename from frontend/src/routes/MapView/MapChat/Unread.js
rename to frontend/src/components/MapChat/Unread.js
diff --git a/frontend/src/routes/MapView/MapChat/index.js b/frontend/src/components/MapChat/index.js
similarity index 99%
rename from frontend/src/routes/MapView/MapChat/index.js
rename to frontend/src/components/MapChat/index.js
index 1334d479..408f5d25 100644
--- a/frontend/src/routes/MapView/MapChat/index.js
+++ b/frontend/src/components/MapChat/index.js
@@ -4,7 +4,7 @@ import Unread from './Unread'
import Participant from './Participant'
import Message from './Message'
import NewMessage from './NewMessage'
-import Util from '../../../Metamaps/Util'
+import Util from '../../Metamaps/Util'
function makeList(messages) {
let currentHeader
diff --git a/frontend/src/routes/MapView/MapInfoBox.js b/frontend/src/components/MapInfoBox.js
similarity index 100%
rename from frontend/src/routes/MapView/MapInfoBox.js
rename to frontend/src/components/MapInfoBox.js
diff --git a/frontend/src/components/MapVis.js b/frontend/src/components/MapVis.js
new file mode 100644
index 00000000..1bb8d2e8
--- /dev/null
+++ b/frontend/src/components/MapVis.js
@@ -0,0 +1,154 @@
+/* global $ */
+
+import _ from 'lodash'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import $jit from '../patched/JIT'
+import JIT from '../Metamaps/JIT'
+
+// There would be separate one of these for mapview and topicview
+
+/*
+it could use the diffing intelligently to know when you
+update the visualization
+
+// JIT MORPH to move between states?
+
+use componentDidUpdate to check for differences in
+- topic list, synapse list, mapping list, etc
+- use that info to intelligently update and animate the viz.
+
+basically port everything from VISUALIZE module over into here
+
+it should dynamically generate and pass in callbacks to the visualization
+*/
+
+class MapVis extends Component {
+ static propTypes = {
+ DataModel: PropTypes.object,
+ filters: PropTypes.array,
+ selectedNodes: PropTypes.array,
+ selectedEdges: PropTypes.array,
+ onSelect: PropTypes.func,
+ onPan: PropTypes.func,
+ onZoom: PropTypes.func,
+ onDrawSelectBox: PropTypes.func
+ }
+
+ constructor(props) {
+ super(props)
+ this.jitGraph = null
+ this.vizData = null
+ this.state = {
+ loading: true
+ }
+ }
+
+ componentDidMount() {
+ $jit.ForceDirected.Plot.NodeTypes.implement(JIT.ForceDirected.nodeSettings)
+ $jit.ForceDirected.Plot.EdgeTypes.implement(JIT.ForceDirected.edgeSettings)
+ }
+
+ componentDidUpdate(prevProps) {
+ const { map, DataModel } = this.props
+ const prevMap = prevProps.map
+ const prevDataModel = prevProps.DataModel
+ if (DataModel) {
+ if (map !== prevMap) {
+ this.initialize()
+ }
+ }
+ }
+
+ initialize() {
+ const { DataModel } = this.props
+ this.createJitGraph()
+ this.vizData = JIT.convertModelsToJIT(DataModel.Topics, DataModel.Synapses)
+ this.waitForMetacodesThenLoad()
+ }
+
+ divMounted(div) {
+ console.log(div)
+ }
+
+ createJitGraph() {
+ const FDSettings = $.extend(true, {}, JIT.ForceDirected.graphSettings)
+ FDSettings.width = $('body').width()
+ FDSettings.height = $('body').height()
+ this.jitGraph = new $jit.ForceDirected(FDSettings)
+ }
+
+ waitForMetacodesThenLoad() {
+ const { DataModel } = this.props
+ // hold until all the needed metacode images are loaded
+ // hold for a maximum of 80 passes, or 4 seconds of waiting time
+ var tries = 0
+ const hold = () => {
+ const unique = _.uniq(DataModel.Topics.models, function(metacode) { return metacode.get('metacode_id') })
+ const requiredMetacodes = _.map(unique, function(metacode) { return metacode.get('metacode_id') })
+ let loadedCount = 0
+
+ _.each(requiredMetacodes, function(metacodeId) {
+ const metacode = DataModel.Metacodes.get(metacodeId)
+ const img = metacode ? metacode.get('image') : false
+
+ if (img && (img.complete || (typeof img.naturalWidth !== 'undefined' && img.naturalWidth !== 0))) {
+ loadedCount += 1
+ }
+ })
+
+ if (loadedCount === requiredMetacodes.length || tries > 80) {
+ this.runAnimation()
+ } else {
+ setTimeout(function() { tries++; hold() }, 50)
+ }
+ }
+ hold()
+ }
+
+ computePositions() {
+ const { DataModel } = this.props
+ this.jitGraph.graph.eachNode(function(n) {
+ const topic = DataModel.Topics.get(n.id)
+ topic.set({ node: n }, { silent: true })
+ topic.updateNode()
+ const mapping = topic.getMapping()
+ n.eachAdjacency(function(edge) {
+ if (!edge.getData('init')) {
+ edge.setData('init', true)
+ const l = edge.getData('synapseIDs').length
+ for (let i = 0; i < l; i++) {
+ const synapse = DataModel.Synapses.get(edge.getData('synapseIDs')[i])
+ synapse.set({ edge: edge }, { silent: true })
+ synapse.updateEdge()
+ }
+ }
+ })
+ const startPos = new $jit.Complex(0, 0)
+ const endPos = new $jit.Complex(mapping.get('xloc'), mapping.get('yloc'))
+ n.setPos(startPos, 'start')
+ n.setPos(endPos, 'end')
+ })
+ }
+
+ runAnimation() {
+ // load JSON data, if it's not empty
+ if (this.vizData) {
+ // load JSON data.
+ var rootIndex = 0
+ // 0 is rootIndex
+ this.jitGraph.loadJSON(this.vizData, 0)
+ // compute positions and plot.
+ this.computePositions()
+ this.jitGraph.animate(JIT.ForceDirected.animateSavedLayout)
+ }
+ }
+
+ render() {
+ const { loading } = this.state
+ // display loading while loading
+ return
+ }
+}
+
+export default MapVis
diff --git a/frontend/src/components/TopicVis.js b/frontend/src/components/TopicVis.js
new file mode 100644
index 00000000..f753b5a5
--- /dev/null
+++ b/frontend/src/components/TopicVis.js
@@ -0,0 +1,49 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+
+// There would be separate one of these for mapview and topicview
+
+/*
+it could use the diffing intelligently to know when you
+update the visualization
+
+use componentDidUpdate to check for differences in
+- topic list, synapse list, mapping list, etc
+- use that info to intelligently update and animate the viz.
+
+basically port everything from VISUALIZE module over into here
+
+it should dynamically generate and pass in callbacks to the visualization
+*/
+
+class MapVis extends Component {
+ static propTypes = {
+ topics: PropTypes.array,
+ synapses: PropTypes.array,
+ mappings: PropTypes.array,
+ filters: PropTypes.array,
+ selectedNodes: PropTypes.array,
+ selectedEdges: PropTypes.array,
+ onSelect: PropTypes.func,
+ onPan: PropTypes.func,
+ onZoom: PropTypes.func,
+ onDrawSelectBox: PropTypes.func
+ }
+
+ constructor(props) {
+ super(props)
+ this.state = {
+ mGraph: null
+ }
+ }
+
+ componentDidMount() {
+
+ }
+
+ render () {
+ return
+ }
+}
+
+export default MapVis
diff --git a/frontend/src/containers/ContextMenu.js b/frontend/src/containers/ContextMenu.js
new file mode 100644
index 00000000..9b60189d
--- /dev/null
+++ b/frontend/src/containers/ContextMenu.js
@@ -0,0 +1,5 @@
+import { connect } from 'react-redux'
+import { mapStateToProps, mapDispatchToProps } from './UpperOptions.store'
+import UpperOptions from '../components/UpperOptions'
+
+export default connect(mapStateToProps, mapDispatchToProps)(UpperOptions)
diff --git a/frontend/src/containers/ContextMenu.store.js b/frontend/src/containers/ContextMenu.store.js
new file mode 100644
index 00000000..0f89d1e6
--- /dev/null
+++ b/frontend/src/containers/ContextMenu.store.js
@@ -0,0 +1,24 @@
+// import { } from '../actions'
+
+export const mapStateToProps = (state, ownProps) => {
+ return {
+ map: ownProps.map,
+ currentUser: ownProps.currentUser,
+ openImportLightbox: ownProps.openImportLightbox,
+ forkMap: ownProps.forkMap,
+ canEditMap: ownProps.canEditMap,
+ filterData: ownProps.filterData,
+ allForFiltering: ownProps.allForFiltering,
+ visibleForFiltering: ownProps.visibleForFiltering,
+ toggleMetacode: ownProps.toggleMetacode,
+ toggleMapper: ownProps.toggleMapper,
+ toggleSynapse: ownProps.toggleSynapse,
+ filterAllMetacodes: ownProps.filterAllMetacodes,
+ filterAllMappers: ownProps.filterAllMappers,
+ filterAllSynapses: ownProps.filterAllSynapses
+ }
+}
+
+export const mapDispatchToProps = (dispatch, ownProps) => {
+ return {}
+}
diff --git a/frontend/src/containers/InfoAndHelp.js b/frontend/src/containers/InfoAndHelp.js
new file mode 100644
index 00000000..79dd9401
--- /dev/null
+++ b/frontend/src/containers/InfoAndHelp.js
@@ -0,0 +1,5 @@
+import { connect } from 'react-redux'
+import { mapStateToProps, mapDispatchToProps } from './InfoAndHelp.store'
+import InfoAndHelp from '../components/InfoAndHelp'
+
+export default connect(mapStateToProps, mapDispatchToProps)(InfoAndHelp)
diff --git a/frontend/src/containers/InfoAndHelp.store.js b/frontend/src/containers/InfoAndHelp.store.js
new file mode 100644
index 00000000..f317fe9d
--- /dev/null
+++ b/frontend/src/containers/InfoAndHelp.store.js
@@ -0,0 +1,18 @@
+// import { } from '../actions'
+
+export const mapStateToProps = (state, ownProps) => {
+ return {
+ mapIsStarred: ownProps.mapIsStarred,
+ currentUser: ownProps.currentUser,
+ map: ownProps.map,
+ onInfoClick: ownProps.toggleMapInfoBox,
+ onMapStar: ownProps.onMapStar,
+ onMapUnstar: ownProps.onMapUnstar,
+ onHelpClick: ownProps.openHelpLightbox,
+ infoBoxHtml: ownProps.infoBoxHtml
+ }
+}
+
+export const mapDispatchToProps = (dispatch, ownProps) => {
+ return {}
+}
diff --git a/frontend/src/containers/TopicCard.js b/frontend/src/containers/TopicCard.js
new file mode 100644
index 00000000..95f94c67
--- /dev/null
+++ b/frontend/src/containers/TopicCard.js
@@ -0,0 +1,5 @@
+import { connect } from 'react-redux'
+import { mapStateToProps, mapDispatchToProps } from './TopicCard.store'
+import TopicCard from '../components/TopicCard'
+
+export default connect(mapStateToProps, mapDispatchToProps)(TopicCard)
diff --git a/frontend/src/containers/TopicCard.store.js b/frontend/src/containers/TopicCard.store.js
new file mode 100644
index 00000000..0f89d1e6
--- /dev/null
+++ b/frontend/src/containers/TopicCard.store.js
@@ -0,0 +1,24 @@
+// import { } from '../actions'
+
+export const mapStateToProps = (state, ownProps) => {
+ return {
+ map: ownProps.map,
+ currentUser: ownProps.currentUser,
+ openImportLightbox: ownProps.openImportLightbox,
+ forkMap: ownProps.forkMap,
+ canEditMap: ownProps.canEditMap,
+ filterData: ownProps.filterData,
+ allForFiltering: ownProps.allForFiltering,
+ visibleForFiltering: ownProps.visibleForFiltering,
+ toggleMetacode: ownProps.toggleMetacode,
+ toggleMapper: ownProps.toggleMapper,
+ toggleSynapse: ownProps.toggleSynapse,
+ filterAllMetacodes: ownProps.filterAllMetacodes,
+ filterAllMappers: ownProps.filterAllMappers,
+ filterAllSynapses: ownProps.filterAllSynapses
+ }
+}
+
+export const mapDispatchToProps = (dispatch, ownProps) => {
+ return {}
+}
diff --git a/frontend/src/containers/UpperOptions.js b/frontend/src/containers/UpperOptions.js
new file mode 100644
index 00000000..9b60189d
--- /dev/null
+++ b/frontend/src/containers/UpperOptions.js
@@ -0,0 +1,5 @@
+import { connect } from 'react-redux'
+import { mapStateToProps, mapDispatchToProps } from './UpperOptions.store'
+import UpperOptions from '../components/UpperOptions'
+
+export default connect(mapStateToProps, mapDispatchToProps)(UpperOptions)
diff --git a/frontend/src/containers/UpperOptions.store.js b/frontend/src/containers/UpperOptions.store.js
new file mode 100644
index 00000000..0f89d1e6
--- /dev/null
+++ b/frontend/src/containers/UpperOptions.store.js
@@ -0,0 +1,24 @@
+// import { } from '../actions'
+
+export const mapStateToProps = (state, ownProps) => {
+ return {
+ map: ownProps.map,
+ currentUser: ownProps.currentUser,
+ openImportLightbox: ownProps.openImportLightbox,
+ forkMap: ownProps.forkMap,
+ canEditMap: ownProps.canEditMap,
+ filterData: ownProps.filterData,
+ allForFiltering: ownProps.allForFiltering,
+ visibleForFiltering: ownProps.visibleForFiltering,
+ toggleMetacode: ownProps.toggleMetacode,
+ toggleMapper: ownProps.toggleMapper,
+ toggleSynapse: ownProps.toggleSynapse,
+ filterAllMetacodes: ownProps.filterAllMetacodes,
+ filterAllMappers: ownProps.filterAllMappers,
+ filterAllSynapses: ownProps.filterAllSynapses
+ }
+}
+
+export const mapDispatchToProps = (dispatch, ownProps) => {
+ return {}
+}
diff --git a/frontend/src/containers/VisualizationControls.js b/frontend/src/containers/VisualizationControls.js
new file mode 100644
index 00000000..546eaa13
--- /dev/null
+++ b/frontend/src/containers/VisualizationControls.js
@@ -0,0 +1,5 @@
+import { connect } from 'react-redux'
+import { mapStateToProps, mapDispatchToProps } from './VisualizationControls.store'
+import VisualizationControls from '../components/VisualizationControls'
+
+export default connect(mapStateToProps, mapDispatchToProps)(VisualizationControls)
diff --git a/frontend/src/containers/VisualizationControls.store.js b/frontend/src/containers/VisualizationControls.store.js
new file mode 100644
index 00000000..5699f564
--- /dev/null
+++ b/frontend/src/containers/VisualizationControls.store.js
@@ -0,0 +1,15 @@
+// import { } from '../actions'
+
+export const mapStateToProps = (state, ownProps) => {
+ return {
+ topic: ownProps.topic,
+ map: ownProps.map,
+ onClickZoomExtents: ownProps.onZoomExtents,
+ onClickZoomIn: ownProps.onZoomIn,
+ onClickZoomOut: ownProps.onZoomOut
+ }
+}
+
+export const mapDispatchToProps = (dispatch, ownProps) => {
+ return {}
+}
diff --git a/frontend/src/reducers/index.js b/frontend/src/reducers/index.js
new file mode 100644
index 00000000..d0934fea
--- /dev/null
+++ b/frontend/src/reducers/index.js
@@ -0,0 +1,9 @@
+import { combineReducers } from 'redux'
+
+import map from './map'
+//import notifications from './notifications'
+
+export default combineReducers({
+ map//,
+ //notifications
+})
diff --git a/frontend/src/reducers/map/chat.js b/frontend/src/reducers/map/chat.js
new file mode 100644
index 00000000..3bdd42af
--- /dev/null
+++ b/frontend/src/reducers/map/chat.js
@@ -0,0 +1,22 @@
+import {
+ OPEN_CHAT,
+ CLOSE_CHAT
+} from '../../actions/constants'
+
+const initialState = {
+ isOpen: false
+}
+
+export default function (state = initialState, action) {
+ switch (action.type) {
+ case OPEN_CHAT:
+ return {
+ isOpen: true
+ }
+ case CLOSE_CHAT:
+ return {
+ isOpen: false
+ }
+ }
+ return state
+}
diff --git a/frontend/src/reducers/map/contextMenu.js b/frontend/src/reducers/map/contextMenu.js
new file mode 100644
index 00000000..d384069c
--- /dev/null
+++ b/frontend/src/reducers/map/contextMenu.js
@@ -0,0 +1,5 @@
+const initialState = {}
+
+export default function (state = initialState, action) {
+ return state
+}
diff --git a/frontend/src/reducers/map/createSynapse.js b/frontend/src/reducers/map/createSynapse.js
new file mode 100644
index 00000000..d384069c
--- /dev/null
+++ b/frontend/src/reducers/map/createSynapse.js
@@ -0,0 +1,5 @@
+const initialState = {}
+
+export default function (state = initialState, action) {
+ return state
+}
diff --git a/frontend/src/reducers/map/createTopic.js b/frontend/src/reducers/map/createTopic.js
new file mode 100644
index 00000000..d384069c
--- /dev/null
+++ b/frontend/src/reducers/map/createTopic.js
@@ -0,0 +1,5 @@
+const initialState = {}
+
+export default function (state = initialState, action) {
+ return state
+}
diff --git a/frontend/src/reducers/map/filters.js b/frontend/src/reducers/map/filters.js
new file mode 100644
index 00000000..b0947a24
--- /dev/null
+++ b/frontend/src/reducers/map/filters.js
@@ -0,0 +1,21 @@
+const initialState = {
+ dataForPresentation: {
+ metacodes: {},
+ mappers: {},
+ synapses: {}
+ },
+ filters: {
+ metacodes: [],
+ mappers: [],
+ synapses: []
+ },
+ visible: {
+ metacodes: [],
+ mappers: [],
+ synapses: []
+ }
+}
+
+export default function (state = initialState, action) {
+ return state
+}
diff --git a/frontend/src/reducers/map/importDialogue.js b/frontend/src/reducers/map/importDialogue.js
new file mode 100644
index 00000000..d384069c
--- /dev/null
+++ b/frontend/src/reducers/map/importDialogue.js
@@ -0,0 +1,5 @@
+const initialState = {}
+
+export default function (state = initialState, action) {
+ return state
+}
diff --git a/frontend/src/reducers/map/index.js b/frontend/src/reducers/map/index.js
new file mode 100644
index 00000000..7f993e69
--- /dev/null
+++ b/frontend/src/reducers/map/index.js
@@ -0,0 +1,33 @@
+import { combineReducers } from 'redux'
+
+import filters from './filters'
+import selected from './selected'
+import chat from './chat'
+import createTopic from './createTopic'
+import createSynapse from './createSynapse'
+import contextMenu from './contextMenu'
+import topicCard from './topicCard'
+import synapseCard from './synapseCard'
+import realtime from './realtime'
+import settings from './settings'
+import importDialogue from './importDialogue'
+import layout from './layout'
+import mouse from './mouse'
+import metacodeSelect from './metacodeSelect'
+
+export default combineReducers({
+ chat,
+ filters,
+ selected,
+ createTopic,
+ createSynapse,
+ contextMenu,
+ topicCard,
+ synapseCard,
+ realtime,
+ settings,
+ importDialogue,
+ layout,
+ mouse,
+ metacodeSelect
+})
diff --git a/frontend/src/reducers/map/layout.js b/frontend/src/reducers/map/layout.js
new file mode 100644
index 00000000..d384069c
--- /dev/null
+++ b/frontend/src/reducers/map/layout.js
@@ -0,0 +1,5 @@
+const initialState = {}
+
+export default function (state = initialState, action) {
+ return state
+}
diff --git a/frontend/src/reducers/map/metacodeSelect.js b/frontend/src/reducers/map/metacodeSelect.js
new file mode 100644
index 00000000..d384069c
--- /dev/null
+++ b/frontend/src/reducers/map/metacodeSelect.js
@@ -0,0 +1,5 @@
+const initialState = {}
+
+export default function (state = initialState, action) {
+ return state
+}
diff --git a/frontend/src/reducers/map/mouse.js b/frontend/src/reducers/map/mouse.js
new file mode 100644
index 00000000..d384069c
--- /dev/null
+++ b/frontend/src/reducers/map/mouse.js
@@ -0,0 +1,5 @@
+const initialState = {}
+
+export default function (state = initialState, action) {
+ return state
+}
diff --git a/frontend/src/reducers/map/realtime.js b/frontend/src/reducers/map/realtime.js
new file mode 100644
index 00000000..d384069c
--- /dev/null
+++ b/frontend/src/reducers/map/realtime.js
@@ -0,0 +1,5 @@
+const initialState = {}
+
+export default function (state = initialState, action) {
+ return state
+}
diff --git a/frontend/src/reducers/map/selected.js b/frontend/src/reducers/map/selected.js
new file mode 100644
index 00000000..20e15a9d
--- /dev/null
+++ b/frontend/src/reducers/map/selected.js
@@ -0,0 +1,8 @@
+const initialState = {
+ Nodes: [],
+ Edges: []
+}
+
+export default function (state = initialState, action) {
+ return state
+}
diff --git a/frontend/src/reducers/map/settings.js b/frontend/src/reducers/map/settings.js
new file mode 100644
index 00000000..38d99394
--- /dev/null
+++ b/frontend/src/reducers/map/settings.js
@@ -0,0 +1,21 @@
+const initialState = {
+ colors: {
+ background: '#344A58',
+ synapses: {
+ normal: '#888888',
+ hover: '#888888',
+ selected: '#FFFFFF'
+ },
+ topics: {
+ selected: '#FFFFFF'
+ },
+ labels: {
+ background: '#18202E',
+ text: '#DDD'
+ }
+ }
+}
+
+export default function (state = initialState, action) {
+ return state
+}
diff --git a/frontend/src/reducers/map/synapseCard.js b/frontend/src/reducers/map/synapseCard.js
new file mode 100644
index 00000000..27ce53b9
--- /dev/null
+++ b/frontend/src/reducers/map/synapseCard.js
@@ -0,0 +1,3 @@
+export default function (state = null, action) {
+ return state
+}
diff --git a/frontend/src/reducers/map/topicCard.js b/frontend/src/reducers/map/topicCard.js
new file mode 100644
index 00000000..27ce53b9
--- /dev/null
+++ b/frontend/src/reducers/map/topicCard.js
@@ -0,0 +1,3 @@
+export default function (state = null, action) {
+ return state
+}
diff --git a/frontend/src/reducers/notifications/index.js b/frontend/src/reducers/notifications/index.js
new file mode 100644
index 00000000..be390c35
--- /dev/null
+++ b/frontend/src/reducers/notifications/index.js
@@ -0,0 +1,3 @@
+export default function notifications(state = [], action) {
+ return state
+}
diff --git a/frontend/src/routes/MapView/MapView.js b/frontend/src/routes/MapView/MapView.js
new file mode 100644
index 00000000..4db46981
--- /dev/null
+++ b/frontend/src/routes/MapView/MapView.js
@@ -0,0 +1,95 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+
+import UpperOptions from '../../containers/UpperOptions'
+import InfoAndHelp from '../../containers/InfoAndHelp'
+import VisualizationControls from '../../containers/VisualizationControls'
+import ContextMenu from '../../containers/ContextMenu'
+import TopicCard from '../../containers/TopicCard'
+
+import Instructions from '../../components/Instructions'
+import MapChat from '../../components/MapChat'
+import MapVis from '../../components/MapVis'
+
+export default class MapView extends Component {
+
+ static propTypes = {
+ contextMenu: PropTypes.bool,
+ mobile: PropTypes.bool,
+ mapId: PropTypes.string,
+ map: PropTypes.object,
+ mapIsStarred: PropTypes.bool,
+ onMapStar: PropTypes.func,
+ onMapUnstar: PropTypes.func,
+ filterData: PropTypes.object,
+ allForFiltering: PropTypes.object,
+ visibleForFiltering: PropTypes.object,
+ toggleMetacode: PropTypes.func,
+ toggleMapper: PropTypes.func,
+ toggleSynapse: PropTypes.func,
+ filterAllMetacodes: PropTypes.func,
+ filterAllMappers: PropTypes.func,
+ filterAllSynapses: PropTypes.func,
+ toggleMapInfoBox: PropTypes.func,
+ infoBoxHtml: PropTypes.string,
+ currentUser: PropTypes.object,
+ endActiveMap: PropTypes.func,
+ launchNewMap: PropTypes.func,
+ openImportLightbox: PropTypes.func,
+ forkMap: PropTypes.func,
+ openHelpLightbox: PropTypes.func,
+ onZoomExtents: PropTypes.func,
+ onZoomIn: PropTypes.func,
+ onZoomOut: PropTypes.func,
+ hasLearnedTopicCreation: PropTypes.bool,
+ chatIsOpen: PropTypes.bool,
+ closeChat: PropTypes.func,
+ openChat: PropTypes.func
+ }
+
+ componentWillUnmount() {
+ this.endMap()
+ }
+
+ endMap() {
+ this.props.closeChat()
+ this.mapChat.reset()
+ // TODO: fix upperOptions ref
+ this.upperOptions.reset()
+ this.props.endActiveMap()
+ }
+
+ componentDidUpdate(prevProps) {
+ const oldMapId = prevProps.mapId
+ const { mapId, launchNewMap } = this.props
+ if (!oldMapId && mapId) launchNewMap(mapId)
+ else if (oldMapId && mapId && oldMapId !== mapId) {
+ this.endMap()
+ launchNewMap(mapId)
+ }
+ else if (oldMapId && !mapId) this.endMap()
+ }
+
+ render = () => {
+ const { mobile, map, currentUser, closeChat, openChat, chatIsOpen,
+ toggleMapInfoBox, infoBoxHtml, allForFiltering, visibleForFiltering,
+ toggleMetacode, toggleMapper, toggleSynapse, filterAllMetacodes,
+ filterAllMappers, filterAllSynapses, filterData,
+ openImportLightbox, forkMap, openHelpLightbox,
+ mapIsStarred, onMapStar, onMapUnstar, openTopic,
+ onZoomExtents, onZoomIn, onZoomOut, hasLearnedTopicCreation,
+ contextMenu, DataModel } = this.props
+ const canEditMap = map && map.authorizeToEdit(currentUser)
+ // TODO: stop using {...this.props} and make explicit
+ return
+ this.upperOptions = x} {...this.props} />
+
+ {openTopic && }
+ {contextMenu && }
+ {currentUser && }
+ {currentUser && this.mapChat = x} />}
+
+
+
+ }
+}
diff --git a/frontend/src/routes/MapView/MapView.store.js b/frontend/src/routes/MapView/MapView.store.js
new file mode 100644
index 00000000..5527489c
--- /dev/null
+++ b/frontend/src/routes/MapView/MapView.store.js
@@ -0,0 +1,23 @@
+import {
+ closeChat,
+ openChat
+} from '../../actions'
+
+export const mapStateToProps = (state, ownProps) => {
+ return {
+ chatIsOpen: state.map.chat.isOpen
+ }
+}
+
+export const mapDispatchToProps = (dispatch, ownProps) => {
+ return {
+ openChat: () => {
+ ownProps.onOpen()
+ return dispatch(openChat())
+ },
+ closeChat: () => {
+ ownProps.onClose()
+ return dispatch(closeChat())
+ }
+ }
+}
diff --git a/frontend/src/routes/MapView/index.js b/frontend/src/routes/MapView/index.js
index 027b395d..8bef953c 100644
--- a/frontend/src/routes/MapView/index.js
+++ b/frontend/src/routes/MapView/index.js
@@ -1,132 +1,5 @@
-import React, { Component } from 'react'
-import PropTypes from 'prop-types'
+import { connect } from 'react-redux'
+import { mapStateToProps, mapDispatchToProps } from './MapView.store'
+import MapView from './MapView'
-import ContextMenu from '../../components/ContextMenu'
-import DataVis from '../../components/DataVis'
-import UpperOptions from '../../components/UpperOptions'
-import InfoAndHelp from '../../components/InfoAndHelp'
-import Instructions from './Instructions'
-import VisualizationControls from '../../components/VisualizationControls'
-import MapChat from './MapChat'
-import TopicCard from '../../components/TopicCard'
-
-export default class MapView extends Component {
-
- static propTypes = {
- contextMenu: PropTypes.bool,
- mobile: PropTypes.bool,
- mapId: PropTypes.string,
- map: PropTypes.object,
- mapIsStarred: PropTypes.bool,
- onMapStar: PropTypes.func,
- onMapUnstar: PropTypes.func,
- filterData: PropTypes.object,
- allForFiltering: PropTypes.object,
- visibleForFiltering: PropTypes.object,
- toggleMetacode: PropTypes.func,
- toggleMapper: PropTypes.func,
- toggleSynapse: PropTypes.func,
- filterAllMetacodes: PropTypes.func,
- filterAllMappers: PropTypes.func,
- filterAllSynapses: PropTypes.func,
- toggleMapInfoBox: PropTypes.func,
- infoBoxHtml: PropTypes.string,
- currentUser: PropTypes.object,
- endActiveMap: PropTypes.func,
- launchNewMap: PropTypes.func,
- openImportLightbox: PropTypes.func,
- forkMap: PropTypes.func,
- openHelpLightbox: PropTypes.func,
- onZoomExtents: PropTypes.func,
- onZoomIn: PropTypes.func,
- onZoomOut: PropTypes.func,
- hasLearnedTopicCreation: PropTypes.bool
- }
-
- constructor(props) {
- super(props)
- this.state = {
- chatOpen: false
- }
- }
-
- componentWillUnmount() {
- this.endMap()
- }
-
- endMap() {
- this.setState({
- chatOpen: false
- })
- this.mapChat.reset()
- this.upperOptions.reset()
- this.props.endActiveMap()
- }
-
- componentDidUpdate(prevProps) {
- const oldMapId = prevProps.mapId
- const { mapId, launchNewMap } = this.props
- if (!oldMapId && mapId) launchNewMap(mapId)
- else if (oldMapId && mapId && oldMapId !== mapId) {
- this.endMap()
- launchNewMap(mapId)
- }
- else if (oldMapId && !mapId) this.endMap()
- }
-
- render = () => {
- const { mobile, map, currentUser, onOpen, onClose,
- toggleMapInfoBox, infoBoxHtml, allForFiltering, visibleForFiltering,
- toggleMetacode, toggleMapper, toggleSynapse, filterAllMetacodes,
- filterAllMappers, filterAllSynapses, filterData,
- openImportLightbox, forkMap, openHelpLightbox,
- mapIsStarred, onMapStar, onMapUnstar, openTopic,
- onZoomExtents, onZoomIn, onZoomOut, hasLearnedTopicCreation,
- contextMenu } = this.props
- const { chatOpen } = this.state
- const onChatOpen = () => {
- this.setState({chatOpen: true})
- onOpen()
- }
- const onChatClose = () => {
- this.setState({chatOpen: false})
- onClose()
- }
- const canEditMap = map && map.authorizeToEdit(currentUser)
- // TODO: stop using {...this.props} and make explicit
- return
- this.upperOptions = x}
- map={map}
- currentUser={currentUser}
- onImportClick={openImportLightbox}
- onForkClick={forkMap}
- canEditMap={canEditMap}
- filterData={filterData}
- allForFiltering={allForFiltering}
- visibleForFiltering={visibleForFiltering}
- toggleMetacode={toggleMetacode}
- toggleMapper={toggleMapper}
- toggleSynapse={toggleSynapse}
- filterAllMetacodes={filterAllMetacodes}
- filterAllMappers={filterAllMappers}
- filterAllSynapses={filterAllSynapses} />
-
- {openTopic && }
- {contextMenu && }
- {currentUser && }
- {currentUser && this.mapChat = x} />}
-
-
-
- }
-}
+export default connect(mapStateToProps, mapDispatchToProps)(MapView)
diff --git a/frontend/src/routes/TopicView.js b/frontend/src/routes/TopicView.js
index cc8e54ca..b9cfeb06 100644
--- a/frontend/src/routes/TopicView.js
+++ b/frontend/src/routes/TopicView.js
@@ -1,12 +1,13 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
-import ContextMenu from '../components/ContextMenu'
-import DataVis from '../components/DataVis'
-import UpperOptions from '../components/UpperOptions'
-import InfoAndHelp from '../components/InfoAndHelp'
-import VisualizationControls from '../components/VisualizationControls'
-import TopicCard from '../components/TopicCard'
+import ContextMenu from '../containers/ContextMenu'
+import UpperOptions from '../containers/UpperOptions'
+import InfoAndHelp from '../containers/InfoAndHelp'
+import VisualizationControls from '../containers/VisualizationControls'
+import TopicCard from '../containers/TopicCard'
+
+import TopicVis from '../components/TopicVis'
export default class TopicView extends Component {
@@ -38,6 +39,7 @@ export default class TopicView extends Component {
}
endTopic() {
+ // TODO: fix upperOptions ref
this.upperOptions.reset()
this.props.endActiveTopic()
}
@@ -60,26 +62,12 @@ export default class TopicView extends Component {
openHelpLightbox, onZoomIn, onZoomOut, contextMenu } = this.props
// TODO: stop using {...this.props} and make explicit
return
- this.upperOptions = x}
- currentUser={currentUser}
- topic={topic}
- onForkClick={forkMap}
- filterData={filterData}
- allForFiltering={allForFiltering}
- visibleForFiltering={visibleForFiltering}
- toggleMetacode={toggleMetacode}
- toggleMapper={toggleMapper}
- toggleSynapse={toggleSynapse}
- filterAllMetacodes={filterAllMetacodes}
- filterAllMappers={filterAllMappers}
- filterAllSynapses={filterAllSynapses} />
-
+ this.upperOptions = x} {...this.props} />
+
{contextMenu && }
-
-
+
+
}
}
diff --git a/package.json b/package.json
index 5cece282..20c93c70 100644
--- a/package.json
+++ b/package.json
@@ -49,8 +49,9 @@
"react-draggable": "3.0.3",
"react-dropzone": "4.1.2",
"react-onclickoutside": "6.5.0",
+ "react-redux": "^5.0.6",
"react-router": "3.0.5",
- "redux": "3.7.2",
+ "redux": "^3.7.2",
"riek": "1.1.0",
"simplewebrtc": "2.2.2",
"socket.io": "1.3.7",