more context menu fixes and features
This commit is contained in:
+126
-84
@@ -127,10 +127,12 @@
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* BEGIN Popup/dropdown menu */
|
/* BEGIN Context Menu: popup/dropdown menu */
|
||||||
|
|
||||||
// Function is used by context menu to set permissions.
|
// Function is used by context menu to set permissions.
|
||||||
function topicPermissionSetter(mode, topicName, uid) {
|
function topicPermissionSetter(mode, topicName, uid) {
|
||||||
|
console.log("topicPermissionSetter called with arguments:");
|
||||||
|
console.log(arguments);
|
||||||
var topic = Tinode.getTopic(topicName);
|
var topic = Tinode.getTopic(topicName);
|
||||||
if (!topic) {
|
if (!topic) {
|
||||||
console.log("Topic not found: " + topicName);
|
console.log("Topic not found: " + topicName);
|
||||||
@@ -167,10 +169,10 @@
|
|||||||
}},
|
}},
|
||||||
"message_delete": {title: "Delete", handler: null},
|
"message_delete": {title: "Delete", handler: null},
|
||||||
|
|
||||||
"topic_unmute": {title: "Unmute", handler: topicPermissionSetter.bind("+P")},
|
"topic_unmute": {title: "Unmute", handler: topicPermissionSetter.bind(this, "+P")},
|
||||||
"topic_mute": {title: "Mute", handler: topicPermissionSetter.bind("-P")},
|
"topic_mute": {title: "Mute", handler: topicPermissionSetter.bind(this, "-P")},
|
||||||
"topic_unblock": {title: "Unblock", handler: topicPermissionSetter.bind("+J")},
|
"topic_unblock": {title: "Unblock", handler: topicPermissionSetter.bind(this, "+J")},
|
||||||
"topic_block": {title: "Block", handler: topicPermissionSetter.bind("-J")},
|
"topic_block": {title: "Block", handler: topicPermissionSetter.bind(this, "-J")},
|
||||||
"topic_delete": {title: "Delete", handler: function(topicName) {
|
"topic_delete": {title: "Delete", handler: function(topicName) {
|
||||||
var topic = Tinode.getTopic(topicName);
|
var topic = Tinode.getTopic(topicName);
|
||||||
if (!topic) {
|
if (!topic) {
|
||||||
@@ -180,12 +182,19 @@
|
|||||||
topic.delTopic();
|
topic.delTopic();
|
||||||
}},
|
}},
|
||||||
|
|
||||||
"permissions": {title: "Permissions", handler: null},
|
"permissions": {title: "Edit permissions", handler: null},
|
||||||
"member_delete": {title: "Delete", handler: null},
|
"member_delete": {title: "Remove", handler: function(topicName, user) {
|
||||||
"member_mute": {title: "Mute", handler: topicPermissionSetter.bind("-P")},
|
var topic = Tinode.getTopic(topicName);
|
||||||
"member_unmute": {title: "Unmute", handler: topicPermissionSetter.bind("+P")},
|
if (!topic || !user) {
|
||||||
"member_block": {title: "Block", handler: topicPermissionSetter.bind("-J")},
|
console.log("Topic or user not found: '" + topicName + "', '" + user + "'");
|
||||||
"member_unblock": {title: "Unblock", handler: topicPermissionSetter.bind("+J")},
|
return;
|
||||||
|
}
|
||||||
|
topic.delSubscription(user);
|
||||||
|
}},
|
||||||
|
"member_mute": {title: "Mute", handler: topicPermissionSetter.bind(this, "-P")},
|
||||||
|
"member_unmute": {title: "Unmute", handler: topicPermissionSetter.bind(this, "+P")},
|
||||||
|
"member_block": {title: "Block", handler: topicPermissionSetter.bind(this, "-J")},
|
||||||
|
"member_unblock": {title: "Unblock", handler: topicPermissionSetter.bind(this, "+J")},
|
||||||
};
|
};
|
||||||
|
|
||||||
var ContextMenu = React.createClass({
|
var ContextMenu = React.createClass({
|
||||||
@@ -223,7 +232,6 @@
|
|||||||
this.props.hide();
|
this.props.hide();
|
||||||
var item = this.props.items[e.currentTarget.dataset.id];
|
var item = this.props.items[e.currentTarget.dataset.id];
|
||||||
item.handler(this.props.topic, this.props.user);
|
item.handler(this.props.topic, this.props.user);
|
||||||
//this.props.onAction(this.props.topic, this.props.items[e.currentTarget.dataset.id]);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
@@ -517,6 +525,10 @@
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="panel-form-column">
|
<div className="panel-form-column">
|
||||||
|
{this.props.userTitle ?
|
||||||
|
<ul className="contact-box"><Contact
|
||||||
|
title={this.props.userTitle}
|
||||||
|
avatar={makeImageUrl(this.props.userAvatar ? this.props.userAvatar : null)} /></ul> : null}
|
||||||
<label className="small">Permissions</label>
|
<label className="small">Permissions</label>
|
||||||
<table className="permission-editor">
|
<table className="permission-editor">
|
||||||
{this.props.compare ?
|
{this.props.compare ?
|
||||||
@@ -1178,13 +1190,15 @@
|
|||||||
handleClick: function(e) {
|
handleClick: function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
this.props.onSelected(this.props.topic, this.props.index);
|
if (this.props.onSelected) {
|
||||||
|
this.props.onSelected(this.props.item, this.props.index);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
handleContextClick: function(e) {
|
handleContextClick: function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
this.props.showContextMenu(this.props.topic, e.pageY, e.pageX);
|
this.props.showContextMenu(this.props.item, e.pageY, e.pageX);
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
@@ -1201,7 +1215,7 @@
|
|||||||
onClick={this.handleClick}>
|
onClick={this.handleClick}>
|
||||||
<div className="avatar-box">
|
<div className="avatar-box">
|
||||||
<LetterTile
|
<LetterTile
|
||||||
avatar={avatar} title={this.props.title} topic={this.props.topic} />
|
avatar={avatar} title={this.props.title} topic={this.props.item} />
|
||||||
|
|
||||||
{this.props.showOnline ? <span className={online} /> :
|
{this.props.showOnline ? <span className={online} /> :
|
||||||
(this.props.showCheckmark && this.props.selected ?
|
(this.props.showCheckmark && this.props.selected ?
|
||||||
@@ -1210,7 +1224,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div className="text-box">
|
<div className="text-box">
|
||||||
<div><span className="contact-title">{title}</span>
|
<div><span className="contact-title">{title}</span>
|
||||||
{this.props.unread > 0 ? <Contact.Unread count={this.props.unread} /> : null}</div>
|
{this.props.showUnread && (this.props.unread > 0) ?
|
||||||
|
<Contact.Unread count={this.props.unread} /> : null}</div>
|
||||||
{this.props.comment ? <div className="contact-comment">{this.props.comment}</div> : null}
|
{this.props.comment ? <div className="contact-comment">{this.props.comment}</div> : null}
|
||||||
</div>
|
</div>
|
||||||
{this.props.showContextMenu ?
|
{this.props.showContextMenu ?
|
||||||
@@ -1320,6 +1335,7 @@
|
|||||||
emptyListMessage={<span>You have no chats<br />¯\_(ツ)_/¯</span>}
|
emptyListMessage={<span>You have no chats<br />¯\_(ツ)_/¯</span>}
|
||||||
topicSelected={this.props.topicSelected}
|
topicSelected={this.props.topicSelected}
|
||||||
showOnline={true}
|
showOnline={true}
|
||||||
|
showUnread={true}
|
||||||
onTopicSelected={this.props.onTopicSelected}
|
onTopicSelected={this.props.onTopicSelected}
|
||||||
showContextMenu={this.props.showContextMenu} />
|
showContextMenu={this.props.showContextMenu} />
|
||||||
);
|
);
|
||||||
@@ -1367,9 +1383,10 @@
|
|||||||
showCheckmark={showCheckmark}
|
showCheckmark={showCheckmark}
|
||||||
selected={selected}
|
selected={selected}
|
||||||
showOnline={this.props.showOnline}
|
showOnline={this.props.showOnline}
|
||||||
|
showUnread={this.props.showUnread}
|
||||||
onSelected={this.props.onTopicSelected}
|
onSelected={this.props.onTopicSelected}
|
||||||
showContextMenu={this.props.showContextMenu}
|
showContextMenu={this.props.showContextMenu}
|
||||||
topic={key}
|
item={key}
|
||||||
index={contactNodes.length}
|
index={contactNodes.length}
|
||||||
key={key} />
|
key={key} />
|
||||||
);
|
);
|
||||||
@@ -1392,7 +1409,7 @@
|
|||||||
});
|
});
|
||||||
/* END ContactList */
|
/* END ContactList */
|
||||||
|
|
||||||
/* BEGIN GroupMembers: controlc for managing a list of group members */
|
/* BEGIN GroupMembers: control for managing a list of group members */
|
||||||
var GroupManager = React.createClass({
|
var GroupManager = React.createClass({
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
@@ -1530,6 +1547,8 @@
|
|||||||
filter={this.state.contactFilter}
|
filter={this.state.contactFilter}
|
||||||
filterFunc={this.doContactFiltering}
|
filterFunc={this.doContactFiltering}
|
||||||
emptyListMessage={this.state.noContactsMessage}
|
emptyListMessage={this.state.noContactsMessage}
|
||||||
|
showOnline={false}
|
||||||
|
showUnread={false}
|
||||||
onTopicSelected={this.handleContactSelected} />
|
onTopicSelected={this.handleContactSelected} />
|
||||||
<div id="group-manager-buttons" className="panel-form-row">
|
<div id="group-manager-buttons" className="panel-form-row">
|
||||||
<button className="blue" onClick={this.handleSubmit}>OK</button>
|
<button className="blue" onClick={this.handleSubmit}>OK</button>
|
||||||
@@ -1597,6 +1616,7 @@
|
|||||||
emptyListMessage="Use search to find contacts"
|
emptyListMessage="Use search to find contacts"
|
||||||
topicSelected={this.state.selectedContact}
|
topicSelected={this.state.selectedContact}
|
||||||
showOnline={false}
|
showOnline={false}
|
||||||
|
showUnread={false}
|
||||||
showContextMenu={false}
|
showContextMenu={false}
|
||||||
onTopicSelected={this.handleContactSelected} />
|
onTopicSelected={this.handleContactSelected} />
|
||||||
</div>}
|
</div>}
|
||||||
@@ -1703,13 +1723,15 @@
|
|||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
owner: false,
|
owner: false,
|
||||||
|
admin: false,
|
||||||
|
sharer: false,
|
||||||
|
muted: false,
|
||||||
address: null,
|
address: null,
|
||||||
groupTopic: undefined,
|
groupTopic: undefined,
|
||||||
fullName: undefined,
|
fullName: undefined,
|
||||||
avatar: null,
|
avatar: null,
|
||||||
private: null,
|
private: null,
|
||||||
selectedContact: null,
|
selectedContact: null,
|
||||||
muted: undefined,
|
|
||||||
access: null,
|
access: null,
|
||||||
modeGiven: null,
|
modeGiven: null,
|
||||||
modeWant: null,
|
modeWant: null,
|
||||||
@@ -1850,13 +1872,19 @@
|
|||||||
case 'given':
|
case 'given':
|
||||||
this.props.onChangePermissions(this.props.topic, perm, this.props.topic);
|
this.props.onChangePermissions(this.props.topic, perm, this.props.topic);
|
||||||
break;
|
break;
|
||||||
|
case 'user':
|
||||||
|
this.props.onChangePermissions(this.props.topic, perm, this.state.userPermissionsEdited);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({showPermissionEditorFor: undefined});
|
this.setState({showPermissionEditorFor: undefined});
|
||||||
},
|
},
|
||||||
|
|
||||||
handleLaunchPermissionsEditor: function(which) {
|
handleLaunchPermissionsEditor: function(which, uid) {
|
||||||
var toEdit, toCompare, toSkip, titleEdit, titleCompare;
|
console.log("handleLaunchPermissionsEditor called with arguments");
|
||||||
|
console.log(arguments);
|
||||||
|
|
||||||
|
var toEdit, toCompare, toSkip, titleEdit, titleCompare, userTitle, userAvatar
|
||||||
switch (which) {
|
switch (which) {
|
||||||
case 'mode':
|
case 'mode':
|
||||||
toEdit = this.state.access;
|
toEdit = this.state.access;
|
||||||
@@ -1883,17 +1911,40 @@
|
|||||||
toEdit = this.state.anon;
|
toEdit = this.state.anon;
|
||||||
toSkip = 'O';
|
toSkip = 'O';
|
||||||
break;
|
break;
|
||||||
|
case 'user': {
|
||||||
|
var topic = Tinode.getTopic(this.props.topic);
|
||||||
|
if (!topic) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var user = topic.subscriber(uid);
|
||||||
|
if (!user || !user.acs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
toEdit = user.acs.getGiven();
|
||||||
|
toCompare = user.acs.getWant();
|
||||||
|
toSkip = this.state.owner ? '' : 'O';
|
||||||
|
titleEdit = 'Granted';
|
||||||
|
titleCompare = 'Requested';
|
||||||
|
if (user.public) {
|
||||||
|
userTitle = user.public.fn;
|
||||||
|
userAvatar = user.public.photo;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
console.log("Unknown permission editing mode '" + which + "'");
|
console.log("Unknown permission editing mode '" + which + "'");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
showPermissionEditorFor: which,
|
showPermissionEditorFor: which,
|
||||||
|
userPermissionsEdited: uid,
|
||||||
|
userPermissionsTitle: userTitle,
|
||||||
|
userPermissionsAvatar: userAvatar,
|
||||||
editedPermissions: toEdit,
|
editedPermissions: toEdit,
|
||||||
immutablePermissions: toCompare,
|
immutablePermissions: toCompare,
|
||||||
editedPermissionsTitle: titleEdit,
|
editedPermissionsTitle: titleEdit,
|
||||||
immutablePermissionsTitle: titleCompare,
|
immutablePermissionsTitle: titleCompare,
|
||||||
editedPermissionsSkipped: toSkip
|
editedPermissionsSkipped: toSkip,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1925,8 +1976,28 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleContextMenu: function(item, x, y) {
|
handleContextMenu: function(item, x, y) {
|
||||||
|
console.log("handleContextMenu called with agruments");
|
||||||
console.log(arguments);
|
console.log(arguments);
|
||||||
this.props.showContextMenu(item, x, y);
|
|
||||||
|
var instance = this;
|
||||||
|
var topic = Tinode.getTopic(this.props.topic);
|
||||||
|
if (!topic) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var user = topic.subscriber(item);
|
||||||
|
if (!user || !user.acs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var menuItems = [
|
||||||
|
{title: "Edit permissions", handler: function() {
|
||||||
|
instance.handleLaunchPermissionsEditor("user", item);
|
||||||
|
}},
|
||||||
|
ContextMenuItems["member_delete"],
|
||||||
|
user.acs.isMuted() ? ContextMenuItems["member_unmute"] : ContextMenuItems["member_mute"],
|
||||||
|
user.acs.isJoiner() ? ContextMenuItems["member_block"] : ContextMenuItems["member_unblock"]
|
||||||
|
];
|
||||||
|
this.props.showContextMenu(this.props.topic, x, y, item, menuItems);
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
@@ -1953,6 +2024,8 @@
|
|||||||
skip={this.state.editedPermissionsSkipped}
|
skip={this.state.editedPermissionsSkipped}
|
||||||
modeTitle={this.state.editedPermissionsTitle}
|
modeTitle={this.state.editedPermissionsTitle}
|
||||||
compareTitle={this.state.immutablePermissionsTitle}
|
compareTitle={this.state.immutablePermissionsTitle}
|
||||||
|
userTitle={this.state.userPermissionsTitle}
|
||||||
|
userAvatar={this.state.userPermissionsAvatar}
|
||||||
skip={this.state.editedPermissionsSkipped}
|
skip={this.state.editedPermissionsSkipped}
|
||||||
onSubmit={this.handlePermissionsChanged}
|
onSubmit={this.handlePermissionsChanged}
|
||||||
onCancel={this.handleHidePermissionsEditor}
|
onCancel={this.handleHidePermissionsEditor}
|
||||||
@@ -2065,9 +2138,10 @@
|
|||||||
emptyListMessage="No members"
|
emptyListMessage="No members"
|
||||||
topicSelected={this.state.selectedContact}
|
topicSelected={this.state.selectedContact}
|
||||||
showOnline={false}
|
showOnline={false}
|
||||||
|
showUnread={false}
|
||||||
noScroll={true}
|
noScroll={true}
|
||||||
onTopicSelected={this.handleMemberSelected}
|
onTopicSelected={this.handleMemberSelected}
|
||||||
showContextMenu={this.handleContextMenu}
|
showContextMenu={this.state.admin ? this.handleContextMenu : false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
@@ -2851,7 +2925,22 @@
|
|||||||
handleDialogCancel: function() {
|
handleDialogCancel: function() {
|
||||||
this.setState({dialogSelected: null});
|
this.setState({dialogSelected: null});
|
||||||
},
|
},
|
||||||
handleShowContextMenu: function(topicName, y, x) {
|
|
||||||
|
handleShowContextMenu: function(topicName, y, x, uid, menuItems) {
|
||||||
|
console.log("handleShowContextMenu called with arguments");
|
||||||
|
console.log(arguments);
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
contextMenuVisible: true,
|
||||||
|
contextMenuClickAt: {x: x, y: y},
|
||||||
|
contextMenuTopic: topicName,
|
||||||
|
contextMenuUser: uid,
|
||||||
|
contextMenuItems: menuItems || this.defaultTopicContextMenu(topicName),
|
||||||
|
contextMenuBounds: ReactDOM.findDOMNode(this).getBoundingClientRect()
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
defaultTopicContextMenu: function(topicName) {
|
||||||
var muted = false, blocked = false, subscribed = false;
|
var muted = false, blocked = false, subscribed = false;
|
||||||
var topic = Tinode.getTopic(topicName);
|
var topic = Tinode.getTopic(topicName);
|
||||||
if (topic) {
|
if (topic) {
|
||||||
@@ -2862,74 +2951,26 @@
|
|||||||
blocked = acs && !acs.isJoiner();
|
blocked = acs && !acs.isJoiner();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.setState({
|
|
||||||
contextMenuVisible: true,
|
return [
|
||||||
contextMenuClickAt: {x: x, y: y},
|
subscribed ? {title: "Info", handler: this.handleShowInfoView} : null,
|
||||||
contextMenuTopic: topicName,
|
subscribed ? ContextMenuItems["messages_clear"] : null,
|
||||||
contextMenuItems: [
|
subscribed ? (muted ? ContextMenuItems["topic_unmute"] : ContextMenuItems["topic_mute"]) : null,
|
||||||
subscribed ? {title: "Info", handler: this.handleShowInfoView} : null,
|
subscribed ? (blocked ? ContextMenuItems["topic_unblock"] : ContextMenuItems["topic_block"]) : null,
|
||||||
subscribed ? ContextMenuItems["messages_clear"] : null,
|
ContextMenuItems["topic_delete"]
|
||||||
subscribed ? (muted ? ContextMenuItems["topic_unmute"] : ContextMenuItems["topic_mute"]) : null,
|
];
|
||||||
subscribed ? (blocked ? ContextMenuItems["topic_unblock"] : ContextMenuItems["topic_block"]) : null,
|
|
||||||
ContextMenuItems["topic_delete"]
|
|
||||||
],
|
|
||||||
contextMenuBounds: ReactDOM.findDOMNode(this).getBoundingClientRect()
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
handleHideContextMenu: function() {
|
handleHideContextMenu: function() {
|
||||||
this.setState({
|
this.setState({
|
||||||
contextMenuVisible: false,
|
contextMenuVisible: false,
|
||||||
contextMenuClickAt: null,
|
contextMenuClickAt: null,
|
||||||
contextMenuTopic: '',
|
contextMenuTopic: null,
|
||||||
|
contextMenuUser: null,
|
||||||
contextMenuBounds: null
|
contextMenuBounds: null
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
// Menu click.
|
|
||||||
handleContextMenuAction: function(topicName, action) {
|
|
||||||
if (!topicName || !action) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var topic = Tinode.getTopic(topicName);
|
|
||||||
if (!topic) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var metaParam = function(want) {
|
|
||||||
var am = topic.getAccessMode();
|
|
||||||
am.updateWant(want);
|
|
||||||
topic.setMeta({sub: {mode: am.getWant()}});
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (action) {
|
|
||||||
case "Info":
|
|
||||||
this.handleShowInfoView();
|
|
||||||
break;
|
|
||||||
case "Clear messages":
|
|
||||||
topic.delMessagesAll(false).then(function(){
|
|
||||||
console.log("refresh message list");
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case "Mute":
|
|
||||||
metaParam('-P');
|
|
||||||
break;
|
|
||||||
case "Unmute":
|
|
||||||
metaParam('+P');
|
|
||||||
break;
|
|
||||||
case "Block":
|
|
||||||
metaParam('-J');
|
|
||||||
break;
|
|
||||||
case "Unblock":
|
|
||||||
metaParam('+J');
|
|
||||||
break;
|
|
||||||
case "Delete":
|
|
||||||
topic.delTopic();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.log("Unknown menu action '" + action + "'");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleShowInfoView: function() {
|
handleShowInfoView: function() {
|
||||||
this.setState({showInfoPanel: true, infoPanelShowMembers: false});
|
this.setState({showInfoPanel: true, infoPanelShowMembers: false});
|
||||||
},
|
},
|
||||||
@@ -2972,6 +3013,7 @@
|
|||||||
clickAt={this.state.contextMenuClickAt}
|
clickAt={this.state.contextMenuClickAt}
|
||||||
visible={this.state.contextMenuVisible}
|
visible={this.state.contextMenuVisible}
|
||||||
topic={this.state.contextMenuTopic}
|
topic={this.state.contextMenuTopic}
|
||||||
|
user={this.state.contextMenuUser}
|
||||||
items={this.state.contextMenuItems}
|
items={this.state.contextMenuItems}
|
||||||
hide={this.handleHideContextMenu}
|
hide={this.handleHideContextMenu}
|
||||||
onAction={this.handleContextMenuAction} />
|
onAction={this.handleContextMenuAction} />
|
||||||
|
|||||||
Reference in New Issue
Block a user