Skip to content

Commit d1b0469

Browse files
ClearlyClairehiyuki2578
authored andcommitted
Restore hashtag suggestions from local tag history (mastodon#11632)
* Restore hashtag suggestions from local tag history * Append local hashtag suggestions instead of prepending them * Do not display inaccurate usage statistics for hashtags not retrieved from API * Fixup
1 parent 7a55102 commit d1b0469

3 files changed

Lines changed: 30 additions & 5 deletions

File tree

app/javascript/mastodon/actions/compose.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,8 @@ const fetchComposeSuggestionsTags = throttle((dispatch, getState, token) => {
356356
cancelFetchComposeSuggestionsTags();
357357
}
358358

359+
dispatch(updateSuggestionTags(token));
360+
359361
api(getState).get('/api/v2/search', {
360362
cancelToken: new CancelToken(cancel => {
361363
cancelFetchComposeSuggestionsTags = cancel;

app/javascript/mastodon/components/autosuggest_hashtag.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,18 @@ export default class AutosuggestHashtag extends React.PureComponent {
99
tag: PropTypes.shape({
1010
name: PropTypes.string.isRequired,
1111
url: PropTypes.string,
12-
history: PropTypes.array.isRequired,
12+
history: PropTypes.array,
1313
}).isRequired,
1414
};
1515

1616
render () {
1717
const { tag } = this.props;
18-
const weeklyUses = shortNumberFormat(tag.history.reduce((total, day) => total + (day.uses * 1), 0));
18+
const weeklyUses = tag.history && shortNumberFormat(tag.history.reduce((total, day) => total + (day.uses * 1), 0));
1919

2020
return (
2121
<div className='autosuggest-hashtag'>
2222
<div className='autosuggest-hashtag__name'>#<strong>{tag.name}</strong></div>
23-
<div className='autosuggest-hashtag__uses'><FormattedMessage id='autosuggest_hashtag.per_week' defaultMessage='{count} per week' values={{ count: weeklyUses }} /></div>
23+
{tag.history !== undefined && <div className='autosuggest-hashtag__uses'><FormattedMessage id='autosuggest_hashtag.per_week' defaultMessage='{count} per week' values={{ count: weeklyUses }} /></div>}
2424
</div>
2525
);
2626
}

app/javascript/mastodon/reducers/compose.js

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
COMPOSE_SUGGESTIONS_CLEAR,
1818
COMPOSE_SUGGESTIONS_READY,
1919
COMPOSE_SUGGESTION_SELECT,
20+
COMPOSE_SUGGESTION_TAGS_UPDATE,
2021
COMPOSE_TAG_HISTORY_UPDATE,
2122
COMPOSE_SENSITIVITY_CHANGE,
2223
COMPOSE_SPOILERNESS_CHANGE,
@@ -205,16 +206,36 @@ const expiresInFromExpiresAt = expires_at => {
205206
return [300, 1800, 3600, 21600, 86400, 259200, 604800].find(expires_in => expires_in >= delta) || 24 * 3600;
206207
};
207208

208-
const normalizeSuggestions = (state, { accounts, emojis, tags }) => {
209+
const mergeLocalHashtagResults = (suggestions, prefix, tagHistory) => {
210+
prefix = prefix.toLowerCase();
211+
if (suggestions.length < 4) {
212+
const localTags = tagHistory.filter(tag => tag.toLowerCase().startsWith(prefix) && !suggestions.some(suggestion => suggestion.type === 'hashtag' && suggestion.name.toLowerCase() === tag.toLowerCase()));
213+
return suggestions.concat(localTags.slice(0, 4 - suggestions.length).toJS().map(tag => ({ type: 'hashtag', name: tag })));
214+
} else {
215+
return suggestions;
216+
}
217+
};
218+
219+
const normalizeSuggestions = (state, { accounts, emojis, tags, token }) => {
209220
if (accounts) {
210221
return accounts.map(item => ({ id: item.id, type: 'account' }));
211222
} else if (emojis) {
212223
return emojis.map(item => ({ ...item, type: 'emoji' }));
213224
} else {
214-
return sortHashtagsByUse(state, tags.map(item => ({ ...item, type: 'hashtag' })));
225+
return mergeLocalHashtagResults(sortHashtagsByUse(state, tags.map(item => ({ ...item, type: 'hashtag' }))), token.slice(1), state.get('tagHistory'));
215226
}
216227
};
217228

229+
const updateSuggestionTags = (state, token) => {
230+
const prefix = token.slice(1);
231+
232+
const suggestions = state.get('suggestions').toJS();
233+
return state.merge({
234+
suggestions: ImmutableList(mergeLocalHashtagResults(suggestions, prefix, state.get('tagHistory'))),
235+
suggestion_token: token,
236+
});
237+
};
238+
218239
export default function compose(state = initialState, action) {
219240
switch(action.type) {
220241
case STORE_HYDRATE:
@@ -328,6 +349,8 @@ export default function compose(state = initialState, action) {
328349
return state.set('suggestions', ImmutableList(normalizeSuggestions(state, action))).set('suggestion_token', action.token);
329350
case COMPOSE_SUGGESTION_SELECT:
330351
return insertSuggestion(state, action.position, action.token, action.completion, action.path);
352+
case COMPOSE_SUGGESTION_TAGS_UPDATE:
353+
return updateSuggestionTags(state, action.token);
331354
case COMPOSE_TAG_HISTORY_UPDATE:
332355
return state.set('tagHistory', fromJS(action.tags));
333356
case TIMELINE_DELETE:

0 commit comments

Comments
 (0)