Skip to content

Commit

Permalink
Merge pull request #3684 from sagemathinc/mentions
Browse files Browse the repository at this point in the history
Fix #3678 and memoize user data computation
  • Loading branch information
williamstein committed Mar 13, 2019
2 parents b3f65c6 + a964658 commit 1a1f026
Show file tree
Hide file tree
Showing 8 changed files with 283 additions and 248 deletions.
15 changes: 15 additions & 0 deletions src/smc-webapp/chat/actions.coffee
Expand Up @@ -86,6 +86,7 @@ class ChatActions extends Actions
date : time_stamp
@setState(last_sent: mesg)
@save()
@set_input('')

set_editing: (message, is_editing) =>
if not @syncdb?
Expand Down Expand Up @@ -147,6 +148,20 @@ class ChatActions extends Actions
set_use_saved_position: (use_saved_position) =>
@setState(use_saved_position:use_saved_position)

set_unsent_user_mentions: (user_mentions) =>
@setState(unsent_user_mentions: user_mentions)

submit_user_mentions: (project_id, path) =>
@store.get('unsent_user_mentions').map((mention) =>
webapp_client.mention({
project_id: project_id
path: path
target: mention.get('id')
priority: 2
})
)
@setState(unsent_user_mentions: immutable.List())

save_scroll_state: (position, height, offset) =>
# height == 0 means chat room is not rendered
if height != 0
Expand Down
172 changes: 172 additions & 0 deletions src/smc-webapp/chat/input.tsx
@@ -0,0 +1,172 @@
import * as React from "react";
import memoizeOne from "memoize-one";
import * as immutable from "immutable";
import { MentionsInput, Mention } from "react-mentions";

import { cmp_Date } from "smc-util/misc2";
const { Space } = require("../r_misc");
const { Avatar } = require("../other-users");
const { IS_MOBILE, isMobile } = require("../feature");

const USER_MENTION_MARKUP =
'<span class="user-mention" account-id=__id__ >@__display__</span>';

interface Props {
input: string;
input_ref: any;
input_style?: any; // Used to override defaults
enable_mentions: boolean;
project_users: any;
user_store: any;
font_size: number;
on_paste?: (e) => void;
on_change: (value, mentions) => void;
on_send: (value) => void;
on_clear: () => void;
on_set_to_last_input: () => void;
account_id: string;
}

export class ChatInput extends React.PureComponent<Props> {
static defaultProps = {
enable_mentions: true,
font_size: 14
};

input_style = memoizeOne(font_size => {
return {
height: "100%",

"&multiLine": {
highlighter: {
padding: 5
},

control: {
height: "100%",
backgroundColor: "white",
leftMargin: "2px"
},

input: {
height: "100%",
fontSize: font_size,
border: "1px solid #ccc",
borderRadius: "4px",
boxShadow: "inset 0 1px 1px rgba(0,0,0,.075)",
overflow: "auto",
padding: "5px 10px"
}
},

suggestions: {
list: {
backgroundColor: "white",
border: "1px solid #ccc",
borderRadius: "4px",
fontSize: font_size,
position: "absolute",
bottom: "10px",
overflow: "auto",
maxHeight: "145px",
width: "max-content",
display: "flex",
flexDirection: "column"
},

item: {
padding: "5px 15px 5px 10px",
borderBottom: "1px solid rgba(0,0,0,0.15)",

"&focused": {
backgroundColor: "rgb(66, 139, 202, 0.4)"
}
}
}
};
});

mentions_data = memoizeOne((project_users: immutable.Map<string, any>) => {
const user_array = project_users
.keySeq()
.filter(account_id => {
return account_id !== this.props.account_id;
})
.map(account_id => {
return {
id: account_id,
display: this.props.user_store.get_name(account_id),
last_active: this.props.user_store.get_last_active(account_id)
};
})
.toJS();

user_array.sort((x, y) => -cmp_Date(x.last_active, y.last_active));

return user_array;
});

on_change = (e, _, __, mentions) => {
this.props.on_change(e.target.value, mentions);
};

on_keydown = (e: any) => {
// TODO: Add timeout component to is_typing
if (e.keyCode === 13 && e.shiftKey) {
e.preventDefault();
if (this.props.input.length && this.props.input.trim().length >= 1) {
this.props.on_send(this.props.input);
}
} else if (e.keyCode === 38 && this.props.input === "") {
// Up arrow on an empty input
this.props.on_set_to_last_input();
} else if (e.keyCode === 27) {
// Esc
this.props.on_clear();
}
};

render_user_suggestion = (entry: { id: string; display: string }) => {
return (
<span>
<Avatar size={this.props.font_size + 12} account_id={entry.id} />
<Space />
<Space />
{entry.display}
</span>
);
};

render() {
const user_array = this.mentions_data(this.props.project_users);

const style =
this.props.input_style || this.input_style(this.props.font_size);

return (
<MentionsInput
autoFocus={!IS_MOBILE || isMobile.Android()}
displayTransform={(_, display) => "@" + display}
style={style}
markup={USER_MENTION_MARKUP}
inputRef={this.props.input_ref}
onKeyDown={this.on_keydown}
value={this.props.input}
placeholder={
this.props.enable_mentions
? "Type a message, @name..."
: "Type a message..."
}
onPaste={this.props.on_paste}
onChange={this.on_change}
>
<Mention
trigger="@"
data={user_array}
appendSpaceOnAdd={true}
renderSuggestion={this.render_user_suggestion}
/>
</MentionsInput>
);
}
}
4 changes: 3 additions & 1 deletion src/smc-webapp/chat/store.ts
Expand Up @@ -20,6 +20,7 @@ interface ChatState {
is_saving: boolean;
has_uncommitted_changes: boolean;
has_unsaved_changes: boolean;
unsent_user_mentions: immutable.List<{ id: string; display: string }>;
}

export class ChatStore extends Store<ChatState> {
Expand All @@ -39,7 +40,8 @@ export class ChatStore extends Store<ChatState> {
add_collab: true,
is_saving: false,
has_uncommitted_changes: false,
has_unsaved_changes: false
has_unsaved_changes: false,
unsent_user_mentions: immutable.List()
};
};
}
11 changes: 0 additions & 11 deletions src/smc-webapp/editor_chat.cjsx
Expand Up @@ -183,17 +183,6 @@ exports.get_user_name = get_user_name = (account_id, user_map) ->
account_name = "Unknown"

### ChatRoom Methods ###
exports.send_chat = send_chat = (e, log_container, mesg, actions) ->
scroll_to_bottom(log_container, actions)
e.preventDefault()
# block sending empty messages
if mesg.length? and mesg.trim().length >= 1
actions.send_chat(mesg)
clear_input(actions)

exports.clear_input = clear_input = (actions) ->
actions.set_input('')

exports.is_at_bottom = is_at_bottom = (saved_position, offset, height) ->
# 20 for covering margin of bottom message
saved_position + offset + 20 > height
Expand Down
1 change: 1 addition & 0 deletions src/smc-webapp/package.json
Expand Up @@ -70,6 +70,7 @@
"markdown-it-mathjax": "^2.0.0",
"mathjax": "2.7.4",
"md5": "^2",
"memoize-one": "^5.0.0",
"node-forge": "^0.7.6",
"nodeunit": "^0.11.3",
"octicons": "^3.5.0",
Expand Down

0 comments on commit 1a1f026

Please sign in to comment.