Normalized data in Redux, fix for asset URLs when rendered outside request
This commit is contained in:
		
					parent
					
						
							
								7939a216ff
							
						
					
				
			
			
				commit
				
					
						1022d682dc
					
				
			
		
					 9 changed files with 71 additions and 27 deletions
				
			
		|  | @ -7,9 +7,15 @@ const DisplayName = React.createClass({ | |||
|   }, | ||||
| 
 | ||||
|   render () { | ||||
|     let displayName = this.props.account.get('display_name'); | ||||
| 
 | ||||
|     if (displayName.length === 0) { | ||||
|       displayName = this.props.account.get('username'); | ||||
|     } | ||||
| 
 | ||||
|     return ( | ||||
|       <span style={{ display: 'block', maxWidth: '100%', overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis' }}> | ||||
|         <strong style={{ fontWeight: 'bold' }}>{this.props.account.get('display_name')}</strong> <span style={{ fontSize: '14px' }}>@{this.props.account.get('acct')}</span> | ||||
|         <strong style={{ fontWeight: 'bold' }}>{displayName}</strong> <span style={{ fontSize: '14px' }}>@{this.props.account.get('acct')}</span> | ||||
|       </span> | ||||
|     ); | ||||
|   } | ||||
|  |  | |||
|  | @ -3,9 +3,21 @@ import StatusList            from '../components/status_list'; | |||
| import { replyCompose }      from '../actions/compose'; | ||||
| import { reblog, favourite } from '../actions/interactions'; | ||||
| 
 | ||||
| function selectStatus(state, id) { | ||||
|   let status = state.getIn(['timelines', 'statuses', id]); | ||||
| 
 | ||||
|   status = status.set('account', state.getIn(['timelines', 'accounts', status.get('account')])); | ||||
| 
 | ||||
|   if (status.get('reblog') !== null) { | ||||
|     status = status.set('reblog', selectStatus(state, status.get('reblog'))); | ||||
|   } | ||||
| 
 | ||||
|   return status; | ||||
| }; | ||||
| 
 | ||||
| const mapStateToProps = function (state, props) { | ||||
|   return { | ||||
|     statuses: state.getIn(['timelines', props.type]) | ||||
|     statuses: state.getIn(['timelines', props.type]).map(id => selectStatus(state, id)) | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,31 +2,57 @@ import { TIMELINE_SET, TIMELINE_UPDATE }    from '../actions/timelines'; | |||
| import { REBLOG_SUCCESS, FAVOURITE_SUCCESS } from '../actions/interactions'; | ||||
| import Immutable                            from 'immutable'; | ||||
| 
 | ||||
| const initialState = Immutable.Map(); | ||||
| const initialState = Immutable.Map({ | ||||
|   home: Immutable.List(), | ||||
|   mentions: Immutable.List(), | ||||
|   statuses: Immutable.Map(), | ||||
|   accounts: Immutable.Map() | ||||
| }); | ||||
| 
 | ||||
| function updateMatchingStatuses(state, needle, callback) { | ||||
|   return state.map(function (list) { | ||||
|     return list.map(function (status) { | ||||
|       if (status.get('id') === needle.get('id')) { | ||||
|         return callback(status); | ||||
|       } else if (status.getIn(['reblog', 'id'], null) === needle.get('id')) { | ||||
|         return status.set('reblog', callback(status.get('reblog'))); | ||||
|       } | ||||
| function statusToMaps(state, status) { | ||||
|   // Separate account | ||||
|   let account = status.get('account'); | ||||
|   status = status.set('account', account.get('id')); | ||||
| 
 | ||||
|       return status; | ||||
|     }); | ||||
|   // Separate reblog, repeat for reblog | ||||
|   let reblog = status.get('reblog'); | ||||
| 
 | ||||
|   if (reblog !== null) { | ||||
|     status = status.set('reblog', reblog.get('id')); | ||||
|     state  = statusToMaps(state, reblog); | ||||
|   } | ||||
| 
 | ||||
|   return state.withMutations(map => { | ||||
|     map.setIn(['accounts', account.get('id')], account); | ||||
|     map.setIn(['statuses', status.get('id')], status); | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| function timelineToMaps(state, timeline, statuses) { | ||||
|   statuses.forEach((status, i) => { | ||||
|     state = statusToMaps(state, status); | ||||
|     state = state.setIn([timeline, i], status.get('id')); | ||||
|   }); | ||||
| 
 | ||||
|   return state; | ||||
| }; | ||||
| 
 | ||||
| function updateTimelineWithMaps(state, timeline, status) { | ||||
|   state = statusToMaps(state, status); | ||||
|   state = state.update(timeline, list => list.unshift(status.get('id'))); | ||||
| 
 | ||||
|   return state; | ||||
| }; | ||||
| 
 | ||||
| export default function timelines(state = initialState, action) { | ||||
|   switch(action.type) { | ||||
|     case TIMELINE_SET: | ||||
|       return state.set(action.timeline, Immutable.fromJS(action.statuses)); | ||||
|       return timelineToMaps(state, action.timeline, Immutable.fromJS(action.statuses)); | ||||
|     case TIMELINE_UPDATE: | ||||
|       return state.update(action.timeline, list => list.unshift(Immutable.fromJS(action.status))); | ||||
|       return updateTimelineWithMaps(state, action.timeline,Immutable.fromJS(action.status)); | ||||
|     case REBLOG_SUCCESS: | ||||
|     case FAVOURITE_SUCCESS: | ||||
|       return updateMatchingStatuses(state, action.status, () => Immutable.fromJS(action.response)); | ||||
|       return statusToMaps(state, Immutable.fromJS(action.response)); | ||||
|     default: | ||||
|       return state; | ||||
|   } | ||||
|  |  | |||
|  | @ -214,6 +214,6 @@ module AtomBuilderHelper | |||
|   end | ||||
| 
 | ||||
|   def single_link_avatar(xml, account, size, px) | ||||
|     xml.link('rel' => 'avatar', 'type' => account.avatar_content_type, 'media:width' => px, 'media:height' =>px, 'href' => asset_url(account.avatar.url(size, false))) | ||||
|     xml.link('rel' => 'avatar', 'type' => account.avatar_content_type, 'media:width' => px, 'media:height' =>px, 'href' => full_asset_url(account.avatar.url(size, false))) | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -1,11 +1,15 @@ | |||
| module RoutingHelper | ||||
|   extend ActiveSupport::Concern | ||||
|   include Rails.application.routes.url_helpers | ||||
|   include ActionView::Helpers::AssetUrlHelper | ||||
|   include ActionView::Helpers::AssetTagHelper | ||||
| 
 | ||||
|   included do | ||||
|     def default_url_options | ||||
|       ActionMailer::Base.default_url_options | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def full_asset_url(source) | ||||
|     File.join(root_url, ActionController::Base.helpers.asset_url(source)) | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ Nokogiri::XML::Builder.new do |xml| | |||
|     title      xml, @account.display_name | ||||
|     subtitle   xml, @account.note | ||||
|     updated_at xml, stream_updated_at | ||||
|     logo       xml, asset_url(@account.avatar.url(:medium, false)) | ||||
|     logo       xml, full_asset_url(@account.avatar.url(:medium, false)) | ||||
| 
 | ||||
|     author(xml) do | ||||
|       include_author xml, @account | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ object @account | |||
| attributes :id, :username, :acct, :display_name, :note | ||||
| 
 | ||||
| node(:url)             { |account| url_for_target(account) } | ||||
| node(:avatar)          { |account| asset_url(account.avatar.url(:large, false)) } | ||||
| node(:avatar)          { |account| full_asset_url(account.avatar.url(:large, false)) } | ||||
| node(:followers_count) { |account| account.followers.count } | ||||
| node(:following_count) { |account| account.following.count } | ||||
| node(:statuses_count)  { |account| account.statuses.count  } | ||||
|  |  | |||
|  | @ -1,9 +1,9 @@ | |||
| Rails.application.configure do | ||||
|   config.x.local_domain = ENV['LOCAL_DOMAIN'] || 'localhost' | ||||
|   config.x.local_domain = ENV['LOCAL_DOMAIN'] || "localhost:#{ENV['PORT'] || 3000}" | ||||
|   config.x.hub_url      = ENV['HUB_URL']      || 'https://pubsubhubbub.superfeedr.com' | ||||
|   config.x.use_https    = ENV['LOCAL_HTTPS'] == 'true' | ||||
| 
 | ||||
|   config.action_mailer.default_url_options = { host: config.x.local_domain, protocol: config.x.use_https ? 'https://' : 'http://' } | ||||
|   config.action_mailer.default_url_options = { host: config.x.local_domain, protocol: config.x.use_https ? 'https://' : 'http://', trailing_slash: false } | ||||
| 
 | ||||
|   if Rails.env.production? | ||||
|     config.action_cable.allowed_request_origins = ["http#{config.x.use_https ? 's' : ''}://#{config.x.local_domain}"] | ||||
|  |  | |||
|  | @ -1,11 +1,7 @@ | |||
| require 'rails_helper' | ||||
| 
 | ||||
| RSpec.describe ApplicationHelper, type: :helper do | ||||
|   let(:local_domain) { 'local.tld' } | ||||
| 
 | ||||
|   before do | ||||
|     Rails.configuration.x.local_domain = local_domain | ||||
|   end | ||||
|   let(:local_domain) { Rails.configuration.x.local_domain } | ||||
| 
 | ||||
|   describe '#unique_tag' do | ||||
|     it 'returns a string' do | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue