Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
commit
26a4b1f2bd
13 changed files with 251 additions and 280 deletions
|
@ -19,7 +19,7 @@ import sdk from './';
|
||||||
import MultiInviter from './utils/MultiInviter';
|
import MultiInviter from './utils/MultiInviter';
|
||||||
import { _t } from './languageHandler';
|
import { _t } from './languageHandler';
|
||||||
import MatrixClientPeg from './MatrixClientPeg';
|
import MatrixClientPeg from './MatrixClientPeg';
|
||||||
import GroupStoreCache from './stores/GroupStoreCache';
|
import GroupStore from './stores/GroupStore';
|
||||||
|
|
||||||
export function showGroupInviteDialog(groupId) {
|
export function showGroupInviteDialog(groupId) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
@ -116,11 +116,10 @@ function _onGroupInviteFinished(groupId, addrs) {
|
||||||
|
|
||||||
function _onGroupAddRoomFinished(groupId, addrs, addRoomsPublicly) {
|
function _onGroupAddRoomFinished(groupId, addrs, addRoomsPublicly) {
|
||||||
const matrixClient = MatrixClientPeg.get();
|
const matrixClient = MatrixClientPeg.get();
|
||||||
const groupStore = GroupStoreCache.getGroupStore(groupId);
|
|
||||||
const errorList = [];
|
const errorList = [];
|
||||||
return Promise.all(addrs.map((addr) => {
|
return Promise.all(addrs.map((addr) => {
|
||||||
return groupStore
|
return GroupStore
|
||||||
.addRoomToGroup(addr.address, addRoomsPublicly)
|
.addRoomToGroup(groupId, addr.address, addRoomsPublicly)
|
||||||
.catch(() => { errorList.push(addr.address); })
|
.catch(() => { errorList.push(addr.address); })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const roomId = addr.address;
|
const roomId = addr.address;
|
||||||
|
|
|
@ -27,7 +27,6 @@ import AccessibleButton from '../views/elements/AccessibleButton';
|
||||||
import Modal from '../../Modal';
|
import Modal from '../../Modal';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
|
||||||
import GroupStoreCache from '../../stores/GroupStoreCache';
|
|
||||||
import GroupStore from '../../stores/GroupStore';
|
import GroupStore from '../../stores/GroupStore';
|
||||||
import FlairStore from '../../stores/FlairStore';
|
import FlairStore from '../../stores/FlairStore';
|
||||||
import { showGroupAddRoomDialog } from '../../GroupAddressPicker';
|
import { showGroupAddRoomDialog } from '../../GroupAddressPicker';
|
||||||
|
@ -93,8 +92,8 @@ const CategoryRoomList = React.createClass({
|
||||||
if (!success) return;
|
if (!success) return;
|
||||||
const errorList = [];
|
const errorList = [];
|
||||||
Promise.all(addrs.map((addr) => {
|
Promise.all(addrs.map((addr) => {
|
||||||
return this.context.groupStore
|
return GroupStore
|
||||||
.addRoomToGroupSummary(addr.address)
|
.addRoomToGroupSummary(this.props.groupId, addr.address)
|
||||||
.catch(() => { errorList.push(addr.address); })
|
.catch(() => { errorList.push(addr.address); })
|
||||||
.reflect();
|
.reflect();
|
||||||
})).then(() => {
|
})).then(() => {
|
||||||
|
@ -174,7 +173,8 @@ const FeaturedRoom = React.createClass({
|
||||||
onDeleteClicked: function(e) {
|
onDeleteClicked: function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
this.context.groupStore.removeRoomFromGroupSummary(
|
GroupStore.removeRoomFromGroupSummary(
|
||||||
|
this.props.groupId,
|
||||||
this.props.summaryInfo.room_id,
|
this.props.summaryInfo.room_id,
|
||||||
).catch((err) => {
|
).catch((err) => {
|
||||||
console.error('Error whilst removing room from group summary', err);
|
console.error('Error whilst removing room from group summary', err);
|
||||||
|
@ -269,7 +269,7 @@ const RoleUserList = React.createClass({
|
||||||
if (!success) return;
|
if (!success) return;
|
||||||
const errorList = [];
|
const errorList = [];
|
||||||
Promise.all(addrs.map((addr) => {
|
Promise.all(addrs.map((addr) => {
|
||||||
return this.context.groupStore
|
return GroupStore
|
||||||
.addUserToGroupSummary(addr.address)
|
.addUserToGroupSummary(addr.address)
|
||||||
.catch(() => { errorList.push(addr.address); })
|
.catch(() => { errorList.push(addr.address); })
|
||||||
.reflect();
|
.reflect();
|
||||||
|
@ -344,7 +344,8 @@ const FeaturedUser = React.createClass({
|
||||||
onDeleteClicked: function(e) {
|
onDeleteClicked: function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
this.context.groupStore.removeUserFromGroupSummary(
|
GroupStore.removeUserFromGroupSummary(
|
||||||
|
this.props.groupId,
|
||||||
this.props.summaryInfo.user_id,
|
this.props.summaryInfo.user_id,
|
||||||
).catch((err) => {
|
).catch((err) => {
|
||||||
console.error('Error whilst removing user from group summary', err);
|
console.error('Error whilst removing user from group summary', err);
|
||||||
|
@ -390,15 +391,6 @@ const FeaturedUser = React.createClass({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const GroupContext = {
|
|
||||||
groupStore: PropTypes.instanceOf(GroupStore).isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
CategoryRoomList.contextTypes = GroupContext;
|
|
||||||
FeaturedRoom.contextTypes = GroupContext;
|
|
||||||
RoleUserList.contextTypes = GroupContext;
|
|
||||||
FeaturedUser.contextTypes = GroupContext;
|
|
||||||
|
|
||||||
const GROUP_JOINPOLICY_OPEN = "open";
|
const GROUP_JOINPOLICY_OPEN = "open";
|
||||||
const GROUP_JOINPOLICY_INVITE = "invite";
|
const GROUP_JOINPOLICY_INVITE = "invite";
|
||||||
|
|
||||||
|
@ -415,12 +407,6 @@ export default React.createClass({
|
||||||
groupStore: PropTypes.instanceOf(GroupStore),
|
groupStore: PropTypes.instanceOf(GroupStore),
|
||||||
},
|
},
|
||||||
|
|
||||||
getChildContext: function() {
|
|
||||||
return {
|
|
||||||
groupStore: this._groupStore,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
summary: null,
|
summary: null,
|
||||||
|
@ -440,6 +426,7 @@ export default React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentWillMount: function() {
|
||||||
|
this._unmounted = false;
|
||||||
this._matrixClient = MatrixClientPeg.get();
|
this._matrixClient = MatrixClientPeg.get();
|
||||||
this._matrixClient.on("Group.myMembership", this._onGroupMyMembership);
|
this._matrixClient.on("Group.myMembership", this._onGroupMyMembership);
|
||||||
|
|
||||||
|
@ -448,8 +435,8 @@ export default React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount: function() {
|
componentWillUnmount: function() {
|
||||||
|
this._unmounted = true;
|
||||||
this._matrixClient.removeListener("Group.myMembership", this._onGroupMyMembership);
|
this._matrixClient.removeListener("Group.myMembership", this._onGroupMyMembership);
|
||||||
this._groupStore.removeAllListeners();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillReceiveProps: function(newProps) {
|
componentWillReceiveProps: function(newProps) {
|
||||||
|
@ -464,8 +451,7 @@ export default React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
_onGroupMyMembership: function(group) {
|
_onGroupMyMembership: function(group) {
|
||||||
if (group.groupId !== this.props.groupId) return;
|
if (this._unmounted || group.groupId !== this.props.groupId) return;
|
||||||
|
|
||||||
if (group.myMembership === 'leave') {
|
if (group.myMembership === 'leave') {
|
||||||
// Leave settings - the user might have clicked the "Leave" button
|
// Leave settings - the user might have clicked the "Leave" button
|
||||||
this._closeSettings();
|
this._closeSettings();
|
||||||
|
@ -478,34 +464,11 @@ export default React.createClass({
|
||||||
if (group && group.inviter && group.inviter.userId) {
|
if (group && group.inviter && group.inviter.userId) {
|
||||||
this._fetchInviterProfile(group.inviter.userId);
|
this._fetchInviterProfile(group.inviter.userId);
|
||||||
}
|
}
|
||||||
this._groupStore = GroupStoreCache.getGroupStore(groupId);
|
GroupStore.registerListener(groupId, this.onGroupStoreUpdated.bind(this, firstInit));
|
||||||
this._groupStore.registerListener(() => {
|
|
||||||
const summary = this._groupStore.getSummary();
|
|
||||||
if (summary.profile) {
|
|
||||||
// Default profile fields should be "" for later sending to the server (which
|
|
||||||
// requires that the fields are strings, not null)
|
|
||||||
["avatar_url", "long_description", "name", "short_description"].forEach((k) => {
|
|
||||||
summary.profile[k] = summary.profile[k] || "";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.setState({
|
|
||||||
summary,
|
|
||||||
summaryLoading: !this._groupStore.isStateReady(GroupStore.STATE_KEY.Summary),
|
|
||||||
isGroupPublicised: this._groupStore.getGroupPublicity(),
|
|
||||||
isUserPrivileged: this._groupStore.isUserPrivileged(),
|
|
||||||
groupRooms: this._groupStore.getGroupRooms(),
|
|
||||||
groupRoomsLoading: !this._groupStore.isStateReady(GroupStore.STATE_KEY.GroupRooms),
|
|
||||||
isUserMember: this._groupStore.getGroupMembers().some(
|
|
||||||
(m) => m.userId === this._matrixClient.credentials.userId,
|
|
||||||
),
|
|
||||||
error: null,
|
|
||||||
});
|
|
||||||
if (this.props.groupIsNew && firstInit) {
|
|
||||||
this._onEditClick();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
let willDoOnboarding = false;
|
let willDoOnboarding = false;
|
||||||
this._groupStore.on('error', (err) => {
|
// XXX: This should be more fluxy - let's get the error from GroupStore .getError or something
|
||||||
|
GroupStore.on('error', (err, errorGroupId) => {
|
||||||
|
if (this._unmounted || groupId !== errorGroupId) return;
|
||||||
if (err.errcode === 'M_GUEST_ACCESS_FORBIDDEN' && !willDoOnboarding) {
|
if (err.errcode === 'M_GUEST_ACCESS_FORBIDDEN' && !willDoOnboarding) {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'do_after_sync_prepared',
|
action: 'do_after_sync_prepared',
|
||||||
|
@ -520,15 +483,45 @@ export default React.createClass({
|
||||||
this.setState({
|
this.setState({
|
||||||
summary: null,
|
summary: null,
|
||||||
error: err,
|
error: err,
|
||||||
|
editing: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onGroupStoreUpdated(firstInit) {
|
||||||
|
if (this._unmounted) return;
|
||||||
|
const summary = GroupStore.getSummary(this.props.groupId);
|
||||||
|
if (summary.profile) {
|
||||||
|
// Default profile fields should be "" for later sending to the server (which
|
||||||
|
// requires that the fields are strings, not null)
|
||||||
|
["avatar_url", "long_description", "name", "short_description"].forEach((k) => {
|
||||||
|
summary.profile[k] = summary.profile[k] || "";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
summary,
|
||||||
|
summaryLoading: !GroupStore.isStateReady(this.props.groupId, GroupStore.STATE_KEY.Summary),
|
||||||
|
isGroupPublicised: GroupStore.getGroupPublicity(this.props.groupId),
|
||||||
|
isUserPrivileged: GroupStore.isUserPrivileged(this.props.groupId),
|
||||||
|
groupRooms: GroupStore.getGroupRooms(this.props.groupId),
|
||||||
|
groupRoomsLoading: !GroupStore.isStateReady(this.props.groupId, GroupStore.STATE_KEY.GroupRooms),
|
||||||
|
isUserMember: GroupStore.getGroupMembers(this.props.groupId).some(
|
||||||
|
(m) => m.userId === this._matrixClient.credentials.userId,
|
||||||
|
),
|
||||||
|
error: null,
|
||||||
|
});
|
||||||
|
// XXX: This might not work but this.props.groupIsNew unused anyway
|
||||||
|
if (this.props.groupIsNew && firstInit) {
|
||||||
|
this._onEditClick();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_fetchInviterProfile(userId) {
|
_fetchInviterProfile(userId) {
|
||||||
this.setState({
|
this.setState({
|
||||||
inviterProfileBusy: true,
|
inviterProfileBusy: true,
|
||||||
});
|
});
|
||||||
this._matrixClient.getProfileInfo(userId).then((resp) => {
|
this._matrixClient.getProfileInfo(userId).then((resp) => {
|
||||||
|
if (this._unmounted) return;
|
||||||
this.setState({
|
this.setState({
|
||||||
inviterProfile: {
|
inviterProfile: {
|
||||||
avatarUrl: resp.avatar_url,
|
avatarUrl: resp.avatar_url,
|
||||||
|
@ -538,6 +531,7 @@ export default React.createClass({
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
console.error('Error getting group inviter profile', e);
|
console.error('Error getting group inviter profile', e);
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
|
if (this._unmounted) return;
|
||||||
this.setState({
|
this.setState({
|
||||||
inviterProfileBusy: false,
|
inviterProfileBusy: false,
|
||||||
});
|
});
|
||||||
|
@ -677,7 +671,7 @@ export default React.createClass({
|
||||||
// spinner disappearing after we have fetched new group data.
|
// spinner disappearing after we have fetched new group data.
|
||||||
await Promise.delay(500);
|
await Promise.delay(500);
|
||||||
|
|
||||||
this._groupStore.acceptGroupInvite().then(() => {
|
GroupStore.acceptGroupInvite(this.props.groupId).then(() => {
|
||||||
// don't reset membershipBusy here: wait for the membership change to come down the sync
|
// don't reset membershipBusy here: wait for the membership change to come down the sync
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
this.setState({membershipBusy: false});
|
this.setState({membershipBusy: false});
|
||||||
|
@ -696,7 +690,7 @@ export default React.createClass({
|
||||||
// spinner disappearing after we have fetched new group data.
|
// spinner disappearing after we have fetched new group data.
|
||||||
await Promise.delay(500);
|
await Promise.delay(500);
|
||||||
|
|
||||||
this._groupStore.leaveGroup().then(() => {
|
GroupStore.leaveGroup(this.props.groupId).then(() => {
|
||||||
// don't reset membershipBusy here: wait for the membership change to come down the sync
|
// don't reset membershipBusy here: wait for the membership change to come down the sync
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
this.setState({membershipBusy: false});
|
this.setState({membershipBusy: false});
|
||||||
|
@ -715,7 +709,7 @@ export default React.createClass({
|
||||||
// spinner disappearing after we have fetched new group data.
|
// spinner disappearing after we have fetched new group data.
|
||||||
await Promise.delay(500);
|
await Promise.delay(500);
|
||||||
|
|
||||||
this._groupStore.joinGroup().then(() => {
|
GroupStore.joinGroup(this.props.groupId).then(() => {
|
||||||
// don't reset membershipBusy here: wait for the membership change to come down the sync
|
// don't reset membershipBusy here: wait for the membership change to come down the sync
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
this.setState({membershipBusy: false});
|
this.setState({membershipBusy: false});
|
||||||
|
@ -743,7 +737,7 @@ export default React.createClass({
|
||||||
// spinner disappearing after we have fetched new group data.
|
// spinner disappearing after we have fetched new group data.
|
||||||
await Promise.delay(500);
|
await Promise.delay(500);
|
||||||
|
|
||||||
this._groupStore.leaveGroup().then(() => {
|
GroupStore.leaveGroup(this.props.groupId).then(() => {
|
||||||
// don't reset membershipBusy here: wait for the membership change to come down the sync
|
// don't reset membershipBusy here: wait for the membership change to come down the sync
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
this.setState({membershipBusy: false});
|
this.setState({membershipBusy: false});
|
||||||
|
|
|
@ -27,7 +27,7 @@ import Analytics from '../../Analytics';
|
||||||
import RateLimitedFunc from '../../ratelimitedfunc';
|
import RateLimitedFunc from '../../ratelimitedfunc';
|
||||||
import AccessibleButton from '../../components/views/elements/AccessibleButton';
|
import AccessibleButton from '../../components/views/elements/AccessibleButton';
|
||||||
import { showGroupInviteDialog, showGroupAddRoomDialog } from '../../GroupAddressPicker';
|
import { showGroupInviteDialog, showGroupAddRoomDialog } from '../../GroupAddressPicker';
|
||||||
import GroupStoreCache from '../../stores/GroupStoreCache';
|
import GroupStore from '../../stores/GroupStore';
|
||||||
|
|
||||||
import { formatCount } from '../../utils/FormattingUtils';
|
import { formatCount } from '../../utils/FormattingUtils';
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ module.exports = React.createClass({
|
||||||
if (this.context.matrixClient) {
|
if (this.context.matrixClient) {
|
||||||
this.context.matrixClient.removeListener("RoomState.members", this.onRoomStateMember);
|
this.context.matrixClient.removeListener("RoomState.members", this.onRoomStateMember);
|
||||||
}
|
}
|
||||||
this._unregisterGroupStore();
|
this._unregisterGroupStore(this.props.groupId);
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
|
@ -132,26 +132,23 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
componentWillReceiveProps(newProps) {
|
componentWillReceiveProps(newProps) {
|
||||||
if (newProps.groupId !== this.props.groupId) {
|
if (newProps.groupId !== this.props.groupId) {
|
||||||
this._unregisterGroupStore();
|
this._unregisterGroupStore(this.props.groupId);
|
||||||
this._initGroupStore(newProps.groupId);
|
this._initGroupStore(newProps.groupId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_initGroupStore(groupId) {
|
_initGroupStore(groupId) {
|
||||||
if (!groupId) return;
|
if (!groupId) return;
|
||||||
this._groupStore = GroupStoreCache.getGroupStore(groupId);
|
GroupStore.registerListener(groupId, this.onGroupStoreUpdated);
|
||||||
this._groupStore.registerListener(this.onGroupStoreUpdated);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_unregisterGroupStore() {
|
_unregisterGroupStore() {
|
||||||
if (this._groupStore) {
|
GroupStore.unregisterListener(this.onGroupStoreUpdated);
|
||||||
this._groupStore.unregisterListener(this.onGroupStoreUpdated);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onGroupStoreUpdated: function() {
|
onGroupStoreUpdated: function() {
|
||||||
this.setState({
|
this.setState({
|
||||||
isUserPrivilegedInGroup: this._groupStore.isUserPrivileged(),
|
isUserPrivilegedInGroup: GroupStore.isUserPrivileged(this.props.groupId),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ import sdk from '../../../index';
|
||||||
import MatrixClientPeg from '../../../MatrixClientPeg';
|
import MatrixClientPeg from '../../../MatrixClientPeg';
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
import { addressTypes, getAddressType } from '../../../UserAddress.js';
|
import { addressTypes, getAddressType } from '../../../UserAddress.js';
|
||||||
import GroupStoreCache from '../../../stores/GroupStoreCache';
|
import GroupStore from '../../../stores/GroupStore';
|
||||||
|
|
||||||
const TRUNCATE_QUERY_LIST = 40;
|
const TRUNCATE_QUERY_LIST = 40;
|
||||||
const QUERY_USER_DIRECTORY_DEBOUNCE_MS = 200;
|
const QUERY_USER_DIRECTORY_DEBOUNCE_MS = 200;
|
||||||
|
@ -243,9 +243,8 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
_doNaiveGroupRoomSearch: function(query) {
|
_doNaiveGroupRoomSearch: function(query) {
|
||||||
const lowerCaseQuery = query.toLowerCase();
|
const lowerCaseQuery = query.toLowerCase();
|
||||||
const groupStore = GroupStoreCache.getGroupStore(this.props.groupId);
|
|
||||||
const results = [];
|
const results = [];
|
||||||
groupStore.getGroupRooms().forEach((r) => {
|
GroupStore.getGroupRooms(this.props.groupId).forEach((r) => {
|
||||||
const nameMatch = (r.name || '').toLowerCase().includes(lowerCaseQuery);
|
const nameMatch = (r.name || '').toLowerCase().includes(lowerCaseQuery);
|
||||||
const topicMatch = (r.topic || '').toLowerCase().includes(lowerCaseQuery);
|
const topicMatch = (r.topic || '').toLowerCase().includes(lowerCaseQuery);
|
||||||
const aliasMatch = (r.canonical_alias || '').toLowerCase().includes(lowerCaseQuery);
|
const aliasMatch = (r.canonical_alias || '').toLowerCase().includes(lowerCaseQuery);
|
||||||
|
|
|
@ -23,7 +23,7 @@ import Modal from '../../../Modal';
|
||||||
import sdk from '../../../index';
|
import sdk from '../../../index';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import { GroupMemberType } from '../../../groups';
|
import { GroupMemberType } from '../../../groups';
|
||||||
import GroupStoreCache from '../../../stores/GroupStoreCache';
|
import GroupStore from '../../../stores/GroupStore';
|
||||||
import AccessibleButton from '../elements/AccessibleButton';
|
import AccessibleButton from '../elements/AccessibleButton';
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
|
@ -47,33 +47,37 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentWillMount: function() {
|
||||||
|
this._unmounted = false;
|
||||||
this._initGroupStore(this.props.groupId);
|
this._initGroupStore(this.props.groupId);
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillReceiveProps(newProps) {
|
componentWillReceiveProps(newProps) {
|
||||||
if (newProps.groupId !== this.props.groupId) {
|
if (newProps.groupId !== this.props.groupId) {
|
||||||
this._unregisterGroupStore();
|
this._unregisterGroupStore(this.props.groupId);
|
||||||
this._initGroupStore(newProps.groupId);
|
this._initGroupStore(newProps.groupId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_initGroupStore(groupId) {
|
componentWillUnmount() {
|
||||||
this._groupStore = GroupStoreCache.getGroupStore(this.props.groupId);
|
this._unmounted = true;
|
||||||
this._groupStore.registerListener(this.onGroupStoreUpdated);
|
this._unregisterGroupStore(this.props.groupId);
|
||||||
},
|
},
|
||||||
|
|
||||||
_unregisterGroupStore() {
|
_initGroupStore(groupId) {
|
||||||
if (this._groupStore) {
|
GroupStore.registerListener(groupId, this.onGroupStoreUpdated);
|
||||||
this._groupStore.unregisterListener(this.onGroupStoreUpdated);
|
},
|
||||||
}
|
|
||||||
|
_unregisterGroupStore(groupId) {
|
||||||
|
GroupStore.unregisterListener(this.onGroupStoreUpdated);
|
||||||
},
|
},
|
||||||
|
|
||||||
onGroupStoreUpdated: function() {
|
onGroupStoreUpdated: function() {
|
||||||
|
if (this._unmounted) return;
|
||||||
this.setState({
|
this.setState({
|
||||||
isUserInvited: this._groupStore.getGroupInvitedMembers().some(
|
isUserInvited: GroupStore.getGroupInvitedMembers(this.props.groupId).some(
|
||||||
(m) => m.userId === this.props.groupMember.userId,
|
(m) => m.userId === this.props.groupMember.userId,
|
||||||
),
|
),
|
||||||
isUserPrivilegedInGroup: this._groupStore.isUserPrivileged(),
|
isUserPrivilegedInGroup: GroupStore.isUserPrivileged(this.props.groupId),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import sdk from '../../../index';
|
import sdk from '../../../index';
|
||||||
import GroupStoreCache from '../../../stores/GroupStoreCache';
|
import GroupStore from '../../../stores/GroupStore';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
const INITIAL_LOAD_NUM_MEMBERS = 30;
|
const INITIAL_LOAD_NUM_MEMBERS = 30;
|
||||||
|
@ -42,9 +42,12 @@ export default React.createClass({
|
||||||
this._initGroupStore(this.props.groupId);
|
this._initGroupStore(this.props.groupId);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
componentWillUnmount: function() {
|
||||||
|
this._unmounted = true;
|
||||||
|
},
|
||||||
|
|
||||||
_initGroupStore: function(groupId) {
|
_initGroupStore: function(groupId) {
|
||||||
this._groupStore = GroupStoreCache.getGroupStore(groupId);
|
GroupStore.registerListener(groupId, () => {
|
||||||
this._groupStore.registerListener(() => {
|
|
||||||
this._fetchMembers();
|
this._fetchMembers();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -52,8 +55,8 @@ export default React.createClass({
|
||||||
_fetchMembers: function() {
|
_fetchMembers: function() {
|
||||||
if (this._unmounted) return;
|
if (this._unmounted) return;
|
||||||
this.setState({
|
this.setState({
|
||||||
members: this._groupStore.getGroupMembers(),
|
members: GroupStore.getGroupMembers(this.props.groupId),
|
||||||
invitedMembers: this._groupStore.getGroupInvitedMembers(),
|
invitedMembers: GroupStore.getGroupInvitedMembers(this.props.groupId),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import sdk from '../../../index';
|
import sdk from '../../../index';
|
||||||
import GroupStoreCache from '../../../stores/GroupStoreCache';
|
|
||||||
import GroupStore from '../../../stores/GroupStore';
|
import GroupStore from '../../../stores/GroupStore';
|
||||||
import { _t } from '../../../languageHandler.js';
|
import { _t } from '../../../languageHandler.js';
|
||||||
|
|
||||||
|
@ -41,15 +40,18 @@ export default React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
_initGroupStore: function(groupId) {
|
_initGroupStore: function(groupId) {
|
||||||
this._groupStore = GroupStoreCache.getGroupStore(groupId);
|
this._groupStoreToken = GroupStore.registerListener(groupId, () => {
|
||||||
this._groupStore.registerListener(() => {
|
|
||||||
this.setState({
|
this.setState({
|
||||||
isGroupPublicised: this._groupStore.getGroupPublicity(),
|
isGroupPublicised: GroupStore.getGroupPublicity(groupId),
|
||||||
ready: this._groupStore.isStateReady(GroupStore.STATE_KEY.Summary),
|
ready: GroupStore.isStateReady(groupId, GroupStore.STATE_KEY.Summary),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
if (this._groupStoreToken) this._groupStoreToken.unregister();
|
||||||
|
},
|
||||||
|
|
||||||
_onPublicityToggle: function(e) {
|
_onPublicityToggle: function(e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -57,7 +59,7 @@ export default React.createClass({
|
||||||
// Optimistic early update
|
// Optimistic early update
|
||||||
isGroupPublicised: !this.state.isGroupPublicised,
|
isGroupPublicised: !this.state.isGroupPublicised,
|
||||||
});
|
});
|
||||||
this._groupStore.setGroupPublicity(!this.state.isGroupPublicised).then(() => {
|
GroupStore.setGroupPublicity(this.props.groupId, !this.state.isGroupPublicised).then(() => {
|
||||||
this.setState({
|
this.setState({
|
||||||
busy: false,
|
busy: false,
|
||||||
});
|
});
|
||||||
|
|
|
@ -21,7 +21,7 @@ import dis from '../../../dispatcher';
|
||||||
import Modal from '../../../Modal';
|
import Modal from '../../../Modal';
|
||||||
import sdk from '../../../index';
|
import sdk from '../../../index';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import GroupStoreCache from '../../../stores/GroupStoreCache';
|
import GroupStore from '../../../stores/GroupStore';
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
displayName: 'GroupRoomInfo',
|
displayName: 'GroupRoomInfo',
|
||||||
|
@ -50,29 +50,26 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
componentWillReceiveProps(newProps) {
|
componentWillReceiveProps(newProps) {
|
||||||
if (newProps.groupId !== this.props.groupId) {
|
if (newProps.groupId !== this.props.groupId) {
|
||||||
this._unregisterGroupStore();
|
this._unregisterGroupStore(this.props.groupId);
|
||||||
this._initGroupStore(newProps.groupId);
|
this._initGroupStore(newProps.groupId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this._unregisterGroupStore();
|
this._unregisterGroupStore(this.props.groupId);
|
||||||
},
|
},
|
||||||
|
|
||||||
_initGroupStore(groupId) {
|
_initGroupStore(groupId) {
|
||||||
this._groupStore = GroupStoreCache.getGroupStore(this.props.groupId);
|
GroupStore.registerListener(groupId, this.onGroupStoreUpdated);
|
||||||
this._groupStore.registerListener(this.onGroupStoreUpdated);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_unregisterGroupStore() {
|
_unregisterGroupStore(groupId) {
|
||||||
if (this._groupStore) {
|
GroupStore.unregisterListener(this.onGroupStoreUpdated);
|
||||||
this._groupStore.unregisterListener(this.onGroupStoreUpdated);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateGroupRoom() {
|
_updateGroupRoom() {
|
||||||
this.setState({
|
this.setState({
|
||||||
groupRoom: this._groupStore.getGroupRooms().find(
|
groupRoom: GroupStore.getGroupRooms(this.props.groupId).find(
|
||||||
(r) => r.roomId === this.props.groupRoomId,
|
(r) => r.roomId === this.props.groupRoomId,
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
@ -80,7 +77,7 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
onGroupStoreUpdated: function() {
|
onGroupStoreUpdated: function() {
|
||||||
this.setState({
|
this.setState({
|
||||||
isUserPrivilegedInGroup: this._groupStore.isUserPrivileged(),
|
isUserPrivilegedInGroup: GroupStore.isUserPrivileged(this.props.groupId),
|
||||||
});
|
});
|
||||||
this._updateGroupRoom();
|
this._updateGroupRoom();
|
||||||
},
|
},
|
||||||
|
@ -100,7 +97,7 @@ module.exports = React.createClass({
|
||||||
this.setState({groupRoomRemoveLoading: true});
|
this.setState({groupRoomRemoveLoading: true});
|
||||||
const groupId = this.props.groupId;
|
const groupId = this.props.groupId;
|
||||||
const roomId = this.props.groupRoomId;
|
const roomId = this.props.groupRoomId;
|
||||||
this._groupStore.removeRoomFromGroup(roomId).then(() => {
|
GroupStore.removeRoomFromGroup(this.props.groupId, roomId).then(() => {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: "view_group_room_list",
|
action: "view_group_room_list",
|
||||||
});
|
});
|
||||||
|
@ -134,7 +131,7 @@ module.exports = React.createClass({
|
||||||
const groupId = this.props.groupId;
|
const groupId = this.props.groupId;
|
||||||
const roomId = this.props.groupRoomId;
|
const roomId = this.props.groupRoomId;
|
||||||
const roomName = this.state.groupRoom.displayname;
|
const roomName = this.state.groupRoom.displayname;
|
||||||
this._groupStore.updateGroupRoomVisibility(roomId, isPublic).catch((err) => {
|
GroupStore.updateGroupRoomVisibility(this.props.groupId, roomId, isPublic).catch((err) => {
|
||||||
console.error(`Error whilst changing visibility of ${roomId} in ${groupId} to ${isPublic}`, err);
|
console.error(`Error whilst changing visibility of ${roomId} in ${groupId} to ${isPublic}`, err);
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createTrackedDialog('Failed to remove room from group', '', ErrorDialog, {
|
Modal.createTrackedDialog('Failed to remove room from group', '', ErrorDialog, {
|
||||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import sdk from '../../../index';
|
import sdk from '../../../index';
|
||||||
import GroupStoreCache from '../../../stores/GroupStoreCache';
|
import GroupStore from '../../../stores/GroupStore';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
const INITIAL_LOAD_NUM_ROOMS = 30;
|
const INITIAL_LOAD_NUM_ROOMS = 30;
|
||||||
|
@ -39,22 +39,31 @@ export default React.createClass({
|
||||||
this._initGroupStore(this.props.groupId);
|
this._initGroupStore(this.props.groupId);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this._unmounted = true;
|
||||||
|
this._unregisterGroupStore();
|
||||||
|
},
|
||||||
|
|
||||||
|
_unregisterGroupStore() {
|
||||||
|
GroupStore.unregisterListener(this.onGroupStoreUpdated);
|
||||||
|
},
|
||||||
|
|
||||||
_initGroupStore: function(groupId) {
|
_initGroupStore: function(groupId) {
|
||||||
this._groupStore = GroupStoreCache.getGroupStore(groupId);
|
GroupStore.registerListener(groupId, this.onGroupStoreUpdated);
|
||||||
this._groupStore.registerListener(() => {
|
// XXX: This should be more fluxy - let's get the error from GroupStore .getError or something
|
||||||
this._fetchRooms();
|
// XXX: This is also leaked - we should remove it when unmounting
|
||||||
});
|
GroupStore.on('error', (err, errorGroupId) => {
|
||||||
this._groupStore.on('error', (err) => {
|
if (errorGroupId !== groupId) return;
|
||||||
this.setState({
|
this.setState({
|
||||||
rooms: null,
|
rooms: null,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_fetchRooms: function() {
|
onGroupStoreUpdated: function() {
|
||||||
if (this._unmounted) return;
|
if (this._unmounted) return;
|
||||||
this.setState({
|
this.setState({
|
||||||
rooms: this._groupStore.getGroupRooms(),
|
rooms: GroupStore.getGroupRooms(this.props.groupId),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ import DMRoomMap from '../../../utils/DMRoomMap';
|
||||||
const Receipt = require('../../../utils/Receipt');
|
const Receipt = require('../../../utils/Receipt');
|
||||||
import TagOrderStore from '../../../stores/TagOrderStore';
|
import TagOrderStore from '../../../stores/TagOrderStore';
|
||||||
import RoomListStore from '../../../stores/RoomListStore';
|
import RoomListStore from '../../../stores/RoomListStore';
|
||||||
import GroupStoreCache from '../../../stores/GroupStoreCache';
|
import GroupStore from '../../../stores/GroupStore';
|
||||||
|
|
||||||
const HIDE_CONFERENCE_CHANS = true;
|
const HIDE_CONFERENCE_CHANS = true;
|
||||||
const STANDARD_TAGS_REGEX = /^(m\.(favourite|lowpriority)|im\.vector\.fake\.(invite|recent|direct|archived))$/;
|
const STANDARD_TAGS_REGEX = /^(m\.(favourite|lowpriority)|im\.vector\.fake\.(invite|recent|direct|archived))$/;
|
||||||
|
@ -83,8 +83,6 @@ module.exports = React.createClass({
|
||||||
cli.on("Group.myMembership", this._onGroupMyMembership);
|
cli.on("Group.myMembership", this._onGroupMyMembership);
|
||||||
|
|
||||||
const dmRoomMap = DMRoomMap.shared();
|
const dmRoomMap = DMRoomMap.shared();
|
||||||
this._groupStores = {};
|
|
||||||
this._groupStoreTokens = [];
|
|
||||||
// A map between tags which are group IDs and the room IDs of rooms that should be kept
|
// A map between tags which are group IDs and the room IDs of rooms that should be kept
|
||||||
// in the room list when filtering by that tag.
|
// in the room list when filtering by that tag.
|
||||||
this._visibleRoomsForGroup = {
|
this._visibleRoomsForGroup = {
|
||||||
|
@ -96,17 +94,14 @@ module.exports = React.createClass({
|
||||||
// When the selected tags are changed, initialise a group store if necessary
|
// When the selected tags are changed, initialise a group store if necessary
|
||||||
this._tagStoreToken = TagOrderStore.addListener(() => {
|
this._tagStoreToken = TagOrderStore.addListener(() => {
|
||||||
(TagOrderStore.getOrderedTags() || []).forEach((tag) => {
|
(TagOrderStore.getOrderedTags() || []).forEach((tag) => {
|
||||||
if (tag[0] !== '+' || this._groupStores[tag]) {
|
if (tag[0] !== '+') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._groupStores[tag] = GroupStoreCache.getGroupStore(tag);
|
this._groupStoreToken = GroupStore.registerListener(tag, () => {
|
||||||
this._groupStoreTokens.push(
|
// This group's rooms or members may have updated, update rooms for its tag
|
||||||
this._groupStores[tag].registerListener(() => {
|
this.updateVisibleRoomsForTag(dmRoomMap, tag);
|
||||||
// This group's rooms or members may have updated, update rooms for its tag
|
this.updateVisibleRooms();
|
||||||
this.updateVisibleRoomsForTag(dmRoomMap, tag);
|
});
|
||||||
this.updateVisibleRooms();
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
// Filters themselves have changed, refresh the selected tags
|
// Filters themselves have changed, refresh the selected tags
|
||||||
this.updateVisibleRooms();
|
this.updateVisibleRooms();
|
||||||
|
@ -183,9 +178,9 @@ module.exports = React.createClass({
|
||||||
this._roomListStoreToken.remove();
|
this._roomListStoreToken.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._groupStoreTokens.length > 0) {
|
// NB: GroupStore is not a Flux.Store
|
||||||
// NB: GroupStore is not a Flux.Store
|
if (this._groupStoreToken) {
|
||||||
this._groupStoreTokens.forEach((token) => token.unregister());
|
this._groupStoreToken.unregister();
|
||||||
}
|
}
|
||||||
|
|
||||||
// cancel any pending calls to the rate_limited_funcs
|
// cancel any pending calls to the rate_limited_funcs
|
||||||
|
@ -259,12 +254,11 @@ module.exports = React.createClass({
|
||||||
updateVisibleRoomsForTag: function(dmRoomMap, tag) {
|
updateVisibleRoomsForTag: function(dmRoomMap, tag) {
|
||||||
if (!this.mounted) return;
|
if (!this.mounted) return;
|
||||||
// For now, only handle group tags
|
// For now, only handle group tags
|
||||||
const store = this._groupStores[tag];
|
if (tag[0] !== '+') return;
|
||||||
if (!store) return;
|
|
||||||
|
|
||||||
this._visibleRoomsForGroup[tag] = [];
|
this._visibleRoomsForGroup[tag] = [];
|
||||||
store.getGroupRooms().forEach((room) => this._visibleRoomsForGroup[tag].push(room.roomId));
|
GroupStore.getGroupRooms(tag).forEach((room) => this._visibleRoomsForGroup[tag].push(room.roomId));
|
||||||
store.getGroupMembers().forEach((member) => {
|
GroupStore.getGroupMembers(tag).forEach((member) => {
|
||||||
if (member.userId === MatrixClientPeg.get().credentials.userId) return;
|
if (member.userId === MatrixClientPeg.get().credentials.userId) return;
|
||||||
dmRoomMap.getDMRoomsForUserId(member.userId).forEach(
|
dmRoomMap.getDMRoomsForUserId(member.userId).forEach(
|
||||||
(roomId) => this._visibleRoomsForGroup[tag].push(roomId),
|
(roomId) => this._visibleRoomsForGroup[tag].push(roomId),
|
||||||
|
|
|
@ -70,84 +70,90 @@ function limitConcurrency(fn) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the group summary for a room and provides an API to change it and
|
* Global store for tracking group summary, members, invited members and rooms.
|
||||||
* other useful group APIs that may have an effect on the group summary.
|
|
||||||
*/
|
*/
|
||||||
export default class GroupStore extends EventEmitter {
|
class GroupStore extends EventEmitter {
|
||||||
|
STATE_KEY = {
|
||||||
static STATE_KEY = {
|
|
||||||
GroupMembers: 'GroupMembers',
|
GroupMembers: 'GroupMembers',
|
||||||
GroupInvitedMembers: 'GroupInvitedMembers',
|
GroupInvitedMembers: 'GroupInvitedMembers',
|
||||||
Summary: 'Summary',
|
Summary: 'Summary',
|
||||||
GroupRooms: 'GroupRooms',
|
GroupRooms: 'GroupRooms',
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(groupId) {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
if (!groupId) {
|
|
||||||
throw new Error('GroupStore needs a valid groupId to be created');
|
|
||||||
}
|
|
||||||
this.groupId = groupId;
|
|
||||||
this._state = {};
|
this._state = {};
|
||||||
this._state[GroupStore.STATE_KEY.Summary] = {};
|
this._state[this.STATE_KEY.Summary] = {};
|
||||||
this._state[GroupStore.STATE_KEY.GroupRooms] = [];
|
this._state[this.STATE_KEY.GroupRooms] = {};
|
||||||
this._state[GroupStore.STATE_KEY.GroupMembers] = [];
|
this._state[this.STATE_KEY.GroupMembers] = {};
|
||||||
this._state[GroupStore.STATE_KEY.GroupInvitedMembers] = [];
|
this._state[this.STATE_KEY.GroupInvitedMembers] = {};
|
||||||
this._ready = {};
|
|
||||||
|
this._ready = {};
|
||||||
|
this._ready[this.STATE_KEY.Summary] = {};
|
||||||
|
this._ready[this.STATE_KEY.GroupRooms] = {};
|
||||||
|
this._ready[this.STATE_KEY.GroupMembers] = {};
|
||||||
|
this._ready[this.STATE_KEY.GroupInvitedMembers] = {};
|
||||||
|
|
||||||
|
this._fetchResourcePromise = {
|
||||||
|
[this.STATE_KEY.Summary]: {},
|
||||||
|
[this.STATE_KEY.GroupRooms]: {},
|
||||||
|
[this.STATE_KEY.GroupMembers]: {},
|
||||||
|
[this.STATE_KEY.GroupInvitedMembers]: {},
|
||||||
|
};
|
||||||
|
|
||||||
this._fetchResourcePromise = {};
|
|
||||||
this._resourceFetcher = {
|
this._resourceFetcher = {
|
||||||
[GroupStore.STATE_KEY.Summary]: () => {
|
[this.STATE_KEY.Summary]: (groupId) => {
|
||||||
return limitConcurrency(
|
return limitConcurrency(
|
||||||
() => MatrixClientPeg.get().getGroupSummary(this.groupId),
|
() => MatrixClientPeg.get().getGroupSummary(groupId),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[GroupStore.STATE_KEY.GroupRooms]: () => {
|
[this.STATE_KEY.GroupRooms]: (groupId) => {
|
||||||
return limitConcurrency(
|
return limitConcurrency(
|
||||||
() => MatrixClientPeg.get().getGroupRooms(this.groupId).then(parseRoomsResponse),
|
() => MatrixClientPeg.get().getGroupRooms(groupId).then(parseRoomsResponse),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[GroupStore.STATE_KEY.GroupMembers]: () => {
|
[this.STATE_KEY.GroupMembers]: (groupId) => {
|
||||||
return limitConcurrency(
|
return limitConcurrency(
|
||||||
() => MatrixClientPeg.get().getGroupUsers(this.groupId).then(parseMembersResponse),
|
() => MatrixClientPeg.get().getGroupUsers(groupId).then(parseMembersResponse),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[GroupStore.STATE_KEY.GroupInvitedMembers]: () => {
|
[this.STATE_KEY.GroupInvitedMembers]: (groupId) => {
|
||||||
return limitConcurrency(
|
return limitConcurrency(
|
||||||
() => MatrixClientPeg.get().getGroupInvitedUsers(this.groupId).then(parseMembersResponse),
|
() => MatrixClientPeg.get().getGroupInvitedUsers(groupId).then(parseMembersResponse),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
this.on('error', (err) => {
|
this.on('error', (err, groupId) => {
|
||||||
console.error(`GroupStore for ${this.groupId} encountered error`, err);
|
console.error(`GroupStore encountered error whilst fetching data for ${groupId}`, err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_fetchResource(stateKey) {
|
_fetchResource(stateKey, groupId) {
|
||||||
// Ongoing request, ignore
|
// Ongoing request, ignore
|
||||||
if (this._fetchResourcePromise[stateKey]) return;
|
if (this._fetchResourcePromise[stateKey][groupId]) return;
|
||||||
|
|
||||||
const clientPromise = this._resourceFetcher[stateKey]();
|
const clientPromise = this._resourceFetcher[stateKey](groupId);
|
||||||
|
|
||||||
// Indicate ongoing request
|
// Indicate ongoing request
|
||||||
this._fetchResourcePromise[stateKey] = clientPromise;
|
this._fetchResourcePromise[stateKey][groupId] = clientPromise;
|
||||||
|
|
||||||
clientPromise.then((result) => {
|
clientPromise.then((result) => {
|
||||||
this._state[stateKey] = result;
|
this._state[stateKey][groupId] = result;
|
||||||
this._ready[stateKey] = true;
|
console.info(this._state);
|
||||||
|
this._ready[stateKey][groupId] = true;
|
||||||
this._notifyListeners();
|
this._notifyListeners();
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
// Invited users not visible to non-members
|
// Invited users not visible to non-members
|
||||||
if (stateKey === GroupStore.STATE_KEY.GroupInvitedMembers && err.httpStatus === 403) {
|
if (stateKey === this.STATE_KEY.GroupInvitedMembers && err.httpStatus === 403) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.error("Failed to get resource " + stateKey + ":" + err);
|
console.error(`Failed to get resource ${stateKey} for ${groupId}`, err);
|
||||||
this.emit('error', err);
|
this.emit('error', err, groupId);
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
// Indicate finished request, allow for future fetches
|
// Indicate finished request, allow for future fetches
|
||||||
delete this._fetchResourcePromise[stateKey];
|
delete this._fetchResourcePromise[stateKey][groupId];
|
||||||
});
|
});
|
||||||
|
|
||||||
return clientPromise;
|
return clientPromise;
|
||||||
|
@ -162,25 +168,26 @@ export default class GroupStore extends EventEmitter {
|
||||||
* immediately triggers an update to send the current state of the
|
* immediately triggers an update to send the current state of the
|
||||||
* store (which could be the initial state).
|
* store (which could be the initial state).
|
||||||
*
|
*
|
||||||
* This also causes a fetch of all group data, which might cause
|
* This also causes a fetch of all data of the specified group,
|
||||||
* 4 separate HTTP requests, but only said requests aren't already
|
* which might cause 4 separate HTTP requests, but only if said
|
||||||
* ongoing.
|
* requests aren't already ongoing.
|
||||||
*
|
*
|
||||||
|
* @param {string} groupId the ID of the group to fetch data for.
|
||||||
* @param {function} fn the function to call when the store updates.
|
* @param {function} fn the function to call when the store updates.
|
||||||
* @return {Object} tok a registration "token" with a single
|
* @return {Object} tok a registration "token" with a single
|
||||||
* property `unregister`, a function that can
|
* property `unregister`, a function that can
|
||||||
* be called to unregister the listener such
|
* be called to unregister the listener such
|
||||||
* that it won't be called any more.
|
* that it won't be called any more.
|
||||||
*/
|
*/
|
||||||
registerListener(fn) {
|
registerListener(groupId, fn) {
|
||||||
this.on('update', fn);
|
this.on('update', fn);
|
||||||
// Call to set initial state (before fetching starts)
|
// Call to set initial state (before fetching starts)
|
||||||
this.emit('update');
|
this.emit('update');
|
||||||
|
|
||||||
this._fetchResource(GroupStore.STATE_KEY.Summary);
|
this._fetchResource(this.STATE_KEY.Summary, groupId);
|
||||||
this._fetchResource(GroupStore.STATE_KEY.GroupRooms);
|
this._fetchResource(this.STATE_KEY.GroupRooms, groupId);
|
||||||
this._fetchResource(GroupStore.STATE_KEY.GroupMembers);
|
this._fetchResource(this.STATE_KEY.GroupMembers, groupId);
|
||||||
this._fetchResource(GroupStore.STATE_KEY.GroupInvitedMembers);
|
this._fetchResource(this.STATE_KEY.GroupInvitedMembers, groupId);
|
||||||
|
|
||||||
// Similar to the Store of flux/utils, we return a "token" that
|
// Similar to the Store of flux/utils, we return a "token" that
|
||||||
// can be used to unregister the listener.
|
// can be used to unregister the listener.
|
||||||
|
@ -195,123 +202,129 @@ export default class GroupStore extends EventEmitter {
|
||||||
this.removeListener('update', fn);
|
this.removeListener('update', fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
isStateReady(id) {
|
isStateReady(groupId, id) {
|
||||||
return this._ready[id];
|
return this._ready[id][groupId];
|
||||||
}
|
}
|
||||||
|
|
||||||
getSummary() {
|
getSummary(groupId) {
|
||||||
return this._state[GroupStore.STATE_KEY.Summary];
|
return this._state[this.STATE_KEY.Summary][groupId] || {};
|
||||||
}
|
}
|
||||||
|
|
||||||
getGroupRooms() {
|
getGroupRooms(groupId) {
|
||||||
return this._state[GroupStore.STATE_KEY.GroupRooms];
|
return this._state[this.STATE_KEY.GroupRooms][groupId] || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
getGroupMembers() {
|
getGroupMembers(groupId) {
|
||||||
return this._state[GroupStore.STATE_KEY.GroupMembers];
|
return this._state[this.STATE_KEY.GroupMembers][groupId] || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
getGroupInvitedMembers() {
|
getGroupInvitedMembers(groupId) {
|
||||||
return this._state[GroupStore.STATE_KEY.GroupInvitedMembers];
|
return this._state[this.STATE_KEY.GroupInvitedMembers][groupId] || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
getGroupPublicity() {
|
getGroupPublicity(groupId) {
|
||||||
return this._state[GroupStore.STATE_KEY.Summary].user ?
|
return (this._state[this.STATE_KEY.Summary][groupId] || {}).user ?
|
||||||
this._state[GroupStore.STATE_KEY.Summary].user.is_publicised : null;
|
(this._state[this.STATE_KEY.Summary][groupId] || {}).user.is_publicised : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
isUserPrivileged() {
|
isUserPrivileged(groupId) {
|
||||||
return this._state[GroupStore.STATE_KEY.Summary].user ?
|
return (this._state[this.STATE_KEY.Summary][groupId] || {}).user ?
|
||||||
this._state[GroupStore.STATE_KEY.Summary].user.is_privileged : null;
|
(this._state[this.STATE_KEY.Summary][groupId] || {}).user.is_privileged : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
addRoomToGroup(roomId, isPublic) {
|
addRoomToGroup(groupId, roomId, isPublic) {
|
||||||
return MatrixClientPeg.get()
|
return MatrixClientPeg.get()
|
||||||
.addRoomToGroup(this.groupId, roomId, isPublic)
|
.addRoomToGroup(groupId, roomId, isPublic)
|
||||||
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.GroupRooms));
|
.then(this._fetchResource.bind(this, this.STATE_KEY.GroupRooms, groupId));
|
||||||
}
|
}
|
||||||
|
|
||||||
updateGroupRoomVisibility(roomId, isPublic) {
|
updateGroupRoomVisibility(groupId, roomId, isPublic) {
|
||||||
return MatrixClientPeg.get()
|
return MatrixClientPeg.get()
|
||||||
.updateGroupRoomVisibility(this.groupId, roomId, isPublic)
|
.updateGroupRoomVisibility(groupId, roomId, isPublic)
|
||||||
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.GroupRooms));
|
.then(this._fetchResource.bind(this, this.STATE_KEY.GroupRooms, groupId));
|
||||||
}
|
}
|
||||||
|
|
||||||
removeRoomFromGroup(roomId) {
|
removeRoomFromGroup(groupId, roomId) {
|
||||||
return MatrixClientPeg.get()
|
return MatrixClientPeg.get()
|
||||||
.removeRoomFromGroup(this.groupId, roomId)
|
.removeRoomFromGroup(groupId, roomId)
|
||||||
// Room might be in the summary, refresh just in case
|
// Room might be in the summary, refresh just in case
|
||||||
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.Summary))
|
.then(this._fetchResource.bind(this, this.STATE_KEY.Summary, groupId))
|
||||||
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.GroupRooms));
|
.then(this._fetchResource.bind(this, this.STATE_KEY.GroupRooms, groupId));
|
||||||
}
|
}
|
||||||
|
|
||||||
inviteUserToGroup(userId) {
|
inviteUserToGroup(groupId, userId) {
|
||||||
return MatrixClientPeg.get().inviteUserToGroup(this.groupId, userId)
|
return MatrixClientPeg.get().inviteUserToGroup(groupId, userId)
|
||||||
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.GroupInvitedMembers));
|
.then(this._fetchResource.bind(this, this.STATE_KEY.GroupInvitedMembers, groupId));
|
||||||
}
|
}
|
||||||
|
|
||||||
acceptGroupInvite() {
|
acceptGroupInvite(groupId) {
|
||||||
return MatrixClientPeg.get().acceptGroupInvite(this.groupId)
|
return MatrixClientPeg.get().acceptGroupInvite(groupId)
|
||||||
// The user should now be able to access (personal) group settings
|
// The user should now be able to access (personal) group settings
|
||||||
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.Summary))
|
.then(this._fetchResource.bind(this, this.STATE_KEY.Summary, groupId))
|
||||||
// The user might be able to see more rooms now
|
// The user might be able to see more rooms now
|
||||||
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.GroupRooms))
|
.then(this._fetchResource.bind(this, this.STATE_KEY.GroupRooms, groupId))
|
||||||
// The user should now appear as a member
|
// The user should now appear as a member
|
||||||
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.GroupMembers))
|
.then(this._fetchResource.bind(this, this.STATE_KEY.GroupMembers, groupId))
|
||||||
// The user should now not appear as an invited member
|
// The user should now not appear as an invited member
|
||||||
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.GroupInvitedMembers));
|
.then(this._fetchResource.bind(this, this.STATE_KEY.GroupInvitedMembers, groupId));
|
||||||
}
|
}
|
||||||
|
|
||||||
joinGroup() {
|
joinGroup(groupId) {
|
||||||
return MatrixClientPeg.get().joinGroup(this.groupId)
|
return MatrixClientPeg.get().joinGroup(groupId)
|
||||||
// The user should now be able to access (personal) group settings
|
// The user should now be able to access (personal) group settings
|
||||||
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.Summary))
|
.then(this._fetchResource.bind(this, this.STATE_KEY.Summary, groupId))
|
||||||
// The user might be able to see more rooms now
|
// The user might be able to see more rooms now
|
||||||
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.GroupRooms))
|
.then(this._fetchResource.bind(this, this.STATE_KEY.GroupRooms, groupId))
|
||||||
// The user should now appear as a member
|
// The user should now appear as a member
|
||||||
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.GroupMembers))
|
.then(this._fetchResource.bind(this, this.STATE_KEY.GroupMembers, groupId))
|
||||||
// The user should now not appear as an invited member
|
// The user should now not appear as an invited member
|
||||||
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.GroupInvitedMembers));
|
.then(this._fetchResource.bind(this, this.STATE_KEY.GroupInvitedMembers, groupId));
|
||||||
}
|
}
|
||||||
|
|
||||||
leaveGroup() {
|
leaveGroup(groupId) {
|
||||||
return MatrixClientPeg.get().leaveGroup(this.groupId)
|
return MatrixClientPeg.get().leaveGroup(groupId)
|
||||||
// The user should now not be able to access group settings
|
// The user should now not be able to access group settings
|
||||||
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.Summary))
|
.then(this._fetchResource.bind(this, this.STATE_KEY.Summary, groupId))
|
||||||
// The user might only be able to see a subset of rooms now
|
// The user might only be able to see a subset of rooms now
|
||||||
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.GroupRooms))
|
.then(this._fetchResource.bind(this, this.STATE_KEY.GroupRooms, groupId))
|
||||||
// The user should now not appear as a member
|
// The user should now not appear as a member
|
||||||
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.GroupMembers));
|
.then(this._fetchResource.bind(this, this.STATE_KEY.GroupMembers, groupId));
|
||||||
}
|
}
|
||||||
|
|
||||||
addRoomToGroupSummary(roomId, categoryId) {
|
addRoomToGroupSummary(groupId, roomId, categoryId) {
|
||||||
return MatrixClientPeg.get()
|
return MatrixClientPeg.get()
|
||||||
.addRoomToGroupSummary(this.groupId, roomId, categoryId)
|
.addRoomToGroupSummary(groupId, roomId, categoryId)
|
||||||
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.Summary));
|
.then(this._fetchResource.bind(this, this.STATE_KEY.Summary, groupId));
|
||||||
}
|
}
|
||||||
|
|
||||||
addUserToGroupSummary(userId, roleId) {
|
addUserToGroupSummary(groupId, userId, roleId) {
|
||||||
return MatrixClientPeg.get()
|
return MatrixClientPeg.get()
|
||||||
.addUserToGroupSummary(this.groupId, userId, roleId)
|
.addUserToGroupSummary(groupId, userId, roleId)
|
||||||
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.Summary));
|
.then(this._fetchResource.bind(this, this.STATE_KEY.Summary, groupId));
|
||||||
}
|
}
|
||||||
|
|
||||||
removeRoomFromGroupSummary(roomId) {
|
removeRoomFromGroupSummary(groupId, roomId) {
|
||||||
return MatrixClientPeg.get()
|
return MatrixClientPeg.get()
|
||||||
.removeRoomFromGroupSummary(this.groupId, roomId)
|
.removeRoomFromGroupSummary(groupId, roomId)
|
||||||
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.Summary));
|
.then(this._fetchResource.bind(this, this.STATE_KEY.Summary, groupId));
|
||||||
}
|
}
|
||||||
|
|
||||||
removeUserFromGroupSummary(userId) {
|
removeUserFromGroupSummary(groupId, userId) {
|
||||||
return MatrixClientPeg.get()
|
return MatrixClientPeg.get()
|
||||||
.removeUserFromGroupSummary(this.groupId, userId)
|
.removeUserFromGroupSummary(groupId, userId)
|
||||||
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.Summary));
|
.then(this._fetchResource.bind(this, this.STATE_KEY.Summary, groupId));
|
||||||
}
|
}
|
||||||
|
|
||||||
setGroupPublicity(isPublished) {
|
setGroupPublicity(groupId, isPublished) {
|
||||||
return MatrixClientPeg.get()
|
return MatrixClientPeg.get()
|
||||||
.setGroupPublicity(this.groupId, isPublished)
|
.setGroupPublicity(groupId, isPublished)
|
||||||
.then(() => { FlairStore.invalidatePublicisedGroups(MatrixClientPeg.get().credentials.userId); })
|
.then(() => { FlairStore.invalidatePublicisedGroups(MatrixClientPeg.get().credentials.userId); })
|
||||||
.then(this._fetchResource.bind(this, GroupStore.STATE_KEY.Summary));
|
.then(this._fetchResource.bind(this, this.STATE_KEY.Summary, groupId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let singletonGroupStore = null;
|
||||||
|
if (!singletonGroupStore) {
|
||||||
|
singletonGroupStore = new GroupStore();
|
||||||
|
}
|
||||||
|
module.exports = singletonGroupStore;
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
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 GroupStore from './GroupStore';
|
|
||||||
|
|
||||||
class GroupStoreCache {
|
|
||||||
constructor() {
|
|
||||||
this.groupStore = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
getGroupStore(groupId) {
|
|
||||||
if (!this.groupStore || this.groupStore.groupId !== groupId) {
|
|
||||||
// This effectively throws away the reference to any previous GroupStore,
|
|
||||||
// allowing it to be GCd once the components referencing it have stopped
|
|
||||||
// referencing it.
|
|
||||||
this.groupStore = new GroupStore(groupId);
|
|
||||||
}
|
|
||||||
return this.groupStore;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (global.singletonGroupStoreCache === undefined) {
|
|
||||||
global.singletonGroupStoreCache = new GroupStoreCache();
|
|
||||||
}
|
|
||||||
export default global.singletonGroupStoreCache;
|
|
|
@ -18,7 +18,7 @@ limitations under the License.
|
||||||
import MatrixClientPeg from '../MatrixClientPeg';
|
import MatrixClientPeg from '../MatrixClientPeg';
|
||||||
import {getAddressType} from '../UserAddress';
|
import {getAddressType} from '../UserAddress';
|
||||||
import {inviteToRoom} from '../RoomInvite';
|
import {inviteToRoom} from '../RoomInvite';
|
||||||
import GroupStoreCache from '../stores/GroupStoreCache';
|
import GroupStore from '../stores/GroupStore';
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -118,9 +118,7 @@ export default class MultiInviter {
|
||||||
|
|
||||||
let doInvite;
|
let doInvite;
|
||||||
if (this.groupId !== null) {
|
if (this.groupId !== null) {
|
||||||
doInvite = GroupStoreCache
|
doInvite = GroupStore.inviteUserToGroup(this.groupId, addr);
|
||||||
.getGroupStore(this.groupId)
|
|
||||||
.inviteUserToGroup(addr);
|
|
||||||
} else {
|
} else {
|
||||||
doInvite = inviteToRoom(this.roomId, addr);
|
doInvite = inviteToRoom(this.roomId, addr);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue