Merge branch 'frontendonly' of https://github.com/metamaps/metamaps into frontendonly
This commit is contained in:
commit
48fb750560
64 changed files with 1748 additions and 1314 deletions
|
@ -1,2 +1 @@
|
|||
https://github.com/heroku/heroku-buildpack-nodejs.git
|
||||
https://github.com/heroku/heroku-buildpack-ruby.git
|
||||
|
|
|
@ -1,16 +1,10 @@
|
|||
---
|
||||
engines:
|
||||
brakeman:
|
||||
enabled: true
|
||||
bundler-audit:
|
||||
enabled: true
|
||||
duplication:
|
||||
enabled: true
|
||||
config:
|
||||
languages:
|
||||
count_threshold: 3 # rule of three
|
||||
ruby:
|
||||
mass_threshold: 36 # default: 18
|
||||
javascript:
|
||||
mass_threshold: 80 # default: 40
|
||||
eslint:
|
||||
|
@ -18,21 +12,11 @@ engines:
|
|||
channel: "eslint-3"
|
||||
fixme:
|
||||
enabled: true
|
||||
rubocop:
|
||||
enabled: true
|
||||
exclude_fingerprints:
|
||||
- 74f18007b920e8d81148d2f6a2756534
|
||||
ratings:
|
||||
paths:
|
||||
- 'Gemfile.lock'
|
||||
- '**.erb'
|
||||
- '**.rb'
|
||||
- '**.js'
|
||||
- '**.jsx'
|
||||
exclude_paths:
|
||||
- app/assets/images/
|
||||
- app/assets/javascripts/lib/
|
||||
- frontend/src/patched/
|
||||
- db/
|
||||
- script/
|
||||
- spec/
|
||||
- public/images
|
||||
- public/lib
|
||||
- src/patched/
|
||||
|
|
2
.nvmrc
2
.nvmrc
|
@ -1 +1 @@
|
|||
6.2.2
|
||||
8.9.4
|
||||
|
|
4
.travis.yml
Normal file
4
.travis.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
language: node_js
|
||||
addons:
|
||||
code_climate:
|
||||
repo_token: 479d3bf56798fbc7fff3fc8151a5ed09e8ac368fd5af332c437b9e07dbebb44e
|
65
README.md
65
README.md
|
@ -1,25 +1,28 @@
|
|||
|
||||
Make sure you have `nodemon` and `node-sass` installed
|
||||
`$ npm install -g nodemon node-sass`
|
||||
Make sure you're running a good up to date LTS version of `node`, like 8.9.4
|
||||
|
||||
Make sure you have `node-sass` installed
|
||||
`$ npm install -g node-sass`
|
||||
|
||||
Run the following at the same time, in two terminals
|
||||
|
||||
Run the following at the same time, in TWO SEPARATE terminals. We tell the server where the backend process is running with the API environment variable
|
||||
JS files, and CSS will rebuild automatically, just refresh the page
|
||||
If coding the server itself, you will have to use nodemon, or kill and restart the server process manually
|
||||
```
|
||||
$ API=http://localhost:3001 nodemon server.js
|
||||
$ API=http://localhost:3001 node server.js
|
||||
$ node-sass -w sass/application.scss public/css/application.css
|
||||
```
|
||||
|
||||
To run the server as a daemon that will be re-run if it crashes, you can
|
||||
use the forever node package.
|
||||
To make sure the css files get built, use the following in another terminal
|
||||
```
|
||||
$ npm install -g forever
|
||||
$ forever start server.js
|
||||
touch sass/application.scss
|
||||
```
|
||||
|
||||
Run the metamaps api in another terminal using
|
||||
Run the metamaps api in another terminal using (on port 3001, so the UI can talk to it)
|
||||
For now, make sure you are running on the `add-user-route` branch of Metamaps, and that it's up to date with the latest on that branch
|
||||
`$ rails s -p 3001`
|
||||
|
||||
open up http://localhost:3000 and start coding!
|
||||
|
||||
Checklist
|
||||
- [x] Get the Import lightbox working, and not conflicting on screen
|
||||
- [x] Handling CSRF
|
||||
|
@ -27,32 +30,52 @@ Checklist
|
|||
- [x] Figure out how authentication of requests from the frontend to the API works
|
||||
- [x] Figure out how to combine the nodejs realtime server into server.js
|
||||
- [x] Notifications: make sure loading states are working for popup and page
|
||||
- [x] Request unreadNotificationCount
|
||||
- [x] Request invite code
|
||||
- [x] Request user object itself
|
||||
- [x] Load the metacodes
|
||||
- [x] move ImportDialog lightbox into main app
|
||||
- [x] create topic form
|
||||
- [x] Fork map lightbox / component
|
||||
|
||||
- [ ] fix other places where metacode sets are used
|
||||
- [ ] make newtopic form load metacodes from users selected ones
|
||||
- [ ] create synapse form
|
||||
- [ ] replace old loader with react loader
|
||||
- [ ] ensure exports of maps work
|
||||
- [ ] Notifications: make sure notifications either look nice, or redirect
|
||||
- [ ] Notifications: pagination
|
||||
- [ ] Notifications: Request unreadNotificationCount
|
||||
- [ ] Notifications: CSS fixes related to 'controller-x' in body classes
|
||||
- [ ] Make sure loading state for explore maps pages work
|
||||
- [ ] Get actioncable working
|
||||
- [ ] Request invite code
|
||||
- [x] Request user object itself
|
||||
- [ ] lightboxes
|
||||
- [ ] About lightbox
|
||||
- [ ] Switch Metacodes lightbox / component
|
||||
- [ ] break up index.html into parts
|
||||
- [ ] Handle CSS metacode colors
|
||||
- [ ] Fix Request An Invite page
|
||||
- [ ] Make 'new map' action work
|
||||
- [ ] Modify the remaining rails templates into JSX templates
|
||||
- [x] notifications list
|
||||
- [x] notification page
|
||||
- [ ] list metacodes
|
||||
- [ ] new metacode
|
||||
- [ ] edit metacode
|
||||
- [ ] list metacode_sets
|
||||
- [ ] new metacode set
|
||||
- [ ] edit metacode set
|
||||
- [x] list metacodes
|
||||
- [x] new metacode
|
||||
- [x] edit metacode
|
||||
- [x] list metacode_sets
|
||||
- [x] new metacode set
|
||||
- [x] edit metacode set
|
||||
- [ ] authorized apps
|
||||
- [ ] registered apps
|
||||
- [ ] authorize
|
||||
- [ ] user passwords
|
||||
- [ ] Modify the RubyOnRails app to only serve JSON responses, no HTML pages anymore
|
||||
- [ ] Modify the RubyOnRails app to include an endpoint that responds with basic data the front end needs to display (such as the invite code for the user, and the current metamaps build) (a bunch of the data found here: https://github.com/metamaps/metamaps/blob/frontendonly/Metamaps.ServerData.js.erb)
|
||||
- [ ] Modify the frontend to request that data from the API which is necessary at first to load the page
|
||||
- [x] Load the metacodes
|
||||
- [ ] Load the metacode sets
|
||||
- [x] Load the metacode sets
|
||||
|
||||
To run the server as a daemon that will be re-run if it crashes, you can
|
||||
use the forever node package.
|
||||
```
|
||||
$ npm install -g forever
|
||||
$ forever start server.js
|
||||
```
|
|
@ -1,7 +1,8 @@
|
|||
const request = require('request')
|
||||
|
||||
function apiProxyMiddleware (req, res, next) {
|
||||
if (!(req.xhr || req.originalUrl.indexOf('.json') > -1 || req.method !== 'GET')) {
|
||||
// TODO: tidy this up!
|
||||
if (!(req.xhr || req.headers['content-type'] === 'application/json' || req.originalUrl.indexOf('.json') > -1 || req.method !== 'GET')) {
|
||||
return next()
|
||||
}
|
||||
const method = req.method.toLowerCase()
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
"server": "node server.js",
|
||||
"build": "webpack",
|
||||
"build:watch": "webpack --watch",
|
||||
"test": "mocha-webpack --webpack-config webpack.test.config.js --require frontend/test_support/dom.js --recursive frontend/test",
|
||||
"eslint": "eslint frontend",
|
||||
"eslint:fix": "eslint --fix frontend"
|
||||
"test": "mocha-webpack --webpack-config webpack.test.config.js --require test_support/dom.js --recursive test",
|
||||
"eslint": "eslint src",
|
||||
"eslint:fix": "eslint --fix src"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
@ -11,17 +11,18 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Metamaps</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Metamaps</title>
|
||||
|
||||
<link rel="stylesheet" media="all" href="/css/application.css">
|
||||
<link rel="stylesheet" media="all" href="/css/application.css">
|
||||
|
||||
<!-- typekit for vinyl font -->
|
||||
<!-- typekit for vinyl font -->
|
||||
<script type="text/javascript" src="https://use.typekit.net/tki2nyo.js"></script>
|
||||
<script type="text/javascript">try{Typekit.load();}catch(e){}</script>
|
||||
<script type="text/javascript">try { Typekit.load(); } catch (e) { }</script>
|
||||
|
||||
<!--[if (IE)]>
|
||||
<style type="text/css">
|
||||
|
@ -62,35 +63,33 @@
|
|||
});
|
||||
</script>
|
||||
<![endif]-->
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body class="unauthenticated">
|
||||
<div class="main">
|
||||
<div id="app"></div>
|
||||
<div id="loading"></div>
|
||||
</div>
|
||||
<script src="/lib/jquery-1.12.4.min.js"></script>
|
||||
<script src="/lib/jquery-ui.min.js"></script>
|
||||
<script src="/lib/ajaxq.js"></script>
|
||||
<script src="/lib/best_in_place.js"></script>
|
||||
<script src="/lib/bitcoinsrc.js"></script>
|
||||
<script src="/lib/canvas-to-blob.min.js"></script>
|
||||
<script src="/lib/canvasloader.min.js"></script>
|
||||
<script src="/lib/cloudcarousel.js"></script>
|
||||
<script src="/lib/Countable.js"></script>
|
||||
<script src="/lib/embedly.js"></script>
|
||||
<script src="/lib/hogan-2.0.0.js"></script>
|
||||
<script src="/lib/jquery.lettering.js"></script>
|
||||
<script src="/lib/jquery.mousewheel.min.js"></script>
|
||||
<script src="/lib/jquery.roundabout.min.js"></script>
|
||||
<script src="/lib/jquery.typing-0.2.0.min.js"></script>
|
||||
<script src="/lib/typeahead.bundle.js"></script>
|
||||
<script type="text/javascript" src="/metamaps.bundle.js"></script>
|
||||
<!--
|
||||
Metamaps.ServerData.unreadNotificationsCount = { current_user ? user_unread_notification_count : 0 }
|
||||
Metamaps.ServerData.mapIsStarred = { current_user && @map && current_user.starred_map?(@map) ? true : false }
|
||||
<div class="main">
|
||||
<div id="app"></div>
|
||||
<div id="loading"></div>
|
||||
</div>
|
||||
<script src="/lib/jquery-1.12.4.min.js"></script>
|
||||
<script src="/lib/jquery-ui.min.js"></script>
|
||||
<script src="/lib/ajaxq.js"></script>
|
||||
<script src="/lib/best_in_place.js"></script>
|
||||
<script src="/lib/bitcoinsrc.js"></script>
|
||||
<script src="/lib/canvas-to-blob.min.js"></script>
|
||||
<script src="/lib/canvasloader.min.js"></script>
|
||||
<script src="/lib/cloudcarousel.js"></script>
|
||||
<script src="/lib/Countable.js"></script>
|
||||
<script src="/lib/embedly.js"></script>
|
||||
<script src="/lib/hogan-2.0.0.js"></script>
|
||||
<script src="/lib/jquery.lettering.js"></script>
|
||||
<script src="/lib/jquery.mousewheel.min.js"></script>
|
||||
<script src="/lib/jquery.roundabout.min.js"></script>
|
||||
<script src="/lib/jquery.typing-0.2.0.min.js"></script>
|
||||
<script src="/lib/typeahead.bundle.js"></script>
|
||||
<script type="text/javascript" src="/metamaps.bundle.js"></script>
|
||||
<!--
|
||||
Metamaps.ServerData.mobileTitle = "{ yield(:mobile_title) }"
|
||||
Metamaps.ServerData.ActiveMapper = { current_user ? current_user.to_json({follows: true, email: true, follow_settings: true}).html_safe : nil }
|
||||
{ if devise_error_messages? }
|
||||
Metamaps.ServerData.toast = "{ devise_error_messages! }"
|
||||
{ elsif notice }
|
||||
|
@ -103,312 +102,201 @@
|
|||
{ render :partial => 'layouts/googleanalytics' if ENV["GA_TRACKING_CODE"].present? }
|
||||
|
||||
-->
|
||||
<script type="text/javascript">
|
||||
Metamaps.ServerData = Metamaps.ServerData || {}
|
||||
Metamaps.ServerData.RAILS_ENV = 'development'
|
||||
Metamaps.ServerData['junto_spinner_darkgrey.gif'] = '/images/junto_spinner_darkgrey.gif'
|
||||
Metamaps.ServerData['user.png'] = '/images/user.png'
|
||||
Metamaps.ServerData['icons/wildcard.png'] = '/images/icons/wildcard.png'
|
||||
Metamaps.ServerData['topic_description_signifier.png'] = '/images/topic_description_signifier.png'
|
||||
Metamaps.ServerData['topic_link_signifier.png'] = '/images/topic_link_signifier.png'
|
||||
Metamaps.ServerData['synapse16.png'] = '/images/synapse16.png'
|
||||
Metamaps.ServerData['sounds/MM_sounds.mp3'] = '/images/sounds/MM_sounds.mp3'
|
||||
Metamaps.ServerData['sounds/MM_sounds.ogg'] = '/images/sounds/MM_sounds.ogg'
|
||||
Metamaps.ServerData['exploremaps_sprite.png'] = '/images/exploremaps_sprite.png'
|
||||
Metamaps.ServerData['map_control_sprite.png'] = '/images/map_control_sprite.png'
|
||||
Metamaps.ServerData['user_sprite.png'] = '/images/user_sprite.png'
|
||||
Metamaps.Loading.setup()
|
||||
<script type="text/javascript">
|
||||
Metamaps.ServerData = Metamaps.ServerData || {}
|
||||
Metamaps.ServerData.RAILS_ENV = 'development'
|
||||
Metamaps.ServerData['junto_spinner_darkgrey.gif'] = '/images/junto_spinner_darkgrey.gif'
|
||||
Metamaps.ServerData['user.png'] = '/images/user.png'
|
||||
Metamaps.ServerData['icons/wildcard.png'] = '/images/icons/wildcard.png'
|
||||
Metamaps.ServerData['topic_description_signifier.png'] = '/images/topic_description_signifier.png'
|
||||
Metamaps.ServerData['topic_link_signifier.png'] = '/images/topic_link_signifier.png'
|
||||
Metamaps.ServerData['synapse16.png'] = '/images/synapse16.png'
|
||||
Metamaps.ServerData['sounds/MM_sounds.mp3'] = '/images/sounds/MM_sounds.mp3'
|
||||
Metamaps.ServerData['sounds/MM_sounds.ogg'] = '/images/sounds/MM_sounds.ogg'
|
||||
Metamaps.ServerData['exploremaps_sprite.png'] = '/images/exploremaps_sprite.png'
|
||||
Metamaps.ServerData['map_control_sprite.png'] = '/images/map_control_sprite.png'
|
||||
Metamaps.ServerData['user_sprite.png'] = '/images/user_sprite.png'
|
||||
Metamaps.Loading.setup()
|
||||
</script>
|
||||
|
||||
<div class="templates">
|
||||
<script type="text/template" id="mapInfoBoxTemplate">
|
||||
<div class="requestTitle">Click here to name this map</div>
|
||||
<div class="mapInfoName" id="mapInfoName">{{{name}}}</div>
|
||||
|
||||
<div class="mapInfoStat">
|
||||
<div class="infoStatIcon mapContributors hoverForTip">
|
||||
<img id="mapContribs" class="{{contributors_class}}"
|
||||
width="25" height="25" src="{{contributor_image}}" />
|
||||
<span class="count">{{contributor_count}}</span>
|
||||
<div class="tip">{{{contributor_list}}}</div>
|
||||
</div>
|
||||
<div class="infoStatIcon mapTopics">
|
||||
{{topic_count}}
|
||||
</div>
|
||||
<div class="infoStatIcon mapSynapses">
|
||||
{{synapse_count}}
|
||||
</div>
|
||||
<div class="infoStatIcon mapPermission {{permission}} hoverForTip">
|
||||
{{{map_creator_tip}}}
|
||||
</div>
|
||||
<div class="clearfloat"></div>
|
||||
</div>
|
||||
<div class="mapInfoDesc" id="mapInfoDesc">
|
||||
{{{desc}}}
|
||||
</div>
|
||||
|
||||
<div class="mapInfoMeta">
|
||||
<p class="mapCreatedAt"><span>Created by:</span> {{user_name}} on {{created_at}}</p>
|
||||
<p class="mapEditedAt"><span>Last edited:</span> {{updated_at}}</p>
|
||||
<div class="mapInfoButtonsWrapper">
|
||||
<div class="mapInfoThumbnail">
|
||||
<div class="thumbnail"></div>
|
||||
<div class="tooltip">Update Thumbnail</div>
|
||||
<span>Thumb</span>
|
||||
</div>
|
||||
<div class="mapInfoDelete">
|
||||
<div class="deleteMap"></div>
|
||||
<span>Delete</span>
|
||||
</div>
|
||||
<div class="mapInfoShare">
|
||||
<div class="mapInfoShareIcon"></div>
|
||||
<span>Share</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<div class="templates">
|
||||
<script type="text/template" id="mapInfoBoxTemplate">
|
||||
<div class="requestTitle">Click here to name this map</div>
|
||||
<div class="mapInfoName" id="mapInfoName">{{{name}}}</div>
|
||||
|
||||
<div class="mapInfoStat">
|
||||
<div class="infoStatIcon mapContributors hoverForTip">
|
||||
<img id="mapContribs" class="{{contributors_class}}"
|
||||
width="25" height="25" src="{{contributor_image}}" />
|
||||
<span class="count">{{contributor_count}}</span>
|
||||
<div class="tip">{{{contributor_list}}}</div>
|
||||
</div>
|
||||
<div class="infoStatIcon mapTopics">
|
||||
{{topic_count}}
|
||||
</div>
|
||||
<div class="infoStatIcon mapSynapses">
|
||||
{{synapse_count}}
|
||||
</div>
|
||||
<div class="infoStatIcon mapPermission {{permission}} hoverForTip">
|
||||
{{{map_creator_tip}}}
|
||||
</div>
|
||||
<div class="clearfloat"></div>
|
||||
<script type="text/template" id="topicSearchTemplate">
|
||||
<div class="result{{rtype}}">
|
||||
<div class="topicMetacode searchResIconWrapper">
|
||||
<img src="{{typeImageURL}}" class="topicIcon" />
|
||||
<div class="metacodeTip">{{type}}</div>
|
||||
</div>
|
||||
<div class="resultText">
|
||||
<p class="resultTitle">{{label}}</p>
|
||||
<p class="resultDesc">{{description}}</p>
|
||||
</div>
|
||||
<div class="autoOptions">
|
||||
<button class="addToMap hoverForTip" onclick="return Metamaps.Topic.getTopicFromSearch(event, {{id}})">
|
||||
<span class="tip">add to map</span>
|
||||
</button>
|
||||
<div class="mapCount">
|
||||
{{mapCount}}
|
||||
</div>
|
||||
<div class="mapInfoDesc" id="mapInfoDesc">
|
||||
{{{desc}}}
|
||||
<div class="synapseCount">
|
||||
{{synapseCount}}
|
||||
</div>
|
||||
|
||||
<div class="mapInfoMeta">
|
||||
<p class="mapCreatedAt"><span>Created by:</span> {{user_name}} on {{created_at}}</p>
|
||||
<p class="mapEditedAt"><span>Last edited:</span> {{updated_at}}</p>
|
||||
<div class="mapInfoButtonsWrapper">
|
||||
<div class="mapInfoThumbnail">
|
||||
<div class="thumbnail"></div>
|
||||
<div class="tooltip">Update Thumbnail</div>
|
||||
<span>Thumb</span>
|
||||
</div>
|
||||
<div class="mapInfoDelete">
|
||||
<div class="deleteMap"></div>
|
||||
<span>Delete</span>
|
||||
</div>
|
||||
<div class="mapInfoShare">
|
||||
<div class="mapInfoShareIcon"></div>
|
||||
<span>Share</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="topicOriginatorIcon hoverForTip">
|
||||
<img width="18" height="18" src="{{originatorImage}}">
|
||||
<span class="tip topicOriginator">{{originator}}</span>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="topicSearchTemplate">
|
||||
<div class="result{{rtype}}">
|
||||
<div class="topicMetacode searchResIconWrapper">
|
||||
<img src="{{typeImageURL}}" class="topicIcon" />
|
||||
<div class="metacodeTip">{{type}}</div>
|
||||
</div>
|
||||
<div class="resultText">
|
||||
<p class="resultTitle">{{label}}</p>
|
||||
<p class="resultDesc">{{description}}</p>
|
||||
</div>
|
||||
<div class="autoOptions">
|
||||
<button class="addToMap hoverForTip" onclick="return Metamaps.Topic.getTopicFromSearch(event, {{id}})">
|
||||
<span class="tip">add to map</span>
|
||||
</button>
|
||||
<div class="mapCount">
|
||||
{{mapCount}}
|
||||
</div>
|
||||
<div class="synapseCount">
|
||||
{{synapseCount}}
|
||||
</div>
|
||||
<div class="topicOriginatorIcon hoverForTip">
|
||||
<img width="18" height="18" src="{{originatorImage}}">
|
||||
<span class="tip topicOriginator">{{originator}}</span>
|
||||
</div>
|
||||
<div class="topicPermission {{permission}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfloat"></div>
|
||||
<div class="topicPermission {{permission}}">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="mapSearchTemplate">
|
||||
<div class="result{{rtype}}">
|
||||
<div class="searchResIconWrapper">
|
||||
<img class="icon" src="/images/metamap36c.png">
|
||||
</div>
|
||||
<div class="resultText">
|
||||
<p class="resultTitle">{{label}}</p>
|
||||
<p class="resultDesc">{{description}}</p>
|
||||
</div>
|
||||
<div class="autoOptions">
|
||||
<div class="topicCount">
|
||||
{{topicCount}}
|
||||
</div>
|
||||
<div class="synapseCount">
|
||||
{{synapseCount}}
|
||||
</div>
|
||||
<div class="mapContributorsIcon hoverForTip">
|
||||
<img id="mapContribs" width="25" height="25" src="{{mapContributorImage}}" />
|
||||
<div class="tip">
|
||||
<ul>
|
||||
{{{contributorTip}}}
|
||||
</ul>
|
||||
</div>
|
||||
<span>{{contributorCount}}</span>
|
||||
</div>
|
||||
<div class="mapPermission {{permission}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfloat"></div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="mapperSearchTemplate">
|
||||
<div class="result{{rtype}}">
|
||||
<div class="searchResIconWrapper">
|
||||
<img class="icon" width="32" height="32" src="{{profile}}">
|
||||
</div>
|
||||
<div class="resultText">
|
||||
<p class="resultTitle">{{label}}</p>
|
||||
</div>
|
||||
<div class="autoOptions">
|
||||
<div class="mapperCreated">
|
||||
<p>Mapping since: {{created_at}}</p>
|
||||
</div>
|
||||
<div class="mapperGeneration">
|
||||
<p>Generation: {{generation}}</p>
|
||||
</div>
|
||||
<div class="mapCount">
|
||||
{{mapCount}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfloat"></div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="collaboratorSearchTemplate">
|
||||
<div class="collabResult">
|
||||
<div class="collabIconWrapper">
|
||||
<img class="icon" width="25" height="25" src="{{profile}}">
|
||||
</div>
|
||||
<div class="collabNameWrapper">
|
||||
<p class="collabName">{{label}}</p>
|
||||
</div>
|
||||
<div class="clearfloat"></div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="synapseAutocompleteTemplate">
|
||||
<div class="result{{rtype}}">
|
||||
<p class="autocompleteSection synapseDesc">{{label}}</p>
|
||||
<div class="synapseMetadata">
|
||||
<div class="synapseOriginatorIcon hoverForTip">
|
||||
<img width="24" height="24" src="{{originatorImage}}" />
|
||||
<span class="tooltips synapseOriginator">{{originator}}</span>
|
||||
</div>
|
||||
<div class="synapsePermission {{permission}}"></div>
|
||||
</div>
|
||||
<div class="clearfloat"></div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="topicAutocompleteTemplate">
|
||||
<div>
|
||||
<img class="autocompleteSection topicType" width="24" height="24"
|
||||
src="{{typeImageURL}}" alt="{{type}}" title="{{type}}" />
|
||||
<p class="autocompleteSection topicTitle">{{label}}</p>
|
||||
<div class="expandTopicMetadata"></div>
|
||||
<div class="topicMetadata">
|
||||
<div class="topicNumMaps">{{mapCount}}</div>
|
||||
<div class="topicNumSynapses">{{synapseCount}}</div>
|
||||
<div class="topicOriginatorIcon hoverForTip">
|
||||
<img width="24" height="24" src="{{originatorImage}}" />
|
||||
<span class="tooltips topicOriginator">{{originator}}</span>
|
||||
</div>
|
||||
<div class="topicPermission {{permission}}"></div>
|
||||
</div>
|
||||
<div class="clearfloat"></div>
|
||||
</div>
|
||||
</script>
|
||||
</div>
|
||||
<div class="clearfloat"></div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<div id="lightbox_overlay">
|
||||
<div id="lightbox_main">
|
||||
<a id="lightbox_close" href="#"></a>
|
||||
<div id="lightbox_content">
|
||||
|
||||
<div class="lightboxContent" id="about">
|
||||
<h3>About Metamaps.cc</h3>
|
||||
<div id="aboutParms">
|
||||
<div id="leftAboutParms">
|
||||
<p>STATUS: </p>
|
||||
<p>VERSION:</p>
|
||||
<p>BUILD:</p>
|
||||
<p>LAST UPDATE:</p>
|
||||
</div>
|
||||
|
||||
<div id="rightAboutParms">
|
||||
<p>PRIVATE BETA</p>
|
||||
<p></p>
|
||||
<p></p>
|
||||
<p></p>
|
||||
</div>
|
||||
<div class="clearfloat"></div>
|
||||
</div>
|
||||
|
||||
<p>Metamaps.cc is a free and open source web platform that supports real-time sense-making and distributed collaboration between individuals, communities and organizations.</p>
|
||||
|
||||
<p>Using an intuitive graph-based interface, Metamaps.cc helps map out networks of people, ideas, resources, stories, experiences, conversations and much more. The platform is evolving for a range of applications amidst a growing network of designers, developers, facilitators, practitioners, entrepreneurs, and artists.</p>
|
||||
|
||||
<p>Metamaps.cc is created and maintained by a distributed community of contributors passionate about the evolution of collaboration, alternative forms of value creation and increase of collective intelligence through the lens of the open culture and the peer-to-peer revolution.</p>
|
||||
|
||||
<ul class="lightbox_links">
|
||||
<li>
|
||||
<a class="icon_twitter" href="https://twitter.com/metamapps" target="_blank">
|
||||
<div class="lightboxAboutIcon"></div>
|
||||
@metamapps
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="icon_community" href="https://www.hylo.com/c/metamaps/join/mice-late-hit-two-shown" target="_blank">
|
||||
<div class="lightboxAboutIcon"></div>
|
||||
community
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="icon_source_code" href="https://github.com/metamaps/metamaps" target="_blank">
|
||||
<div class="lightboxAboutIcon"></div>
|
||||
source code
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="icon_howtos" href="https://docs.metamaps.cc" target="_blank">
|
||||
<div class="lightboxAboutIcon"></div>
|
||||
howtos
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="icon_terms" href="https://metamaps.cc/maps/331" target="_blank">
|
||||
<div class="lightboxAboutIcon"></div>
|
||||
terms
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfloat"></div>
|
||||
</div>
|
||||
|
||||
<div class="lightboxContent" id="noIE">
|
||||
<h3>OOPS! <br> YOUR BROWSER IS NOT SUPPORTED.</h3>
|
||||
<p id="noIEsubheading">To view this experience, please upgrade to the latest one of these browsers:</p>
|
||||
<a id="chromeIcon" href="https://www.google.com/chrome/browser/" target="_blank">Chrome</a>
|
||||
<a id="fireFoxIcon" href="https://www.mozilla.org/en-US/firefox/new/" target="_blank">Firefox</a>
|
||||
<a id="safariIcon" href="http://support.apple.com/downloads/#safari" target="_blank">Safari</a>
|
||||
<p id="noIEbody">While it's downloading, explore our <a href="http://blog.metamaps.cc/">blog</a>,<br> watch the <a href="http://vimeo.com/88334167">tutorials</a>, or visit our <a href="https://docs.metamaps.cc">knowledge base</a>!
|
||||
|
||||
</div>
|
||||
|
||||
<div class="lightboxContent" id="tutorial">
|
||||
<h3>Tutorial</h3>
|
||||
<iframe src="//player.vimeo.com/video/88334167?title=0&byline=0&portrait=0" width="510" height="319" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
<div class="lightboxContent" id="cheatsheet">
|
||||
<!--<%= render :partial => 'shared/cheatsheet' %>-->
|
||||
</div>
|
||||
|
||||
<div class="lightboxContent" id="invite">
|
||||
<h3>SHARE INVITE</h3>
|
||||
|
||||
<div class="leaveSpace"></div>
|
||||
<p>The Metamaps platform is currently in an invite-only beta with the express purpose of creating a high value knowledge ecosystem, a diverse community of contributors and a culture of collaboration and curiosity.</p>
|
||||
<p>As a valued beta tester, you have the ability to invite your peers, colleagues and collaborators onto the platform.</p>
|
||||
<p>Below is a personal invite link containing your unique access code, which can be used multiple times.</p>
|
||||
<div id="joinCodesBox">
|
||||
<p class="joinCodes">
|
||||
<button class="button" onclick="Metamaps.GlobalUI.shareInvite('<%= @invite_link %>');">COPY INVITE LINK!</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="lightboxContent" id="forkmap">
|
||||
<!--<%= render :partial => 'shared/forkmap' %>-->
|
||||
</div>
|
||||
|
||||
<div class="lightboxContent" id="switchMetacodes">
|
||||
<!--<%= render :partial => 'shared/switchmetacodes' %>-->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script type="text/template" id="mapSearchTemplate">
|
||||
<div class="result{{rtype}}">
|
||||
<div class="searchResIconWrapper">
|
||||
<img class="icon" src="/images/metamap36c.png">
|
||||
</div>
|
||||
<div class="resultText">
|
||||
<p class="resultTitle">{{label}}</p>
|
||||
<p class="resultDesc">{{description}}</p>
|
||||
</div>
|
||||
<div class="autoOptions">
|
||||
<div class="topicCount">
|
||||
{{topicCount}}
|
||||
</div>
|
||||
<div class="synapseCount">
|
||||
{{synapseCount}}
|
||||
</div>
|
||||
<div class="mapContributorsIcon hoverForTip">
|
||||
<img id="mapContribs" width="25" height="25" src="{{mapContributorImage}}" />
|
||||
<div class="tip">
|
||||
<ul>
|
||||
{{{contributorTip}}}
|
||||
</ul>
|
||||
</div>
|
||||
<div id="lightbox_screen" style="height: 100%;"></div>
|
||||
</div>
|
||||
<span>{{contributorCount}}</span>
|
||||
</div>
|
||||
<div class="mapPermission {{permission}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfloat"></div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="mapperSearchTemplate">
|
||||
<div class="result{{rtype}}">
|
||||
<div class="searchResIconWrapper">
|
||||
<img class="icon" width="32" height="32" src="{{profile}}">
|
||||
</div>
|
||||
<div class="resultText">
|
||||
<p class="resultTitle">{{label}}</p>
|
||||
</div>
|
||||
<div class="autoOptions">
|
||||
<div class="mapperCreated">
|
||||
<p>Mapping since: {{created_at}}</p>
|
||||
</div>
|
||||
<div class="mapperGeneration">
|
||||
<p>Generation: {{generation}}</p>
|
||||
</div>
|
||||
<div class="mapCount">
|
||||
{{mapCount}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfloat"></div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="collaboratorSearchTemplate">
|
||||
<div class="collabResult">
|
||||
<div class="collabIconWrapper">
|
||||
<img class="icon" width="25" height="25" src="{{profile}}">
|
||||
</div>
|
||||
<div class="collabNameWrapper">
|
||||
<p class="collabName">{{label}}</p>
|
||||
</div>
|
||||
<div class="clearfloat"></div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="synapseAutocompleteTemplate">
|
||||
<div class="result{{rtype}}">
|
||||
<p class="autocompleteSection synapseDesc">{{label}}</p>
|
||||
<div class="synapseMetadata">
|
||||
<div class="synapseOriginatorIcon hoverForTip">
|
||||
<img width="24" height="24" src="{{originatorImage}}" />
|
||||
<span class="tooltips synapseOriginator">{{originator}}</span>
|
||||
</div>
|
||||
<div class="synapsePermission {{permission}}"></div>
|
||||
</div>
|
||||
<div class="clearfloat"></div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="topicAutocompleteTemplate">
|
||||
<div>
|
||||
<img class="autocompleteSection topicType" width="24" height="24"
|
||||
src="{{typeImageURL}}" alt="{{type}}" title="{{type}}" />
|
||||
<p class="autocompleteSection topicTitle">{{label}}</p>
|
||||
<div class="expandTopicMetadata"></div>
|
||||
<div class="topicMetadata">
|
||||
<div class="topicNumMaps">{{mapCount}}</div>
|
||||
<div class="topicNumSynapses">{{synapseCount}}</div>
|
||||
<div class="topicOriginatorIcon hoverForTip">
|
||||
<img width="24" height="24" src="{{originatorImage}}" />
|
||||
<span class="tooltips topicOriginator">{{originator}}</span>
|
||||
</div>
|
||||
<div class="topicPermission {{permission}}"></div>
|
||||
</div>
|
||||
<div class="clearfloat"></div>
|
||||
</div>
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -81,67 +81,69 @@ $unread_notifications_dot_size: 8px;
|
|||
}
|
||||
}
|
||||
|
||||
.controller-notifications {
|
||||
.notificationPage,
|
||||
.notificationsPage {
|
||||
font-family: 'din-regular', Sans-Serif;
|
||||
.notificationPage,
|
||||
.notificationsPage {
|
||||
font-family: 'din-regular', Sans-Serif;
|
||||
|
||||
& a:hover {
|
||||
text-decoration: none;
|
||||
& a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
& > .notification-title {
|
||||
border-bottom: 1px solid #eee;
|
||||
padding-bottom: 0.25em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.back {
|
||||
margin-top: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.notificationsPage {
|
||||
header {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.emptyInbox {
|
||||
padding-top: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.notificationPage {
|
||||
.thirty-two-avatar {
|
||||
display: inline-block;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 16px;
|
||||
vertical-align: middle;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.button {
|
||||
line-height: 32px;
|
||||
|
||||
img {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
& > .notification-title {
|
||||
border-bottom: 1px solid #eee;
|
||||
padding-bottom: 0.25em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.back {
|
||||
margin-top: 1em;
|
||||
&.decline {
|
||||
margin-left: 8px;
|
||||
background: #DB5D5D;
|
||||
&:hover {
|
||||
background: #DC4B4B;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.notificationsPage {
|
||||
header {
|
||||
margin-bottom: 0;
|
||||
.notification-body {
|
||||
p, div {
|
||||
margin: 1em auto;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.emptyInbox {
|
||||
padding-top: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.notificationPage {
|
||||
.thirty-two-avatar {
|
||||
display: inline-block;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 16px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.button {
|
||||
line-height: 32px;
|
||||
|
||||
img {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
&.decline {
|
||||
background: #DB5D5D;
|
||||
&:hover {
|
||||
background: #DC4B4B;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.notification-body {
|
||||
p, div {
|
||||
margin: 1em auto;
|
||||
line-height: 20px;
|
||||
}
|
||||
.accessRequestError {
|
||||
color: #DB5D5D;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
/* global $ */
|
||||
|
||||
const Admin = {
|
||||
selectMetacodes: [],
|
||||
allMetacodes: [],
|
||||
init: function() {
|
||||
var self = Admin
|
||||
|
||||
$('#metacodes_value').val(self.selectMetacodes.toString())
|
||||
},
|
||||
selectAll: function() {
|
||||
var self = Admin
|
||||
|
||||
$('.editMetacodes li').removeClass('toggledOff')
|
||||
self.selectMetacodes = self.allMetacodes.slice(0)
|
||||
$('#metacodes_value').val(self.selectMetacodes.toString())
|
||||
},
|
||||
deselectAll: function() {
|
||||
var self = Admin
|
||||
|
||||
$('.editMetacodes li').addClass('toggledOff')
|
||||
self.selectMetacodes = []
|
||||
$('#metacodes_value').val(0)
|
||||
},
|
||||
liClickHandler: function() {
|
||||
var self = Admin
|
||||
|
||||
if ($(this).attr('class') !== 'toggledOff') {
|
||||
$(this).addClass('toggledOff')
|
||||
const valueToRemove = $(this).attr('id')
|
||||
self.selectMetacodes.splice(self.selectMetacodes.indexOf(valueToRemove), 1)
|
||||
$('#metacodes_value').val(self.selectMetacodes.toString())
|
||||
} else if ($(this).attr('class') === 'toggledOff') {
|
||||
$(this).removeClass('toggledOff')
|
||||
self.selectMetacodes.push($(this).attr('id'))
|
||||
$('#metacodes_value').val(self.selectMetacodes.toString())
|
||||
}
|
||||
},
|
||||
validate: function() {
|
||||
var self = Admin
|
||||
|
||||
if (self.selectMetacodes.length === 0) {
|
||||
window.alert('Would you pretty please select at least one metacode for the set?')
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Admin
|
|
@ -19,8 +19,6 @@ const Create = {
|
|||
newSelectedMetacodes: [],
|
||||
init: function() {
|
||||
var self = Create
|
||||
self.newTopic.init()
|
||||
self.newSynapse.init()
|
||||
|
||||
// // SWITCHING METACODE SETS
|
||||
|
||||
|
|
|
@ -1,20 +1,166 @@
|
|||
function fetchWithCookies(url) {
|
||||
return fetch(url, { credentials: 'same-origin' })
|
||||
function get(url) {
|
||||
return fetch(url, {
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function post(url, data = {}) {
|
||||
return fetch(url, {
|
||||
credentials: 'same-origin',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
}
|
||||
|
||||
function postNoStringify(url, data = {}) {
|
||||
return fetch(url, {
|
||||
credentials: 'same-origin',
|
||||
method: 'POST',
|
||||
body: data
|
||||
})
|
||||
}
|
||||
|
||||
function put(url, data = {}) {
|
||||
return fetch(url, {
|
||||
credentials: 'same-origin',
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
}
|
||||
|
||||
function putNoStringify(url, data = {}) {
|
||||
return fetch(url, {
|
||||
credentials: 'same-origin',
|
||||
method: 'PUT',
|
||||
body: data
|
||||
})
|
||||
}
|
||||
|
||||
function deleteReq(url) {
|
||||
return fetch(url, {
|
||||
credentials: 'same-origin',
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function getMetacodes() {
|
||||
const res = await fetchWithCookies('/metacodes.json')
|
||||
const res = await get('/metacodes')
|
||||
const data = await res.json()
|
||||
return data
|
||||
}
|
||||
|
||||
async function getCurrentUser() {
|
||||
const res = await fetchWithCookies('/users/current.json')
|
||||
async function getMetacodeSets() {
|
||||
const res = await get('/metacode_sets')
|
||||
const data = await res.json()
|
||||
return data
|
||||
}
|
||||
|
||||
async function createMetacodeSet(metacodes, name, desc) {
|
||||
const res = await post(`/metacode_sets`, {
|
||||
metacodes: {
|
||||
value: metacodes.toString()
|
||||
},
|
||||
metacode_set: {
|
||||
name,
|
||||
desc
|
||||
}
|
||||
})
|
||||
if (!res.ok) {
|
||||
throw new Error()
|
||||
return
|
||||
}
|
||||
const data = await res.json()
|
||||
return data
|
||||
}
|
||||
|
||||
async function updateMetacodeSet(id, metacodes, name, desc) {
|
||||
const res = await put(`/metacode_sets/${id}`, {
|
||||
metacodes: {
|
||||
value: metacodes.toString()
|
||||
},
|
||||
metacode_set: {
|
||||
name,
|
||||
desc
|
||||
}
|
||||
})
|
||||
if (!res.ok) {
|
||||
throw new Error()
|
||||
return
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
async function deleteMetacodeSet(id) {
|
||||
const res = await deleteReq(`/metacode_sets/${id}`)
|
||||
return res.ok
|
||||
}
|
||||
|
||||
async function createMetacode(name, color, icon) {
|
||||
const formdata = new FormData()
|
||||
formdata.append('metacode[name]', name)
|
||||
formdata.append('metacode[color]', color)
|
||||
formdata.append('metacode[aws_icon]', icon)
|
||||
const res = await postNoStringify(`/metacodes`, formdata)
|
||||
if (!res.ok) {
|
||||
throw new Error()
|
||||
return
|
||||
}
|
||||
const data = await res.json()
|
||||
return data
|
||||
}
|
||||
|
||||
async function updateMetacode(id, name, color, icon) {
|
||||
const formdata = new FormData()
|
||||
formdata.append('metacode[name]', name)
|
||||
formdata.append('metacode[color]', color)
|
||||
if (icon) formdata.append('metacode[aws_icon]', icon)
|
||||
const res = await putNoStringify(`/metacodes/${id}`, formdata)
|
||||
return res.ok
|
||||
}
|
||||
|
||||
async function getCurrentUser() {
|
||||
const res = await get('/users/current')
|
||||
const data = await res.json()
|
||||
return data
|
||||
}
|
||||
|
||||
async function approveAccessRequest(mapId, requestId) {
|
||||
const res = await post(`/maps/${mapId}/approve_access/${requestId}`)
|
||||
return res.ok
|
||||
}
|
||||
|
||||
async function denyAccessRequest(mapId, requestId) {
|
||||
const res = await post(`/maps/${mapId}/deny_access/${requestId}`)
|
||||
return res.ok
|
||||
}
|
||||
|
||||
async function requestAccess(mapId) {
|
||||
const res = await post(`/maps/${mapId}/access_request`)
|
||||
return res.ok
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getMetacodes,
|
||||
getCurrentUser
|
||||
getMetacodeSets,
|
||||
createMetacodeSet,
|
||||
updateMetacodeSet,
|
||||
deleteMetacodeSet,
|
||||
createMetacode,
|
||||
updateMetacode,
|
||||
getCurrentUser,
|
||||
approveAccessRequest,
|
||||
denyAccessRequest,
|
||||
requestAccess
|
||||
}
|
|
@ -1,36 +1,14 @@
|
|||
/* global $ */
|
||||
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import outdent from 'outdent'
|
||||
|
||||
import ImportDialogBox from '../../routes/MapView/ImportDialogBox'
|
||||
|
||||
import PasteInput from '../PasteInput'
|
||||
import Map from '../Map'
|
||||
|
||||
const ImportDialog = {
|
||||
openLightbox: null,
|
||||
closeLightbox: null,
|
||||
|
||||
init: function(serverData, openLightbox, closeLightbox) {
|
||||
const self = ImportDialog
|
||||
self.openLightbox = openLightbox
|
||||
self.closeLightbox = closeLightbox
|
||||
|
||||
$('#lightbox_content').append($(outdent`
|
||||
<div class="lightboxContent" id="import-dialog">
|
||||
<div class="importDialogWrapper" />
|
||||
</div>
|
||||
`))
|
||||
ReactDOM.render(React.createElement(ImportDialogBox, {
|
||||
onFileAdded: PasteInput.handleFile,
|
||||
exampleImageUrl: serverData['import-example.png'],
|
||||
downloadScreenshot: ImportDialog.downloadScreenshot,
|
||||
onExport: format => () => {
|
||||
window.open(`${window.location.pathname}/export.${format}`, '_blank')
|
||||
}
|
||||
}), $('.importDialogWrapper').get(0))
|
||||
},
|
||||
show: function() {
|
||||
ImportDialog.openLightbox('import-dialog')
|
||||
|
|
|
@ -7,7 +7,9 @@ const Notifications = {
|
|||
notificationsLoading: false,
|
||||
unreadNotificationsCount: 0,
|
||||
init: serverData => {
|
||||
Notifications.unreadNotificationsCount = serverData.unreadNotificationsCount
|
||||
if (serverData.ActiveMapper) {
|
||||
Notifications.unreadNotificationsCount = serverData.ActiveMapper.unread_notifications_count
|
||||
}
|
||||
},
|
||||
fetchNotifications: render => {
|
||||
Notifications.notificationsLoading = true
|
||||
|
|
|
@ -10,10 +10,13 @@ import { notifyUser } from './index.js'
|
|||
import ImportDialog from './ImportDialog'
|
||||
import Notifications from './Notifications'
|
||||
import Active from '../Active'
|
||||
import Create from '../Create'
|
||||
import DataModel from '../DataModel'
|
||||
import DataFetcher from '../DataFetcher'
|
||||
import { ExploreMaps, ChatView, TopicCard, ContextMenu } from '../Views'
|
||||
import Filter from '../Filter'
|
||||
import JIT from '../JIT'
|
||||
import PasteInput from '../PasteInput'
|
||||
import Realtime from '../Realtime'
|
||||
import Map, { InfoBox } from '../Map'
|
||||
import Topic from '../Topic'
|
||||
|
@ -107,7 +110,10 @@ const ReactApp = {
|
|||
fetchNotifications: apply(Notifications.fetchNotifications, ReactApp.render),
|
||||
fetchNotification: apply(Notifications.fetchNotification, ReactApp.render),
|
||||
markAsRead: apply(Notifications.markAsRead, ReactApp.render),
|
||||
markAsUnread: apply(Notifications.markAsUnread, ReactApp.render)
|
||||
markAsUnread: apply(Notifications.markAsUnread, ReactApp.render),
|
||||
denyAccessRequest: DataFetcher.denyAccessRequest,
|
||||
approveAccessRequest: DataFetcher.approveAccessRequest,
|
||||
metacodes: DataModel.Metacodes.toJSON()
|
||||
},
|
||||
self.getMapProps(),
|
||||
self.getTopicProps(),
|
||||
|
@ -116,7 +122,8 @@ const ReactApp = {
|
|||
self.getMapsProps(),
|
||||
self.getContextMenuProps(),
|
||||
self.getTopicCardProps(),
|
||||
self.getChatProps())
|
||||
self.getChatProps(),
|
||||
self.getAdminProps())
|
||||
},
|
||||
getMapProps: function() {
|
||||
const self = ReactApp
|
||||
|
@ -134,9 +141,18 @@ const ReactApp = {
|
|||
toggleMapInfoBox: InfoBox.toggleBox,
|
||||
infoBoxHtml: InfoBox.html,
|
||||
openImportLightbox: () => ImportDialog.show(),
|
||||
openMetacodeSwitcher: () => self.openLightbox('metacodeSwitcher'),
|
||||
forkMap: Map.fork,
|
||||
onMapStar: Map.star,
|
||||
onMapUnstar: Map.unstar
|
||||
onMapUnstar: Map.unstar,
|
||||
initNewTopic: Create.newTopic.init,
|
||||
initNewSynapse: Create.newSynapse.init,
|
||||
importHandleFile: PasteInput.handleFile,
|
||||
downloadScreenshot: ImportDialog.downloadScreenshot,
|
||||
onExport: format => () => {
|
||||
window.open(`${window.location.pathname}/export.${format}`, '_blank')
|
||||
},
|
||||
requestAccess: DataFetcher.requestAccess
|
||||
}
|
||||
},
|
||||
getCommonProps: function() {
|
||||
|
@ -240,6 +256,16 @@ const ReactApp = {
|
|||
filterAllSynapses: Filter.filterAllSynapses
|
||||
}
|
||||
},
|
||||
getAdminProps: function() {
|
||||
const self = ReactApp
|
||||
return {
|
||||
createMetacodeSet: DataFetcher.createMetacodeSet,
|
||||
updateMetacodeSet: DataFetcher.updateMetacodeSet,
|
||||
deleteMetacodeSet: DataFetcher.deleteMetacodeSet,
|
||||
createMetacode: DataFetcher.createMetacode,
|
||||
updateMetacode: DataFetcher.updateMetacode
|
||||
}
|
||||
},
|
||||
resize: function() {
|
||||
const self = ReactApp
|
||||
const maps = ExploreMaps.collection
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
/* global $ */
|
||||
|
||||
import clipboard from 'clipboard-js'
|
||||
|
||||
import Create from '../Create'
|
||||
|
||||
import Notifications from './Notifications'
|
||||
|
@ -34,6 +32,11 @@ const GlobalUI = {
|
|||
})
|
||||
|
||||
$('#lightbox_screen, #lightbox_close').click(self.closeLightbox)
|
||||
|
||||
// tab the cheatsheet
|
||||
$('#cheatSheet').tabs()
|
||||
$('#quickReference').tabs().addClass('ui-tabs-vertical ui-helper-clearfix')
|
||||
$('#quickReference .ui-tabs-nav li').removeClass('ui-corner-top').addClass('ui-corner-left')
|
||||
},
|
||||
showDiv: function(selector) {
|
||||
$(selector).show()
|
||||
|
@ -137,19 +140,6 @@ const GlobalUI = {
|
|||
ReactApp.render()
|
||||
self.notifying = false
|
||||
}
|
||||
},
|
||||
shareInvite: function(inviteLink) {
|
||||
clipboard.copy({
|
||||
'text/plain': inviteLink
|
||||
}).then(() => {
|
||||
$('#joinCodesBox .popup').remove()
|
||||
$('#joinCodesBox').append('<p class="popup" style="text-align: center">Copied!</p>')
|
||||
window.setTimeout(() => $('#joinCodesBox .popup').remove(), 1500)
|
||||
}, () => {
|
||||
$('#joinCodesBox .popup').remove()
|
||||
$('#joinCodesBox').append(`<p class="popup" style="text-align: center">Your browser doesn't support copying, please copy manually.</p>`)
|
||||
window.setTimeout(() => $('#joinCodesBox .popup').remove(), 1500)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
/* global $ */
|
||||
|
||||
const CheatSheet = {
|
||||
init: function() {
|
||||
// tab the cheatsheet
|
||||
$('#cheatSheet').tabs()
|
||||
$('#quickReference').tabs().addClass('ui-tabs-vertical ui-helper-clearfix')
|
||||
$('#quickReference .ui-tabs-nav li').removeClass('ui-corner-top').addClass('ui-corner-left')
|
||||
}
|
||||
}
|
||||
|
||||
export default CheatSheet
|
|
@ -20,7 +20,6 @@ import ContextMenu from '../Views/ContextMenu'
|
|||
import TopicCard from '../Views/TopicCard'
|
||||
import Visualize from '../Visualize'
|
||||
|
||||
import CheatSheet from './CheatSheet'
|
||||
import InfoBox from './InfoBox'
|
||||
|
||||
const Map = {
|
||||
|
@ -45,7 +44,6 @@ const Map = {
|
|||
InfoBox.init(serverData, function updateThumbnail() {
|
||||
self.uploadMapScreenshot()
|
||||
})
|
||||
CheatSheet.init(serverData)
|
||||
$(document).on(Map.events.editedByActiveMapper, self.editedByActiveMapper)
|
||||
},
|
||||
setHasLearnedTopicCreation: function(value) {
|
||||
|
@ -130,6 +128,14 @@ const Map = {
|
|||
DataModel.attachCollectionEvents()
|
||||
self.requests = data.requests
|
||||
isLoaded()
|
||||
},
|
||||
error: function(res) {
|
||||
// forbidden
|
||||
if (res.status === 403) {
|
||||
browserHistory.push(`/maps/${id}/request_access`)
|
||||
} else {
|
||||
GlobalUI.notifyUser('There was an error fetching the map')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -383,5 +389,5 @@ const Map = {
|
|||
}
|
||||
}
|
||||
|
||||
export { CheatSheet, InfoBox }
|
||||
export { InfoBox }
|
||||
export default Map
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import Active from './Active'
|
||||
import Admin from './Admin'
|
||||
import AutoLayout from './AutoLayout'
|
||||
import Cable from './Cable'
|
||||
import Control from './Control'
|
||||
|
@ -15,7 +14,7 @@ import Import from './Import'
|
|||
import JIT from './JIT'
|
||||
import Listeners from './Listeners'
|
||||
import Loading from './Loading'
|
||||
import Map, { CheatSheet, InfoBox } from './Map'
|
||||
import Map, { InfoBox } from './Map'
|
||||
import Mapper from './Mapper'
|
||||
import Mouse from './Mouse'
|
||||
import Organize from './Organize'
|
||||
|
@ -32,7 +31,6 @@ import Visualize from './Visualize'
|
|||
|
||||
const Metamaps = window.Metamaps || {}
|
||||
Metamaps.Active = Active
|
||||
Metamaps.Admin = Admin
|
||||
Metamaps.AutoLayout = AutoLayout
|
||||
Metamaps.Cable = Cable
|
||||
Metamaps.Control = Control
|
||||
|
@ -52,7 +50,6 @@ Metamaps.JIT = JIT
|
|||
Metamaps.Listeners = Listeners
|
||||
Metamaps.Loading = Loading
|
||||
Metamaps.Map = Map
|
||||
Metamaps.Map.CheatSheet = CheatSheet
|
||||
Metamaps.Map.InfoBox = InfoBox
|
||||
Metamaps.Maps = {}
|
||||
Metamaps.Mapper = Mapper
|
||||
|
@ -87,9 +84,13 @@ function runInitFunctions(serverData) {
|
|||
document.addEventListener('DOMContentLoaded', async function() {
|
||||
Metamaps.ServerData = Metamaps.ServerData || {}
|
||||
try {
|
||||
// TODO: do these in parallel (Promise.all)
|
||||
const metacodes = await DataFetcher.getMetacodes()
|
||||
Metamaps.ServerData.Metacodes = metacodes
|
||||
|
||||
const metacodeSets = await DataFetcher.getMetacodeSets()
|
||||
Metamaps.ServerData.metacodeSets = metacodeSets
|
||||
|
||||
const activeMapper = await DataFetcher.getCurrentUser()
|
||||
if (activeMapper) {
|
||||
Metamaps.ServerData.ActiveMapper = activeMapper
|
||||
|
|
64
src/components/LightBoxes/About.js
Normal file
64
src/components/LightBoxes/About.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
import React, { Component } from 'react'
|
||||
|
||||
class About extends Component {
|
||||
render = () => {
|
||||
return (
|
||||
<div className="lightboxContent" id="about">
|
||||
<h3>About Metamaps.cc</h3>
|
||||
<div id="aboutParms">
|
||||
<div id="leftAboutParms">
|
||||
<p>STATUS: </p>
|
||||
<p>VERSION: </p>
|
||||
<p>BUILD: </p>
|
||||
<p>LAST UPDATE: </p>
|
||||
</div>
|
||||
<div id="rightAboutParms">
|
||||
<p>PRIVATE BETA</p>
|
||||
<p></p>
|
||||
<p></p>
|
||||
<p></p>
|
||||
</div>
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
<p>Metamaps.cc is a free and open source web platform that supports real-time sense-making and distributed collaboration between individuals, communities and organizations.</p>
|
||||
<p>Using an intuitive graph-based interface, Metamaps.cc helps map out networks of people, ideas, resources, stories, experiences, conversations and much more. The platform is evolving for a range of applications amidst a growing network of designers, developers, facilitators, practitioners, entrepreneurs, and artists.</p>
|
||||
<p>Metamaps.cc is created and maintained by a distributed community of contributors passionate about the evolution of collaboration, alternative forms of value creation and increase of collective intelligence through the lens of the open culture and the peer-to-peer revolution.</p>
|
||||
<ul className="lightbox_links">
|
||||
<li>
|
||||
<a className="icon_twitter" href="https://twitter.com/metamapps" target="_blank">
|
||||
<div className="lightboxAboutIcon"></div>
|
||||
@metamapps
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a className="icon_community" href="https://www.hylo.com/c/metamaps/join/mice-late-hit-two-shown" target="_blank">
|
||||
<div className="lightboxAboutIcon"></div>
|
||||
community
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a className="icon_source_code" href="https://github.com/metamaps/metamaps" target="_blank">
|
||||
<div className="lightboxAboutIcon"></div>
|
||||
source code
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a className="icon_howtos" href="https://docs.metamaps.cc" target="_blank">
|
||||
<div className="lightboxAboutIcon"></div>
|
||||
howtos
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a className="icon_terms" href="https://metamaps.cc/maps/331" target="_blank">
|
||||
<div className="lightboxAboutIcon"></div>
|
||||
terms
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default About
|
163
src/components/LightBoxes/CheatSheet.js
Normal file
163
src/components/LightBoxes/CheatSheet.js
Normal file
|
@ -0,0 +1,163 @@
|
|||
import React, { Component } from 'react'
|
||||
|
||||
class CheatSheet extends Component {
|
||||
render = () => {
|
||||
return (
|
||||
<div className="lightboxContent" id="cheatsheet">
|
||||
<h3>HELP</h3>
|
||||
<div id="cheatSheet">
|
||||
<ul id="helpWrapper">
|
||||
<li><a href="#quickReference">QUICK REFERENCE</a></li>
|
||||
<li><a href="#tutorials">TUTORIAL</a></li>
|
||||
<li><a href="#moreResources">MORE RESOURCES</a></li>
|
||||
</ul>
|
||||
<div id="quickReference">
|
||||
<ul>
|
||||
<li><a href="#csCreatingTopics">Creating Topics</a></li>
|
||||
<li><a href="#csEditingTopics">Editing Topics</a></li>
|
||||
<li><a href="#csCreatingSynapses">Creating Synapses</a></li>
|
||||
<li><a href="#csEditingSynapses">Editing Synapses</a></li>
|
||||
<li><a href="#csNavigation">Navigation</a></li>
|
||||
<li><a href="#csSelection">Selection</a></li>
|
||||
<li><a href="#csSearch">Search</a></li>
|
||||
<li><a href="#csTopicView">Topic View</a></li>
|
||||
<li><a href="#csKeyboardShortcuts">Keyboard Shortcuts</a></li>
|
||||
</ul>
|
||||
<div id="csTopicView">
|
||||
<div className="csItem"><span className="csTitle">Enter Topic (radial) View:</span> Click on a Topic result from Search, or click the synapse <img src="/images/synapse16.png" width="16" /> icon inside open Topic Card on map</div>
|
||||
<div className="csItem"><span className="csTitle">Recenter Topics around chosen Topic:</span> Alt + click on the topic OR Alt + E</div>
|
||||
<div className="csItem"><span className="csTitle">Reveal the siblings for a Topic:</span> Right-click and choose 'Reveal siblings' OR Alt + R</div>
|
||||
<div className="csItem"><span className="csTitle">Center topic and reveal siblings:</span> Alt + T</div>
|
||||
<div className="csItem"><span className="csTitle">Filter out visible Topics:</span> Open Filter menu *** and toggle off/on</div>
|
||||
</div>
|
||||
<div id="csCreatingTopics">
|
||||
<div className="csItem"><span className="csTitle">Double-click on canvas:</span> Bring up the metacode spinner</div>
|
||||
<div className="csItem indented"><span className="csTitle">Scroll:</span> change metacode spinner selection</div>
|
||||
<div className="csItem indented"><span className="csTitle">Tab:</span> rotate spinner counter-clockwise</div>
|
||||
<div className="csItem indented"><span className="csTitle">Shift + tab:</span> rotate spinner clockwise</div>
|
||||
<div className="csItem indented"><span className="csTitle">Esc:</span> Hides auto-suggestion results</div>
|
||||
<div className="csItem indented"><span className="csTitle">Enter:</span> create a new topic</div>
|
||||
<div className="csItem indented"><span className="csTitle">Gear Icon:</span> open up metacode settings</div>
|
||||
<div className="csItem"><br /><a href="https://docs.metamaps.cc/creating_topics.html" target="_blank">Learn More</a></div>
|
||||
</div>
|
||||
<div id="csEditingTopics">
|
||||
<div className="csItem">
|
||||
<span className="csTitle">Open Topic card:</span> Double-click on topic icon
|
||||
</div>
|
||||
<div className="csItem indented">
|
||||
<span className="csTitle">Move Topic card:</span> Click and drag on topic card metacode
|
||||
</div>
|
||||
<div className="csItem indented">
|
||||
<span className="csTitle">Change metacode:</span> Mouse over metacode icon, then click on solid colored bar for metacode menu
|
||||
</div>
|
||||
<div className="csItem indented">
|
||||
<span className="csTitle">Edit Topic title, description, link:</span> Click on text in respective area (click small "X" to reset link)
|
||||
</div>
|
||||
<div className="csItem indented">
|
||||
<span className="csTitle">Save Topic title, description, link:</span> Hit enter, or click away
|
||||
</div>
|
||||
<div className="csItem indented">
|
||||
<span className="csTitle">Change Topic permission:</span> Click on 'Permission' icon (only for topic creator)
|
||||
</div>
|
||||
<div className="csItem indented">
|
||||
<span className="csTitle">Open Topic view:</span> Click on <img src="/images/synapse16.png" width="16" /> icon within topic card bar
|
||||
</div>
|
||||
<div className="csItem indented">
|
||||
<span className="csTitle">Close Topic card:</span> Click on canvas
|
||||
</div>
|
||||
<div className="csItem">
|
||||
<span className="csTitle">Open 'Context Menu':</span> Right-click/alt+click on topic icon or synapse or selection (multiple) to Hide/Remove/Delete, change metacode or permission
|
||||
</div>
|
||||
<div className="csItem"><br /><a href="https://docs.metamaps.cc/creating_topics.html" target="_blank">Learn More</a></div>
|
||||
</div>
|
||||
<div id="csCreatingSynapses">
|
||||
<div className="csItem"><span className="csTitle">Open 'Create Synapse' prompt:</span> Right-click & drag from one topic to another</div>
|
||||
<div className="csItem indented"><span className="csTitle">Enter a label</span> Begin typing (or leave blank)</div>
|
||||
<div className="csItem indented"><span className="csTitle">Confirm new Synapse:</span> Enter or Tab</div>
|
||||
<div className="csItem indented"><span className="csTitle">Cancel new Synapse:</span> Escape or Delete</div>
|
||||
<div className="csItem"><span className="csTitle">Create new Topic with Synapse:</span> Right-click + drag from existing topic to open canvas</div>
|
||||
<div className="csItem indented"><span className="csTitle">Create Topic:</span> Same as elsewhere</div>
|
||||
<div className="csItem indented"><span className="csTitle">Create Synapse:</span> Same as above</div>
|
||||
<div className="csItem"><br /><a href="https://docs.metamaps.cc/creating_synapses.html" target="_blank">Learn More</a></div>
|
||||
</div>
|
||||
<div id="csEditingSynapses">
|
||||
<div className="csItem"><span className="csTitle">Open Synapse card:</span> Double-click on Synapse </div>
|
||||
<div className="csItem indented"><span className="csTitle">Edit Synapse description:</span> Click on current description text</div>
|
||||
<div className="csItem indented"><span className="csTitle">Save Synapse description:</span> Hit enter</div>
|
||||
<div className="csItem indented"><span className="csTitle">Edit directionality:</span> Select appropriate arrow boxes</div>
|
||||
<div className="csItem indented"><span className="csTitle">Change synapse permission:</span> Click on 'permission' icon (only for synapse creator)</div>
|
||||
<div className="csItem indented"><span className="csTitle">Browse / select from multiple (stacked) synapses:</span> Click dropdown icon and select desired synapse</div>
|
||||
<div className="csItem"><span className="csTitle">Open 'Context Menu':</span> Right-click/alt-click on Synapse</div>
|
||||
<div className="csItem indented">*Hide/Remove/Delete synapse within context menu</div>
|
||||
<div className="csItem"><br /><a href="https://docs.metamaps.cc/creating_synapses.html" target="_blank">Learn More</a></div>
|
||||
</div>
|
||||
<div id="csNavigation">
|
||||
<div className="csItem"><span className="csTitle">Move around Canvas:</span> Click and drag</div>
|
||||
<div className="csItem indented"><span className="csTitle">Zoom in/out:</span> Scroll OR click on <div id="zoomIn"> </div> & <div id="zoomOut"> </div></div>
|
||||
<div className="csItem indented"><span className="csTitle">Zoom to see all:</span> Click <div id="centerMap"></div> OR Ctrl + E</div>
|
||||
<div className="csItem"><span className="csTitle">Filter Map Contents:</span> Open the Filter Menu *** and toggle items off/on</div>
|
||||
<div className="csItem"><span className="csTitle">Return to 'Explore Maps' (home) page:</span> Click the Metamaps logo in the upper left corner</div>
|
||||
<div className="csItem"><br /><a href="https://docs.metamaps.cc/exploring_maps.html" target="_blank">Learn More</a></div>
|
||||
</div>
|
||||
<div id="csSelection">
|
||||
<div className="csItem"><span className="csTitle">Select/Deselect Topic:</span> Click on topic icon</div>
|
||||
<div className="csItem"><span className="csTitle">Select/Deselect Synapse:</span> Click on synapse</div>
|
||||
<div className="csItem"><span className="csTitle">Select multiple Topics/Synapses:</span> Shift + click to include each</div>
|
||||
<div className="csItem"><span className="csTitle">Select multiple with Selection Box:</span> Right-click/Shift-click + drag on Canvas</div>
|
||||
<div className="csItem"><span className="csTitle">Move all selected Topics & Synapses:</span> Click + drag on selected topic(s)/synapse(s)</div>
|
||||
<div className="csItem"><span className="csTitle">Open 'Context Menu':</span> Right-click/Alt-click on selected topic(s)</div>
|
||||
<div className="csItem indented">*Hide/Remove/Delete/Change permissions of multiple topics & synapses within context menu</div>
|
||||
<div className="csItem"><span className="csTitle">Zoom to selection box</span> Ctrl-click + drag</div>
|
||||
<div className="csItem"><span className="csTitle">Deselect all topics & Synapses:</span> Click on background or Esc</div>
|
||||
</div>
|
||||
<div id="csSearch">
|
||||
<div className="csItem"><span className="csTitle">Search for Topics and Maps:</span> Type query terms into search bar, wait for results below</div>
|
||||
<div className="csItem"><span className="csTitle">Limit search results:</span> Click checkbox for only items you created; click arrow above Topics or Maps section to collapse</div>
|
||||
<div className="csItem"><span className="csTitle">Add Topic to current Map:</span> Click "+" on a topic result</div>
|
||||
<div className="csItem"><span className="csTitle">Jump to Topic View:</span> Click anywhere else on a topic result</div>
|
||||
<div className="csItem"><span className="csTitle">Search by metacode:</span> type "[name of metacode]:", then your search query. i.e. idea:create...</div>
|
||||
<div className="csItem"><span className="csTitle">Search for map:</span> type "map:", then your search query. i.e. map:exploring...</div>
|
||||
<div className="csItem"><span className="csTitle">Search for mapper:</span> type "mapper:", then your search query. i.e. mapper:Robert</div>
|
||||
</div>
|
||||
<div id="csKeyboardShortcuts">
|
||||
<div className="csItem"><span className="csTitle">Ctrl + /:</span> Open 'Search' prompt</div>
|
||||
<div className="csItem"><span className="csTitle">Ctrl + H:</span> Hide selection on map</div>
|
||||
<div className="csItem"><span className="csTitle">Ctrl + M:</span> Remove selection from map</div>
|
||||
<div className="csItem"><span className="csTitle">Ctrl + D:</span> Delete selection</div>
|
||||
<div className="csItem"><span className="csTitle">Ctrl + A:</span> Select all topics</div>
|
||||
<div className="csItem"><span className="csTitle">Ctrl + E:</span> See all on map (zoom to extents)</div>
|
||||
<div className="csItem"><span className="csTitle">Esc (while in search):</span> Close search</div>
|
||||
<div className="csItem"><span className="csTitle">Esc (with selection):</span> Deselect all</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tutorials">
|
||||
<iframe id="tutorialVideo" src="//player.vimeo.com/video/88334167" width="552" height="320" frameBorder="0" allowFullScreen></iframe>
|
||||
</div>
|
||||
<div id="moreResources">
|
||||
<p>For more information about Metamaps.cc, visit our Knowledge Base or skip directly to a section by clicking on one of the categories below.</p>
|
||||
<div className="resourcesColumnOne resourcesColumn">
|
||||
<a href="https://hylo.com/c/metamaps" target="_blank" className="button">Hylo User Community</a>
|
||||
<ul>
|
||||
<li><a href="https://docs.metamaps.cc/getting_started.html" target="_blank">Getting Started</a></li>
|
||||
<li><a href="https://docs.metamaps.cc/best_practices.html" target="_blank">Best Practices</a></li>
|
||||
<li><a href="https://docs.metamaps.cc/applications_and_use_cases.html" target="_blank">Applications & Use Cases</a></li>
|
||||
<li><a href="https://docs.metamaps.cc/advanced_features.html" target="_blank">Advanced Features</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="resourcesColumnTwo resourcesColumn">
|
||||
<a href="https://docs.metamaps.cc" target="_blank" className="button">KNOWLEDGE BASE</a>
|
||||
<ul>
|
||||
<li><a href="https://docs.metamaps.cc/general_questions.html" target="_blank">General Questions</a></li>
|
||||
<li><a href="https://docs.metamaps.cc/project_organization_and_governance.html" target="_blank">Organization & Governance</a></li>
|
||||
<li><a href="https://docs.metamaps.cc/realtime_collaboration_junto.html" target="_blank">Realtime Collaboration</a></li>
|
||||
<li><a href="https://docs.metamaps.cc/importing_and_exporting_data.html" target="_blank">Importing and Exporting Data</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default CheatSheet
|
66
src/components/LightBoxes/ForkMap.js
Normal file
66
src/components/LightBoxes/ForkMap.js
Normal file
|
@ -0,0 +1,66 @@
|
|||
import React, { Component } from 'react'
|
||||
|
||||
class ForkMap extends Component {
|
||||
render = () => {
|
||||
return (
|
||||
<div className="lightboxContent" id="forkmap">
|
||||
<div className="onConsole">
|
||||
<form className="new_map" id="fork_map" action="/maps" acceptCharset="UTF-8" data-remote="true" method="post">
|
||||
<input name="utf8" type="hidden" value="✓" />
|
||||
<h3 className="forCreateMap">Save To New Map</h3>
|
||||
<div className="inputGroup">
|
||||
<label htmlFor="map_name">Name: </label>
|
||||
<input maxLength="140" size="140" type="text" name="map[name]" id="map_name" />
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
<div className="inputGroup">
|
||||
<label htmlFor="map_desc">Description: </label>
|
||||
<textarea className="description" rows="5" cols="43" name="map[desc]" id="map_desc"></textarea>
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
<div className="inputGroup">
|
||||
<label htmlFor="map_permission">Permission*: </label>
|
||||
<p className="permHelper">*new topics and synapses take on the same permission as the map they are created on</p>
|
||||
<div className="permIconWrapper">
|
||||
<div className="permIcon" data-permission="commons">
|
||||
<div id="newmap_co" className="mapCommonsIcon mapPermIcon selected">
|
||||
<div className="tip">
|
||||
Anyone with an account can edit this map. Anyone without an account can only view it.
|
||||
</div>
|
||||
</div>
|
||||
<h4>COMMONS</h4>
|
||||
</div>
|
||||
<div className="permIcon" data-permission="public">
|
||||
<div id="newmap_pu" className="mapPublicIcon mapPermIcon">
|
||||
<div className="tip">
|
||||
Only people you allow can edit this map. Anyone can view it.
|
||||
</div>
|
||||
</div>
|
||||
<h4>PUBLIC</h4>
|
||||
</div>
|
||||
<div className="permIcon" data-permission="private">
|
||||
<div id="newmap_pr" className="mapPrivateIcon mapPermIcon">
|
||||
<div className="tip">
|
||||
Only people you allow can edit this map. No one else can view it.
|
||||
</div>
|
||||
</div>
|
||||
<h4>PRIVATE</h4>
|
||||
</div>
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
<p className="permText">Anyone with an account can edit this map. Anyone without an account can only view it.</p>
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
<div className="buttonWrapper">
|
||||
<button className="button cancel">Cancel</button>
|
||||
<button className="button submitMap">Create!</button>
|
||||
</div>
|
||||
<div className="clearfloat"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default ForkMap
|
46
src/components/LightBoxes/ImportDialogBox.js
Normal file
46
src/components/LightBoxes/ImportDialogBox.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Dropzone from 'react-dropzone'
|
||||
|
||||
class ImportDialogBox extends Component {
|
||||
handleFile = (files, e) => {
|
||||
e.preventDefault() // prevent it from triggering the default drag-drop handler
|
||||
this.props.onFileAdded(files[0])
|
||||
}
|
||||
|
||||
render = () => {
|
||||
return (
|
||||
<div className="lightboxContent" id="import-dialog">
|
||||
<div className="importDialogWrapper">
|
||||
<div className="import-dialog">
|
||||
<h3>EXPORT</h3>
|
||||
<div className="export-csv import-blue-button" onClick={this.props.onExport('csv')}>
|
||||
Export as CSV
|
||||
</div>
|
||||
<div className="export-json import-blue-button" onClick={this.props.onExport('json')}>
|
||||
Export as JSON
|
||||
</div>
|
||||
<div className="download-screenshot import-blue-button" onClick={this.props.downloadScreenshot}>
|
||||
Download screenshot
|
||||
</div>
|
||||
<h3>IMPORT</h3>
|
||||
<p>To upload a file, drop it here:</p>
|
||||
<Dropzone onDropAccepted={this.handleFile}
|
||||
className="fileupload">
|
||||
Drop files here!
|
||||
</Dropzone>
|
||||
<p>See <a href="https://docs.metamaps.cc/importing_and_exporting_data.html">docs.metamaps.cc</a> for instructions.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ImportDialogBox.propTypes = {
|
||||
onFileAdded: PropTypes.func,
|
||||
downloadScreenshot: PropTypes.func,
|
||||
onExport: PropTypes.func
|
||||
}
|
||||
|
||||
export default ImportDialogBox
|
56
src/components/LightBoxes/Invite.js
Normal file
56
src/components/LightBoxes/Invite.js
Normal file
|
@ -0,0 +1,56 @@
|
|||
import React, { Component } from 'react'
|
||||
import clipboard from 'clipboard-js'
|
||||
|
||||
class Invite extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
copied: false,
|
||||
unable: false
|
||||
}
|
||||
}
|
||||
|
||||
inviteLink = () => {
|
||||
const { host, protocol } = window ? window.location : {}
|
||||
const inviteLink = `${protocol}//${host}/join?code=${this.props.inviteCode}`
|
||||
return inviteLink
|
||||
}
|
||||
|
||||
shareInvite = () => {
|
||||
const inviteLink = this.inviteLink()
|
||||
clipboard.copy({
|
||||
'text/plain': inviteLink
|
||||
}).then(() => {
|
||||
this.setState({ copied: true })
|
||||
window.setTimeout(() => this.setState({ copied: false }), 1500)
|
||||
}, () => {
|
||||
this.setState({ unable: true })
|
||||
window.setTimeout(() => this.setState({ unable: false }), 1500)
|
||||
})
|
||||
}
|
||||
|
||||
render = () => {
|
||||
const inviteLink = this.inviteLink()
|
||||
return (
|
||||
<div className="lightboxContent" id="invite">
|
||||
<h3>SHARE INVITE</h3>
|
||||
<div className="leaveSpace"></div>
|
||||
<p>The Metamaps platform is currently in an invite-only beta with the express purpose of creating a high value knowledge ecosystem, a diverse community of contributors and a culture of collaboration and curiosity.</p>
|
||||
<p>As a valued beta tester, you have the ability to invite your peers, colleagues and collaborators onto the platform.</p>
|
||||
<p>Below is a personal invite link containing your unique access code, which can be used multiple times.</p>
|
||||
<div id="joinCodesBox">
|
||||
<p className="joinCodes">
|
||||
{inviteLink}
|
||||
<button className="button" onClick={this.shareInvite}>COPY INVITE LINK!</button>
|
||||
</p>
|
||||
<p className="popup" style={{textAlign: 'center'}}>
|
||||
{this.state.copied && 'Copied!'}
|
||||
{this.state.unable && "Your browser doesn't support copying, please copy manually."}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Invite
|
22
src/components/LightBoxes/NoIE.js
Normal file
22
src/components/LightBoxes/NoIE.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
import React, { Component } from 'react'
|
||||
|
||||
class NoIE extends Component {
|
||||
render = () => {
|
||||
return (
|
||||
<div className="lightboxContent" id="noIE">
|
||||
<h3>OOPS! <br /> YOUR BROWSER IS NOT SUPPORTED.</h3>
|
||||
<p id="noIEsubheading">To view this experience, please upgrade to the latest one of these browsers:</p>
|
||||
<a id="chromeIcon" href="https://www.google.com/chrome/browser/" target="_blank">Chrome</a>
|
||||
<a id="fireFoxIcon" href="https://www.mozilla.org/en-US/firefox/new/" target="_blank">Firefox</a>
|
||||
<a id="safariIcon" href="http://support.apple.com/downloads/#safari" target="_blank">Safari</a>
|
||||
<p id="noIEbody">
|
||||
While it's downloading, explore our <a href="http://blog.metamaps.cc/">blog</a>,<br />
|
||||
watch the <a href="http://vimeo.com/88334167">tutorials</a>,
|
||||
or visit our <a href="https://docs.metamaps.cc">knowledge base</a>!
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default NoIE
|
12
src/components/LightBoxes/SwitchMetacodes.js
Normal file
12
src/components/LightBoxes/SwitchMetacodes.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
import React, { Component } from 'react'
|
||||
|
||||
class SwitchMetacodes extends Component {
|
||||
render = () => {
|
||||
return (
|
||||
<div className="lightboxContent" id="switchMetacodes">
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default SwitchMetacodes
|
14
src/components/LightBoxes/Tutorial.js
Normal file
14
src/components/LightBoxes/Tutorial.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
import React, { Component } from 'react'
|
||||
|
||||
class Tutorial extends Component {
|
||||
render = () => {
|
||||
return (
|
||||
<div className="lightboxContent" id="tutorial">
|
||||
<h3>Tutorial</h3>
|
||||
<iframe src="//player.vimeo.com/video/88334167?title=0&byline=0&portrait=0" width="510" height="319" frameBorder="0" allowFullScreen></iframe>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Tutorial
|
40
src/components/LightBoxes/index.js
Normal file
40
src/components/LightBoxes/index.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
import React, { Component } from 'react'
|
||||
|
||||
import About from './About'
|
||||
import CheatSheet from './CheatSheet'
|
||||
import ForkMap from './ForkMap'
|
||||
import ImportDialogBox from './ImportDialogBox'
|
||||
import Invite from './Invite'
|
||||
import NoIE from './NoIE'
|
||||
import SwitchMetacodes from './SwitchMetacodes'
|
||||
import Tutorial from './Tutorial'
|
||||
|
||||
class LightBoxes extends Component {
|
||||
render = () => {
|
||||
const importProps = {
|
||||
onFileAdded: this.props.importHandleFile,
|
||||
downloadScreenshot: this.props.downloadScreenshot,
|
||||
onExport: this.props.onExport
|
||||
}
|
||||
return (
|
||||
<div id="lightbox_overlay">
|
||||
<div id="lightbox_main">
|
||||
<a id="lightbox_close" href="#"></a>
|
||||
<div id="lightbox_content">
|
||||
<About />
|
||||
<CheatSheet />
|
||||
<ForkMap />
|
||||
<ImportDialogBox {...importProps} />
|
||||
<Invite inviteCode={this.props.inviteCode} />
|
||||
<NoIE />
|
||||
<SwitchMetacodes />
|
||||
<Tutorial />
|
||||
</div>
|
||||
</div>
|
||||
<div id="lightbox_screen" style={{height: '100%'}}></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default LightBoxes
|
|
@ -44,11 +44,11 @@ class MobileHeader extends Component {
|
|||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/maps/new">
|
||||
<Link to="/maps/new">
|
||||
<Sprite src={serverData['map_control_sprite.png']}
|
||||
width={32} height={32} xIndex={4} yIndex={0} />
|
||||
New Map
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/explore/mine">
|
||||
|
@ -79,34 +79,34 @@ class MobileHeader extends Component {
|
|||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<a href={`/users/${currentUser.id}/edit`}>
|
||||
<Link to={`/users/${currentUser.id}/edit`}>
|
||||
<Sprite src={serverData['user_sprite.png']}
|
||||
width={32} height={32} xIndex={0} yIndex={0} />
|
||||
Account
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
<li className="notifications">
|
||||
<a href="/notifications">
|
||||
<Link to="/notifications">
|
||||
<Sprite src={serverData['map_control_sprite.png']}
|
||||
width={32} height={32} xIndex={0} yIndex={0} />
|
||||
Notifications
|
||||
</a>
|
||||
</Link>
|
||||
{unreadNotificationsCount > 0 && <div className="unread-notifications-dot"></div>}
|
||||
</li>
|
||||
<li>
|
||||
<a id="Logout" href="/logout">
|
||||
<Link id="Logout" to="/logout">
|
||||
<Sprite src={serverData['user_sprite.png']}
|
||||
width={32} height={32} xIndex={0} yIndex={3} />
|
||||
Sign Out
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
</ul>}
|
||||
{!currentUser && <ul onClick={this.toggle}>
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><Link to="/">Home</Link></li>
|
||||
<li><Link to="/explore/active">All Maps</Link></li>
|
||||
<li><Link to="/explore/featured">Featured Maps</Link></li>
|
||||
<li><a href="/request">Request Invite</a></li>
|
||||
<li><a href="/login">Login</a></li>
|
||||
<li><Link to="/request">Request Invite</Link></li>
|
||||
<li><Link to="/login">Login</Link></li>
|
||||
</ul>}
|
||||
</div>}
|
||||
</div>
|
||||
|
|
18
src/components/NewSynapse.js
Normal file
18
src/components/NewSynapse.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
import React, { Component } from 'react'
|
||||
|
||||
class NewSynapse extends Component {
|
||||
componentDidMount() {
|
||||
this.props.initNewSynapse()
|
||||
}
|
||||
|
||||
render = () => {
|
||||
return (
|
||||
<form className="new_synapse" id="new_synapse" action="/synapses" acceptCharset="UTF-8" data-remote="true" method="post">
|
||||
<input name="utf8" type="hidden" value="✓" />
|
||||
<input placeholder="describe the connection..." type="text" name="synapse[desc]" id="synapse_desc" className="tt-input" autoComplete="off" spellCheck="false" dir="auto" />
|
||||
</form>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default NewSynapse
|
54
src/components/NewTopic.js
Normal file
54
src/components/NewTopic.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
import React, { Component } from 'react'
|
||||
|
||||
class NewTopic extends Component {
|
||||
componentDidMount() {
|
||||
this.props.initNewTopic()
|
||||
}
|
||||
|
||||
render = () => {
|
||||
const metacodes = [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Action",
|
||||
"created_at": "2017-03-04T17:33:07.394Z",
|
||||
"updated_at": "2017-03-04T17:33:07.394Z",
|
||||
"color": "#BD6C85",
|
||||
"icon": "https://s3.amazonaws.com/metamaps-assets/metacodes/blueprint/96px/bp_action.png"
|
||||
}
|
||||
]
|
||||
return (
|
||||
<form className="new_topic" id="new_topic" action="/topics" acceptCharset="UTF-8" data-remote="true" method="post">
|
||||
<input name="utf8" type="hidden" value="✓" />
|
||||
<div className="openMetacodeSwitcher" onClick={() => this.props.openMetacodeSwitcher()}>
|
||||
<div className="tooltipsAbove">Switch Metacodes</div>
|
||||
</div>
|
||||
|
||||
<div className="pinCarousel">
|
||||
<div className="tooltipsAbove helpPin">Pin Open</div>
|
||||
<div className="tooltipsAbove helpUnpin">Unpin</div>
|
||||
</div>
|
||||
|
||||
<div id="metacodeImg">
|
||||
{metacodes.map(m => <img key={m.id} className="cloudcarousel" width="40" height="40" src={m.icon} alt={m.name} title={m.name} data-id={m.id} />)}
|
||||
</div>
|
||||
|
||||
<input maxLength="140" placeholder="title..." size="140" type="text" name="topic[name]" id="topic_name" className="tt-input" autoComplete="off" spellCheck="false" dir="auto" />
|
||||
|
||||
<div id="metacodeImgTitle"></div>
|
||||
<div className="clearfloat"></div>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default NewTopic
|
||||
|
||||
/*
|
||||
TODO:
|
||||
{ @metacodes.each do |metacode| }
|
||||
Metamaps.Create.selectedMetacodes.push("{ metacode.id }");
|
||||
Metamaps.Create.newSelectedMetacodes.push("{ metacode.id }");
|
||||
Metamaps.Create.selectedMetacodeNames.push("{ metacode.name }");
|
||||
Metamaps.Create.newSelectedMetacodeNames.push("{ metacode.name }");
|
||||
{ end }
|
||||
*/
|
|
@ -61,11 +61,11 @@ class NotificationBox extends Component {
|
|||
}
|
||||
|
||||
render = () => {
|
||||
const { loading } = this.props
|
||||
const { notifications, loading } = this.props
|
||||
return <div className='notificationsBox'>
|
||||
<div className='notificationsBoxTriangle' />
|
||||
<ul className='notifications'>
|
||||
{loading ? this.showLoading() : this.showNotifications()}
|
||||
{notifications.length === 0 && loading ? this.showLoading() : this.showNotifications()}
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React, { Component } from 'react'
|
||||
import NavBar from '../components/NavBar'
|
||||
import NavBarLink from '../components/NavBarLink'
|
||||
import NavBar from '../../components/NavBar'
|
||||
import NavBarLink from '../../components/NavBarLink'
|
||||
|
||||
class Admin extends Component {
|
||||
class AdminHeader extends Component {
|
||||
render = () => {
|
||||
return (
|
||||
<NavBar>
|
||||
|
@ -15,4 +15,4 @@ class Admin extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default Admin
|
||||
export default AdminHeader
|
98
src/routes/Admin/EditMetacode.js
Normal file
98
src/routes/Admin/EditMetacode.js
Normal file
|
@ -0,0 +1,98 @@
|
|||
import React, { Component } from 'react'
|
||||
import { Link, browserHistory } from 'react-router'
|
||||
import AdminHeader from './AdminHeader'
|
||||
|
||||
class EditMetacode extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
existingIcon: null,
|
||||
icon: null,
|
||||
name: '',
|
||||
color: ''
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { metacodes } = this.props
|
||||
const id = parseInt(this.props.params.id, 10)
|
||||
const metacode = metacodes.find(m => m.id === id)
|
||||
this.setState({
|
||||
existingIcon: metacode.icon,
|
||||
name: metacode.name,
|
||||
color: metacode.color
|
||||
})
|
||||
}
|
||||
|
||||
validate = (event) => {
|
||||
if (this.state.name.length === 0) {
|
||||
event.preventDefault()
|
||||
window.alert('A name must be provided')
|
||||
} else if (!this.state.color.startsWith('#')) {
|
||||
event.preventDefault()
|
||||
window.alert('Please begin color with a # symbol')
|
||||
}
|
||||
}
|
||||
|
||||
updateForKey = (key) => event => this.setState({[key]: event.target.value})
|
||||
|
||||
handleFile = (event) => {
|
||||
this.setState({
|
||||
icon: event.target.files[0]
|
||||
})
|
||||
}
|
||||
|
||||
onSubmit = async (event) => {
|
||||
event.preventDefault()
|
||||
const { name, color, icon } = this.state
|
||||
const { updateMetacode, params: { id } } = this.props
|
||||
try {
|
||||
const result = await updateMetacode(id, name, color, icon)
|
||||
browserHistory.push(`/metacodes`)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
window.alert('There was an error updating the metacode, check the console')
|
||||
}
|
||||
}
|
||||
|
||||
render = () => {
|
||||
return (
|
||||
<div>
|
||||
<div id="yield">
|
||||
<div className="centerContent">
|
||||
<form onSubmit={this.onSubmit} className="edit_metacode" id="edit_metacode" encType="multipart/form-data" acceptCharset="UTF-8">
|
||||
<input name="utf8" type="hidden" value="✓" />
|
||||
<div className="field">
|
||||
<label htmlFor="metacode_name">Name</label>
|
||||
<input value={this.state.name} onChange={this.updateForKey('name')} type="text" name="metacode[name]" id="metacode_name" />
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
<div className="field">
|
||||
<label>Current Icon</label>
|
||||
<img width="96" src={this.state.existingIcon} alt={this.state.name} />
|
||||
</div>
|
||||
<div className="field">
|
||||
<label htmlFor="metacode_Icon">Replace Icon</label>
|
||||
<input type="hidden" name="metacode[manual_icon]" id="metacode_manual_icon" />
|
||||
<input onChange={this.handleFile} type="file" name="metacode[aws_icon]" id="metacode_aws_icon" />
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
<div className="field">
|
||||
<label htmlFor="metacode_color">Color (hex with # sign)</label>
|
||||
<input value={this.state.color} onChange={this.updateForKey('color')} type="text" name="metacode[color]" id="metacode_color" />
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
<div className="actions">
|
||||
<Link className="button" to="/metacodes">Cancel</Link>
|
||||
<input onClick={this.validate} type="submit" name="commit" value="Update Metacode" className="add" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<AdminHeader />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default EditMetacode
|
41
src/routes/Admin/EditMetacodeSet.js
Normal file
41
src/routes/Admin/EditMetacodeSet.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
import React, { Component } from 'react'
|
||||
import { browserHistory } from 'react-router'
|
||||
|
||||
import AdminHeader from './AdminHeader'
|
||||
import MetacodeSetEditor from './MetacodeSetEditor'
|
||||
|
||||
/*
|
||||
TODO:
|
||||
get the data actually updating after the network response
|
||||
*/
|
||||
|
||||
class EditMetacodeSet extends Component {
|
||||
onSubmit = async (metacodes, name, desc) => {
|
||||
const { updateMetacodeSet, params: { id } } = this.props
|
||||
try {
|
||||
const result = await updateMetacodeSet(id, metacodes, name, desc)
|
||||
browserHistory.push(`/metacode_sets`)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
window.alert('There was an error updating the metacode set')
|
||||
}
|
||||
}
|
||||
|
||||
render = () => {
|
||||
const { metacodeSets, metacodes } = this.props
|
||||
const id = parseInt(this.props.params.id, 10)
|
||||
const metacodeSet = metacodeSets.find(m => m.id === id)
|
||||
return (
|
||||
<div>
|
||||
<div id="yield">
|
||||
<div className="centerContent">
|
||||
<MetacodeSetEditor metacodeSet={metacodeSet} metacodes={metacodes} onSubmit={this.onSubmit} forEdit />
|
||||
</div>
|
||||
</div>
|
||||
<AdminHeader />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default EditMetacodeSet
|
135
src/routes/Admin/MetacodeSetEditor.js
Normal file
135
src/routes/Admin/MetacodeSetEditor.js
Normal file
|
@ -0,0 +1,135 @@
|
|||
import React, { Component } from 'react'
|
||||
import { Link } from 'react-router'
|
||||
|
||||
class MetacodeSetEditor extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
selectMetacodes: [],
|
||||
name: '',
|
||||
desc: ''
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { forEdit, metacodeSet } = this.props
|
||||
if (forEdit) {
|
||||
this.setState({
|
||||
selectMetacodes: metacodeSet.metacodes,
|
||||
name: metacodeSet.name,
|
||||
desc: metacodeSet.desc
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
selectAll = () => {
|
||||
this.setState({
|
||||
selectMetacodes: this.props.metacodes.map(m => m.id)
|
||||
})
|
||||
}
|
||||
|
||||
deselectAll = () => {
|
||||
this.setState({ selectMetacodes: [] })
|
||||
}
|
||||
|
||||
liClickHandler = (metacodeId) => {
|
||||
const { selectMetacodes } = this.state
|
||||
if (selectMetacodes.indexOf(metacodeId) > -1) {
|
||||
this.setState({
|
||||
selectMetacodes: selectMetacodes.filter(id => id !== metacodeId)
|
||||
})
|
||||
} else {
|
||||
this.setState({
|
||||
selectMetacodes: selectMetacodes.concat([metacodeId])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
updateForKey = (key) => event => this.setState({[key]: event.target.value})
|
||||
|
||||
validate = (event) => {
|
||||
if (this.state.selectMetacodes.length === 0) {
|
||||
event.preventDefault()
|
||||
window.alert('Please select at least one metacode for the set')
|
||||
} else if (this.state.name.length === 0) {
|
||||
event.preventDefault()
|
||||
window.alert('A name must be provided')
|
||||
}
|
||||
}
|
||||
|
||||
onSubmit = (event) => {
|
||||
event.preventDefault()
|
||||
const { selectMetacodes, name, desc } = this.state
|
||||
this.props.onSubmit(selectMetacodes, name, desc)
|
||||
}
|
||||
|
||||
render = () => {
|
||||
const { selectMetacodes } = this.state
|
||||
const { metacodes, forNew, forEdit } = this.props
|
||||
const { length } = metacodes
|
||||
return (
|
||||
<form className={forNew ? "new_metacode_set" : "edit_metacode_set"} id={forNew ? "new_metacode_set" : "edit_metacode_set"} onSubmit={this.onSubmit} acceptCharset="UTF-8">
|
||||
<input name="utf8" type="hidden" value="✓" />
|
||||
<div className="field">
|
||||
<label htmlFor="metacode_set_name">Name</label>
|
||||
<input value={this.state.name} onChange={this.updateForKey('name')} type="text" name="metacode_set[name]" id="metacode_set_name" />
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
<div className="field">
|
||||
<label htmlFor="metacode_set_desc">Description</label>
|
||||
<textarea value={this.state.desc} onChange={this.updateForKey('desc')} cols="40" rows="4" name="metacode_set[desc]" id="metacode_set_desc" />
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
<br />
|
||||
<p>Choose Metacodes</p>
|
||||
<div className="allMetacodes">
|
||||
<span id="showAll" onClick={this.selectAll}>Select All</span>
|
||||
<span id="hideAll" onClick={this.deselectAll}>Unselect All</span>
|
||||
</div>
|
||||
<div className="clearfloat"></div>
|
||||
<div className="editMetacodes">
|
||||
<ul id="filters-one">
|
||||
{metacodes.filter((m, i) => i < length/4).map((m, i) => {
|
||||
return <MetacodeListItem selected={selectMetacodes.indexOf(m.id) > -1} metacode={m} key={i} onClick={() => this.liClickHandler(m.id)} />
|
||||
})}
|
||||
</ul>
|
||||
<ul id="filters-two">
|
||||
{metacodes.filter((m, i) => i >= length/4 && i < length/4*2).map((m, i) => {
|
||||
return <MetacodeListItem selected={selectMetacodes.indexOf(m.id) > -1} metacode={m} key={i} onClick={() => this.liClickHandler(m.id)} />
|
||||
})}
|
||||
</ul>
|
||||
<ul id="filters-three">
|
||||
{metacodes.filter((m, i) => i >= length/4*2 && i < length/4*3).map((m, i) => {
|
||||
return <MetacodeListItem selected={selectMetacodes.indexOf(m.id) > -1} metacode={m} key={i} onClick={() => this.liClickHandler(m.id)} />
|
||||
})}
|
||||
</ul>
|
||||
<ul id="filters-four">
|
||||
{metacodes.filter((m, i) => i >= length/4*3 && i < length).map((m, i) => {
|
||||
return <MetacodeListItem selected={selectMetacodes.indexOf(m.id) > -1} metacode={m} key={i} onClick={() => this.liClickHandler(m.id)} />
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="clearfloat"></div>
|
||||
<div className="actions">
|
||||
<Link className="button" to="/metacode_sets">Cancel</Link>
|
||||
<input onClick={this.validate} type="submit" name="commit" value={forNew ? "Create Metacode Set" : "Update Metacode Set"} className="add" />
|
||||
</div>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class MetacodeListItem extends Component {
|
||||
render = () => {
|
||||
const { selected, onClick, metacode } = this.props
|
||||
return (
|
||||
<li id={metacode.id} className={selected ? "" : "toggledOff"} onClick={onClick}>
|
||||
<img src={metacode.icon} alt={metacode.name} />
|
||||
<p>{metacode.name.toLowerCase()}</p>
|
||||
<div className="clearfloat"></div>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default MetacodeSetEditor
|
70
src/routes/Admin/MetacodeSets.js
Normal file
70
src/routes/Admin/MetacodeSets.js
Normal file
|
@ -0,0 +1,70 @@
|
|||
import React, { Component } from 'react'
|
||||
import { Link } from 'react-router'
|
||||
import AdminHeader from './AdminHeader'
|
||||
|
||||
/*
|
||||
TODO:
|
||||
make the delete metacode set button work
|
||||
*/
|
||||
|
||||
class MetacodeSets extends Component {
|
||||
render = () => {
|
||||
const { metacodeSets, metacodes } = this.props
|
||||
return (
|
||||
<div>
|
||||
<div id="yield">
|
||||
<div className="centerContent">
|
||||
<br />
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Metacodes</th>
|
||||
</tr>
|
||||
{metacodeSets.filter(m => m.id).map((metacodeSet, i) => {
|
||||
return <MetacodeSetRow key={i} metacodeSet={metacodeSet} metacodes={metacodes} />
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<AdminHeader />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class MetacodeSetRow extends Component {
|
||||
render = () => {
|
||||
const { metacodeSet, metacodes } = this.props
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
{metacodeSet.name}
|
||||
<br />
|
||||
<Link to={`/metacode_sets/${metacodeSet.id}/edit`}>Edit</Link>
|
||||
<br />
|
||||
<a data-confirm="Are you sure?" rel="nofollow" data-method="delete" href={`/metacode_sets/${metacodeSet.id}`}>Delete</a>
|
||||
</td>
|
||||
<td className="metacodeSetDesc">
|
||||
{metacodeSet.desc}
|
||||
</td>
|
||||
<td>
|
||||
{metacodeSet.metacodes.map((mId, index) => {
|
||||
const metacode = metacodes.find(m => m.id === mId)
|
||||
return (
|
||||
<span key={index}>
|
||||
<img className="metacodeSetImage" src={metacode.icon} />
|
||||
{(index+1) % 4 === 0 && <div className='clearfloat'></div>}
|
||||
</span>
|
||||
)
|
||||
})}
|
||||
<div className='clearfloat'></div>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default MetacodeSets
|
43
src/routes/Admin/Metacodes.js
Normal file
43
src/routes/Admin/Metacodes.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
import React, { Component } from 'react'
|
||||
import { Link } from 'react-router'
|
||||
import AdminHeader from './AdminHeader'
|
||||
|
||||
class Metacodes extends Component {
|
||||
render = () => {
|
||||
return (
|
||||
<div>
|
||||
<div id="yield">
|
||||
<div className="centerContent">
|
||||
<br />
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Icon</th>
|
||||
<th>Color</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{this.props.metacodes.map(metacode => {
|
||||
return (
|
||||
<tr key={metacode.id}>
|
||||
<td>{metacode.name}</td>
|
||||
<td className="iconURL">{metacode.icon}</td>
|
||||
{metacode.color && <td className="iconColor" style={{backgroundColor: metacode.color}}>{metacode.color}</td>}
|
||||
{!metacode.color && <td></td>}
|
||||
<td><img width="40" src={metacode.icon} alt="metacode image" /></td>
|
||||
<td><Link to={`/metacodes/${metacode.id}/edit`}>Edit</Link></td>
|
||||
</tr>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<AdminHeader />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Metacodes
|
82
src/routes/Admin/NewMetacode.js
Normal file
82
src/routes/Admin/NewMetacode.js
Normal file
|
@ -0,0 +1,82 @@
|
|||
import React, { Component } from 'react'
|
||||
import { Link, browserHistory } from 'react-router'
|
||||
import AdminHeader from './AdminHeader'
|
||||
|
||||
class NewMetacode extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
icon: null,
|
||||
name: '',
|
||||
color: ''
|
||||
}
|
||||
}
|
||||
|
||||
validate = (event) => {
|
||||
if (this.state.name.length === 0) {
|
||||
event.preventDefault()
|
||||
window.alert('A name must be provided')
|
||||
} else if (!this.state.color.startsWith('#')) {
|
||||
event.preventDefault()
|
||||
window.alert('Please begin color with a # symbol')
|
||||
}
|
||||
}
|
||||
|
||||
updateForKey = (key) => event => this.setState({[key]: event.target.value})
|
||||
|
||||
handleFile = (event) => {
|
||||
this.setState({
|
||||
icon: event.target.files[0]
|
||||
})
|
||||
}
|
||||
|
||||
onSubmit = async (event) => {
|
||||
event.preventDefault()
|
||||
const { name, color, icon } = this.state
|
||||
const { createMetacode } = this.props
|
||||
try {
|
||||
const result = await createMetacode(name, color, icon)
|
||||
browserHistory.push(`/metacodes`)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
window.alert('There was an error creating the metacode, check the console')
|
||||
}
|
||||
}
|
||||
|
||||
render = () => {
|
||||
return (
|
||||
<div>
|
||||
<div id="yield">
|
||||
<div className="centerContent">
|
||||
<form onSubmit={this.onSubmit} className="new_metacode" id="new_metacode" encType="multipart/form-data" acceptCharset="UTF-8">
|
||||
<input name="utf8" type="hidden" value="✓" />
|
||||
<div className="field">
|
||||
<label htmlFor="metacode_name">Name</label>
|
||||
<input value={this.state.name} onChange={this.updateForKey('name')} type="text" name="metacode[name]" id="metacode_name" />
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
<div className="field">
|
||||
<label htmlFor="metacode_Icon">Icon</label>
|
||||
<input type="hidden" name="metacode[manual_icon]" id="metacode_manual_icon" />
|
||||
<input onChange={this.handleFile} type="file" name="metacode[aws_icon]" id="metacode_aws_icon" />
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
<div className="field">
|
||||
<label htmlFor="metacode_color">Color (hex with # sign)</label>
|
||||
<input value={this.state.color} onChange={this.updateForKey('color')} type="text" name="metacode[color]" id="metacode_color" />
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
<div className="actions">
|
||||
<Link className="button" to="/metacodes">Cancel</Link>
|
||||
<input onClick={this.validate} type="submit" name="commit" value="Create Metacode" className="add" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<AdminHeader />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default NewMetacode
|
38
src/routes/Admin/NewMetacodeSet.js
Normal file
38
src/routes/Admin/NewMetacodeSet.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
import React, { Component } from 'react'
|
||||
import { browserHistory } from 'react-router'
|
||||
|
||||
import AdminHeader from './AdminHeader'
|
||||
import MetacodeSetEditor from './MetacodeSetEditor'
|
||||
/*
|
||||
TODO:
|
||||
get the data actually updating after the network response
|
||||
*/
|
||||
|
||||
class NewMetacodeSet extends Component {
|
||||
onSubmit = async (metacodes, name, desc) => {
|
||||
const { createMetacodeSet } = this.props
|
||||
try {
|
||||
const result = await createMetacodeSet(metacodes, name, desc)
|
||||
browserHistory.push(`/metacode_sets`)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
window.alert('There was an error creating the metacode set')
|
||||
}
|
||||
}
|
||||
|
||||
render = () => {
|
||||
const { metacodes } = this.props
|
||||
return (
|
||||
<div>
|
||||
<div id="yield">
|
||||
<div className="centerContent">
|
||||
<MetacodeSetEditor metacodes = {metacodes} onSubmit={this.onSubmit} forNew />
|
||||
</div>
|
||||
</div>
|
||||
<AdminHeader />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default NewMetacodeSet
|
|
@ -5,6 +5,7 @@ import MobileHeader from '../components/MobileHeader'
|
|||
import UpperLeftUI from '../components/UpperLeftUI'
|
||||
import UpperRightUI from '../components/UpperRightUI'
|
||||
import Toast from '../components/Toast'
|
||||
import LightBoxes from '../components/LightBoxes'
|
||||
|
||||
class App extends Component {
|
||||
static propTypes = {
|
||||
|
@ -43,7 +44,8 @@ class App extends Component {
|
|||
mobile, mobileTitle, mobileTitleWidth, mobileTitleClick, location,
|
||||
map, userRequested, requestAnswered, requestApproved, serverData,
|
||||
onRequestAccess, notifications, fetchNotifications,
|
||||
markAsRead, markAsUnread, notificationsLoading } = this.props
|
||||
markAsRead, markAsUnread, notificationsLoading,
|
||||
importHandleFile, downloadScreenshot, onExport } = this.props
|
||||
const { pathname } = location || {}
|
||||
// this fixes a bug that happens otherwise when you logout
|
||||
const currentUser = this.props.currentUser && this.props.currentUser.id ? this.props.currentUser : null
|
||||
|
@ -72,6 +74,10 @@ class App extends Component {
|
|||
signInPage={pathname === '/login'} />}
|
||||
<Toast message={toast} />
|
||||
{children}
|
||||
<LightBoxes inviteCode={currentUser && currentUser.get('invite_code')}
|
||||
importHandleFile={importHandleFile}
|
||||
downloadScreenshot={downloadScreenshot}
|
||||
onExport={onExport} />
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Dropzone from 'react-dropzone'
|
||||
|
||||
class ImportDialogBox extends Component {
|
||||
handleFile = (files, e) => {
|
||||
e.preventDefault() // prevent it from triggering the default drag-drop handler
|
||||
this.props.onFileAdded(files[0])
|
||||
}
|
||||
|
||||
render = () => {
|
||||
return (
|
||||
<div className="import-dialog">
|
||||
<h3>EXPORT</h3>
|
||||
<div className="export-csv import-blue-button" onClick={this.props.onExport('csv')}>
|
||||
Export as CSV
|
||||
</div>
|
||||
<div className="export-json import-blue-button" onClick={this.props.onExport('json')}>
|
||||
Export as JSON
|
||||
</div>
|
||||
<div className="download-screenshot import-blue-button" onClick={this.props.downloadScreenshot}>
|
||||
Download screenshot
|
||||
</div>
|
||||
<h3>IMPORT</h3>
|
||||
<p>To upload a file, drop it here:</p>
|
||||
<Dropzone onDropAccepted={this.handleFile}
|
||||
className="fileupload"
|
||||
>
|
||||
Drop files here!
|
||||
</Dropzone>
|
||||
<p>See <a href="https://docs.metamaps.cc/importing_and_exporting_data.html">docs.metamaps.cc</a> for instructions.</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ImportDialogBox.propTypes = {
|
||||
onFileAdded: PropTypes.func,
|
||||
downloadScreenshot: PropTypes.func,
|
||||
onExport: PropTypes.func
|
||||
}
|
||||
|
||||
export default ImportDialogBox
|
|
@ -9,6 +9,8 @@ import Instructions from './Instructions'
|
|||
import VisualizationControls from '../../components/VisualizationControls'
|
||||
import MapChat from './MapChat'
|
||||
import TopicCard from '../../components/TopicCard'
|
||||
import NewTopic from '../../components/NewTopic'
|
||||
import NewSynapse from '../../components/NewSynapse'
|
||||
|
||||
export default class MapView extends Component {
|
||||
|
||||
|
@ -82,7 +84,7 @@ export default class MapView extends Component {
|
|||
openImportLightbox, forkMap, openHelpLightbox,
|
||||
mapIsStarred, onMapStar, onMapUnstar, openTopic,
|
||||
onZoomExtents, onZoomIn, onZoomOut, hasLearnedTopicCreation,
|
||||
contextMenu } = this.props
|
||||
contextMenu, initNewTopic, initNewSynapse, openMetacodeSwitcher } = this.props
|
||||
const { chatOpen } = this.state
|
||||
const onChatOpen = () => {
|
||||
this.setState({chatOpen: true})
|
||||
|
@ -111,6 +113,8 @@ export default class MapView extends Component {
|
|||
filterAllMappers={filterAllMappers}
|
||||
filterAllSynapses={filterAllSynapses} />
|
||||
<DataVis />
|
||||
<NewTopic initNewTopic={initNewTopic} openMetacodeSwitcher={openMetacodeSwitcher} />
|
||||
<NewSynapse initNewSynapse={initNewSynapse} />
|
||||
{openTopic && <TopicCard {...this.props} />}
|
||||
{contextMenu && <ContextMenu {...this.props} />}
|
||||
{currentUser && <Instructions mobile={mobile} hasLearnedTopicCreation={hasLearnedTopicCreation} />}
|
||||
|
|
|
@ -7,12 +7,18 @@ import LoadingPage from '../helpers/LoadingPage'
|
|||
import Loading from '../../components/Loading'
|
||||
import NotificationBody from '../../components/NotificationBody'
|
||||
|
||||
/* TODO:
|
||||
allow / decline access loading states
|
||||
make backend serve HTML for raw body too
|
||||
*/
|
||||
|
||||
class NotificationPage extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
allowPending: false,
|
||||
declinePending: false,
|
||||
allowed: false,
|
||||
declined: false,
|
||||
error: false
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// the notification id
|
||||
const id = parseInt(this.props.params.id, 10)
|
||||
|
@ -20,6 +26,35 @@ class NotificationPage extends Component {
|
|||
this.props.fetchNotification(id)
|
||||
}
|
||||
}
|
||||
|
||||
deny = async () => {
|
||||
const id = parseInt(this.props.params.id, 10)
|
||||
const notification = this.props.notifications.find(n => n.id === id)
|
||||
const request = notification.data.object
|
||||
const map = notification.data.map
|
||||
this.setState({ declinePending: true })
|
||||
const success = await this.props.denyAccessRequest(map.id, request.id)
|
||||
if (success) {
|
||||
this.setState({ declined: true, declinePending: false })
|
||||
} else {
|
||||
this.setState({ error: true })
|
||||
}
|
||||
}
|
||||
|
||||
approve = async () => {
|
||||
const id = parseInt(this.props.params.id, 10)
|
||||
const notification = this.props.notifications.find(n => n.id === id)
|
||||
const request = notification.data.object
|
||||
const map = notification.data.map
|
||||
this.setState({ allowPending: true })
|
||||
const success = await this.props.approveAccessRequest(map.id, request.id)
|
||||
if (success) {
|
||||
this.setState({ allowed: true, allowPending: false })
|
||||
} else {
|
||||
this.setState({ error: true })
|
||||
}
|
||||
}
|
||||
|
||||
render = () => {
|
||||
const id = parseInt(this.props.params.id, 10)
|
||||
const notification = this.props.notifications.find(n => n.id === id)
|
||||
|
@ -34,8 +69,9 @@ class NotificationPage extends Component {
|
|||
const request = notification.data.object
|
||||
const map = notification.data.map
|
||||
const subject = notification.type === MAP_ACCESS_REQUEST ?
|
||||
(<span><span style={{ fontWeight: 'bold' }} className='requesterName'>{request.user.name}</span> wants to collaborate on map <span style={{fontWeight: 'bold'}}>{ map.name }</span></span>)
|
||||
(<span><span style={{ fontWeight: 'bold' }} className='requesterName'>{notification.actor.name}</span> wants to collaborate on map <span style={{fontWeight: 'bold'}}>{ map.name }</span></span>)
|
||||
: notification.subject
|
||||
const localAnswered = this.state.allowed || this.state.declined
|
||||
return (
|
||||
<div>
|
||||
<div id="yield">
|
||||
|
@ -48,21 +84,34 @@ class NotificationPage extends Component {
|
|||
{subject}
|
||||
</h2>
|
||||
{notification.type === MAP_ACCESS_REQUEST && <div className="notification-body">
|
||||
<p className="main-text">
|
||||
{request.answered && <span>
|
||||
<div className="main-text">
|
||||
{this.state.error && <div className="accessRequestError">There was an error, please refresh and try again</div>}
|
||||
{request.answered && <div>
|
||||
{request.approved && <span>You already responded to this access request, and allowed access.</span>}
|
||||
{!request.approved && <span>You already responded to this access request, and declined access. If you changed your mind, you can still grant
|
||||
them access by going to the map and adding them as a collaborator.</span>}
|
||||
</span>}
|
||||
{!request.answered && <span>
|
||||
</div>}
|
||||
{!localAnswered && !request.answered && <div>
|
||||
<img src='/images/ellipsis.gif' className='hidden' />
|
||||
<a className="button allow" data-remote="true" rel="nofollow" data-method="post" href={`/maps/${map.id}/approve_access/${request.id}`}>Allow</a>
|
||||
<a className="button decline" data-remote="true" rel="nofollow" data-method="post" href={`/maps/${map.id}/deny_access/${request.id}`}>Decline</a>
|
||||
</span>}
|
||||
</p>
|
||||
<Link to={`/maps/${map.id}`}>Go to map</Link>
|
||||
|
||||
<Link to={`/explore/mapper/${request.user.id}`}>View mapper profile</Link>
|
||||
{!this.state.declined && !this.state.declinePending && <button onClick={this.approve} className="button allow">
|
||||
{this.state.allowPending ? <img src='/images/ellipsis.gif' /> : 'Allow'}
|
||||
</button>}
|
||||
{!this.state.allowed && !this.state.allowPending && <button onClick={this.deny} className="button decline">
|
||||
{this.state.declinePending ? <img src='/images/ellipsis.gif' /> : 'Decline'}
|
||||
</button>}
|
||||
</div>}
|
||||
{this.state.allowed && <div>
|
||||
{notification.actor.name} has been shared on the map and notified.
|
||||
</div>}
|
||||
{this.state.declined && <div>
|
||||
Fair enough.
|
||||
</div>}
|
||||
</div>
|
||||
<div>
|
||||
<Link to={`/maps/${map.id}`}>Go to map</Link>
|
||||
|
||||
<Link to={`/explore/mapper/${notification.actor.id}`}>View mapper profile</Link>
|
||||
</div>
|
||||
</div>}
|
||||
{notification.type !== MAP_ACCESS_REQUEST && <NotificationBody notification={notification} />}
|
||||
</div>
|
||||
|
@ -73,14 +122,4 @@ class NotificationPage extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default NotificationPage
|
||||
|
||||
/*
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('.notification-body .button').click(function() {
|
||||
$(this).html('<img src="{ asset_path('ellipsis.gif') }" />')
|
||||
})
|
||||
})
|
||||
</script>
|
||||
*/
|
||||
export default NotificationPage
|
|
@ -27,7 +27,7 @@ class Notifications extends Component {
|
|||
render = () => {
|
||||
const { notificationsLoading, markAsRead, markAsUnread } = this.props
|
||||
const notifications = (this.props.notifications || []).filter(n => !(BLACKLIST.indexOf(n.type) > -1 && (!n.data.object || !n.data.map)))
|
||||
if (notificationsLoading) {
|
||||
if (notifications.length === 0 && notificationsLoading) {
|
||||
return (
|
||||
<div>
|
||||
<LoadingPage />
|
||||
|
|
|
@ -1,7 +1,35 @@
|
|||
import React, { Component } from 'react'
|
||||
|
||||
class RequestAccess extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
requestPending: false,
|
||||
requestSent: false,
|
||||
error: false
|
||||
}
|
||||
}
|
||||
|
||||
requestAccess = async () => {
|
||||
if (this.state.requestSent || this.state.requestPending || this.state.error) {
|
||||
return
|
||||
}
|
||||
this.setState({ requestPending: true })
|
||||
const success = this.props.requestAccess(this.props.params.id)
|
||||
if (success) {
|
||||
this.setState({
|
||||
requestPending: false,
|
||||
requestSent: true
|
||||
})
|
||||
} else {
|
||||
this.setState({
|
||||
requestPending: false,
|
||||
error: true
|
||||
})
|
||||
}
|
||||
}
|
||||
render = () => {
|
||||
const { requestPending, requestSent, error } = this.state
|
||||
return (
|
||||
<div id="yield">
|
||||
<div className='request_access'>
|
||||
|
@ -9,32 +37,16 @@ class RequestAccess extends Component {
|
|||
<div className='explainer_text'>
|
||||
Hmmm. This map is private, but you can request to edit it from the map creator.
|
||||
</div>
|
||||
<div className='make_request'>REQUEST ACCESS</div>
|
||||
<div className='make_request' onClick={this.requestAccess}>
|
||||
{!requestPending && !requestSent && !error && 'REQUEST ACCESS'}
|
||||
{requestSent && 'Request Sent'}
|
||||
{requestPending && 'requesting...'}
|
||||
{error && 'There was an error'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default RequestAccess
|
||||
|
||||
/*
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('.make_request').click(function() {
|
||||
var that = $(this)
|
||||
that.off('click')
|
||||
that.text('requesting...')
|
||||
$.ajax({
|
||||
url: '/maps/<%= params[:id] %>/access_request',
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
statusCode: {
|
||||
200: function () { that.text('Request Sent'); setTimeout(function () {window.location.href = '/'}, 2000) },
|
||||
400: function () { that.text('An error occurred') }
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
</script>
|
||||
*/
|
||||
export default RequestAccess
|
|
@ -1,10 +1,15 @@
|
|||
import React from 'react'
|
||||
import { Route, IndexRoute } from 'react-router'
|
||||
import Admin from './Admin'
|
||||
import { Route, IndexRoute, Redirect } from 'react-router'
|
||||
import App from './App'
|
||||
import Apps from './Apps'
|
||||
import Maps from './Maps'
|
||||
import MapView from './MapView'
|
||||
import Metacodes from './Admin/Metacodes'
|
||||
import NewMetacode from './Admin/NewMetacode'
|
||||
import EditMetacode from './Admin/EditMetacode'
|
||||
import MetacodeSets from './Admin/MetacodeSets'
|
||||
import NewMetacodeSet from './Admin/NewMetacodeSet'
|
||||
import EditMetacodeSet from './Admin/EditMetacodeSet'
|
||||
import Notifications from './Notifications/Notifications'
|
||||
import NotificationPage from './Notifications/NotificationPage'
|
||||
import TopicView from './TopicView'
|
||||
|
@ -36,9 +41,12 @@ export default function makeRoutes (currentUser) {
|
|||
<Route path="request_access" component={RequestAccess} />
|
||||
</Route>
|
||||
<Route path="topics/:id" component={TopicView} />
|
||||
<Route path="login" component={Login} />
|
||||
<Route path="join" component={Join} />
|
||||
<Route path="request" component={RequestInvite} />
|
||||
{!currentUser && <Route path="login" component={Login} />}
|
||||
{!currentUser && <Route path="join" component={Join} />}
|
||||
{!currentUser && <Route path="request" component={RequestInvite} />}
|
||||
{currentUser && <Redirect path="login" to="/" />}
|
||||
{currentUser && <Redirect path="join" to="/" />}
|
||||
{currentUser && <Redirect path="request" to="/" />}
|
||||
<Route path="notifications">
|
||||
<IndexRoute component={Notifications} />
|
||||
<Route path=":id" component={NotificationPage} />
|
||||
|
@ -50,14 +58,14 @@ export default function makeRoutes (currentUser) {
|
|||
<Route path="password/edit" component={nullComponent} />
|
||||
</Route>
|
||||
<Route path="metacodes">
|
||||
<IndexRoute component={Admin} />
|
||||
<Route path="new" component={Admin} />
|
||||
<Route path=":id/edit" component={Admin} />
|
||||
<IndexRoute component={Metacodes} />
|
||||
<Route path="new" component={NewMetacode} />
|
||||
<Route path=":id/edit" component={EditMetacode} />
|
||||
</Route>
|
||||
<Route path="metacode_sets">
|
||||
<IndexRoute component={Admin} />
|
||||
<Route path="new" component={Admin} />
|
||||
<Route path=":id/edit" component={Admin} />
|
||||
<IndexRoute component={MetacodeSets} />
|
||||
<Route path="new" component={NewMetacodeSet} />
|
||||
<Route path=":id/edit" component={EditMetacodeSet} />
|
||||
</Route>
|
||||
<Route path="oauth">
|
||||
<Route path="token/info" component={Apps} />
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* global describe, it */
|
||||
import React from 'react'
|
||||
import ImportDialogBox from '../../../src/routes/MapView/ImportDialogBox.js'
|
||||
import ImportDialogBox from '../../../src/components/LightBoxes/ImportDialogBox.js'
|
||||
import Dropzone from 'react-dropzone'
|
||||
import { expect } from 'chai'
|
||||
import { shallow } from 'enzyme'
|
|
@ -1 +0,0 @@
|
|||
$('.main-text').text($('.requesterName').text() + ' has been shared on the map and notified.')
|
|
@ -1 +0,0 @@
|
|||
$('.main-text').text('Fair enough.')
|
|
@ -1,7 +0,0 @@
|
|||
$('#notification-{ @notification.id } .notification-read-unread > a')
|
||||
.text('mark as unread')
|
||||
.attr('href', '{ mark_unread_notification_path(@notification.id) }')
|
||||
$('#notification-{ @notification.id }')
|
||||
.removeClass('unread')
|
||||
.addClass('read')
|
||||
Metamaps.GlobalUI.Notifications.decrementUnread(Metamaps.GlobalUI.ReactApp.render)
|
|
@ -1,7 +0,0 @@
|
|||
$('#notification-{ @notification.id } .notification-read-unread > a')
|
||||
.text('mark as read')
|
||||
.attr('href', '{ mark_read_notification_path(@notification.id) }')
|
||||
$('#notification-{ @notification.id }')
|
||||
.removeClass('read')
|
||||
.addClass('unread')
|
||||
Metamaps.GlobalUI.Notifications.incrementUnread(Metamaps.GlobalUI.ReactApp.render)
|
|
@ -1,113 +0,0 @@
|
|||
|
||||
<div id="lightbox_overlay">
|
||||
<div id="lightbox_main">
|
||||
<a id="lightbox_close" href="#"></a>
|
||||
<div id="lightbox_content">
|
||||
|
||||
<div className="lightboxContent" id="about">
|
||||
<h3>About Metamaps.cc</h3>
|
||||
<div id="aboutParms">
|
||||
<div id="leftAboutParms">
|
||||
<p>STATUS: </p>
|
||||
<p>VERSION:</p>
|
||||
<p>BUILD:</p>
|
||||
<p>LAST UPDATE:</p>
|
||||
</div>
|
||||
|
||||
<div id="rightAboutParms">
|
||||
<p>PRIVATE BETA</p>
|
||||
<p>{ METAMAPS_VERSION }</p>
|
||||
<p>{ METAMAPS_BUILD }</p>
|
||||
<p>{ METAMAPS_LAST_UPDATED }</p>
|
||||
</div>
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
|
||||
<p>Metamaps.cc is a free and open source web platform that supports real-time sense-making and distributed collaboration between individuals, communities and organizations.</p>
|
||||
|
||||
<p>Using an intuitive graph-based interface, Metamaps.cc helps map out networks of people, ideas, resources, stories, experiences, conversations and much more. The platform is evolving for a range of applications amidst a growing network of designers, developers, facilitators, practitioners, entrepreneurs, and artists.</p>
|
||||
|
||||
<p>Metamaps.cc is created and maintained by a distributed community of contributors passionate about the evolution of collaboration, alternative forms of value creation and increase of collective intelligence through the lens of the open culture and the peer-to-peer revolution.</p>
|
||||
|
||||
<ul className="lightbox_links">
|
||||
<li>
|
||||
<a className="icon_twitter" href="https://twitter.com/metamapps" target="_blank">
|
||||
<div className="lightboxAboutIcon"></div>
|
||||
@metamapps
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a className="icon_community" href="https://www.hylo.com/c/metamaps/join/mice-late-hit-two-shown" target="_blank">
|
||||
<div className="lightboxAboutIcon"></div>
|
||||
community
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a className="icon_source_code" href="https://github.com/metamaps/metamaps" target="_blank">
|
||||
<div className="lightboxAboutIcon"></div>
|
||||
source code
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a className="icon_howtos" href="https://docs.metamaps.cc" target="_blank">
|
||||
<div className="lightboxAboutIcon"></div>
|
||||
howtos
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a className="icon_terms" href="https://metamaps.cc/maps/331" target="_blank">
|
||||
<div className="lightboxAboutIcon"></div>
|
||||
terms
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
|
||||
<div className="lightboxContent" id="noIE">
|
||||
<h3>OOPS! <br> YOUR BROWSER IS NOT SUPPORTED.</h3>
|
||||
<p id="noIEsubheading">To view this experience, please upgrade to the latest one of these browsers:</p>
|
||||
<a id="chromeIcon" href="https://www.google.com/chrome/browser/" target="_blank">Chrome</a>
|
||||
<a id="fireFoxIcon" href="https://www.mozilla.org/en-US/firefox/new/" target="_blank">Firefox</a>
|
||||
<a id="safariIcon" href="http://support.apple.com/downloads/#safari" target="_blank">Safari</a>
|
||||
<p id="noIEbody">While it's downloading, explore our <a href="http://blog.metamaps.cc/">blog</a>,<br> watch the <a href="http://vimeo.com/88334167">tutorials</a>, or visit our <a href="https://docs.metamaps.cc">knowledge base</a>!
|
||||
|
||||
</div>
|
||||
|
||||
<div className="lightboxContent" id="tutorial">
|
||||
<h3>Tutorial</h3>
|
||||
<iframe src="//player.vimeo.com/video/88334167?title=0&byline=0&portrait=0" width="510" height="319" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
<div className="lightboxContent" id="cheatsheet">
|
||||
{ render :partial => 'shared/cheatsheet' }
|
||||
</div>
|
||||
|
||||
{ if current_user }
|
||||
<div className="lightboxContent" id="invite">
|
||||
<h3>SHARE INVITE</h3>
|
||||
|
||||
<div className="leaveSpace"></div>
|
||||
<p>The Metamaps platform is currently in an invite-only beta with the express purpose of creating a high value knowledge ecosystem, a diverse community of contributors and a culture of collaboration and curiosity.</p>
|
||||
<p>As a valued beta tester, you have the ability to invite your peers, colleagues and collaborators onto the platform.</p>
|
||||
<p>Below is a personal invite link containing your unique access code, which can be used multiple times.</p>
|
||||
<div id="joinCodesBox">
|
||||
<p className="joinCodes">{ invite_link() }
|
||||
<button className="button" onclick="Metamaps.GlobalUI.shareInvite('{ @invite_link }');">COPY INVITE LINK!</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="lightboxContent" id="forkmap">
|
||||
{ render :partial => 'shared/forkmap' }
|
||||
</div>
|
||||
|
||||
<div className="lightboxContent" id="switchMetacodes">
|
||||
{ render :partial => 'shared/switchmetacodes' }
|
||||
</div>
|
||||
{ end }
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="lightbox_screen" style="height: 100%;"></div>
|
||||
</div>
|
|
@ -1,181 +0,0 @@
|
|||
|
||||
|
||||
<div className="templates">
|
||||
<script type="text/template" id="mapInfoBoxTemplate">
|
||||
<div className="requestTitle">Click here to name this map</div>
|
||||
<div className="mapInfoName" id="mapInfoName">{{{name}}}</div>
|
||||
|
||||
<div className="mapInfoStat">
|
||||
<div className="infoStatIcon mapContributors hoverForTip">
|
||||
<img id="mapContribs" className="{{contributors_className}}"
|
||||
width="25" height="25" src="{{contributor_image}}" />
|
||||
<span className="count">{{contributor_count}}</span>
|
||||
<div className="tip">{{{contributor_list}}}</div>
|
||||
</div>
|
||||
<div className="infoStatIcon mapTopics">
|
||||
{{topic_count}}
|
||||
</div>
|
||||
<div className="infoStatIcon mapSynapses">
|
||||
{{synapse_count}}
|
||||
</div>
|
||||
<div className="infoStatIcon mapPermission {{permission}} hoverForTip">
|
||||
{{{map_creator_tip}}}
|
||||
</div>
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
<div className="mapInfoDesc" id="mapInfoDesc">
|
||||
{{{desc}}}
|
||||
</div>
|
||||
|
||||
<div className="mapInfoMeta">
|
||||
<p className="mapCreatedAt"><span>Created by:</span> {{user_name}} on {{created_at}}</p>
|
||||
<p className="mapEditedAt"><span>Last edited:</span> {{updated_at}}</p>
|
||||
<div className="mapInfoButtonsWrapper">
|
||||
<div className="mapInfoThumbnail">
|
||||
<div className="thumbnail"></div>
|
||||
<div className="tooltip">Update Thumbnail</div>
|
||||
<span>Thumb</span>
|
||||
</div>
|
||||
<div className="mapInfoDelete">
|
||||
<div className="deleteMap"></div>
|
||||
<span>Delete</span>
|
||||
</div>
|
||||
<div className="mapInfoShare">
|
||||
<div className="mapInfoShareIcon"></div>
|
||||
<span>Share</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="topicSearchTemplate">
|
||||
<div className="result{{rtype}}">
|
||||
<div className="topicMetacode searchResIconWrapper">
|
||||
<img src="{{typeImageURL}}" className="topicIcon" />
|
||||
<div className="metacodeTip">{{type}}</div>
|
||||
</div>
|
||||
<div className="resultText">
|
||||
<p className="resultTitle">{{label}}</p>
|
||||
<p className="resultDesc">{{description}}</p>
|
||||
</div>
|
||||
<div className="autoOptions">
|
||||
<button className="addToMap hoverForTip" onclick="return Metamaps.Topic.getTopicFromSearch(event, {{id}})">
|
||||
<span className="tip">add to map</span>
|
||||
</button>
|
||||
<div className="mapCount">
|
||||
{{mapCount}}
|
||||
</div>
|
||||
<div className="synapseCount">
|
||||
{{synapseCount}}
|
||||
</div>
|
||||
<div className="topicOriginatorIcon hoverForTip">
|
||||
<img width="18" height="18" src="{{originatorImage}}">
|
||||
<span className="tip topicOriginator">{{originator}}</span>
|
||||
</div>
|
||||
<div className="topicPermission {{permission}}">
|
||||
</div>
|
||||
</div>
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="mapSearchTemplate">
|
||||
<div className="result{{rtype}}">
|
||||
<div className="searchResIconWrapper">
|
||||
<img className="icon" src="/images/metamap36c.png">
|
||||
</div>
|
||||
<div className="resultText">
|
||||
<p className="resultTitle">{{label}}</p>
|
||||
<p className="resultDesc">{{description}}</p>
|
||||
</div>
|
||||
<div className="autoOptions">
|
||||
<div className="topicCount">
|
||||
{{topicCount}}
|
||||
</div>
|
||||
<div className="synapseCount">
|
||||
{{synapseCount}}
|
||||
</div>
|
||||
<div className="mapContributorsIcon hoverForTip">
|
||||
<img id="mapContribs" width="25" height="25" src="{{mapContributorImage}}" />
|
||||
<div className="tip">
|
||||
<ul>
|
||||
{{{contributorTip}}}
|
||||
</ul>
|
||||
</div>
|
||||
<span>{{contributorCount}}</span>
|
||||
</div>
|
||||
<div className="mapPermission {{permission}}">
|
||||
</div>
|
||||
</div>
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="mapperSearchTemplate">
|
||||
<div className="result{{rtype}}">
|
||||
<div className="searchResIconWrapper">
|
||||
<img className="icon" width="32" height="32" src="{{profile}}">
|
||||
</div>
|
||||
<div className="resultText">
|
||||
<p className="resultTitle">{{label}}</p>
|
||||
</div>
|
||||
<div className="autoOptions">
|
||||
<div className="mapperCreated">
|
||||
<p>Mapping since: {{created_at}}</p>
|
||||
</div>
|
||||
<div className="mapperGeneration">
|
||||
<p>Generation: {{generation}}</p>
|
||||
</div>
|
||||
<div className="mapCount">
|
||||
{{mapCount}}
|
||||
</div>
|
||||
</div>
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="collaboratorSearchTemplate">
|
||||
<div className="collabResult">
|
||||
<div className="collabIconWrapper">
|
||||
<img className="icon" width="25" height="25" src="{{profile}}">
|
||||
</div>
|
||||
<div className="collabNameWrapper">
|
||||
<p className="collabName">{{label}}</p>
|
||||
</div>
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="synapseAutocompleteTemplate">
|
||||
<div className="result{{rtype}}">
|
||||
<p className="autocompleteSection synapseDesc">{{label}}</p>
|
||||
<div className="synapseMetadata">
|
||||
<div className="synapseOriginatorIcon hoverForTip">
|
||||
<img width="24" height="24" src="{{originatorImage}}" />
|
||||
<span className="tooltips synapseOriginator">{{originator}}</span>
|
||||
</div>
|
||||
<div className="synapsePermission {{permission}}"></div>
|
||||
</div>
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="topicAutocompleteTemplate">
|
||||
<div>
|
||||
<img className="autocompleteSection topicType" width="24" height="24"
|
||||
src="{{typeImageURL}}" alt="{{type}}" title="{{type}}" />
|
||||
<p className="autocompleteSection topicTitle">{{label}}</p>
|
||||
<div className="expandTopicMetadata"></div>
|
||||
<div className="topicMetadata">
|
||||
<div className="topicNumMaps">{{mapCount}}</div>
|
||||
<div className="topicNumSynapses">{{synapseCount}}</div>
|
||||
<div className="topicOriginatorIcon hoverForTip">
|
||||
<img width="24" height="24" src="{{originatorImage}}" />
|
||||
<span className="tooltips topicOriginator">{{originator}}</span>
|
||||
</div>
|
||||
<div className="topicPermission {{permission}}"></div>
|
||||
</div>
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
</script>
|
||||
</div>
|
|
@ -1,3 +0,0 @@
|
|||
{ form_for Synapse.new, url: synapses_url, remote: true do |form| }
|
||||
{ form.text_field :desc, :placeholder => "describe the connection..." }
|
||||
{ end }
|
|
@ -1,32 +0,0 @@
|
|||
{ @metacodes = user_metacodes() }
|
||||
|
||||
{ form_for Topic.new, url: topics_url, remote: true do |form| }
|
||||
<div className="openMetacodeSwitcher openLightbox" data-open="switchMetacodes">
|
||||
<div className="tooltipsAbove">Switch Metacodes</div>
|
||||
</div>
|
||||
|
||||
<div className="pinCarousel">
|
||||
<div className="tooltipsAbove helpPin">Pin Open</div>
|
||||
<div className="tooltipsAbove helpUnpin">Unpin</div>
|
||||
</div>
|
||||
|
||||
<div id="metacodeImg">
|
||||
{ @metacodes.each do |metacode| }
|
||||
<img className="cloudcarousel" width="40" height="40" src="{ asset_path metacode.icon }" alt="{ metacode.name }" title="{ metacode.name }" data-id="{ metacode.id }" />
|
||||
{ end }
|
||||
</div>
|
||||
|
||||
{ form.text_field :name, :maxlength => 140, :placeholder => "title..." }
|
||||
|
||||
<div id="metacodeImgTitle"></div>
|
||||
<div className="clearfloat"></div>
|
||||
|
||||
<script>
|
||||
{ @metacodes.each do |metacode| }
|
||||
Metamaps.Create.selectedMetacodes.push("{ metacode.id }");
|
||||
Metamaps.Create.newSelectedMetacodes.push("{ metacode.id }");
|
||||
Metamaps.Create.selectedMetacodeNames.push("{ metacode.name }");
|
||||
Metamaps.Create.newSelectedMetacodeNames.push("{ metacode.name }");
|
||||
{ end }
|
||||
</script>
|
||||
{ end }
|
|
@ -1,89 +0,0 @@
|
|||
{ form_for(@metacode_set) do |f| }
|
||||
{ if @metacode_set.errors.any? }
|
||||
<div id="error_explanation">
|
||||
<h2>{ pluralize(@metacode_set.errors.count, "error") } prohibited this metacode set from being saved:</h2>
|
||||
|
||||
<ul>
|
||||
{ @metacode_set.errors.full_messages.each do |msg| }
|
||||
<li>{ msg }</li>
|
||||
{ end }
|
||||
</ul>
|
||||
</div>
|
||||
{ end }
|
||||
|
||||
<div className="field">
|
||||
{ f.label :name }
|
||||
{ f.text_field :name }
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
<div className="field">
|
||||
{ f.label :desc, "Description" }
|
||||
{ f.text_area :desc, :cols => "40", :rows => "4" }
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<p>Choose Metacodes</p>
|
||||
<div className="allMetacodes">
|
||||
<span id="showAll" onclick="Metamaps.Admin.selectAll();">Select All</span>
|
||||
<span id="hideAll" onclick="Metamaps.Admin.deselectAll();">Unselect All</span>
|
||||
</div>
|
||||
<div className="clearfloat"></div>
|
||||
<div className="editMetacodes">
|
||||
<ul id="filters-one">
|
||||
{ $i = 0 }
|
||||
{ @m = Metacode.order("name").all }
|
||||
{ while $i < (Metacode.all.length / 4) do }
|
||||
<li id="{ @m[$i].id }" { if not @m[$i].in_metacode_set(@metacode_set) }className="toggledOff"{ end }
|
||||
onclick="Metamaps.Admin.liClickHandler.call(this);">
|
||||
<img src="{ asset_path @m[$i].icon }" alt="{ @m[$i].name }" />
|
||||
<p>{ @m[$i].name.downcase }</p>
|
||||
<div className="clearfloat"></div>
|
||||
</li>
|
||||
{ $i += 1 }
|
||||
{ end }
|
||||
</ul>
|
||||
<ul id="filters-two">
|
||||
{ while $i < (Metacode.all.length / 4 * 2) do }
|
||||
<li id="{ @m[$i].id }" { if not @m[$i].in_metacode_set(@metacode_set) }className="toggledOff"{ end }
|
||||
onclick="Metamaps.Admin.liClickHandler.call(this);">
|
||||
<img src="{ asset_path @m[$i].icon }" alt="{ @m[$i].name }" />
|
||||
<p>{ @m[$i].name.downcase }</p>
|
||||
<div className="clearfloat"></div>
|
||||
</li>
|
||||
{ $i += 1 }
|
||||
{ end }
|
||||
</ul>
|
||||
<ul id="filters-three">
|
||||
{ while $i < (Metacode.all.length / 4 * 3) do }
|
||||
<li id="{ @m[$i].id }" { if not @m[$i].in_metacode_set(@metacode_set) }className="toggledOff"{ end }
|
||||
onclick="Metamaps.Admin.liClickHandler.call(this);">
|
||||
<img src="{ asset_path @m[$i].icon }" alt="{ @m[$i].name }" />
|
||||
<p>{ @m[$i].name.downcase }</p>
|
||||
<div className="clearfloat"></div>
|
||||
</li>
|
||||
{ $i += 1 }
|
||||
{ end }
|
||||
</ul>
|
||||
<ul id="filters-four">
|
||||
{ while $i < Metacode.all.length do }
|
||||
<li id="{ @m[$i].id }" { if not @m[$i].in_metacode_set(@metacode_set) }className="toggledOff"{ end }
|
||||
onclick="Metamaps.Admin.liClickHandler.call(this);">
|
||||
<img src="{ asset_path @m[$i].icon }" alt="{ @m[$i].name }" />
|
||||
<p>{ @m[$i].name.downcase }</p>
|
||||
<div className="clearfloat"></div>
|
||||
</li>
|
||||
{ $i += 1 }
|
||||
{ end }
|
||||
</ul>
|
||||
</div>
|
||||
{ hidden_field(:metacodes, :value, {:value => 0}) }
|
||||
<div className="clearfloat"></div>
|
||||
|
||||
<div className="actions">
|
||||
{ link_to 'Cancel', metacode_sets_path,
|
||||
{ :className => 'button' } }
|
||||
{ f.submit :className => 'add', :onclick => "return Metamaps.Admin.validate();" }
|
||||
</div>
|
||||
{ end }
|
|
@ -1,24 +0,0 @@
|
|||
import React, { Component } from react
|
||||
|
||||
class MyComponent extends Component {
|
||||
render = () => {
|
||||
return (
|
||||
<div id="yield">
|
||||
<div className='centerContent'>
|
||||
{ render 'form' }
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default MyComponent
|
||||
|
||||
<script>
|
||||
{ Metacode.all.each do |m| }
|
||||
{ if m.in_metacode_set(@metacode_set) }
|
||||
Metamaps.Admin.selectMetacodes.push("{ m.id }");
|
||||
{ end }
|
||||
Metamaps.Admin.allMetacodes.push("{ m.id }");
|
||||
{ end }
|
||||
</script>
|
|
@ -1,46 +0,0 @@
|
|||
import React, { Component } from react
|
||||
|
||||
class MyComponent extends Component {
|
||||
render = () => {
|
||||
return (
|
||||
<div id="yield">
|
||||
<div className='centerContent'>
|
||||
<br />
|
||||
<table>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th className='metacodeSetsDescription'>Description</th>
|
||||
<th>Metacodes</th>
|
||||
</tr>
|
||||
|
||||
{ @metacode_sets.each do |metacode_set| }
|
||||
<tr>
|
||||
<td>
|
||||
{ metacode_set.name }<br />
|
||||
{ link_to 'Edit',
|
||||
edit_metacode_set_path(metacode_set) }
|
||||
<br />
|
||||
{ link_to 'Delete',
|
||||
metacode_set, method: :delete,
|
||||
data: { confirm: 'Are you sure?' } }
|
||||
</td>
|
||||
<td className='metacodeSetDesc'>{ metacode_set.desc }</td>
|
||||
<td>
|
||||
{ metacode_set.metacodes.each_with_index do |metacode, index| }
|
||||
<img className='metacodeSetImage' src='{ asset_path metacode.icon }' />
|
||||
{ if (index+1)%4 == 0 }
|
||||
<div className='clearfloat'></div>
|
||||
{ end }
|
||||
{ end }
|
||||
<div className='clearfloat'></div>
|
||||
</td>
|
||||
</tr>
|
||||
{ end }
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default MyComponent
|
|
@ -1,24 +0,0 @@
|
|||
import React, { Component } from react
|
||||
|
||||
class MyComponent extends Component {
|
||||
render = () => {
|
||||
return (
|
||||
<div id="yield">
|
||||
<div className='centerContent'>
|
||||
{ render 'form' }
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default MyComponent
|
||||
|
||||
<script>
|
||||
{ Metacode.all.each do |m| }
|
||||
{ if m.in_metacode_set(@metacode_set) }
|
||||
Metamaps.Admin.selectMetacodes.push("{ m.id }");
|
||||
{ end }
|
||||
Metamaps.Admin.allMetacodes.push("{ m.id }");
|
||||
{ end }
|
||||
</script>
|
|
@ -1,43 +0,0 @@
|
|||
{ form_for(@metacode) do |f| }
|
||||
{ if @metacode.errors.any? }
|
||||
<div id="error_explanation">
|
||||
<h2>{ pluralize(@metacode.errors.count, "error") } prohibited this metacode from being saved:</h2>
|
||||
<ul>
|
||||
{ @metacode.errors.full_messages.each do |msg| }
|
||||
<li>{ msg }</li>
|
||||
{ end }
|
||||
</ul>
|
||||
</div>
|
||||
{ end }
|
||||
|
||||
<div className="field">
|
||||
{ f.label :name }
|
||||
{ f.text_field :name }
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
{ unless @metacode.new_record? }
|
||||
<div className="field">
|
||||
{ f.label 'Current Icon' }
|
||||
{ image_tag @metacode.icon, width: 96 }
|
||||
</div>
|
||||
{ end }
|
||||
<div className="field">
|
||||
{ if @metacode.new_record? }
|
||||
{ f.label 'Icon' }
|
||||
{ else }
|
||||
{ f.label 'Replace Icon: ' }
|
||||
{ end }
|
||||
{ f.hidden_field :manual_icon, value: nil }
|
||||
{ f.file_field :aws_icon }
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
<div className="field">
|
||||
{ f.label :color, "Color (hex with # sign)" }
|
||||
{ f.text_field :color }
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
<div className="actions">
|
||||
{ link_to 'Cancel', metacodes_path, { :className => 'button' } }
|
||||
{ f.submit :className => 'add' }
|
||||
</div>
|
||||
{ end }
|
|
@ -1,15 +0,0 @@
|
|||
import React, { Component } from react
|
||||
|
||||
class MyComponent extends Component {
|
||||
render = () => {
|
||||
return (
|
||||
<div id="yield">
|
||||
<div className='centerContent'>
|
||||
{ render 'form' }
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default MyComponent
|
|
@ -1,40 +0,0 @@
|
|||
import React, { Component } from react
|
||||
|
||||
class MyComponent extends Component {
|
||||
render = () => {
|
||||
return (
|
||||
<div id="yield">
|
||||
<div className='centerContent'>
|
||||
<br />
|
||||
<table>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Icon</th>
|
||||
<th>Color</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
|
||||
{ @metacodes.each do |metacode| }
|
||||
<tr>
|
||||
<td>{ metacode.name }</td>
|
||||
<td className="iconURL">{ metacode.icon }</td>
|
||||
{ if metacode.color }
|
||||
<td className="iconColor" style="background-color: { metacode.color }">
|
||||
{ metacode.color }
|
||||
</td>
|
||||
{ else }
|
||||
<td></td>
|
||||
{ end }
|
||||
<td>{ image_tag metacode.icon, width: 40 }</td>
|
||||
<td>{ link_to 'Edit', edit_metacode_path(metacode) }</td>
|
||||
</tr>
|
||||
{ end }
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default MyComponent
|
|
@ -1,15 +0,0 @@
|
|||
import React, { Component } from react
|
||||
|
||||
class MyComponent extends Component {
|
||||
render = () => {
|
||||
return (
|
||||
<div id="yield">
|
||||
<div className='centerContent'>
|
||||
{ render 'form' }
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default MyComponent
|
Loading…
Reference in a new issue