diff options
Diffstat (limited to 'app')
18 files changed, 103 insertions, 20 deletions
diff --git a/app/assets/javascripts/components/actions/accounts.jsx b/app/assets/javascripts/components/actions/accounts.jsx index 05fa8e68d..37ebb9969 100644 --- a/app/assets/javascripts/components/actions/accounts.jsx +++ b/app/assets/javascripts/components/actions/accounts.jsx @@ -579,15 +579,18 @@ export function expandFollowingFail(id, error) { }; }; -export function fetchRelationships(account_ids) { +export function fetchRelationships(accountIds) { return (dispatch, getState) => { - if (account_ids.length === 0) { + const loadedRelationships = getState().get('relationships'); + const newAccountIds = accountIds.filter(id => loadedRelationships.get(id, null) === null); + + if (newAccountIds.length === 0) { return; } - dispatch(fetchRelationshipsRequest(account_ids)); + dispatch(fetchRelationshipsRequest(newAccountIds)); - api(getState).get(`/api/v1/accounts/relationships?${account_ids.map(id => `id[]=${id}`).join('&')}`).then(response => { + api(getState).get(`/api/v1/accounts/relationships?${newAccountIds.map(id => `id[]=${id}`).join('&')}`).then(response => { dispatch(fetchRelationshipsSuccess(response.data)); }).catch(error => { dispatch(fetchRelationshipsFail(error)); diff --git a/app/assets/javascripts/components/actions/timelines.jsx b/app/assets/javascripts/components/actions/timelines.jsx index 3e2d4ff43..6cd1f04b3 100644 --- a/app/assets/javascripts/components/actions/timelines.jsx +++ b/app/assets/javascripts/components/actions/timelines.jsx @@ -14,6 +14,9 @@ export const TIMELINE_EXPAND_FAIL = 'TIMELINE_EXPAND_FAIL'; export const TIMELINE_SCROLL_TOP = 'TIMELINE_SCROLL_TOP'; +export const TIMELINE_CONNECT = 'TIMELINE_CONNECT'; +export const TIMELINE_DISCONNECT = 'TIMELINE_DISCONNECT'; + export function refreshTimelineSuccess(timeline, statuses, skipLoading, next) { return { type: TIMELINE_REFRESH_SUCCESS, @@ -76,6 +79,11 @@ export function refreshTimeline(timeline, id = null) { let skipLoading = false; if (newestId !== null && getState().getIn(['timelines', timeline, 'loaded']) && (id === null || getState().getIn(['timelines', timeline, 'id']) === id)) { + if (id === null && getState().getIn(['timelines', timeline, 'online'])) { + // Skip refreshing when timeline is live anyway + return; + } + params = { ...params, since_id: newestId }; skipLoading = true; } @@ -162,3 +170,17 @@ export function scrollTopTimeline(timeline, top) { top }; }; + +export function connectTimeline(timeline) { + return { + type: TIMELINE_CONNECT, + timeline + }; +}; + +export function disconnectTimeline(timeline) { + return { + type: TIMELINE_DISCONNECT, + timeline + }; +}; diff --git a/app/assets/javascripts/components/containers/mastodon.jsx b/app/assets/javascripts/components/containers/mastodon.jsx index 40fbac525..6dc08bb4c 100644 --- a/app/assets/javascripts/components/containers/mastodon.jsx +++ b/app/assets/javascripts/components/containers/mastodon.jsx @@ -4,7 +4,9 @@ import { refreshTimelineSuccess, updateTimeline, deleteFromTimelines, - refreshTimeline + refreshTimeline, + connectTimeline, + disconnectTimeline } from '../actions/timelines'; import { updateNotifications, refreshNotifications } from '../actions/notifications'; import createBrowserHistory from 'history/lib/createBrowserHistory'; @@ -70,6 +72,14 @@ const Mastodon = React.createClass({ this.subscription = createStream(accessToken, 'user', { + connected () { + store.dispatch(connectTimeline('home')); + }, + + disconnected () { + store.dispatch(disconnectTimeline('home')); + }, + received (data) { switch(data.event) { case 'update': @@ -85,6 +95,7 @@ const Mastodon = React.createClass({ }, reconnected () { + store.dispatch(connectTimeline('home')); store.dispatch(refreshTimeline('home')); store.dispatch(refreshNotifications()); } diff --git a/app/assets/javascripts/components/features/community_timeline/index.jsx b/app/assets/javascripts/components/features/community_timeline/index.jsx index 2cfd7b2fe..0957338cf 100644 --- a/app/assets/javascripts/components/features/community_timeline/index.jsx +++ b/app/assets/javascripts/components/features/community_timeline/index.jsx @@ -5,7 +5,9 @@ import Column from '../ui/components/column'; import { refreshTimeline, updateTimeline, - deleteFromTimelines + deleteFromTimelines, + connectTimeline, + disconnectTimeline } from '../../actions/timelines'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ColumnBackButtonSlim from '../../components/column_back_button_slim'; @@ -44,6 +46,18 @@ const CommunityTimeline = React.createClass({ subscription = createStream(accessToken, 'public:local', { + connected () { + dispatch(connectTimeline('community')); + }, + + reconnected () { + dispatch(connectTimeline('community')); + }, + + disconnected () { + dispatch(disconnectTimeline('community')); + }, + received (data) { switch(data.event) { case 'update': diff --git a/app/assets/javascripts/components/features/compose/index.jsx b/app/assets/javascripts/components/features/compose/index.jsx index d4df259dc..9421de3ff 100644 --- a/app/assets/javascripts/components/features/compose/index.jsx +++ b/app/assets/javascripts/components/features/compose/index.jsx @@ -72,7 +72,7 @@ const Compose = React.createClass({ <Motion defaultStyle={{ x: -100 }} style={{ x: spring(showSearch ? 0 : -100, { stiffness: 210, damping: 20 }) }}> {({ x }) => - <div className='drawer__inner darker' style={{ transform: `translateX(${x}%)` }}> + <div className='drawer__inner darker' style={{ transform: `translateX(${x}%)`, visibility: x === -100 ? 'hidden' : 'visible' }}> <SearchResultsContainer /> </div> } diff --git a/app/assets/javascripts/components/features/home_timeline/components/column_settings.jsx b/app/assets/javascripts/components/features/home_timeline/components/column_settings.jsx index 3317210bf..92e700874 100644 --- a/app/assets/javascripts/components/features/home_timeline/components/column_settings.jsx +++ b/app/assets/javascripts/components/features/home_timeline/components/column_settings.jsx @@ -6,7 +6,7 @@ import SettingToggle from '../../notifications/components/setting_toggle'; import SettingText from './setting_text'; const messages = defineMessages({ - filter_regex: { id: 'home.column_settings.filter_regex', defaultMessage: 'Filter by regular expressions' } + filter_regex: { id: 'home.column_settings.filter_regex', defaultMessage: 'Filter out by regular expressions' } }); const outerStyle = { @@ -44,7 +44,7 @@ const ColumnSettings = React.createClass({ <span className='column-settings--section' style={sectionStyle}><FormattedMessage id='home.column_settings.basic' defaultMessage='Basic' /></span> <div style={rowStyle}> - <SettingToggle settings={settings} settingKey={['shows', 'reblog']} onChange={onChange} label={<FormattedMessage id='home.column_settings.show_reblogs' defaultMessage='Show reblogs' />} /> + <SettingToggle settings={settings} settingKey={['shows', 'reblog']} onChange={onChange} label={<FormattedMessage id='home.column_settings.show_reblogs' defaultMessage='Show boosts' />} /> </div> <div style={rowStyle}> diff --git a/app/assets/javascripts/components/features/public_timeline/index.jsx b/app/assets/javascripts/components/features/public_timeline/index.jsx index b2342abbd..6d766a83b 100644 --- a/app/assets/javascripts/components/features/public_timeline/index.jsx +++ b/app/assets/javascripts/components/features/public_timeline/index.jsx @@ -5,7 +5,9 @@ import Column from '../ui/components/column'; import { refreshTimeline, updateTimeline, - deleteFromTimelines + deleteFromTimelines, + connectTimeline, + disconnectTimeline } from '../../actions/timelines'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ColumnBackButtonSlim from '../../components/column_back_button_slim'; @@ -44,6 +46,18 @@ const PublicTimeline = React.createClass({ subscription = createStream(accessToken, 'public', { + connected () { + dispatch(connectTimeline('public')); + }, + + reconnected () { + dispatch(connectTimeline('public')); + }, + + disconnected () { + dispatch(disconnectTimeline('public')); + }, + received (data) { switch(data.event) { case 'update': diff --git a/app/assets/javascripts/components/locales/fr.jsx b/app/assets/javascripts/components/locales/fr.jsx index 2f5dd182f..a45b04b0c 100644 --- a/app/assets/javascripts/components/locales/fr.jsx +++ b/app/assets/javascripts/components/locales/fr.jsx @@ -33,6 +33,7 @@ const fr = { "navigation_bar.logout": "Déconnexion", "navigation_bar.preferences": "Préférences", "navigation_bar.public_timeline": "Fil public", + "navigation_bar.local_timeline": "Fil local", "notification.favourite": "{name} a ajouté à ses favoris :", "notification.follow": "{name} vous suit.", "notification.mention": "{name} vous a mentionné⋅e :", diff --git a/app/assets/javascripts/components/reducers/timelines.jsx b/app/assets/javascripts/components/reducers/timelines.jsx index c67d05423..675a52759 100644 --- a/app/assets/javascripts/components/reducers/timelines.jsx +++ b/app/assets/javascripts/components/reducers/timelines.jsx @@ -7,7 +7,9 @@ import { TIMELINE_EXPAND_SUCCESS, TIMELINE_EXPAND_REQUEST, TIMELINE_EXPAND_FAIL, - TIMELINE_SCROLL_TOP + TIMELINE_SCROLL_TOP, + TIMELINE_CONNECT, + TIMELINE_DISCONNECT } from '../actions/timelines'; import { REBLOG_SUCCESS, @@ -35,6 +37,7 @@ const initialState = Immutable.Map({ path: () => '/api/v1/timelines/home', next: null, isLoading: false, + online: false, loaded: false, top: true, unread: 0, @@ -45,6 +48,7 @@ const initialState = Immutable.Map({ path: () => '/api/v1/timelines/public', next: null, isLoading: false, + online: false, loaded: false, top: true, unread: 0, @@ -56,6 +60,7 @@ const initialState = Immutable.Map({ next: null, params: { local: true }, isLoading: false, + online: false, loaded: false, top: true, unread: 0, @@ -300,6 +305,10 @@ export default function timelines(state = initialState, action) { return filterTimelines(state, action.relationship, action.statuses); case TIMELINE_SCROLL_TOP: return updateTop(state, action.timeline, action.top); + case TIMELINE_CONNECT: + return state.setIn([action.timeline, 'online'], true); + case TIMELINE_DISCONNECT: + return state.setIn([action.timeline, 'online'], false); default: return state; } diff --git a/app/assets/javascripts/components/selectors/index.jsx b/app/assets/javascripts/components/selectors/index.jsx index 0e88654a1..01a6cb264 100644 --- a/app/assets/javascripts/components/selectors/index.jsx +++ b/app/assets/javascripts/components/selectors/index.jsx @@ -5,7 +5,7 @@ const getStatuses = state => state.get('statuses'); const getAccounts = state => state.get('accounts'); const getAccountBase = (state, id) => state.getIn(['accounts', id], null); -const getAccountRelationship = (state, id) => state.getIn(['relationships', id]); +const getAccountRelationship = (state, id) => state.getIn(['relationships', id], null); export const makeGetAccount = () => { return createSelector([getAccountBase, getAccountRelationship], (base, relationship) => { diff --git a/app/assets/stylesheets/accounts.scss b/app/assets/stylesheets/accounts.scss index 7c48c91f3..25e24a95a 100644 --- a/app/assets/stylesheets/accounts.scss +++ b/app/assets/stylesheets/accounts.scss @@ -311,6 +311,7 @@ padding: 10px; padding-top: 15px; color: $color3; + word-wrap: break-word; } } } diff --git a/app/assets/stylesheets/components.scss b/app/assets/stylesheets/components.scss index d87e09453..f8003e5fd 100644 --- a/app/assets/stylesheets/components.scss +++ b/app/assets/stylesheets/components.scss @@ -424,6 +424,7 @@ a.status__content__spoiler-link { .account__header__content { word-wrap: break-word; + word-break: normal; font-weight: 400; overflow: hidden; color: $color3; diff --git a/app/controllers/about_controller.rb b/app/controllers/about_controller.rb index 491036db2..abf4b7df4 100644 --- a/app/controllers/about_controller.rb +++ b/app/controllers/about_controller.rb @@ -5,6 +5,9 @@ class AboutController < ApplicationController def index @description = Setting.site_description + + @user = User.new + @user.build_account end def more diff --git a/app/controllers/admin/reports_controller.rb b/app/controllers/admin/reports_controller.rb index 67d57e4eb..0117a18ee 100644 --- a/app/controllers/admin/reports_controller.rb +++ b/app/controllers/admin/reports_controller.rb @@ -7,7 +7,7 @@ class Admin::ReportsController < ApplicationController layout 'admin' def index - @reports = Report.includes(:account, :target_account).paginate(page: params[:page], per_page: 40) + @reports = Report.includes(:account, :target_account).order('id desc').paginate(page: params[:page], per_page: 40) @reports = params[:action_taken].present? ? @reports.resolved : @reports.unresolved end diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb index b0dda1256..cd6ca1291 100644 --- a/app/lib/feed_manager.rb +++ b/app/lib/feed_manager.rb @@ -52,7 +52,7 @@ class FeedManager timeline_key = key(:home, into_account.id) from_account.statuses.limit(MAX_ITEMS).each do |status| - next if filter?(:home, status, into_account) + next if status.direct_visibility? || filter?(:home, status, into_account) redis.zadd(timeline_key, status.id, status.id) end diff --git a/app/services/fan_out_on_write_service.rb b/app/services/fan_out_on_write_service.rb index 0cacfd7cd..402b84b2f 100644 --- a/app/services/fan_out_on_write_service.rb +++ b/app/services/fan_out_on_write_service.rb @@ -6,7 +6,11 @@ class FanOutOnWriteService < BaseService def call(status) deliver_to_self(status) if status.account.local? - status.direct_visibility? ? deliver_to_mentioned_followers(status) : deliver_to_followers(status) + if status.direct_visibility? + deliver_to_mentioned_followers(status) + else + deliver_to_followers(status) + end return if status.account.silenced? || !status.public_visibility? || status.reblog? diff --git a/app/services/precompute_feed_service.rb b/app/services/precompute_feed_service.rb index 54d11b631..e1ec56e8d 100644 --- a/app/services/precompute_feed_service.rb +++ b/app/services/precompute_feed_service.rb @@ -4,10 +4,10 @@ class PrecomputeFeedService < BaseService # Fill up a user's home/mentions feed from DB and return a subset # @param [Symbol] type :home or :mentions # @param [Account] account - def call(type, account) - Status.send("as_#{type}_timeline", account).limit(FeedManager::MAX_ITEMS).each do |status| - next if FeedManager.instance.filter?(type, status, account) - redis.zadd(FeedManager.instance.key(type, account.id), status.id, status.reblog? ? status.reblog_of_id : status.id) + def call(_, account) + Status.as_home_timeline(account).limit(FeedManager::MAX_ITEMS).each do |status| + next if status.direct_visibility? || FeedManager.instance.filter?(:home, status, account) + redis.zadd(FeedManager.instance.key(:home, account.id), status.id, status.reblog? ? status.reblog_of_id : status.id) end end diff --git a/app/views/about/index.html.haml b/app/views/about/index.html.haml index be5e406c5..fdfb2b916 100644 --- a/app/views/about/index.html.haml +++ b/app/views/about/index.html.haml @@ -24,7 +24,7 @@ .screenshot-with-signup .mascot= image_tag 'fluffy-elephant-friend.png' - = simple_form_for(:user, url: user_registration_path) do |f| + = simple_form_for(@user, url: user_registration_path) do |f| = f.simple_fields_for :account do |ff| = ff.input :username, autofocus: true, placeholder: t('simple_form.labels.defaults.username'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.username') } |