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",