diff --git a/src/GroupInvite.js b/src/GroupInvite.js
index c526ace188..e04e90d751 100644
--- a/src/GroupInvite.js
+++ b/src/GroupInvite.js
@@ -20,8 +20,8 @@ import MultiInviter from './utils/MultiInviter';
import { _t } from './languageHandler';
export function showGroupInviteDialog(groupId) {
- const UserPickerDialog = sdk.getComponent("dialogs.UserPickerDialog");
- Modal.createTrackedDialog('Group Invite', '', UserPickerDialog, {
+ const AddressPickerDialog = sdk.getComponent("dialogs.AddressPickerDialog");
+ Modal.createTrackedDialog('Group Invite', '', AddressPickerDialog, {
title: _t('Invite new group members'),
description: _t("Who would you like to add to this group?"),
placeholder: _t("Name or matrix ID"),
diff --git a/src/RoomInvite.js b/src/RoomInvite.js
index 9be3da53e4..af0ba3d1e7 100644
--- a/src/RoomInvite.js
+++ b/src/RoomInvite.js
@@ -50,8 +50,8 @@ export function inviteMultipleToRoom(roomId, addrs) {
}
export function showStartChatInviteDialog() {
- const UserPickerDialog = sdk.getComponent("dialogs.UserPickerDialog");
- Modal.createTrackedDialog('Start a chat', '', UserPickerDialog, {
+ const AddressPickerDialog = sdk.getComponent("dialogs.AddressPickerDialog");
+ Modal.createTrackedDialog('Start a chat', '', AddressPickerDialog, {
title: _t('Start a chat'),
description: _t("Who would you like to communicate with?"),
placeholder: _t("Email, name or matrix ID"),
@@ -61,8 +61,8 @@ export function showStartChatInviteDialog() {
}
export function showRoomInviteDialog(roomId) {
- const UserPickerDialog = sdk.getComponent("dialogs.UserPickerDialog");
- Modal.createTrackedDialog('Chat Invite', '', UserPickerDialog, {
+ const AddressPickerDialog = sdk.getComponent("dialogs.AddressPickerDialog");
+ Modal.createTrackedDialog('Chat Invite', '', AddressPickerDialog, {
title: _t('Invite new room members'),
description: _t('Who would you like to add to this room?'),
button: _t('Send Invites'),
diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js
index ef56a90330..422b822df3 100644
--- a/src/components/structures/GroupView.js
+++ b/src/components/structures/GroupView.js
@@ -55,32 +55,74 @@ const CategoryRoomList = React.createClass({
name: PropTypes.string,
}).isRequired,
}),
+ groupId: PropTypes.string.isRequired,
// Whether the list should be editable
editing: PropTypes.bool.isRequired,
},
+ onAddRoomsClicked: function(ev) {
+ ev.preventDefault();
+ const AddressPickerDialog = sdk.getComponent("dialogs.AddressPickerDialog");
+ Modal.createTrackedDialog('Add Rooms to Group Summary', '', AddressPickerDialog, {
+ title: _t('Add rooms to the group summary'),
+ description: _t("Which rooms would you like to add to this summary?"),
+ placeholder: _t("Room name or alias"),
+ button: _t("Add to summary"),
+ pickerType: 'room',
+ validAddressTypes: ['mx'],
+ groupId: this.props.groupId,
+ onFinished: (success, addrs) => {
+ if (!success) return;
+ const errorList = [];
+ Promise.all(addrs.map((addr) => {
+ return MatrixClientPeg.get()
+ .addRoomToGroupSummary(this.props.groupId, addr.address)
+ .catch(() => { errorList.push(addr.address); })
+ .reflect();
+ })).then(() => {
+ if (errorList.length === 0) {
+ return;
+ }
+ const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
+ Modal.createTrackedDialog(
+ 'Failed to add the following room to the group summary',
+ '', ErrorDialog,
+ {
+ title: _t(
+ "Failed to add the following rooms to the summary of %(groupId)s:",
+ {groupId: this.props.groupId},
+ ),
+ description: errorList.join(", "),
+ });
+ });
+ },
+ });
+ },
+
render: function() {
+ const TintableSvg = sdk.getComponent("elements.TintableSvg");
+ const addButton = this.props.editing ?
+ (
+
+
+ {_t('Add a Room')}
+
+ ) :
;
+
const roomNodes = this.props.rooms.map((r) => {
return ;
});
- let catHeader = null;
+ let catHeader = ;
if (this.props.category && this.props.category.profile) {
catHeader = {this.props.category.profile.name}
;
}
return
{catHeader}
{roomNodes}
+ {addButton}
;
- // TODO: Modify UserPickerDialog to allow picking of rooms, and then use it here
- // const TintableSvg = sdk.getComponent("elements.TintableSvg");
- //
- //
- //
- // {_t('Add a Room')}
- //
- //
},
});
@@ -146,8 +188,8 @@ const RoleUserList = React.createClass({
onAddUsersClicked: function(ev) {
ev.preventDefault();
- const UserPickerDialog = sdk.getComponent("dialogs.UserPickerDialog");
- Modal.createTrackedDialog('Add Users to Group Summary', '', UserPickerDialog, {
+ const AddressPickerDialog = sdk.getComponent("dialogs.AddressPickerDialog");
+ Modal.createTrackedDialog('Add Users to Group Summary', '', AddressPickerDialog, {
title: _t('Add users to the group summary'),
description: _t("Who would you like to add to this summary?"),
placeholder: _t("Name or matrix ID"),
@@ -190,11 +232,11 @@ const RoleUserList = React.createClass({
{_t('Add a User')}
- ) : null;
+ ) : ;
const userNodes = this.props.users.map((u) => {
return ;
});
- let roleHeader = null;
+ let roleHeader = ;
if (this.props.role && this.props.role.profile) {
roleHeader = {this.props.role.profile.name}
;
}
@@ -456,6 +498,7 @@ export default React.createClass({
const defaultCategoryNode = ;
const categoryRoomNodes = Object.keys(categoryRooms).map((catId) => {
const cat = summary.rooms_section.categories[catId];
@@ -463,6 +506,7 @@ export default React.createClass({
key={catId}
rooms={categoryRooms[catId]}
category={cat}
+ groupId={this.props.groupId}
editing={this.state.editing}/>;
});
diff --git a/src/components/views/dialogs/UserPickerDialog.js b/src/components/views/dialogs/AddressPickerDialog.js
similarity index 85%
rename from src/components/views/dialogs/UserPickerDialog.js
rename to src/components/views/dialogs/AddressPickerDialog.js
index 415a3d910e..741ff1fe8c 100644
--- a/src/components/views/dialogs/UserPickerDialog.js
+++ b/src/components/views/dialogs/AddressPickerDialog.js
@@ -28,7 +28,7 @@ const TRUNCATE_QUERY_LIST = 40;
const QUERY_USER_DIRECTORY_DEBOUNCE_MS = 200;
module.exports = React.createClass({
- displayName: "UserPickerDialog",
+ displayName: "AddressPickerDialog",
propTypes: {
title: PropTypes.string.isRequired,
@@ -41,6 +41,7 @@ module.exports = React.createClass({
validAddressTypes: PropTypes.arrayOf(PropTypes.oneOf(addressTypes)),
onFinished: PropTypes.func.isRequired,
groupId: PropTypes.string,
+ pickerType: PropTypes.oneOf(['user', 'room']),
},
getDefaultProps: function() {
@@ -48,6 +49,7 @@ module.exports = React.createClass({
value: "",
focus: true,
validAddressTypes: addressTypes,
+ pickerType: 'user',
};
},
@@ -141,12 +143,22 @@ module.exports = React.createClass({
// Only do search if there is something to search
if (query.length > 0 && query != '@' && query.length >= 2) {
this.queryChangedDebouncer = setTimeout(() => {
- if (this.props.groupId) {
- this._doNaiveGroupSearch(query);
- } else if (this.state.serverSupportsUserDirectory) {
- this._doUserDirectorySearch(query);
+ if (this.props.pickerType === 'user') {
+ if (this.props.groupId) {
+ this._doNaiveGroupSearch(query);
+ } else if (this.state.serverSupportsUserDirectory) {
+ this._doUserDirectorySearch(query);
+ } else {
+ this._doLocalSearch(query);
+ }
+ } else if (this.props.pickerType === 'room') {
+ if (this.props.groupId) {
+ this._doNaiveGroupRoomSearch(query);
+ } else {
+ console.error('Room searching only implemented for groups');
+ }
} else {
- this._doLocalSearch(query);
+ console.error('Unknown pickerType', this.props.pickerType);
}
}, QUERY_USER_DIRECTORY_DEBOUNCE_MS);
} else {
@@ -210,6 +222,36 @@ module.exports = React.createClass({
});
});
this._processResults(results, query);
+ }).catch((err) => {
+ console.error('Error whilst searching group rooms: ', err);
+ this.setState({
+ searchError: err.errcode ? err.message : _t('Something went wrong!'),
+ });
+ }).done(() => {
+ this.setState({
+ busy: false,
+ });
+ });
+ },
+
+ _doNaiveGroupRoomSearch: function(query) {
+ const lowerCaseQuery = query.toLowerCase();
+ MatrixClientPeg.get().getGroupRooms(this.props.groupId).then((resp) => {
+ const results = [];
+ resp.chunk.forEach((r) => {
+ const nameMatch = (r.name || '').toLowerCase().includes(lowerCaseQuery);
+ const topicMatch = (r.topic || '').toLowerCase().includes(lowerCaseQuery);
+ const aliasMatch = (r.canonical_alias || '').toLowerCase().includes(lowerCaseQuery);
+ if (!(nameMatch || topicMatch || aliasMatch)) {
+ return;
+ }
+ results.push({
+ room_id: r.room_id,
+ avatar_url: r.avatar_url,
+ name: r.name,
+ });
+ });
+ this._processResults(results, query);
}).catch((err) => {
console.error('Error whilst searching group users: ', err);
this.setState({
@@ -282,17 +324,28 @@ module.exports = React.createClass({
_processResults: function(results, query) {
const queryList = [];
- results.forEach((user) => {
- if (user.user_id === MatrixClientPeg.get().credentials.userId) {
+ results.forEach((result) => {
+ if (result.room_id) {
+ queryList.push({
+ addressType: 'mx',
+ address: result.room_id,
+ displayName: result.name,
+ avatarMxc: result.avatar_url,
+ isKnown: true,
+ });
return;
}
+ if (result.user_id === MatrixClientPeg.get().credentials.userId) {
+ return;
+ }
+
// Return objects, structure of which is defined
// by UserAddressType
queryList.push({
addressType: 'mx',
- address: user.user_id,
- displayName: user.display_name,
- avatarMxc: user.avatar_url,
+ address: result.user_id,
+ displayName: result.display_name,
+ avatarMxc: result.avatar_url,
isKnown: true,
});
});
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 0ff1b9bc84..9c7318eb60 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -893,5 +893,8 @@
"Who would you like to add to this summary?": "Who would you like to add to this summary?",
"Add to summary": "Add to summary",
"Failed to add the following users to the summary of %(groupId)s:": "Failed to add the following users to the summary of %(groupId)s:",
+ "Add rooms to the group summary": "Add rooms to the group summary",
+ "Which rooms would you like to add to this summary?": "Which rooms would you like to add to this summary?",
+ "Room name or alias": "Room name or alias",
"You are an administrator of this group": "You are an administrator of this group"
}