diff --git a/frontend/src/Metamaps/GlobalUI/ReactApp.js b/frontend/src/Metamaps/GlobalUI/ReactApp.js
index 7a744433..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,7 +100,9 @@ const ReactApp = {
render: function() {
const self = ReactApp
const createElement = (Component, props) =>
- const app =
+ const app =
+
+
ReactDOM.render(app, document.getElementById('react-app'))
},
getProps: function() {
diff --git a/frontend/src/Metamaps/Map/index.js b/frontend/src/Metamaps/Map/index.js
index 43af6b2a..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'
diff --git a/frontend/src/actions/constants.js b/frontend/src/actions/constants.js
new file mode 100644
index 00000000..caa733c0
--- /dev/null
+++ b/frontend/src/actions/constants.js
@@ -0,0 +1,2 @@
+export const OPEN_CHAT = 'OPEN_CHAT'
+export const CLOSE_CHAT = 'CLOSE_CHAT'
diff --git a/frontend/src/actions/index.js b/frontend/src/actions/index.js
new file mode 100644
index 00000000..37aa5f75
--- /dev/null
+++ b/frontend/src/actions/index.js
@@ -0,0 +1,13 @@
+import * as constants from './constants'
+
+export const openChat = () => {
+ return {
+ type: constants.OPEN_CHAT
+ }
+}
+
+export const closeChat = () => {
+ return {
+ type: constants.CLOSE_CHAT
+ }
+}
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..1c477e5e
--- /dev/null
+++ b/frontend/src/routes/MapView/MapView.js
@@ -0,0 +1,117 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+
+import ContextMenu from '../../components/ContextMenu'
+import MapVis from '../../components/MapVis'
+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,
+ chatIsOpen: PropTypes.bool,
+ closeChat: PropTypes.func,
+ openChat: PropTypes.func
+ }
+
+ componentWillUnmount() {
+ this.endMap()
+ }
+
+ endMap() {
+ this.props.closeChat()
+ 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, 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}
+ 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} />}
+
+
+
+ }
+}
diff --git a/frontend/src/routes/MapView/index.js b/frontend/src/routes/MapView/index.js
index 0c15448e..9905327a 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 './store'
+import MapView from './MapView'
-import ContextMenu from '../../components/ContextMenu'
-import MapVis from '../../components/MapVis'
-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, DataModel } = 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/MapView/store.js b/frontend/src/routes/MapView/store.js
new file mode 100644
index 00000000..5527489c
--- /dev/null
+++ b/frontend/src/routes/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/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",