diff --git a/src/GroupInvite.js b/src/GroupAddressPicker.js similarity index 59% rename from src/GroupInvite.js rename to src/GroupAddressPicker.js index e04e90d751..c8cff0ab3e 100644 --- a/src/GroupInvite.js +++ b/src/GroupAddressPicker.js @@ -18,11 +18,12 @@ import Modal from './Modal'; import sdk from './'; import MultiInviter from './utils/MultiInviter'; import { _t } from './languageHandler'; +import MatrixClientPeg from './MatrixClientPeg'; export function showGroupInviteDialog(groupId) { const AddressPickerDialog = sdk.getComponent("dialogs.AddressPickerDialog"); Modal.createTrackedDialog('Group Invite', '', AddressPickerDialog, { - title: _t('Invite new group members'), + title: _t("Invite new group members"), description: _t("Who would you like to add to this group?"), placeholder: _t("Name or matrix ID"), button: _t("Invite to Group"), @@ -35,6 +36,25 @@ export function showGroupInviteDialog(groupId) { }); } +export function showGroupAddRoomDialog(groupId) { + return new Promise((resolve, reject) => { + const AddressPickerDialog = sdk.getComponent("dialogs.AddressPickerDialog"); + Modal.createTrackedDialog('Add Rooms to Group', '', AddressPickerDialog, { + title: _t("Add rooms to the group"), + description: _t("Which rooms would you like to add to this group?"), + placeholder: _t("Room name or alias"), + button: _t("Add to group"), + pickerType: 'room', + validAddressTypes: ['mx'], + onFinished: (success, addrs) => { + if (!success) return; + + _onGroupAddRoomFinished(groupId, addrs).then(resolve, reject); + }, + }); + }); +} + function _onGroupInviteFinished(groupId, addrs) { const multiInviter = new MultiInviter(groupId); @@ -65,3 +85,27 @@ function _onGroupInviteFinished(groupId, addrs) { }); } +function _onGroupAddRoomFinished(groupId, addrs) { + const errorList = []; + return Promise.all(addrs.map((addr) => { + return MatrixClientPeg.get() + .addRoomToGroup(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', + '', ErrorDialog, + { + title: _t( + "Failed to add the following rooms to %(groupId)s:", + {groupId}, + ), + description: errorList.join(", "), + }); + }); +} diff --git a/src/components/views/dialogs/AddressPickerDialog.js b/src/components/views/dialogs/AddressPickerDialog.js index 741ff1fe8c..523dd9ad0d 100644 --- a/src/components/views/dialogs/AddressPickerDialog.js +++ b/src/components/views/dialogs/AddressPickerDialog.js @@ -155,7 +155,7 @@ module.exports = React.createClass({ if (this.props.groupId) { this._doNaiveGroupRoomSearch(query); } else { - console.error('Room searching only implemented for groups'); + this._doRoomSearch(query); } } else { console.error('Unknown pickerType', this.props.pickerType); @@ -264,6 +264,33 @@ module.exports = React.createClass({ }); }, + _doRoomSearch: function(query) { + MatrixClientPeg.get().publicRooms({ + filter: { + generic_search_term: query, + }, + }).then((resp) => { + const results = []; + resp.chunk.forEach((r) => { + 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 public rooms: ', err); + this.setState({ + searchError: err.errcode ? err.message : _t('Something went wrong!'), + }); + }).done(() => { + this.setState({ + busy: false, + }); + }); + }, + _doUserDirectorySearch: function(query) { this.setState({ busy: true, diff --git a/src/components/views/groups/GroupMemberList.js b/src/components/views/groups/GroupMemberList.js index 273a04da20..809dac93d0 100644 --- a/src/components/views/groups/GroupMemberList.js +++ b/src/components/views/groups/GroupMemberList.js @@ -131,7 +131,7 @@ export default withMatrixClient(React.createClass({ const inputBox = (
diff --git a/src/components/views/groups/GroupRoomList.js b/src/components/views/groups/GroupRoomList.js new file mode 100644 index 0000000000..0a9dbb4d76 --- /dev/null +++ b/src/components/views/groups/GroupRoomList.js @@ -0,0 +1,143 @@ +/* +Copyright 2017 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 sdk from '../../../index'; +import { groupRoomFromApiObject } from '../../../groups'; +import GeminiScrollbar from 'react-gemini-scrollbar'; +import PropTypes from 'prop-types'; +import {MatrixClient} from 'matrix-js-sdk'; + +const INITIAL_LOAD_NUM_ROOMS = 30; + +export default React.createClass({ + contextTypes: { + matrixClient: React.PropTypes.instanceOf(MatrixClient).isRequired, + }, + + propTypes: { + groupId: PropTypes.string.isRequired, + }, + + getInitialState: function() { + return { + fetching: false, + rooms: null, + truncateAt: INITIAL_LOAD_NUM_ROOMS, + searchQuery: "", + }; + }, + + componentWillMount: function() { + this._unmounted = false; + this._fetchRooms(); + }, + + _fetchRooms: function() { + this.setState({fetching: true}); + this.context.matrixClient.getGroupRooms(this.props.groupId).then((result) => { + this.setState({ + rooms: result.chunk.map((apiRoom) => { + return groupRoomFromApiObject(apiRoom); + }), + fetching: false, + }); + }).catch((e) => { + this.setState({fetching: false}); + console.error("Failed to get group room list: ", e); + }); + }, + + _createOverflowTile: function(overflowCount, totalCount) { + // For now we'll pretend this is any entity. It should probably be a separate tile. + const EntityTile = sdk.getComponent("rooms.EntityTile"); + const BaseAvatar = sdk.getComponent("avatars.BaseAvatar"); + const text = _t("and %(count)s others...", { count: overflowCount }); + return ( +