Merge pull request #1993 from matrix-org/t3chguy/community_autocomplete

Autocomplete and Pillify Communities
This commit is contained in:
Luke Barnard 2018-06-22 15:46:06 +01:00 committed by GitHub
commit 5596dc4e57
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 205 additions and 33 deletions

View file

@ -4,6 +4,7 @@
.mx_UserPill, .mx_UserPill,
.mx_RoomPill, .mx_RoomPill,
.mx_GroupPill,
.mx_AtRoomPill { .mx_AtRoomPill {
border-radius: 16px; border-radius: 16px;
display: inline-block; display: inline-block;
@ -13,7 +14,8 @@
} }
.mx_EventTile_body .mx_UserPill, .mx_EventTile_body .mx_UserPill,
.mx_EventTile_body .mx_RoomPill { .mx_EventTile_body .mx_RoomPill,
.mx_EventTile_body .mx_GroupPill {
cursor: pointer; cursor: pointer;
} }
@ -35,14 +37,25 @@
/* More specific to override `.markdown-body a` color */ /* More specific to override `.markdown-body a` color */
.mx_EventTile_content .markdown-body a.mx_RoomPill, .mx_EventTile_content .markdown-body a.mx_RoomPill,
.mx_RoomPill { .mx_EventTile_content .markdown-body a.mx_GroupPill,
.mx_RoomPill,
.mx_GroupPill {
color: $accent-fg-color; color: $accent-fg-color;
background-color: $rte-room-pill-color; background-color: $rte-room-pill-color;
padding-right: 5px; padding-right: 5px;
} }
/* More specific to override `.markdown-body a` color */
.mx_EventTile_content .markdown-body a.mx_GroupPill,
.mx_GroupPill {
color: $accent-fg-color;
background-color: $rte-group-pill-color;
padding-right: 5px;
}
.mx_UserPill .mx_BaseAvatar, .mx_UserPill .mx_BaseAvatar,
.mx_RoomPill .mx_BaseAvatar, .mx_RoomPill .mx_BaseAvatar,
.mx_GroupPill .mx_BaseAvatar,
.mx_AtRoomPill .mx_BaseAvatar { .mx_AtRoomPill .mx_BaseAvatar {
position: relative; position: relative;
left: -3px; left: -3px;

View file

@ -97,6 +97,7 @@ $voip-accept-color: #80f480;
$rte-bg-color: #e9e9e9; $rte-bg-color: #e9e9e9;
$rte-code-bg-color: rgba(0, 0, 0, 0.04); $rte-code-bg-color: rgba(0, 0, 0, 0.04);
$rte-room-pill-color: #aaa; $rte-room-pill-color: #aaa;
$rte-group-pill-color: #aaa;
// ******************** // ********************

View file

@ -216,10 +216,17 @@ const sanitizeHtmlParams = {
m = attribs.href.match(linkifyMatrix.MATRIXTO_URL_PATTERN); m = attribs.href.match(linkifyMatrix.MATRIXTO_URL_PATTERN);
if (m) { if (m) {
const entity = m[1]; const entity = m[1];
if (entity[0] === '@') { switch (entity[0]) {
attribs.href = '#/user/' + entity; case '@':
} else if (entity[0] === '#' || entity[0] === '!') { attribs.href = '#/user/' + entity;
attribs.href = '#/room/' + entity; break;
case '+':
attribs.href = '#/group/' + entity;
break;
case '#':
case '!':
attribs.href = '#/room/' + entity;
break;
} }
delete attribs.target; delete attribs.target;
} }

View file

@ -1,7 +1,7 @@
/* /*
Copyright 2016 Aviral Dasgupta Copyright 2016 Aviral Dasgupta
Copyright 2017 Vector Creations Ltd Copyright 2017 Vector Creations Ltd
Copyright 2017 New Vector Ltd Copyright 2017, 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -36,7 +36,7 @@ export default class AutocompleteProvider {
/** /**
* Of the matched commands in the query, returns the first that contains or is contained by the selection, or null. * Of the matched commands in the query, returns the first that contains or is contained by the selection, or null.
*/ */
getCurrentCommand(query: string, selection: {start: number, end: number}, force: boolean = false): ?string { getCurrentCommand(query: string, selection: SelectionRange, force: boolean = false): ?string {
let commandRegex = this.commandRegex; let commandRegex = this.commandRegex;
if (force && this.shouldForceComplete()) { if (force && this.shouldForceComplete()) {
@ -51,14 +51,14 @@ export default class AutocompleteProvider {
let match; let match;
while ((match = commandRegex.exec(query)) != null) { while ((match = commandRegex.exec(query)) != null) {
let matchStart = match.index, const start = match.index;
matchEnd = matchStart + match[0].length; const end = start + match[0].length;
if (selection.start <= matchEnd && selection.end >= matchStart) { if (selection.start <= end && selection.end >= start) {
return { return {
command: match, command: match,
range: { range: {
start: matchStart, start,
end: matchEnd, end,
}, },
}; };
} }

View file

@ -1,6 +1,6 @@
/* /*
Copyright 2016 Aviral Dasgupta Copyright 2016 Aviral Dasgupta
Copyright 2017 New Vector Ltd Copyright 2017, 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -18,7 +18,9 @@ limitations under the License.
// @flow // @flow
import type {Component} from 'react'; import type {Component} from 'react';
import {Room} from 'matrix-js-sdk';
import CommandProvider from './CommandProvider'; import CommandProvider from './CommandProvider';
import CommunityProvider from './CommunityProvider';
import DuckDuckGoProvider from './DuckDuckGoProvider'; import DuckDuckGoProvider from './DuckDuckGoProvider';
import RoomProvider from './RoomProvider'; import RoomProvider from './RoomProvider';
import UserProvider from './UserProvider'; import UserProvider from './UserProvider';
@ -47,6 +49,7 @@ const PROVIDERS = [
EmojiProvider, EmojiProvider,
NotifProvider, NotifProvider,
CommandProvider, CommandProvider,
CommunityProvider,
DuckDuckGoProvider, DuckDuckGoProvider,
]; ];
@ -54,7 +57,7 @@ const PROVIDERS = [
const PROVIDER_COMPLETION_TIMEOUT = 3000; const PROVIDER_COMPLETION_TIMEOUT = 3000;
export default class Autocompleter { export default class Autocompleter {
constructor(room) { constructor(room: Room) {
this.room = room; this.room = room;
this.providers = PROVIDERS.map((p) => { this.providers = PROVIDERS.map((p) => {
return new p(room); return new p(room);

View file

@ -22,8 +22,8 @@ import {_t} from '../languageHandler';
import AutocompleteProvider from './AutocompleteProvider'; import AutocompleteProvider from './AutocompleteProvider';
import FuzzyMatcher from './FuzzyMatcher'; import FuzzyMatcher from './FuzzyMatcher';
import {TextualCompletion} from './Components'; import {TextualCompletion} from './Components';
import type {Completion, SelectionRange} from "./Autocompleter";
import {CommandMap} from '../SlashCommands'; import {CommandMap} from '../SlashCommands';
import type {SelectionRange} from "./Autocompleter";
const COMMANDS = Object.values(CommandMap); const COMMANDS = Object.values(CommandMap);
@ -37,7 +37,7 @@ export default class CommandProvider extends AutocompleteProvider {
}); });
} }
async getCompletions(query: string, selection: SelectionRange, force?: boolean) { async getCompletions(query: string, selection: SelectionRange, force?: boolean): Array<Completion> {
const {command, range} = this.getCurrentCommand(query, selection); const {command, range} = this.getCurrentCommand(query, selection);
if (!command) return []; if (!command) return [];

View file

@ -0,0 +1,110 @@
/*
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import { _t } from '../languageHandler';
import AutocompleteProvider from './AutocompleteProvider';
import MatrixClientPeg from '../MatrixClientPeg';
import FuzzyMatcher from './FuzzyMatcher';
import {PillCompletion} from './Components';
import sdk from '../index';
import _sortBy from 'lodash/sortBy';
import {makeGroupPermalink} from "../matrix-to";
import type {Completion, SelectionRange} from "./Autocompleter";
import FlairStore from "../stores/FlairStore";
const COMMUNITY_REGEX = /(?=\+)(\S*)/g;
function score(query, space) {
const index = space.indexOf(query);
if (index === -1) {
return Infinity;
} else {
return index;
}
}
export default class CommunityProvider extends AutocompleteProvider {
constructor() {
super(COMMUNITY_REGEX);
this.matcher = new FuzzyMatcher([], {
keys: ['groupId', 'name', 'shortDescription'],
});
}
async getCompletions(query: string, selection: SelectionRange, force?: boolean = false): Array<Completion> {
const BaseAvatar = sdk.getComponent('views.avatars.BaseAvatar');
// Disable autocompletions when composing commands because of various issues
// (see https://github.com/vector-im/riot-web/issues/4762)
if (/^(\/join|\/leave)/.test(query)) {
return [];
}
const cli = MatrixClientPeg.get();
let completions = [];
const {command, range} = this.getCurrentCommand(query, selection, force);
if (command) {
const joinedGroups = cli.getGroups().filter(({myMembership}) => myMembership === 'join');
const groups = (await Promise.all(joinedGroups.map(async ({groupId}) => {
try {
return FlairStore.getGroupProfileCached(cli, groupId);
} catch (e) { // if FlairStore failed, fall back to just groupId
return Promise.resolve({
name: '',
groupId,
avatarUrl: '',
shortDescription: '',
});
}
})));
this.matcher.setObjects(groups);
const matchedString = command[0];
completions = this.matcher.match(matchedString);
completions = _sortBy(completions, [
(c) => score(matchedString, c.groupId),
(c) => c.groupId.length,
]).map(({avatarUrl, groupId, name}) => ({
completion: groupId,
suffix: ' ',
href: makeGroupPermalink(groupId),
component: (
<PillCompletion initialComponent={
<BaseAvatar name={name || groupId}
width={24} height={24}
url={avatarUrl ? cli.mxcUrlToHttp(avatarUrl, 24, 24) : null} />
} title={name} description={groupId} />
),
range,
}))
.slice(0, 4);
}
return completions;
}
getName() {
return '💬 ' + _t('Communities');
}
renderCompletions(completions: [React.Component]): ?React.Component {
return <div className="mx_Autocomplete_Completion_container_pill mx_Autocomplete_Completion_container_truncate">
{ completions }
</div>;
}
}

View file

@ -1,7 +1,7 @@
/* /*
Copyright 2016 Aviral Dasgupta Copyright 2016 Aviral Dasgupta
Copyright 2017 Vector Creations Ltd Copyright 2017 Vector Creations Ltd
Copyright 2017 New Vector Ltd Copyright 2017, 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -22,6 +22,7 @@ import AutocompleteProvider from './AutocompleteProvider';
import 'whatwg-fetch'; import 'whatwg-fetch';
import {TextualCompletion} from './Components'; import {TextualCompletion} from './Components';
import type {SelectionRange} from "./Autocompleter";
const DDG_REGEX = /\/ddg\s+(.+)$/g; const DDG_REGEX = /\/ddg\s+(.+)$/g;
const REFERRER = 'vector'; const REFERRER = 'vector';
@ -36,7 +37,7 @@ export default class DuckDuckGoProvider extends AutocompleteProvider {
+ `&format=json&no_redirect=1&no_html=1&t=${encodeURIComponent(REFERRER)}`; + `&format=json&no_redirect=1&no_html=1&t=${encodeURIComponent(REFERRER)}`;
} }
async getCompletions(query: string, selection: {start: number, end: number}) { async getCompletions(query: string, selection: SelectionRange, force?: boolean = false) {
const {command, range} = this.getCurrentCommand(query, selection); const {command, range} = this.getCurrentCommand(query, selection);
if (!query || !command) { if (!query || !command) {
return []; return [];

View file

@ -1,7 +1,7 @@
/* /*
Copyright 2016 Aviral Dasgupta Copyright 2016 Aviral Dasgupta
Copyright 2017 Vector Creations Ltd Copyright 2017 Vector Creations Ltd
Copyright 2017 New Vector Ltd Copyright 2017, 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -19,11 +19,11 @@ limitations under the License.
import React from 'react'; import React from 'react';
import { _t } from '../languageHandler'; import { _t } from '../languageHandler';
import AutocompleteProvider from './AutocompleteProvider'; import AutocompleteProvider from './AutocompleteProvider';
import {emojioneList, shortnameToImage, shortnameToUnicode, asciiRegexp, unicodeRegexp} from 'emojione'; import {shortnameToUnicode, asciiRegexp, unicodeRegexp} from 'emojione';
import FuzzyMatcher from './FuzzyMatcher'; import FuzzyMatcher from './FuzzyMatcher';
import sdk from '../index'; import sdk from '../index';
import {PillCompletion} from './Components'; import {PillCompletion} from './Components';
import type {SelectionRange, Completion} from './Autocompleter'; import type {Completion, SelectionRange} from './Autocompleter';
import _uniq from 'lodash/uniq'; import _uniq from 'lodash/uniq';
import _sortBy from 'lodash/sortBy'; import _sortBy from 'lodash/sortBy';
import SettingsStore from "../settings/SettingsStore"; import SettingsStore from "../settings/SettingsStore";
@ -95,7 +95,7 @@ export default class EmojiProvider extends AutocompleteProvider {
}); });
} }
async getCompletions(query: string, selection: SelectionRange) { async getCompletions(query: string, selection: SelectionRange, force?: boolean): Array<Completion> {
if (SettingsStore.getValue("MessageComposerInput.dontSuggestEmoji")) { if (SettingsStore.getValue("MessageComposerInput.dontSuggestEmoji")) {
return []; // don't give any suggestions if the user doesn't want them return []; // don't give any suggestions if the user doesn't want them
} }

View file

@ -20,6 +20,7 @@ import { _t } from '../languageHandler';
import MatrixClientPeg from '../MatrixClientPeg'; import MatrixClientPeg from '../MatrixClientPeg';
import {PillCompletion} from './Components'; import {PillCompletion} from './Components';
import sdk from '../index'; import sdk from '../index';
import type {Completion, SelectionRange} from "./Autocompleter";
const AT_ROOM_REGEX = /@\S*/g; const AT_ROOM_REGEX = /@\S*/g;
@ -29,7 +30,7 @@ export default class NotifProvider extends AutocompleteProvider {
this.room = room; this.room = room;
} }
async getCompletions(query: string, selection: {start: number, end: number}, force = false) { async getCompletions(query: string, selection: SelectionRange, force?:boolean = false): Array<Completion> {
const RoomAvatar = sdk.getComponent('views.avatars.RoomAvatar'); const RoomAvatar = sdk.getComponent('views.avatars.RoomAvatar');
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.get();

View file

@ -1,7 +1,7 @@
/* /*
Copyright 2016 Aviral Dasgupta Copyright 2016 Aviral Dasgupta
Copyright 2017 Vector Creations Ltd Copyright 2017 Vector Creations Ltd
Copyright 2017 New Vector Ltd Copyright 2017, 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -26,6 +26,7 @@ import {getDisplayAliasForRoom} from '../Rooms';
import sdk from '../index'; import sdk from '../index';
import _sortBy from 'lodash/sortBy'; import _sortBy from 'lodash/sortBy';
import {makeRoomPermalink} from "../matrix-to"; import {makeRoomPermalink} from "../matrix-to";
import type {Completion, SelectionRange} from "./Autocompleter";
const ROOM_REGEX = /(?=#)(\S*)/g; const ROOM_REGEX = /(?=#)(\S*)/g;
@ -46,7 +47,7 @@ export default class RoomProvider extends AutocompleteProvider {
}); });
} }
async getCompletions(query: string, selection: {start: number, end: number}, force = false) { async getCompletions(query: string, selection: SelectionRange, force?: boolean = false): Array<Completion> {
const RoomAvatar = sdk.getComponent('views.avatars.RoomAvatar'); const RoomAvatar = sdk.getComponent('views.avatars.RoomAvatar');
// Disable autocompletions when composing commands because of various issues // Disable autocompletions when composing commands because of various issues

View file

@ -2,7 +2,7 @@
/* /*
Copyright 2016 Aviral Dasgupta Copyright 2016 Aviral Dasgupta
Copyright 2017 Vector Creations Ltd Copyright 2017 Vector Creations Ltd
Copyright 2017 New Vector Ltd Copyright 2017, 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -23,12 +23,12 @@ import AutocompleteProvider from './AutocompleteProvider';
import {PillCompletion} from './Components'; import {PillCompletion} from './Components';
import sdk from '../index'; import sdk from '../index';
import FuzzyMatcher from './FuzzyMatcher'; import FuzzyMatcher from './FuzzyMatcher';
import _pull from 'lodash/pull';
import _sortBy from 'lodash/sortBy'; import _sortBy from 'lodash/sortBy';
import MatrixClientPeg from '../MatrixClientPeg'; import MatrixClientPeg from '../MatrixClientPeg';
import type {Room, RoomMember} from 'matrix-js-sdk'; import type {Room, RoomMember} from 'matrix-js-sdk';
import {makeUserPermalink} from "../matrix-to"; import {makeUserPermalink} from "../matrix-to";
import type {SelectionRange} from "./Autocompleter";
const USER_REGEX = /@\S*/g; const USER_REGEX = /@\S*/g;
@ -36,7 +36,7 @@ export default class UserProvider extends AutocompleteProvider {
users: Array<RoomMember> = null; users: Array<RoomMember> = null;
room: Room = null; room: Room = null;
constructor(room) { constructor(room: Room) {
super(USER_REGEX, { super(USER_REGEX, {
keys: ['name'], keys: ['name'],
}); });
@ -87,7 +87,7 @@ export default class UserProvider extends AutocompleteProvider {
this.users = null; this.users = null;
} }
async getCompletions(query: string, selection: {start: number, end: number}, force = false) { async getCompletions(query: string, selection: SelectionRange, force?: boolean = false) {
const MemberAvatar = sdk.getComponent('views.avatars.MemberAvatar'); const MemberAvatar = sdk.getComponent('views.avatars.MemberAvatar');
// Disable autocompletions when composing commands because of various issues // Disable autocompletions when composing commands because of various issues

View file

@ -1,5 +1,6 @@
/* /*
Copyright 2017 Vector Creations Ltd Copyright 2017 Vector Creations Ltd
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -22,12 +23,13 @@ import PropTypes from 'prop-types';
import MatrixClientPeg from '../../../MatrixClientPeg'; import MatrixClientPeg from '../../../MatrixClientPeg';
import { MATRIXTO_URL_PATTERN } from '../../../linkify-matrix'; import { MATRIXTO_URL_PATTERN } from '../../../linkify-matrix';
import { getDisplayAliasForRoom } from '../../../Rooms'; import { getDisplayAliasForRoom } from '../../../Rooms';
import FlairStore from "../../../stores/FlairStore";
const REGEX_MATRIXTO = new RegExp(MATRIXTO_URL_PATTERN); const REGEX_MATRIXTO = new RegExp(MATRIXTO_URL_PATTERN);
// For URLs of matrix.to links in the timeline which have been reformatted by // For URLs of matrix.to links in the timeline which have been reformatted by
// HttpUtils transformTags to relative links. This excludes event URLs (with `[^\/]*`) // HttpUtils transformTags to relative links. This excludes event URLs (with `[^\/]*`)
const REGEX_LOCAL_MATRIXTO = /^#\/(?:user|room)\/(([\#\!\@\+])[^\/]*)$/; const REGEX_LOCAL_MATRIXTO = /^#\/(?:user|room|group)\/(([#!@+])[^\/]*)$/;
const Pill = React.createClass({ const Pill = React.createClass({
statics: { statics: {
@ -45,6 +47,7 @@ const Pill = React.createClass({
}, },
TYPE_USER_MENTION: 'TYPE_USER_MENTION', TYPE_USER_MENTION: 'TYPE_USER_MENTION',
TYPE_ROOM_MENTION: 'TYPE_ROOM_MENTION', TYPE_ROOM_MENTION: 'TYPE_ROOM_MENTION',
TYPE_GROUP_MENTION: 'TYPE_GROUP_MENTION',
TYPE_AT_ROOM_MENTION: 'TYPE_AT_ROOM_MENTION', // '@room' mention TYPE_AT_ROOM_MENTION: 'TYPE_AT_ROOM_MENTION', // '@room' mention
}, },
@ -81,12 +84,14 @@ const Pill = React.createClass({
// The member related to the user pill // The member related to the user pill
member: null, member: null,
// The group related to the group pill
group: null,
// The room related to the room pill // The room related to the room pill
room: null, room: null,
}; };
}, },
componentWillReceiveProps(nextProps) { async componentWillReceiveProps(nextProps) {
let regex = REGEX_MATRIXTO; let regex = REGEX_MATRIXTO;
if (nextProps.inMessage) { if (nextProps.inMessage) {
regex = REGEX_LOCAL_MATRIXTO; regex = REGEX_LOCAL_MATRIXTO;
@ -109,9 +114,11 @@ const Pill = React.createClass({
'@': Pill.TYPE_USER_MENTION, '@': Pill.TYPE_USER_MENTION,
'#': Pill.TYPE_ROOM_MENTION, '#': Pill.TYPE_ROOM_MENTION,
'!': Pill.TYPE_ROOM_MENTION, '!': Pill.TYPE_ROOM_MENTION,
'+': Pill.TYPE_GROUP_MENTION,
}[prefix]; }[prefix];
let member; let member;
let group;
let room; let room;
switch (pillType) { switch (pillType) {
case Pill.TYPE_AT_ROOM_MENTION: { case Pill.TYPE_AT_ROOM_MENTION: {
@ -140,8 +147,21 @@ const Pill = React.createClass({
} }
} }
break; break;
case Pill.TYPE_GROUP_MENTION: {
const cli = MatrixClientPeg.get();
try {
group = await FlairStore.getGroupProfileCached(cli, resourceId);
} catch (e) { // if FlairStore failed, fall back to just groupId
group = {
groupId: resourceId,
avatarUrl: null,
name: null,
};
}
}
} }
this.setState({resourceId, pillType, member, room}); this.setState({resourceId, pillType, member, group, room});
}, },
componentWillMount() { componentWillMount() {
@ -179,6 +199,7 @@ const Pill = React.createClass({
}); });
}, },
render: function() { render: function() {
const BaseAvatar = sdk.getComponent('views.avatars.BaseAvatar');
const MemberAvatar = sdk.getComponent('avatars.MemberAvatar'); const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
const RoomAvatar = sdk.getComponent('avatars.RoomAvatar'); const RoomAvatar = sdk.getComponent('avatars.RoomAvatar');
@ -229,6 +250,20 @@ const Pill = React.createClass({
} }
} }
break; break;
case Pill.TYPE_GROUP_MENTION: {
if (this.state.group) {
const {avatarUrl, groupId, name} = this.state.group;
const cli = MatrixClientPeg.get();
linkText = groupId;
if (this.props.shouldShowPillAvatar) {
avatar = <BaseAvatar name={name || groupId} width={16} height={16}
url={avatarUrl ? cli.mxcUrlToHttp(avatarUrl, 16, 16) : null} />;
}
pillClass = 'mx_GroupPill';
}
}
break;
} }
const classes = classNames(pillClass, { const classes = classNames(pillClass, {