[NEW] Slash commands (#886)
* setup database * added getSlashCommands to loginSucess * added slash command first prototype * added preview feture for commands that have preview enabled * address requested changes * added preview options for other types of files too * address changes * done requested changes * undone un-nessary changes * done suggested changes * fixed lint * done requested changes * fixed lint * fix e2e
This commit is contained in:
parent
d68eb01b82
commit
82afb63327
|
@ -0,0 +1,47 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { TouchableOpacity, ActivityIndicator } from 'react-native';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
|
||||
import styles from './styles';
|
||||
import { CustomIcon } from '../../lib/Icons';
|
||||
import { COLOR_PRIMARY } from '../../constants/colors';
|
||||
|
||||
export default class CommandPreview extends React.PureComponent {
|
||||
static propTypes = {
|
||||
onPress: PropTypes.func,
|
||||
item: PropTypes.object
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { loading: true };
|
||||
}
|
||||
|
||||
render() {
|
||||
const { onPress, item } = this.props;
|
||||
const { loading } = this.state;
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={styles.commandPreview}
|
||||
onPress={() => onPress(item)}
|
||||
testID={`command-preview-item${ item.id }`}
|
||||
>
|
||||
{item.type === 'image'
|
||||
? (
|
||||
<FastImage
|
||||
style={styles.commandPreviewImage}
|
||||
source={{ uri: item.value }}
|
||||
resizeMode={FastImage.resizeMode.cover}
|
||||
onLoadStart={() => this.setState({ loading: true })}
|
||||
onLoad={() => this.setState({ loading: false })}
|
||||
>
|
||||
{ loading ? <ActivityIndicator /> : null }
|
||||
</FastImage>
|
||||
)
|
||||
: <CustomIcon name='file-generic' size={36} color={COLOR_PRIMARY} />
|
||||
}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
View, TextInput, FlatList, Text, TouchableOpacity, Alert
|
||||
View, TextInput, FlatList, Text, TouchableOpacity, Alert, ScrollView
|
||||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { emojify } from 'react-emojione';
|
||||
|
@ -32,9 +32,12 @@ import { COLOR_TEXT_DESCRIPTION } from '../../constants/colors';
|
|||
import LeftButtons from './LeftButtons';
|
||||
import RightButtons from './RightButtons';
|
||||
import { isAndroid } from '../../utils/deviceInfo';
|
||||
import CommandPreview from './CommandPreview';
|
||||
|
||||
const MENTIONS_TRACKING_TYPE_USERS = '@';
|
||||
const MENTIONS_TRACKING_TYPE_EMOJIS = ':';
|
||||
const MENTIONS_TRACKING_TYPE_COMMANDS = '/';
|
||||
const MENTIONS_COUNT_TO_DISPLAY = 4;
|
||||
|
||||
const onlyUnique = function onlyUnique(value, index, self) {
|
||||
return self.indexOf(({ _id }) => value._id === _id) === index;
|
||||
|
@ -93,8 +96,11 @@ class MessageBox extends Component {
|
|||
trackingType: '',
|
||||
file: {
|
||||
isVisible: false
|
||||
}
|
||||
},
|
||||
commandPreview: []
|
||||
};
|
||||
this.showCommandPreview = false;
|
||||
this.commands = [];
|
||||
this.users = [];
|
||||
this.rooms = [];
|
||||
this.emojis = [];
|
||||
|
@ -147,7 +153,7 @@ class MessageBox extends Component {
|
|||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
const {
|
||||
showEmojiKeyboard, showSend, recording, mentions, file
|
||||
showEmojiKeyboard, showSend, recording, mentions, file, commandPreview
|
||||
} = this.state;
|
||||
const {
|
||||
roomType, replying, editing, isFocused
|
||||
|
@ -176,6 +182,9 @@ class MessageBox extends Component {
|
|||
if (!equal(nextState.mentions, mentions)) {
|
||||
return true;
|
||||
}
|
||||
if (!equal(nextState.commandPreview, commandPreview)) {
|
||||
return true;
|
||||
}
|
||||
if (!equal(nextState.file, file)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -187,20 +196,36 @@ class MessageBox extends Component {
|
|||
this.setShowSend(!isTextEmpty);
|
||||
this.handleTyping(!isTextEmpty);
|
||||
this.setInput(text);
|
||||
// matches if their is text that stats with '/' and group the command and params so we can use it "/command params"
|
||||
const slashCommand = text.match(/^\/([a-z0-9._-]+) (.+)/im);
|
||||
if (slashCommand) {
|
||||
const [, name, params] = slashCommand;
|
||||
const command = database.objects('slashCommand').filtered('command == $0', name);
|
||||
if (command && command[0] && command[0].providesPreview) {
|
||||
return this.setCommandPreview(name, params);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isTextEmpty) {
|
||||
const { start, end } = this.component._lastNativeSelection;
|
||||
const cursor = Math.max(start, end);
|
||||
const lastNativeText = this.component._lastNativeText;
|
||||
const regexp = /(#|@|:)([a-z0-9._-]+)$/im;
|
||||
// matches if text either starts with '/' or have (@,#,:) then it groups whatever comes next of mention type
|
||||
const regexp = /(#|@|:|^\/)([a-z0-9._-]+)$/im;
|
||||
const result = lastNativeText.substr(0, cursor).match(regexp);
|
||||
this.showCommandPreview = false;
|
||||
if (!result) {
|
||||
const slash = lastNativeText.match(/^\/$/); // matches only '/' in input
|
||||
if (slash) {
|
||||
return this.identifyMentionKeyword('', MENTIONS_TRACKING_TYPE_COMMANDS);
|
||||
}
|
||||
return this.stopTrackingMention();
|
||||
}
|
||||
const [, lastChar, name] = result;
|
||||
this.identifyMentionKeyword(name, lastChar);
|
||||
} else {
|
||||
this.stopTrackingMention();
|
||||
this.showCommandPreview = false;
|
||||
}
|
||||
}, 100)
|
||||
|
||||
|
@ -220,13 +245,32 @@ class MessageBox extends Component {
|
|||
const result = msg.substr(0, cursor).replace(regexp, '');
|
||||
const mentionName = trackingType === MENTIONS_TRACKING_TYPE_EMOJIS
|
||||
? `${ item.name || item }:`
|
||||
: (item.username || item.name);
|
||||
: (item.username || item.name || item.command);
|
||||
const text = `${ result }${ mentionName } ${ msg.slice(cursor) }`;
|
||||
if ((trackingType === MENTIONS_TRACKING_TYPE_COMMANDS) && item.providesPreview) {
|
||||
this.showCommandPreview = true;
|
||||
}
|
||||
this.setInput(text);
|
||||
this.focus();
|
||||
requestAnimationFrame(() => this.stopTrackingMention());
|
||||
}
|
||||
|
||||
onPressCommandPreview = (item) => {
|
||||
const { rid } = this.props;
|
||||
const { text } = this;
|
||||
const command = text.substr(0, text.indexOf(' ')).slice(1);
|
||||
const params = text.substr(text.indexOf(' ') + 1) || 'params';
|
||||
this.showCommandPreview = false;
|
||||
this.setState({ commandPreview: [] });
|
||||
this.stopTrackingMention();
|
||||
this.clearInput();
|
||||
try {
|
||||
RocketChat.executeCommandPreview(command, params, rid, item);
|
||||
} catch (e) {
|
||||
log('onPressCommandPreview', e);
|
||||
}
|
||||
}
|
||||
|
||||
onEmojiSelected = (keyboardId, params) => {
|
||||
const { text } = this;
|
||||
const { emoji } = params;
|
||||
|
@ -301,7 +345,7 @@ class MessageBox extends Component {
|
|||
console.warn('spotlight canceled');
|
||||
} finally {
|
||||
delete this.oldPromise;
|
||||
this.users = database.objects('users').filtered('username CONTAINS[c] $0', keyword).slice();
|
||||
this.users = database.objects('users').filtered('username CONTAINS[c] $0', keyword).slice(0, MENTIONS_COUNT_TO_DISPLAY);
|
||||
this.getFixedMentions(keyword);
|
||||
this.setState({ mentions: this.users });
|
||||
}
|
||||
|
@ -351,13 +395,18 @@ class MessageBox extends Component {
|
|||
|
||||
getEmojis = (keyword) => {
|
||||
if (keyword) {
|
||||
this.customEmojis = database.objects('customEmojis').filtered('name CONTAINS[c] $0', keyword).slice(0, 4);
|
||||
this.emojis = emojis.filter(emoji => emoji.indexOf(keyword) !== -1).slice(0, 4);
|
||||
const mergedEmojis = [...this.customEmojis, ...this.emojis];
|
||||
this.customEmojis = database.objects('customEmojis').filtered('name CONTAINS[c] $0', keyword).slice(0, MENTIONS_COUNT_TO_DISPLAY);
|
||||
this.emojis = emojis.filter(emoji => emoji.indexOf(keyword) !== -1).slice(0, MENTIONS_COUNT_TO_DISPLAY);
|
||||
const mergedEmojis = [...this.customEmojis, ...this.emojis].slice(0, MENTIONS_COUNT_TO_DISPLAY);
|
||||
this.setState({ mentions: mergedEmojis });
|
||||
}
|
||||
}
|
||||
|
||||
getSlashCommands = (keyword) => {
|
||||
this.commands = database.objects('slashCommand').filtered('command CONTAINS[c] $0', keyword);
|
||||
this.setState({ mentions: this.commands });
|
||||
}
|
||||
|
||||
focus = () => {
|
||||
if (this.component && this.component.focus) {
|
||||
this.component.focus();
|
||||
|
@ -385,6 +434,18 @@ class MessageBox extends Component {
|
|||
}, 1000);
|
||||
}
|
||||
|
||||
setCommandPreview = async(command, params) => {
|
||||
const { rid } = this.props;
|
||||
try {
|
||||
const { preview } = await RocketChat.getCommandPreview(command, rid, params);
|
||||
this.showCommandPreview = true;
|
||||
this.setState({ commandPreview: preview.items });
|
||||
} catch (e) {
|
||||
this.showCommandPreview = false;
|
||||
log('command Preview', e);
|
||||
}
|
||||
}
|
||||
|
||||
setInput = (text) => {
|
||||
this.text = text;
|
||||
if (this.component && this.component.setNativeProps) {
|
||||
|
@ -505,7 +566,7 @@ class MessageBox extends Component {
|
|||
|
||||
submit = async() => {
|
||||
const {
|
||||
message: editingMessage, editRequest, onSubmit
|
||||
message: editingMessage, editRequest, onSubmit, rid: roomId
|
||||
} = this.props;
|
||||
const message = this.text;
|
||||
|
||||
|
@ -521,6 +582,22 @@ class MessageBox extends Component {
|
|||
editing, replying
|
||||
} = this.props;
|
||||
|
||||
// Slash command
|
||||
|
||||
if (message[0] === MENTIONS_TRACKING_TYPE_COMMANDS) {
|
||||
const command = message.replace(/ .*/, '').slice(1);
|
||||
const slashCommand = database.objects('slashCommand').filtered('command CONTAINS[c] $0', command);
|
||||
if (slashCommand.length > 0) {
|
||||
try {
|
||||
const messageWithoutCommand = message.substr(message.indexOf(' ') + 1);
|
||||
RocketChat.runSlashCommand(command, roomId, messageWithoutCommand);
|
||||
} catch (e) {
|
||||
log('slashCommand', e);
|
||||
}
|
||||
this.clearInput();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Edit
|
||||
if (editing) {
|
||||
const { _id, rid } = editingMessage;
|
||||
|
@ -561,6 +638,8 @@ class MessageBox extends Component {
|
|||
this.getUsers(keyword);
|
||||
} else if (type === MENTIONS_TRACKING_TYPE_EMOJIS) {
|
||||
this.getEmojis(keyword);
|
||||
} else if (type === MENTIONS_TRACKING_TYPE_COMMANDS) {
|
||||
this.getSlashCommands(keyword);
|
||||
} else {
|
||||
this.getRooms(keyword);
|
||||
}
|
||||
|
@ -579,15 +658,16 @@ class MessageBox extends Component {
|
|||
if (!trackingType) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
mentions: [],
|
||||
trackingType: ''
|
||||
trackingType: '',
|
||||
commandPreview: []
|
||||
});
|
||||
this.users = [];
|
||||
this.rooms = [];
|
||||
this.customEmojis = [];
|
||||
this.emojis = [];
|
||||
this.commands = [];
|
||||
}
|
||||
|
||||
renderFixedMentionItem = item => (
|
||||
|
@ -623,41 +703,67 @@ class MessageBox extends Component {
|
|||
);
|
||||
}
|
||||
|
||||
renderMentionItem = (item) => {
|
||||
renderMentionItem = ({ item }) => {
|
||||
const { trackingType } = this.state;
|
||||
const { baseUrl, user } = this.props;
|
||||
|
||||
if (item.username === 'all' || item.username === 'here') {
|
||||
return this.renderFixedMentionItem(item);
|
||||
}
|
||||
const defineTestID = (type) => {
|
||||
switch (type) {
|
||||
case MENTIONS_TRACKING_TYPE_EMOJIS:
|
||||
return `mention-item-${ item.name || item }`;
|
||||
case MENTIONS_TRACKING_TYPE_COMMANDS:
|
||||
return `mention-item-${ item.command || item }`;
|
||||
default:
|
||||
return `mention-item-${ item.username || item.name || item }`;
|
||||
}
|
||||
};
|
||||
|
||||
const testID = defineTestID(trackingType);
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={styles.mentionItem}
|
||||
onPress={() => this.onPressMention(item)}
|
||||
testID={`mention-item-${ trackingType === MENTIONS_TRACKING_TYPE_EMOJIS ? item.name || item : item.username || item.name }`}
|
||||
testID={testID}
|
||||
>
|
||||
{trackingType === MENTIONS_TRACKING_TYPE_EMOJIS
|
||||
? (
|
||||
<React.Fragment>
|
||||
{this.renderMentionEmoji(item)}
|
||||
<Text key='mention-item-name' style={styles.mentionText}>:{ item.name || item }:</Text>
|
||||
</React.Fragment>
|
||||
)
|
||||
: (
|
||||
<React.Fragment>
|
||||
<Avatar
|
||||
key='mention-item-avatar'
|
||||
style={{ margin: 8 }}
|
||||
text={item.username || item.name}
|
||||
size={30}
|
||||
type={item.username ? 'd' : 'c'}
|
||||
baseUrl={baseUrl}
|
||||
userId={user.id}
|
||||
token={user.token}
|
||||
/>
|
||||
<Text key='mention-item-name' style={styles.mentionText}>{ item.username || item.name }</Text>
|
||||
</React.Fragment>
|
||||
)
|
||||
|
||||
{(() => {
|
||||
switch (trackingType) {
|
||||
case MENTIONS_TRACKING_TYPE_EMOJIS:
|
||||
return (
|
||||
<React.Fragment>
|
||||
{this.renderMentionEmoji(item)}
|
||||
<Text key='mention-item-name' style={styles.mentionText}>:{ item.name || item }:</Text>
|
||||
</React.Fragment>
|
||||
);
|
||||
case MENTIONS_TRACKING_TYPE_COMMANDS:
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Text key='mention-item-command' style={styles.slash}>/</Text>
|
||||
<Text key='mention-item-param'>{ item.command}</Text>
|
||||
</React.Fragment>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Avatar
|
||||
key='mention-item-avatar'
|
||||
style={styles.avatar}
|
||||
text={item.username || item.name}
|
||||
size={30}
|
||||
type={item.username ? 'd' : 'c'}
|
||||
baseUrl={baseUrl}
|
||||
userId={user.id}
|
||||
token={user.token}
|
||||
/>
|
||||
<Text key='mention-item-name' style={styles.mentionText}>{ item.username || item.name || item }</Text>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
})()
|
||||
}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
|
@ -669,17 +775,45 @@ class MessageBox extends Component {
|
|||
return null;
|
||||
}
|
||||
return (
|
||||
<View testID='messagebox-container'>
|
||||
<ScrollView
|
||||
testID='messagebox-container'
|
||||
style={styles.scrollViewMention}
|
||||
keyboardShouldPersistTaps='always'
|
||||
>
|
||||
<FlatList
|
||||
style={styles.mentionList}
|
||||
data={mentions}
|
||||
renderItem={({ item }) => this.renderMentionItem(item)}
|
||||
keyExtractor={item => item._id || item.username || item}
|
||||
renderItem={this.renderMentionItem}
|
||||
keyExtractor={item => item._id || item.username || item.command || item}
|
||||
keyboardShouldPersistTaps='always'
|
||||
/>
|
||||
</ScrollView>
|
||||
);
|
||||
};
|
||||
|
||||
renderCommandPreviewItem = ({ item }) => (
|
||||
<CommandPreview item={item} onPress={this.onPressCommandPreview} />
|
||||
);
|
||||
|
||||
renderCommandPreview = () => {
|
||||
const { commandPreview } = this.state;
|
||||
if (!this.showCommandPreview) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<View key='commandbox-container' testID='commandbox-container'>
|
||||
<FlatList
|
||||
style={styles.mentionList}
|
||||
data={commandPreview}
|
||||
renderItem={this.renderCommandPreviewItem}
|
||||
keyExtractor={item => item.id}
|
||||
keyboardShouldPersistTaps='always'
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
renderReplyPreview = () => {
|
||||
const {
|
||||
|
@ -700,6 +834,7 @@ class MessageBox extends Component {
|
|||
}
|
||||
return (
|
||||
<React.Fragment>
|
||||
{this.renderCommandPreview()}
|
||||
{this.renderMentions()}
|
||||
<View style={styles.composer} key='messagebox'>
|
||||
{this.renderReplyPreview()}
|
||||
|
|
|
@ -3,10 +3,11 @@ import { StyleSheet } from 'react-native';
|
|||
import { isIOS } from '../../utils/deviceInfo';
|
||||
import sharedStyles from '../../views/Styles';
|
||||
import {
|
||||
COLOR_BORDER, COLOR_SEPARATOR, COLOR_BACKGROUND_CONTAINER, COLOR_WHITE
|
||||
COLOR_BORDER, COLOR_SEPARATOR, COLOR_BACKGROUND_CONTAINER, COLOR_WHITE, COLOR_PRIMARY
|
||||
} from '../../constants/colors';
|
||||
|
||||
const MENTION_HEIGHT = 50;
|
||||
const SCROLLVIEW_MENTION_HEIGHT = 4 * MENTION_HEIGHT;
|
||||
|
||||
export default StyleSheet.create({
|
||||
textBox: {
|
||||
|
@ -100,5 +101,35 @@ export default StyleSheet.create({
|
|||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0
|
||||
},
|
||||
slash: {
|
||||
color: COLOR_PRIMARY,
|
||||
backgroundColor: COLOR_BORDER,
|
||||
height: 30,
|
||||
width: 30,
|
||||
padding: 5,
|
||||
paddingHorizontal: 12,
|
||||
marginHorizontal: 10,
|
||||
borderRadius: 2
|
||||
},
|
||||
commandPreviewImage: {
|
||||
justifyContent: 'center',
|
||||
margin: 3,
|
||||
width: 120,
|
||||
height: 80,
|
||||
borderRadius: 4
|
||||
},
|
||||
commandPreview: {
|
||||
backgroundColor: COLOR_BACKGROUND_CONTAINER,
|
||||
height: 100,
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center'
|
||||
},
|
||||
avatar: {
|
||||
margin: 8
|
||||
},
|
||||
scrollViewMention: {
|
||||
maxHeight: SCROLLVIEW_MENTION_HEIGHT
|
||||
}
|
||||
});
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
import { InteractionManager } from 'react-native';
|
||||
|
||||
import database from '../realm';
|
||||
import log from '../../utils/log';
|
||||
|
||||
export default async function() {
|
||||
try {
|
||||
// RC 0.60.2
|
||||
const result = await this.sdk.get('commands.list');
|
||||
|
||||
if (!result.success) {
|
||||
return log('getSlashCommand fetch', result);
|
||||
}
|
||||
|
||||
const { commands } = result;
|
||||
|
||||
if (commands && commands.length) {
|
||||
InteractionManager.runAfterInteractions(() => {
|
||||
database.write(() => commands.forEach((command) => {
|
||||
try {
|
||||
database.create('slashCommand', command, true);
|
||||
} catch (e) {
|
||||
log('get_slash_command', e);
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
log('err_get_slash_command', e);
|
||||
}
|
||||
}
|
|
@ -273,6 +273,18 @@ const frequentlyUsedEmojiSchema = {
|
|||
}
|
||||
};
|
||||
|
||||
const slashCommandSchema = {
|
||||
name: 'slashCommand',
|
||||
primaryKey: 'command',
|
||||
properties: {
|
||||
command: 'string',
|
||||
params: { type: 'string', optional: true },
|
||||
description: { type: 'string', optional: true },
|
||||
clientOnly: { type: 'bool', optional: true },
|
||||
providesPreview: { type: 'bool', optional: true }
|
||||
}
|
||||
};
|
||||
|
||||
const customEmojisSchema = {
|
||||
name: 'customEmojis',
|
||||
primaryKey: '_id',
|
||||
|
@ -347,7 +359,8 @@ const schema = [
|
|||
customEmojisSchema,
|
||||
messagesReactionsSchema,
|
||||
rolesSchema,
|
||||
uploadsSchema
|
||||
uploadsSchema,
|
||||
slashCommandSchema
|
||||
];
|
||||
|
||||
const inMemorySchema = [usersTypingSchema, activeUsersSchema];
|
||||
|
|
|
@ -25,6 +25,7 @@ import getSettings from './methods/getSettings';
|
|||
import getRooms from './methods/getRooms';
|
||||
import getPermissions from './methods/getPermissions';
|
||||
import getCustomEmoji from './methods/getCustomEmojis';
|
||||
import getSlashCommands from './methods/getSlashCommands';
|
||||
import getRoles from './methods/getRoles';
|
||||
import canOpenRoom from './methods/canOpenRoom';
|
||||
|
||||
|
@ -153,6 +154,7 @@ const RocketChat = {
|
|||
this.getPermissions();
|
||||
this.getCustomEmoji();
|
||||
this.getRoles();
|
||||
this.getSlashCommands();
|
||||
this.registerPushToken().catch(e => console.log(e));
|
||||
this.getUserPresence();
|
||||
},
|
||||
|
@ -467,6 +469,7 @@ const RocketChat = {
|
|||
getSettings,
|
||||
getPermissions,
|
||||
getCustomEmoji,
|
||||
getSlashCommands,
|
||||
getRoles,
|
||||
parseSettings: settings => settings.reduce((ret, item) => {
|
||||
ret[item._id] = item[defaultSettings[item._id].type];
|
||||
|
@ -803,6 +806,24 @@ const RocketChat = {
|
|||
rid, updatedSince
|
||||
});
|
||||
},
|
||||
runSlashCommand(command, roomId, params) {
|
||||
// RC 0.60.2
|
||||
return this.sdk.post('commands.run', {
|
||||
command, roomId, params
|
||||
});
|
||||
},
|
||||
getCommandPreview(command, roomId, params) {
|
||||
// RC 0.65.0
|
||||
return this.sdk.get('commands.preview', {
|
||||
command, roomId, params
|
||||
});
|
||||
},
|
||||
executeCommandPreview(command, params, roomId, previewItem) {
|
||||
// RC 0.65.0
|
||||
return this.sdk.post('commands.preview', {
|
||||
command, params, roomId, previewItem
|
||||
});
|
||||
},
|
||||
async getUserPresence() {
|
||||
const serverVersion = reduxStore.getState().server.version;
|
||||
|
||||
|
|
|
@ -158,6 +158,31 @@ describe('Room screen', () => {
|
|||
await expect(element(by.id('messagebox-input'))).toHaveText('#general ');
|
||||
await element(by.id('messagebox-input')).clearText();
|
||||
});
|
||||
|
||||
it('should show and tap on slash command autocomplete and send slash command', async() => {
|
||||
await element(by.id('messagebox-input')).tap();
|
||||
await element(by.id('messagebox-input')).typeText('/');
|
||||
await waitFor(element(by.id('messagebox-container'))).toBeVisible().withTimeout(10000);
|
||||
await expect(element(by.id('messagebox-container'))).toBeVisible();
|
||||
await element(by.id('mention-item-shrug')).tap();
|
||||
await expect(element(by.id('messagebox-input'))).toHaveText('/shrug ');
|
||||
await element(by.id('messagebox-input')).typeText('joy'); // workaround for number keyboard
|
||||
await element(by.id('messagebox-send-message')).tap();
|
||||
await waitFor(element(by.text(`joy ¯\_(ツ)_/¯`))).toBeVisible().withTimeout(60000);
|
||||
});
|
||||
|
||||
it('should show command Preview', async() => {
|
||||
await element(by.id('messagebox-input')).tap();
|
||||
await element(by.id('messagebox-input')).replaceText('/giphy');
|
||||
await waitFor(element(by.id('messagebox-container'))).toBeVisible().withTimeout(10000);
|
||||
await expect(element(by.id('messagebox-container'))).toBeVisible();
|
||||
await element(by.id('mention-item-giphy')).tap();
|
||||
await expect(element(by.id('messagebox-input'))).toHaveText('/giphy ');
|
||||
await element(by.id('messagebox-input')).typeText('no'); // workaround for number keyboard
|
||||
await waitFor(element(by.id('commandbox-container'))).toBeVisible().withTimeout(10000);
|
||||
await expect(element(by.id('commandbox-container'))).toBeVisible();
|
||||
await element(by.id('messagebox-input')).clearText();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Message', async() => {
|
||||
|
@ -360,4 +385,4 @@ describe('Room screen', () => {
|
|||
await expect(element(by.id('rooms-list-view'))).toBeVisible();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue