Enable users to star maps, and to see their starred collection (#615)

* enable starring

* users should be able to star others maps

* proper star icon

* starred maps display as starred without refreshing

* oops

* make phrasing clearer
This commit is contained in:
Connor Turland 2016-08-31 16:58:49 -04:00 committed by GitHub
parent 370499e453
commit 19dabe81cc
17 changed files with 335 additions and 140 deletions

BIN
app/assets/images/star.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 B

View file

@ -105,6 +105,7 @@ Metamaps.GlobalUI = {
var myCollection = Metamaps.Maps.Mine ? Metamaps.Maps.Mine : [];
var sharedCollection = Metamaps.Maps.Shared ? Metamaps.Maps.Shared : [];
var starredCollection = Metamaps.Maps.Starred ? Metamaps.Maps.Starred : [];
var mapperCollection = [];
var mapperOptionsObj = {id: 'mapper', sortBy: 'updated_at' };
if (Metamaps.Maps.Mapper) {
@ -115,6 +116,7 @@ Metamaps.GlobalUI = {
var activeCollection = Metamaps.Maps.Active ? Metamaps.Maps.Active : [];
Metamaps.Maps.Mine = new Metamaps.Backbone.MapsCollection(myCollection, {id: 'mine', sortBy: 'updated_at' });
Metamaps.Maps.Shared = new Metamaps.Backbone.MapsCollection(sharedCollection, {id: 'shared', sortBy: 'updated_at' });
Metamaps.Maps.Starred = new Metamaps.Backbone.MapsCollection(starredCollection, {id: 'starred', sortBy: 'updated_at' });
// 'Mapper' refers to another mapper
Metamaps.Maps.Mapper = new Metamaps.Backbone.MapsCollection(mapperCollection, mapperOptionsObj);
Metamaps.Maps.Featured = new Metamaps.Backbone.MapsCollection(featuredCollection, {id: 'featured', sortBy: 'updated_at' });

View file

@ -49,12 +49,18 @@ Metamaps.Map = {
return false
})
$('.starMap').click(function () {
if ($(this).is('.starred')) self.unstar()
else self.star()
})
$('.sidebarFork').click(function () {
self.fork()
})
Metamaps.GlobalUI.CreateMap.emptyForkMapForm = $('#fork_map').html()
self.updateStar()
self.InfoBox.init()
self.CheatSheet.init()
@ -70,6 +76,7 @@ Metamaps.Map = {
Metamaps.Synapses = new bb.SynapseCollection(data.synapses)
Metamaps.Mappings = new bb.MappingCollection(data.mappings)
Metamaps.Messages = data.messages
Metamaps.Stars = data.stars
Metamaps.Backbone.attachCollectionEvents()
var map = Metamaps.Active.Map
@ -86,6 +93,8 @@ Metamaps.Map = {
$('.wrapper').addClass('commonsMap')
}
Metamaps.Map.updateStar()
// set filter mapper H3 text
$('#filter_by_mapper h3').html('MAPPERS')
@ -134,6 +143,35 @@ Metamaps.Map = {
Metamaps.Realtime.endActiveMap()
}
},
updateStar: function () {
if (!Metamaps.Active.Mapper || !Metamaps.Stars) return
// update the star/unstar icon
if (Metamaps.Stars.find(function (s) { return s.user_id === Metamaps.Active.Mapper.id })) {
$('.starMap').addClass('starred')
$('.starMap .tooltipsAbove').html('Unstar')
} else {
$('.starMap').removeClass('starred')
$('.starMap .tooltipsAbove').html('Star')
}
},
star: function () {
var self = Metamaps.Map
if (!Metamaps.Active.Map) return
$.post('/maps/' + Metamaps.Active.Map.id + '/star')
Metamaps.Stars.push({ user_id: Metamaps.Active.Mapper.id, map_id: Metamaps.Active.Map.id })
Metamaps.Maps.Starred.add(Metamaps.Active.Map)
self.updateStar()
},
unstar: function () {
var self = Metamaps.Map
if (!Metamaps.Active.Map) return
$.post('/maps/' + Metamaps.Active.Map.id + '/unstar')
Metamaps.Stars = Metamaps.Stars.filter(function (s) { return s.user_id != Metamaps.Active.Mapper.id })
Metamaps.Maps.Starred.remove(Metamaps.Active.Map)
self.updateStar()
},
fork: function () {
Metamaps.GlobalUI.openLightbox('forkmap')

View file

@ -75,7 +75,7 @@
// either 'featured', 'mapper', or 'active'
var capitalize = section.charAt(0).toUpperCase() + section.slice(1)
if (section === 'shared' || section === 'featured' || section === 'active') {
if (section === 'shared' || section === 'featured' || section === 'active' || section === 'starred') {
document.title = 'Explore ' + capitalize + ' Maps | Metamaps'
} else if (section === 'mapper') {
$.ajax({

View file

@ -334,7 +334,8 @@
right: 70px;
}
.mapPage .openCheatsheet .tooltipsAbove, .topicPage .openCheatsheet .tooltipsAbove {
left: 29px;
right: 1px;
left: auto;
}
.unauthenticated .homePage .infoAndHelp {
@ -375,7 +376,22 @@
.mapPage .mapInfoIcon {
top: 0;
}
.starMap {
background-image: url(<%= asset_data_uri('star.png') %>);
background-position: 0 0;
background-repeat: no-repeat;
width: 32px;
}
.starMap:hover, .starMap.starred {
background-position: 0 -32px;
}
.starMap.starred:hover {
background-position: 0 0;
}
.unauthenticated .mapPage .starMap {
display: none;
}
/* end infoAndHelp */
@ -433,7 +449,7 @@
}
.zoomExtents:hover .tooltips, .zoomIn:hover .tooltips, .zoomOut:hover .tooltips, .takeScreenshot:hover .tooltips, .sidebarFilterIcon:hover .tooltipsUnder, .sidebarForkIcon:hover .tooltipsUnder, .addMap:hover .tooltipsUnder, .authenticated .sidebarAccountIcon:hover .tooltipsUnder,
.mapInfoIcon:hover .tooltipsAbove, .openCheatsheet:hover .tooltipsAbove, .chat-button:hover .tooltips {
.mapInfoIcon:hover .tooltipsAbove, .openCheatsheet:hover .tooltipsAbove, .chat-button:hover .tooltips, .starMap:hover .tooltipsAbove {
display: block;
}
@ -517,6 +533,13 @@
top: 10px;
}
.starMap .tooltipsAbove {
left: -2px;
}
.starMap.starred .tooltipsAbove {
left: -8px;
}
.openCheatsheet .tooltipsAbove {
left: -4px;
}
@ -554,7 +577,7 @@
right: 37% !important;
}
.mapInfoIcon div:after, .openCheatsheet div:after {
.mapInfoIcon div:after, .openCheatsheet div:after, .starMap div:after {
content: '';
position: absolute;
top: 76%;
@ -700,6 +723,10 @@
background-image: url(<%= asset_data_uri 'exploremaps_sprite.png' %>);
background-position: -64px 0;
}
.exploreMapsCenter .starredMaps .exploreMapsIcon {
background-image: url(<%= asset_data_uri 'exploremaps_sprite.png' %>);
background-position: -64px 0;
}
.myMaps:hover .exploreMapsIcon, .myMaps.active .exploreMapsIcon {
background-position: 0 -32px;
}
@ -709,6 +736,9 @@
.featuredMaps:hover .exploreMapsIcon, .featuredMaps.active .exploreMapsIcon {
background-position: -64px -32px;
}
.starredMaps:hover .exploreMapsIcon, .starredMaps.active .exploreMapsIcon {
background-position: -64px -32px;
}
.sharedMaps:hover .exploreMapsIcon, .sharedMaps.active .exploreMapsIcon {
background-position: -96px -32px;
}

View file

@ -1,7 +1,7 @@
class MapsController < ApplicationController
before_action :require_user, only: [:create, :update, :access, :screenshot, :events, :destroy]
after_action :verify_authorized, except: [:activemaps, :featuredmaps, :mymaps, :sharedmaps, :usermaps, :events]
after_action :verify_policy_scoped, only: [:activemaps, :featuredmaps, :mymaps, :sharedmaps, :usermaps]
before_action :require_user, only: [:create, :update, :access, :star, :unstar, :screenshot, :events, :destroy]
after_action :verify_authorized, except: [:activemaps, :featuredmaps, :mymaps, :sharedmaps, :starredmaps, :usermaps, :events]
after_action :verify_policy_scoped, only: [:activemaps, :featuredmaps, :mymaps, :sharedmaps, :starredmaps, :usermaps]
respond_to :html, :json, :csv
@ -73,6 +73,25 @@ class MapsController < ApplicationController
end
end
# GET /explore/starred
def starredmaps
unless authenticated?
skip_policy_scope
return redirect_to explore_active_path
end
page = params[:page].present? ? params[:page] : 1
stars = current_user.stars.map(&:map_id)
@maps = policy_scope(
Map.where('maps.id IN (?)', stars)
).order('updated_at DESC').page(page).per(20)
respond_to do |format|
format.html { respond_with(@maps, @user) }
format.json { render json: @maps }
end
end
# GET /explore/mapper/:id
def usermaps
page = params[:page].present? ? params[:page] : 1
@ -113,8 +132,9 @@ class MapsController < ApplicationController
@allsynapses = @map.synapses.to_a.delete_if { |s| !policy(s).show? }
@allmappings = @map.mappings.to_a.delete_if { |m| !policy(m).show? }
@allmessages = @map.messages.sort_by(&:created_at)
@allstars = @map.stars
respond_with(@allmappers, @allcollaborators, @allmappings, @allsynapses, @alltopics, @allmessages, @map)
respond_with(@allmappers, @allcollaborators, @allmappings, @allsynapses, @alltopics, @allmessages, @allstars, @map)
end
format.json { render json: @map }
format.csv { redirect_to action: :export, format: :csv }
@ -175,6 +195,7 @@ class MapsController < ApplicationController
@json['mappers'] = @allmappers
@json['collaborators'] = @allcollaborators
@json['messages'] = @map.messages.sort_by(&:created_at)
@json['stars'] = @map.stars
respond_to do |format|
format.json { render json: @json }
@ -279,6 +300,38 @@ class MapsController < ApplicationController
end
end
# POST maps/:id/star
def star
@map = Map.find(params[:id])
authorize @map
star = Star.find_by_map_id_and_user_id(@map.id, current_user.id)
if not star
star = Star.create(map_id: @map.id, user_id: current_user.id)
end
respond_to do |format|
format.json do
render json: { message: 'Successfully starred map' }
end
end
end
# POST maps/:id/unstar
def unstar
@map = Map.find(params[:id])
authorize @map
star = Star.find_by_map_id_and_user_id(@map.id, current_user.id)
if star
star.delete
end
respond_to do |format|
format.json do
render json: { message: 'Successfully unstarred map' }
end
end
end
# POST maps/:id/upload_screenshot
def screenshot
@map = Map.find(params[:id])

View file

@ -6,6 +6,7 @@ class Map < ActiveRecord::Base
has_many :topics, through: :topicmappings, source: :mappable, source_type: 'Topic'
has_many :synapses, through: :synapsemappings, source: :mappable, source_type: 'Synapse'
has_many :messages, as: :resource, dependent: :destroy
has_many :stars
has_many :user_maps, dependent: :destroy
has_many :collaborators, through: :user_maps, source: :user

4
app/models/star.rb Normal file
View file

@ -0,0 +1,4 @@
class Star < ActiveRecord::Base
belongs_to :user
belongs_to :map
end

View file

@ -6,6 +6,7 @@ class User < ActiveRecord::Base
has_many :maps
has_many :mappings
has_many :tokens
has_many :stars
has_many :user_maps, dependent: :destroy
has_many :shared_maps, through: :user_maps, source: :map
@ -78,6 +79,10 @@ class User < ActiveRecord::Base
end
end
def starred_map?(map)
return !!self.stars.index{|s| s.map_id == map.id }
end
def settings
# make sure we always return a UserPreference instance
self[:settings] = UserPreference.new if self[:settings].nil?

View file

@ -57,6 +57,14 @@ class MapPolicy < ApplicationPolicy
user.present? && record.user == user
end
def star?
unstar?
end
def unstar?
user.present?
end
def screenshot?
update?
end

View file

@ -7,6 +7,11 @@
<div class="infoAndHelp">
<%= render :partial => 'maps/mapinfobox' %>
<% starred = current_user && @map && current_user.starred_map?(@map)
starClass = starred ? 'starred' : ''
tooltip = starred ? 'Star' : 'Unstar' %>
<div class="starMap infoElement mapElement <%= starClass %>"><div class="tooltipsAbove"><%= tooltip %></div></div>
<div class="mapInfoIcon infoElement mapElement"><div class="tooltipsAbove">Map Info</div></div>
<div class="openCheatsheet openLightbox infoElement mapElement" data-open="cheatsheet"><div class="tooltipsAbove">Help</div></div>
<div class="clearfloat"></div>

View file

@ -16,5 +16,6 @@
Metamaps.Synapses = <%= @allsynapses.to_json.html_safe %>;
Metamaps.Mappings = <%= @allmappings.to_json.html_safe %>;
Metamaps.Messages = <%= @allmessages.to_json.html_safe %>;
Metamaps.Stars = <%= @allstars.to_json.html_safe %>;
Metamaps.Visualize.type = "ForceDirected";
</script>

View file

@ -0,0 +1,16 @@
<% #
# @file
# Shows a list of current user's starred maps
# GET /explore/starred(.:format)
# %>
<script>
Metamaps.Maps.Starred = <%= @maps.to_json.html_safe %>;
Metamaps.currentPage = "starred";
<% content_for :title, "Starred Maps | Metamaps" %>
<% content_for :mobile_title, "Starred Maps" %>
Metamaps.currentSection = "explore";
Metamaps.GlobalUI.Search.open();
Metamaps.GlobalUI.Search.lock();
</script>

View file

@ -40,11 +40,14 @@ Metamaps::Application.routes.draw do
get 'maps/:id/contains', to: 'maps#contains', as: :contains
post 'maps/:id/upload_screenshot', to: 'maps#screenshot', as: :screenshot
post 'maps/:id/access', to: 'maps#access', as: :access, defaults: { format: :json }
post 'maps/:id/star', to: 'maps#star', defaults: { format: :json }
post 'maps/:id/unstar', to: 'maps#unstar', defaults: { format: :json }
get 'explore/active', to: 'maps#activemaps'
get 'explore/featured', to: 'maps#featuredmaps'
get 'explore/mine', to: 'maps#mymaps'
get 'explore/shared', to: 'maps#sharedmaps'
get 'explore/starred', to: 'maps#starredmaps'
get 'explore/mapper/:id', to: 'maps#usermaps'
devise_for :users, controllers: { registrations: 'users/registrations', passwords: 'users/passwords', sessions: 'devise/sessions' }, skip: :sessions

View file

@ -0,0 +1,9 @@
class Star < ActiveRecord::Migration
def change
create_table :stars do |t|
t.references :user, index: true
t.references :map, index: true
t.timestamps
end
end
end

View file

@ -11,22 +11,23 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20_160_401_133_937) do
# These are extensions that must be enabled in order to support this database
enable_extension 'plpgsql'
ActiveRecord::Schema.define(version: 20160820231717) do
create_table 'delayed_jobs', force: :cascade do |t|
t.integer 'priority', default: 0, null: false
t.integer 'attempts', default: 0, null: false
t.text 'handler', null: false
t.text 'last_error'
t.datetime 'run_at'
t.datetime 'locked_at'
t.datetime 'failed_at'
t.string 'locked_by'
t.string 'queue'
t.datetime 'created_at'
t.datetime 'updated_at'
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "delayed_jobs", force: :cascade do |t|
t.integer "priority", default: 0, null: false
t.integer "attempts", default: 0, null: false
t.text "handler", null: false
t.text "last_error"
t.datetime "run_at"
t.datetime "locked_at"
t.datetime "failed_at"
t.string "locked_by"
t.string "queue"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "delayed_jobs", ["priority", "run_at"], name: "delayed_jobs_priority", using: :btree
@ -37,12 +38,15 @@ ActiveRecord::Schema.define(version: 20_160_401_133_937) do
t.string "eventable_type"
t.integer "user_id"
t.integer "map_id"
t.integer "sequence_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "events", ["eventable_type", "eventable_id"], name: "index_events_on_eventable_type_and_eventable_id", using: :btree
add_index "events", ["map_id", "sequence_id"], name: "index_events_on_map_id_and_sequence_id", unique: true, using: :btree
add_index "events", ["map_id"], name: "index_events_on_map_id", using: :btree
add_index "events", ["sequence_id"], name: "index_events_on_sequence_id", using: :btree
add_index "events", ["user_id"], name: "index_events_on_user_id", using: :btree
create_table "in_metacode_sets", force: :cascade do |t|
@ -52,21 +56,21 @@ ActiveRecord::Schema.define(version: 20_160_401_133_937) do
t.datetime "updated_at", null: false
end
add_index 'in_metacode_sets', ['metacode_id'], name: 'index_in_metacode_sets_on_metacode_id', using: :btree
add_index 'in_metacode_sets', ['metacode_set_id'], name: 'index_in_metacode_sets_on_metacode_set_id', using: :btree
add_index "in_metacode_sets", ["metacode_id"], name: "index_in_metacode_sets_on_metacode_id", using: :btree
add_index "in_metacode_sets", ["metacode_set_id"], name: "index_in_metacode_sets_on_metacode_set_id", using: :btree
create_table 'mappings', force: :cascade do |t|
t.text 'category'
t.integer 'xloc'
t.integer 'yloc'
t.integer 'topic_id'
t.integer 'synapse_id'
t.integer 'map_id'
t.integer 'user_id'
t.datetime 'created_at', null: false
t.datetime 'updated_at', null: false
t.integer 'mappable_id'
t.string 'mappable_type'
create_table "mappings", force: :cascade do |t|
t.text "category"
t.integer "xloc"
t.integer "yloc"
t.integer "topic_id"
t.integer "synapse_id"
t.integer "map_id"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "mappable_id"
t.string "mappable_type"
end
add_index "mappings", ["map_id", "synapse_id"], name: "index_mappings_on_map_id_and_synapse_id", using: :btree
@ -76,29 +80,29 @@ ActiveRecord::Schema.define(version: 20_160_401_133_937) do
add_index "mappings", ["user_id"], name: "index_mappings_on_user_id", using: :btree
create_table "maps", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "name"
t.boolean "arranged"
t.text "desc"
t.text "permission"
t.integer "user_id"
t.boolean "arranged"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "featured"
t.string "screenshot_file_name", limit: 255
t.string "screenshot_content_type", limit: 255
t.string "screenshot_file_name"
t.string "screenshot_content_type"
t.integer "screenshot_file_size"
t.datetime "screenshot_updated_at"
end
add_index 'maps', ['user_id'], name: 'index_maps_on_user_id', using: :btree
add_index "maps", ["user_id"], name: "index_maps_on_user_id", using: :btree
create_table 'messages', force: :cascade do |t|
t.text 'message'
t.integer 'user_id'
t.integer 'resource_id'
t.string 'resource_type'
t.datetime 'created_at'
t.datetime 'updated_at'
create_table "messages", force: :cascade do |t|
t.text "message"
t.integer "user_id"
t.integer "resource_id"
t.string "resource_type"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "messages", ["resource_id"], name: "index_messages_on_resource_id", using: :btree
@ -106,93 +110,103 @@ ActiveRecord::Schema.define(version: 20_160_401_133_937) do
add_index "messages", ["user_id"], name: "index_messages_on_user_id", using: :btree
create_table "metacode_sets", force: :cascade do |t|
t.string "name", limit: 255
t.string "name"
t.text "desc"
t.integer "user_id"
t.boolean "mapperContributed"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "metacode_sets", ["user_id"], name: "index_metacode_sets_on_user_id", using: :btree
create_table "metacodes", force: :cascade do |t|
t.text "name"
t.string "manual_icon", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "color", limit: 255
t.string "manual_icon"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "color"
t.string "aws_icon_file_name"
t.string "aws_icon_content_type"
t.integer "aws_icon_file_size"
t.datetime "aws_icon_updated_at"
end
create_table 'oauth_access_grants', force: :cascade do |t|
t.integer 'resource_owner_id', null: false
t.integer 'application_id', null: false
t.string 'token', null: false
t.integer 'expires_in', null: false
t.text 'redirect_uri', null: false
t.datetime 'created_at', null: false
t.datetime 'revoked_at'
t.string 'scopes'
create_table "oauth_access_grants", force: :cascade do |t|
t.integer "resource_owner_id", null: false
t.integer "application_id", null: false
t.string "token", null: false
t.integer "expires_in", null: false
t.text "redirect_uri", null: false
t.datetime "created_at", null: false
t.datetime "revoked_at"
t.string "scopes"
end
add_index 'oauth_access_grants', ['token'], name: 'index_oauth_access_grants_on_token', unique: true, using: :btree
add_index "oauth_access_grants", ["token"], name: "index_oauth_access_grants_on_token", unique: true, using: :btree
create_table 'oauth_access_tokens', force: :cascade do |t|
t.integer 'resource_owner_id'
t.integer 'application_id'
t.string 'token', null: false
t.string 'refresh_token'
t.integer 'expires_in'
t.datetime 'revoked_at'
t.datetime 'created_at', null: false
t.string 'scopes'
create_table "oauth_access_tokens", force: :cascade do |t|
t.integer "resource_owner_id"
t.integer "application_id"
t.string "token", null: false
t.string "refresh_token"
t.integer "expires_in"
t.datetime "revoked_at"
t.datetime "created_at", null: false
t.string "scopes"
end
add_index 'oauth_access_tokens', ['refresh_token'], name: 'index_oauth_access_tokens_on_refresh_token', unique: true, using: :btree
add_index 'oauth_access_tokens', ['resource_owner_id'], name: 'index_oauth_access_tokens_on_resource_owner_id', using: :btree
add_index 'oauth_access_tokens', ['token'], name: 'index_oauth_access_tokens_on_token', unique: true, using: :btree
add_index "oauth_access_tokens", ["refresh_token"], name: "index_oauth_access_tokens_on_refresh_token", unique: true, using: :btree
add_index "oauth_access_tokens", ["resource_owner_id"], name: "index_oauth_access_tokens_on_resource_owner_id", using: :btree
add_index "oauth_access_tokens", ["token"], name: "index_oauth_access_tokens_on_token", unique: true, using: :btree
create_table 'oauth_applications', force: :cascade do |t|
t.string 'name', null: false
t.string 'uid', null: false
t.string 'secret', null: false
t.text 'redirect_uri', null: false
t.string 'scopes', default: '', null: false
t.datetime 'created_at'
t.datetime 'updated_at'
create_table "oauth_applications", force: :cascade do |t|
t.string "name", null: false
t.string "uid", null: false
t.string "secret", null: false
t.text "redirect_uri", null: false
t.string "scopes", default: "", null: false
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "oauth_applications", ["uid"], name: "index_oauth_applications_on_uid", unique: true, using: :btree
create_table "stars", force: :cascade do |t|
t.integer "user_id"
t.integer "map_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "stars", ["map_id"], name: "index_stars_on_map_id", using: :btree
add_index "stars", ["user_id"], name: "index_stars_on_user_id", using: :btree
create_table "synapses", force: :cascade do |t|
t.text "desc"
t.text "category"
t.text "weight"
t.text "permission"
t.integer "node1_id"
t.integer "node2_id"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "permission"
t.text "weight"
t.integer "defer_to_map_id"
end
add_index 'synapses', %w(node1_id node1_id), name: 'index_synapses_on_node1_id_and_node1_id', using: :btree
add_index 'synapses', ['node1_id'], name: 'index_synapses_on_node1_id', using: :btree
add_index 'synapses', %w(node2_id node2_id), name: 'index_synapses_on_node2_id_and_node2_id', using: :btree
add_index 'synapses', ['node2_id'], name: 'index_synapses_on_node2_id', using: :btree
add_index 'synapses', ['user_id'], name: 'index_synapses_on_user_id', using: :btree
add_index "synapses", ["node1_id", "node1_id"], name: "index_synapses_on_node1_id_and_node1_id", using: :btree
add_index "synapses", ["node1_id"], name: "index_synapses_on_node1_id", using: :btree
add_index "synapses", ["node2_id", "node2_id"], name: "index_synapses_on_node2_id_and_node2_id", using: :btree
add_index "synapses", ["node2_id"], name: "index_synapses_on_node2_id", using: :btree
add_index "synapses", ["user_id"], name: "index_synapses_on_user_id", using: :btree
create_table 'tokens', force: :cascade do |t|
t.string 'token'
t.string 'description'
t.integer 'user_id'
t.datetime 'created_at', null: false
t.datetime 'updated_at', null: false
create_table "tokens", force: :cascade do |t|
t.string "token"
t.string "description"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "tokens", ["user_id"], name: "index_tokens_on_user_id", using: :btree
@ -201,76 +215,76 @@ ActiveRecord::Schema.define(version: 20_160_401_133_937) do
t.text "name"
t.text "desc"
t.text "link"
t.text "permission"
t.integer "user_id"
t.integer "metacode_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "permission"
t.string "image_file_name", limit: 255
t.string "image_content_type", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
t.string "audio_file_name", limit: 255
t.string "audio_content_type", limit: 255
t.string "audio_file_name"
t.string "audio_content_type"
t.integer "audio_file_size"
t.datetime "audio_updated_at"
t.integer "defer_to_map_id"
end
add_index 'topics', ['metacode_id'], name: 'index_topics_on_metacode_id', using: :btree
add_index 'topics', ['user_id'], name: 'index_topics_on_user_id', using: :btree
add_index "topics", ["metacode_id"], name: "index_topics_on_metacode_id", using: :btree
add_index "topics", ["user_id"], name: "index_topics_on_user_id", using: :btree
create_table 'user_maps', force: :cascade do |t|
t.integer 'user_id'
t.integer 'map_id'
t.datetime 'created_at'
t.datetime 'updated_at'
create_table "user_maps", force: :cascade do |t|
t.integer "user_id"
t.integer "map_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "user_maps", ["map_id"], name: "index_user_maps_on_map_id", using: :btree
add_index "user_maps", ["user_id"], name: "index_user_maps_on_user_id", using: :btree
create_table "users", force: :cascade do |t|
t.string "name", limit: 255
t.string "email", limit: 255
t.string "crypted_password", limit: 255
t.string "password_salt", limit: 255
t.string "persistence_token", limit: 255
t.string "perishable_token", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name"
t.string "email"
t.text "settings"
t.string "code", limit: 8
t.string "joinedwithcode", limit: 8
t.text "settings"
t.string "crypted_password"
t.string "password_salt"
t.string "persistence_token"
t.string "perishable_token"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "encrypted_password", limit: 128, default: ""
t.string "remember_token", limit: 255
t.string "remember_token"
t.datetime "remember_created_at"
t.string "reset_password_token", limit: 255
t.string "reset_password_token"
t.datetime "last_sign_in_at"
t.string "last_sign_in_ip", limit: 255
t.string "last_sign_in_ip"
t.integer "sign_in_count", default: 0
t.datetime "current_sign_in_at"
t.string "current_sign_in_ip", limit: 255
t.string "current_sign_in_ip"
t.datetime "reset_password_sent_at"
t.boolean "admin"
t.string "image_file_name", limit: 255
t.string "image_content_type", limit: 255
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
t.integer "generation"
end
add_index 'users', ['reset_password_token'], name: 'index_users_on_reset_password_token', unique: true, using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
create_table 'webhooks', force: :cascade do |t|
t.integer 'hookable_id'
t.string 'hookable_type'
t.string 'kind', null: false
t.string 'uri', null: false
t.text 'event_types', default: [], array: true
create_table "webhooks", force: :cascade do |t|
t.integer "hookable_id"
t.string "hookable_type"
t.string "kind", null: false
t.string "uri", null: false
t.text "event_types", default: [], array: true
end
add_index 'webhooks', %w(hookable_type hookable_id), name: 'index_webhooks_on_hookable_type_and_hookable_id', using: :btree
add_index "webhooks", ["hookable_type", "hookable_id"], name: "index_webhooks_on_hookable_type_and_hookable_id", using: :btree
add_foreign_key 'tokens', 'users'
add_foreign_key "tokens", "users"
end

View file

@ -28,7 +28,7 @@ class Header extends Component {
return forClass
}
const explore = section == "mine" || section == "active" || section == "shared" || section == "featured"
const explore = section == "mine" || section == "active" || section == "starred" || section == "shared" || section == "featured"
const mapper = section == "mapper"
return (
@ -48,6 +48,12 @@ class Header extends Component {
data-router="true"
text="Shared With Me"
/>
<MapLink show={signedIn && explore}
href="/explore/starred"
linkClass={activeClass("starred")}
data-router="true"
text="Starred By Me"
/>
<MapLink show={explore}
href={signedIn ? "/" : "/explore/active"}
linkClass={activeClass("active")}
@ -60,7 +66,7 @@ class Header extends Component {
data-router="true"
text="Featured Maps"
/>
{mapper ? (
<div className='exploreMapsButton active mapperButton'>
<img className='exploreMapperImage' width='24' height='24' src={this.props.user.image} />