Remove race between multiple autocomplete requests (#4860)
Этот коммит содержится в:
коммит произвёл
Harrison Healey
родитель
26e43c671c
Коммит
cadc9e11e4
@@ -2,6 +2,7 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import Suggestion from './suggestion.jsx';
|
||||
import Provider from './provider.jsx';
|
||||
|
||||
import ChannelStore from 'stores/channel_store.jsx';
|
||||
|
||||
@@ -100,8 +101,10 @@ class AtMentionSuggestion extends Suggestion {
|
||||
}
|
||||
}
|
||||
|
||||
export default class AtMentionProvider {
|
||||
export default class AtMentionProvider extends Provider {
|
||||
constructor(channelId) {
|
||||
super();
|
||||
|
||||
this.channelId = channelId;
|
||||
}
|
||||
|
||||
@@ -110,10 +113,16 @@ export default class AtMentionProvider {
|
||||
if (captured) {
|
||||
const prefix = captured[1];
|
||||
|
||||
this.startNewRequest(prefix);
|
||||
|
||||
autocompleteUsersInChannel(
|
||||
prefix,
|
||||
this.channelId,
|
||||
(data) => {
|
||||
if (this.shouldCancelDispatch(prefix)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const members = data.in_channel;
|
||||
for (const id of Object.keys(members)) {
|
||||
members[id].type = Constants.MENTION_MEMBERS;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import Suggestion from './suggestion.jsx';
|
||||
import Provider from './provider.jsx';
|
||||
|
||||
import {autocompleteChannels} from 'actions/channel_actions.jsx';
|
||||
|
||||
@@ -49,15 +50,21 @@ class ChannelMentionSuggestion extends Suggestion {
|
||||
}
|
||||
}
|
||||
|
||||
export default class ChannelMentionProvider {
|
||||
export default class ChannelMentionProvider extends Provider {
|
||||
handlePretextChanged(suggestionId, pretext) {
|
||||
const captured = (/(^|\s)(~([^~]*))$/i).exec(pretext.toLowerCase());
|
||||
if (captured) {
|
||||
const prefix = captured[3];
|
||||
|
||||
this.startNewRequest(prefix);
|
||||
|
||||
autocompleteChannels(
|
||||
prefix,
|
||||
(data) => {
|
||||
if (this.shouldCancelDispatch(prefix)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const channels = data;
|
||||
|
||||
// Wrap channels in an outer object to avoid overwriting the 'type' property.
|
||||
|
||||
28
webapp/components/suggestion/provider.jsx
Обычный файл
28
webapp/components/suggestion/provider.jsx
Обычный файл
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
export default class Provider {
|
||||
constructor() {
|
||||
this.latestPrefix = '';
|
||||
this.latestComplete = true;
|
||||
}
|
||||
|
||||
handlePretextChanged(suggestionId, pretext) { // eslint-disable-line no-unused-vars
|
||||
// NO-OP for inherited classes to override
|
||||
}
|
||||
|
||||
startNewRequest(prefix) {
|
||||
this.latestPrefix = prefix;
|
||||
this.latestComplete = false;
|
||||
}
|
||||
|
||||
shouldCancelDispatch(prefix) {
|
||||
if (prefix === this.latestPrefix) {
|
||||
this.latestComplete = true;
|
||||
} else if (this.latestComplete) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import Suggestion from './suggestion.jsx';
|
||||
import Provider from './provider.jsx';
|
||||
|
||||
import {autocompleteChannels} from 'actions/channel_actions.jsx';
|
||||
|
||||
@@ -32,15 +33,21 @@ class SearchChannelSuggestion extends Suggestion {
|
||||
}
|
||||
}
|
||||
|
||||
export default class SearchChannelProvider {
|
||||
export default class SearchChannelProvider extends Provider {
|
||||
handlePretextChanged(suggestionId, pretext) {
|
||||
const captured = (/\b(?:in|channel):\s*(\S*)$/i).exec(pretext.toLowerCase());
|
||||
if (captured) {
|
||||
const channelPrefix = captured[1];
|
||||
|
||||
this.startNewRequest(channelPrefix);
|
||||
|
||||
autocompleteChannels(
|
||||
channelPrefix,
|
||||
(data) => {
|
||||
if (this.shouldCancelDispatch(channelPrefix)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const publicChannels = data;
|
||||
|
||||
const localChannels = ChannelStore.getAll();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import Suggestion from './suggestion.jsx';
|
||||
import Provider from './provider.jsx';
|
||||
|
||||
import {autocompleteUsersInTeam} from 'actions/user_actions.jsx';
|
||||
|
||||
@@ -56,15 +57,21 @@ class SearchUserSuggestion extends Suggestion {
|
||||
}
|
||||
}
|
||||
|
||||
export default class SearchUserProvider {
|
||||
export default class SearchUserProvider extends Provider {
|
||||
handlePretextChanged(suggestionId, pretext) {
|
||||
const captured = (/\bfrom:\s*(\S*)$/i).exec(pretext.toLowerCase());
|
||||
if (captured) {
|
||||
const usernamePrefix = captured[1];
|
||||
|
||||
this.startNewRequest(usernamePrefix);
|
||||
|
||||
autocompleteUsersInTeam(
|
||||
usernamePrefix,
|
||||
(data) => {
|
||||
if (this.shouldCancelDispatch(usernamePrefix)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const users = data.in_team;
|
||||
const mentions = users.map((user) => user.username);
|
||||
|
||||
|
||||
@@ -38,14 +38,6 @@ export default class SuggestionBox extends React.Component {
|
||||
SuggestionStore.addPretextChangedListener(this.suggestionId, this.handlePretextChanged);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
// Clear any suggestions when the SuggestionBox is cleared
|
||||
if (nextProps.value === '' && this.props.value !== nextProps.value) {
|
||||
// TODO - Find a better way to not "dispatch during dispatch"
|
||||
setTimeout(() => GlobalActions.emitClearSuggestions(this.suggestionId), 1);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
SuggestionStore.removeCompleteWordListener(this.suggestionId, this.handleCompleteWord);
|
||||
SuggestionStore.removePretextChangedListener(this.suggestionId, this.handlePretextChanged);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import Suggestion from './suggestion.jsx';
|
||||
import Provider from './provider.jsx';
|
||||
|
||||
import ChannelStore from 'stores/channel_store.jsx';
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
@@ -58,15 +59,21 @@ class SwitchChannelSuggestion extends Suggestion {
|
||||
}
|
||||
}
|
||||
|
||||
export default class SwitchChannelProvider {
|
||||
export default class SwitchChannelProvider extends Provider {
|
||||
handlePretextChanged(suggestionId, channelPrefix) {
|
||||
if (channelPrefix) {
|
||||
this.startNewRequest(channelPrefix);
|
||||
|
||||
const allChannels = ChannelStore.getAll();
|
||||
const channels = [];
|
||||
|
||||
autocompleteUsers(
|
||||
channelPrefix,
|
||||
(users) => {
|
||||
if (this.shouldCancelDispatch(channelPrefix)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentId = UserStore.getCurrentId();
|
||||
|
||||
for (const id of Object.keys(allChannels)) {
|
||||
|
||||
Ссылка в новой задаче
Block a user