Skip to content
Permalink
Browse files

wip

<!!> Todo:
- remove dumb reliance on jquery for messaging composite components
  and add composite component once in DOM
  => huge performance issue atm

--- WIP (13) ---

Todo:
- make (wip) versions of thread windows

==== OLD LOGS ====

--- WIP (12) ---

Todo:
- restore disabled feature(s) from this PR: #29974

--- WIP (11) ---

In progress:
- component-based architecture for messaging apps

Todo:
- be able to freeze re-ordering of ordered list
composite component, such as when renaming a conversation.

--- WIP (10) ---

Todo:
- discuss content redesign
	- messages (squashed/unsquashed versions) + date separator
	- load more messages on scroll
- discuss control panel redesign
- others:
   1. mass-mailing icon in the sidebar
   2. livechat in sidebar (to be done with readapt of messaging_manager_livechat)
   3. im_support channel in sidebar (to be done with readapt of messaging_manager_support)
   4. snailmail message (to be done with readapt of messaging_manager_snailmail)

Known issues:
- Some UI caused by brute-force re-rendering:
	1. input re-rendered (hack helps keep text + selection, but it cancels composition mode...)
	2. click on '+' of channel then '+' of dm_chat does not work due to re-render when blur on add channel input
	   (this is also the case with commands next to message)
	3. each re-render autoscroll on top
	4. Does not support CSS animations/transitions
  > Note that all the issues above could be solved with smart rendering

Done:
- rendering of mailboxes, channels, dm_chats in sidebar
- dm_chat and channel counters (unread & needaction) and commands (settings & leave)
- add channel/dm_chat/rename conversation inputs with save state on re-rendering
- basic

--- WIP (9) ---

Todo:
- continue rendering of discuss sidebar
- restore all features of discuss (temporarily all removed)

Known issues:
- broken messaging menu item style
- broken chat window interactions (e.g. fold/close/server-sync)

--- WIP (8) ---

- <!!!> [TEMP] iap temporarily disabled auto-install

We should adapt snailmail to mail refactoring before re-enabling it.

--- WIP (7) ---

wip several improvements, should look at init/start model of component/sub-components...

--- WIP (6) ---

TODO:

- since thread.xml now uses `widget.` most of the time,
thread window and other parts are broken because they rely
on old template args (e.g. `thread`, `messages`, etc.)

- flatten thread windows, removed abstract widget
- thread window cleaning
- <!!!!!> removed scrolltop feature in discuss
- thread renderer cleaning

--- WIP (5) ---

todo:
 - fold state not updated on thread window
 (different thread object stored by thread window)
 => should use new thread object from updated messaging store

known issue:
 - discuss rendering is slow due to lots of update & render from messaging changes
 => future improvement with smart rendering relying on diff

--- WIP (4) ---

discuss refactoring

<!!!!!!> temporarily removed features:
	- disabled style of control panel buttons

--- WIP (3) ---

1. new messaging menu (incomplete)

- only multi-user-channel and dms are supported
- previews are not sorted correctly
- click on preview is not working
- click on mark as read preview is not working

2. reintroduced messaging models
- albeit simple objects

--- WIP (2) ---

done:
- reworked messaging `isReady`
- remove message from thread(s) handled by messaging manager
- threads and messages are stored in dictionnary with key as their ids
- messaging store in messaging service
- no longer multi_user_channel, dm_chat, mailbox, livechat, support_channel classes
- <!!!!!> [TEMP] removed fadeout effect of removed messages in discuss
- removed message classes
- messaging mixin

wip:
- manager makes immutable changes to the msg store
- make messaging-dependent component passive components (always render on any changes)

todo:
- isolate messaging window manager

--- WIP (1) ---

- clean bundles
- organize discuss structurally
- rename mail_service to messaging_service
- rename mail bus to messaging bus
- flatten thread models + remove abstract ones
- rename thread_widget to thread_renderer
- clean thread & message models
	- improve thread model instantiation parameters
	- thread name as public attribute
	- isFolded as public attribute
	- simplify autowitch logic
	- isDetached as public attribute
	- renamed detached to minimized js side
		- matches server-side definition of thread with open chat window
	- simplify fold state
	- isTwoUserThread as public attribute
- new messaging service includes: Thread, ThreadMessages and ThreadUnread
	- moved some model logic to messaging service (e.g. fetch, post messages)
- global messaging store, available to all messaging components
- rename MessagingService to MessagingManager
- [TEMP] command/event architecture with messaging_service
- [WIP] turn command/event with do_action/notify_changes and on_action/on_changes
- split systray xml
- unsubscribe handled by manager
- mark as read handled by manager
- toggle star status handled by manager
- compact some messaging manager LOCs for readability
- remove thread mixins
	- channel seen mixin
	- thread typing mixin
	- adapt tests with members already fetched
	- simplify members format (including seen and typing features)
  • Loading branch information...
alexkuhn committed Feb 12, 2019
1 parent 7282a35 commit 6a8cfd8c5fd95937b65391eee5f92869b7bf4128
Showing with 9,262 additions and 0 deletions.
  1. +2 −0 addons/mail/__manifest__.py
  2. +1 −0 addons/mail/static/src/js/discuss.js
  3. +45 −0 addons/mail/static/src/js/wip/discuss/content/composer/discuss_content_composer.js
  4. +32 −0 addons/mail/static/src/js/wip/discuss/content/composer/discuss_content_composer_commands.js
  5. +71 −0 addons/mail/static/src/js/wip/discuss/content/composer/discuss_content_composer_commands_emojis.js
  6. +36 −0 ...c/src/js/wip/discuss/content/composer/discuss_content_composer_commands_emojis_popover_content.js
  7. +48 −0 addons/mail/static/src/js/wip/discuss/content/composer/discuss_content_composer_input.js
  8. +23 −0 addons/mail/static/src/js/wip/discuss/content/discuss_content.js
  9. +44 −0 addons/mail/static/src/js/wip/discuss/content/thread_view/discuss_content_thread_view.js
  10. +74 −0 addons/mail/static/src/js/wip/discuss/content/thread_view/discuss_content_thread_view_message.js
  11. +85 −0 addons/mail/static/src/js/wip/discuss/discuss.js
  12. +82 −0 addons/mail/static/src/js/wip/discuss/discuss_root.js
  13. +43 −0 addons/mail/static/src/js/wip/discuss/sidebar/channel/discuss_sidebar_channel.js
  14. +94 −0 addons/mail/static/src/js/wip/discuss/sidebar/channel/discuss_sidebar_channel_add_item.js
  15. +34 −0 addons/mail/static/src/js/wip/discuss/sidebar/channel/discuss_sidebar_channel_header.js
  16. +45 −0 addons/mail/static/src/js/wip/discuss/sidebar/channel/discuss_sidebar_channel_item.js
  17. +68 −0 addons/mail/static/src/js/wip/discuss/sidebar/channel/discuss_sidebar_channel_item_commands.js
  18. +14 −0 addons/mail/static/src/js/wip/discuss/sidebar/channel/discuss_sidebar_channel_item_type.js
  19. +34 −0 addons/mail/static/src/js/wip/discuss/sidebar/channel/discuss_sidebar_channel_list.js
  20. +24 −0 addons/mail/static/src/js/wip/discuss/sidebar/discuss_sidebar.js
  21. +43 −0 addons/mail/static/src/js/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat.js
  22. +64 −0 addons/mail/static/src/js/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat_add_item.js
  23. +23 −0 addons/mail/static/src/js/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat_header.js
  24. +75 −0 addons/mail/static/src/js/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat_item.js
  25. +34 −0 addons/mail/static/src/js/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat_item_commands.js
  26. +62 −0 addons/mail/static/src/js/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat_item_editable_name.js
  27. +28 −0 addons/mail/static/src/js/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat_item_status.js
  28. +34 −0 addons/mail/static/src/js/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat_list.js
  29. +43 −0 addons/mail/static/src/js/wip/discuss/sidebar/mailbox/discuss_sidebar_mailbox.js
  30. +42 −0 addons/mail/static/src/js/wip/discuss/sidebar/mailbox/discuss_sidebar_mailbox_item.js
  31. +18 −0 addons/mail/static/src/js/wip/discuss/sidebar/mailbox/discuss_sidebar_mailbox_item_type.js
  32. +1,680 −0 addons/mail/static/src/js/wip/lib/core.js
  33. +20 −0 addons/mail/static/src/js/wip/messaging_mixin.js
  34. +82 −0 addons/mail/static/src/js/wip/models/dm_chat.js
  35. +48 −0 addons/mail/static/src/js/wip/models/document_thread.js
  36. +68 −0 addons/mail/static/src/js/wip/models/mail_failure.js
  37. +73 −0 addons/mail/static/src/js/wip/models/mailbox.js
  38. +254 −0 addons/mail/static/src/js/wip/models/message.js
  39. +94 −0 addons/mail/static/src/js/wip/models/multi_user_channel.js
  40. +181 −0 addons/mail/static/src/js/wip/models/utils/cc_throttle_function.js
  41. +69 −0 addons/mail/static/src/js/wip/models/utils/timer.js
  42. +82 −0 addons/mail/static/src/js/wip/models/utils/timers.js
  43. +720 −0 addons/mail/static/src/js/wip/services/chat_window_manager.js
  44. +42 −0 addons/mail/static/src/js/wip/services/chat_window_service.js
  45. +50 −0 addons/mail/static/src/js/wip/services/messaging_service.js
  46. +3,254 −0 addons/mail/static/src/js/wip/services/messaging_store.js
  47. +113 −0 addons/mail/static/src/js/wip/test_app/test_app.js
  48. +11 −0 addons/mail/static/src/js/wip/test_app/test_app_root.js
  49. +37 −0 addons/mail/static/src/scss/wip/discuss/content/composer/discuss_content_composer.scss
  50. +39 −0 addons/mail/static/src/scss/wip/discuss/content/composer/discuss_content_composer_commands.scss
  51. +23 −0 ...c/scss/wip/discuss/content/composer/discuss_content_composer_commands_emojis_popover_content.scss
  52. +18 −0 addons/mail/static/src/scss/wip/discuss/content/composer/discuss_content_composer_input.scss
  53. +16 −0 addons/mail/static/src/scss/wip/discuss/content/discuss_content.scss
  54. +33 −0 addons/mail/static/src/scss/wip/discuss/content/thread_view/discuss_content_thread_view.scss
  55. +106 −0 addons/mail/static/src/scss/wip/discuss/content/thread_view/discuss_content_thread_view_message.scss
  56. +27 −0 addons/mail/static/src/scss/wip/discuss/discuss.scss
  57. +12 −0 addons/mail/static/src/scss/wip/discuss/discuss_root.scss
  58. +13 −0 addons/mail/static/src/scss/wip/discuss/sidebar/channel/discuss_sidebar_channel.scss
  59. +18 −0 addons/mail/static/src/scss/wip/discuss/sidebar/channel/discuss_sidebar_channel_add_item.scss
  60. +44 −0 addons/mail/static/src/scss/wip/discuss/sidebar/channel/discuss_sidebar_channel_header.scss
  61. +66 −0 addons/mail/static/src/scss/wip/discuss/sidebar/channel/discuss_sidebar_channel_item.scss
  62. +31 −0 addons/mail/static/src/scss/wip/discuss/sidebar/channel/discuss_sidebar_channel_item_commands.scss
  63. +17 −0 addons/mail/static/src/scss/wip/discuss/sidebar/channel/discuss_sidebar_channel_item_type.scss
  64. +12 −0 addons/mail/static/src/scss/wip/discuss/sidebar/channel/discuss_sidebar_channel_list.scss
  65. +33 −0 addons/mail/static/src/scss/wip/discuss/sidebar/discuss_sidebar.scss
  66. +13 −0 addons/mail/static/src/scss/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat.scss
  67. +18 −0 addons/mail/static/src/scss/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat_add_item.scss
  68. +39 −0 addons/mail/static/src/scss/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat_header.scss
  69. +64 −0 addons/mail/static/src/scss/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat_item.scss
  70. +30 −0 addons/mail/static/src/scss/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat_item_commands.scss
  71. +17 −0 .../mail/static/src/scss/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat_item_editable_name.scss
  72. +77 −0 addons/mail/static/src/scss/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat_item_status.scss
  73. +12 −0 addons/mail/static/src/scss/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat_list.scss
  74. +13 −0 addons/mail/static/src/scss/wip/discuss/sidebar/mailbox/discuss_sidebar_mailbox.scss
  75. +54 −0 addons/mail/static/src/scss/wip/discuss/sidebar/mailbox/discuss_sidebar_mailbox_item.scss
  76. +15 −0 addons/mail/static/src/xml/wip/component.xml
  77. +25 −0 addons/mail/static/src/xml/wip/discuss.xml
  78. +10 −0 addons/mail/static/src/xml/wip/test_app.xml
  79. +28 −0 addons/mail/views/mail_channel_views.xml
  80. +96 −0 addons/mail/views/mail_templates.xml
@@ -59,5 +59,7 @@
'static/src/xml/announcement.xml',
'static/src/xml/user_menu.xml',
'static/src/xml/web_kanban_activity.xml',
'static/src/xml/wip/discuss.xml',
'static/src/xml/wip/test_app.xml',
],
}
@@ -1615,6 +1615,7 @@ var Discuss = AbstractAction.extend({

core.action_registry.add('mail.discuss', Discuss);


return Discuss;

});
@@ -0,0 +1,45 @@
odoo.define('mail.wip.discuss.content.Composer', function (require) {
"use strict";

const Commands = require('mail.wip.discuss.content.composer.Commands');
const Input = require('mail.wip.discuss.content.composer.Input');

const session = require('web.session');

class Composer extends odoo.core.Component {
widgets = { Commands, Input };
inlineTemplate = `
<div class="o_mail_wip_discuss_content_composer">
<div class="o_mail_wip_discuss_content_composer_sidebar">
<img alt=""
class="o_mail_wip_discuss_content_composer_avatar rounded-circle"
t-att-src="avatar"/>
</div>
<div class="o_mail_wip_discuss_content_composer_core">
<t t-widget="Input"
t-props="{activeThreadID:props.activeThreadID}"
t-ref="input"/>
<t t-widget="Commands"
t-on-send-message="_onSendMessage"
t-on-emoji-selected="_onEmojiSelected"/>
</div>
</div>`;
get avatar() {
const avatar = session.uid > 0 ? session.url('/web/image', {
model: 'res.users',
field: 'image_small',
id: session.uid,
}) : '/web/static/src/img/user_menu_avatar.png';
return avatar;
}
_onEmojiSelected(ev) {
this.refs.input.insertEmoji({ source: ev.data.source });
}
_onSendMessage(ev) {
this.refs.input.postMessage();
}
}

return Composer;

});
@@ -0,0 +1,32 @@
odoo.define('mail.wip.discuss.content.composer.Commands', function (require) {
"use strict";

const Emojis = require('mail.wip.discuss.content.composer.commands.Emojis');

class Commands extends odoo.core.Component {
widgets = { Emojis };
inlineTemplate = `
<div class="o_mail_wip_discuss_content_composer_commands">
<t t-widget="Emojis"
t-on-emoji-selected="_onEmojiSelected"/>
<button aria-label="Add attachment"
class="o_mail_wip_discuss_content_composer_commands_attachments o_command btn btn-secondary fa fa-paperclip"
title="Add attachment"
type="button"/>
<button class="o_mail_wip_discuss_content_composer_commands_send o_command btn btn-primary"
type="button"
t-on-click="_onClickSend">
Send
</button>
</div>`;
_onClickSend(ev) {
this.trigger('send-message');
}
_onEmojiSelected(ev) {
this.trigger('emoji-selected', ev);
}
}

return Commands;

});
@@ -0,0 +1,71 @@
odoo.define('mail.wip.discuss.content.composer.commands.Emojis', function (require) {
"use strict";

const PopoverContent = require('mail.wip.discuss.content.composer.commands.emojis.PopoverContent');

class Emojis extends odoo.core.Component {
inlineTemplate = `
<button aria-label="Emojis"
class="o_mail_wip_discuss_content_composer_commands_emojis o_command btn btn-secondary fa fa-smile-o"
title="Emojis"
type="button"
data-selector="true"
data-toggle="popover"/>`;
constructor(parent, props) {
super(parent, props);
this._documentListenerID = _.uniqueId('composer_commands_emojis_');
this._popover = undefined;
this._popoverID = undefined;
}
mounted() {
const $div = $('<div>', { 'class': 'o_mail_wip_discuss_content_composer_commands_emojis_popover_container' });
const popoverContent = new PopoverContent(this);
popoverContent.on('emoji_selected', this, ev => this._onEmojiSelected(ev));
popoverContent.appendTo($div).then(() => {
const self = this;
this._popover = $(this.el).popover({
html: true,
boundary: 'viewport',
placement: 'top',
trigger: 'click',
offset: '0, 1',
content: function () {
const $this = $(this);
self._popoverID = $this.attr('aria-describedby');
return $div;
},
});
});
$(document).on('click.' + this._documentListenerID, ev => this._onDocumentClick(ev));
}
willUnmount() {
this._hidePopover();
$(document).off('click.' + this._documentListenerID);
}
_hidePopover() {
this._popover.popover('hide');
this._popoverID = undefined;
}
_onDocumentClick(ev) {
if (ev.target === this.el) {
return;
}
if (!this._popoverID) {
return;
}
const $target = $(ev.target);
if ($target.closest('#' + this._popoverID).length) {
return;
}
this._popover.popover('hide');
}
_onEmojiSelected(ev) {
ev.stopPropagation();
this._hidePopover();
this.trigger('emoji-selected', ev);
}
}

return Emojis;

});
@@ -0,0 +1,36 @@
odoo.define('mail.wip.discuss.content.composer.commands.emojis.PopoverContent', function (require) {
"use strict";

const emojis = require('mail.emojis');

const Widget = require('web.Widget');

const EmojisPopoverContent = Widget.extend({
template: 'mail.wip.discuss.content.composer.commands.emojis.PopoverContent',
events: {
'click .o_emoji': '_onClickEmoji',
},
/**
* @override {web.Widget}
*/
init: function () {
this._super.apply(this, arguments);
this.emojis = emojis;
},

//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------

/**
* @private
* @param {MouseEvent} ev
*/
_onClickEmoji: function (ev) {
this.trigger_up('emoji_selected', { source: $(ev.currentTarget).data('source') });
},
});

return EmojisPopoverContent;

});
@@ -0,0 +1,48 @@
odoo.define('mail.wip.discuss.content.composer.Input', function (require) {
"use strict";

const dom = require('web.dom');

class Input extends odoo.core.Component {
inlineTemplate = `
<textarea class="o_mail_wip_discuss_content_composer_input"
placeholder="Write something..."
t-on-keydown="_onKeydown"/>`;
mounted() {
dom.autoresize($(this.el), { min_height: 30 });
}
insertEmoji(data) {
const cursorPosition = dom.getSelectionRange(this.el);
const inputVal = this.el.value;
const leftSubstring = inputVal.substring(0, cursorPosition.start);
const rightSubstring = inputVal.substring(cursorPosition.end);
const newInputVal = [leftSubstring , data.source, rightSubstring].join(" ");
const newCursorPosition = newInputVal.length - rightSubstring.length;
this.el.value = newInputVal;
this.el.focus();
this.el.setSelectionRange(newCursorPosition, newCursorPosition);
}
postMessage() {
if (!this.el.value) {
return;
}
this.env.store.messaging.dispatch({
type: 'POST_MESSAGE_ON_THREAD',
data: {
threadID: this.props.activeThreadID,
messageData: { content: this.el.value },
},
});
this.el.value = '';
}
_onKeydown(ev) {
if (ev.which === $.ui.keyCode.ENTER) {
this.postMessage();
ev.preventDefault();
}
}
}

return Input;

});
@@ -0,0 +1,23 @@
odoo.define('mail.wip.discuss.Content', function (require) {
"use strict";

const Composer = require('mail.wip.discuss.content.Composer');
const ThreadView = require('mail.wip.discuss.content.ThreadView');

class Content extends odoo.core.Component {
widgets = { Composer, ThreadView };
inlineTemplate = `
<div class="o_mail_wip_discuss_content">
<t t-if="activeThreadID">
<t t-widget="ThreadView" t-props="{activeThreadID}"/>
<t t-widget="Composer" t-props="{activeThreadID}"/>
</t>
</div>`;
get activeThreadID() {
return this.props.activeThreadID;
}
}

return Content;

});
@@ -0,0 +1,44 @@
odoo.define('mail.wip.discuss.content.ThreadView', function (require) {
"use strict";

const Message = require('mail.wip.discuss.content.thread_view.Message');

class ThreadView extends odoo.core.Component {
widgets = { Message };
inlineTemplate = `
<div class="o_mail_wip_discuss_content_thread_view">
<div t-if="!thread.caches['[]'].loaded"
class="o_mail_wip_discuss_content_thread_view_loading">
<span>
<i aria-label="Loading..."
class="fa fa-spinner fa-spin"
role="img"
title="Loading..."/>
Loading messages...
</span>
</div>
<t t-else="">
<t t-foreach="messages"
t-as="message"
t-widget="Message"
t-props="{activeThreadID:props.activeThreadID,message}"
t-att-key="'message_' + message.id"/>
</t>
</div>`;
get messages() {
const thread = this.thread;
const messageIDs = thread.caches['[]'].messageIDs;
const messages = messageIDs.map(msgID => this.env.store.messaging.state.messages[msgID])
.sort((msg1, msg2) => msg1.id < msg2.id ? -1 : 1);
return messages;
}
get thread() {
const activeThreadID = this.props.activeThreadID;
const threads = this.env.store.messaging.state.threads;
return threads[activeThreadID];
}
}

return ThreadView;

});
@@ -0,0 +1,74 @@
odoo.define('mail.wip.discuss.content.thread_view.Message', function (require) {
"use strict";

const mailUtils = require('mail.utils');

const time = require('web.time');

class Message extends odoo.core.Component {
inlineTemplate = `
<div class="o_mail_wip_discuss_content_thread_view_message"
t-att-class="state.toggledClick ? 'o_toggled_click' : ''"
t-on-click="_onClick">
<div class="o_mail_wip_discuss_content_thread_view_message_sidebar">
<img alt=""
class="o_mail_wip_discuss_content_thread_view_message_avatar rounded-circle"
t-att-src="props.message.avatar"/>
</div>
<div class="o_mail_wip_discuss_content_thread_view_message_core">
<div class="o_mail_wip_discuss_content_thread_view_message_header">
<div class="o_mail_wip_discuss_content_thread_view_message_author_name">
<t t-esc="props.message.displayedAuthorName"/>
</div>
<div class="o_mail_wip_discuss_content_thread_view_message_date"
t-att-title="datetime(props.message)">
<t t-esc="timeElapsed"/>
</div>
<div class="o_mail_wip_discuss_content_thread_view_message_commands">
<div class="o_mail_wip_discuss_content_thread_view_message_commands_star o_command"
t-att-class="props.message.isStarred ? 'o_starred fa fa-star' : 'fa fa-star-o'"
t-on-click="_onClickCommandStar"/>
</div>
</div>
<div class="o_mail_wip_discuss_content_thread_view_message_content">
<t t-raw="props.message.body"/>
</div>
</div>
</div>`;
constructor(parent, props) {
super(parent, props);
this.state = { toggledClick: false };
}
datetime(message) {
return message.date.format(time.getLangDatetimeFormat());
}
get messages() {
const thread = this.thread;
const messageIDs = thread.caches['[]'].messageIDs;
const messages = messageIDs.map(msgID => this.env.store.messaging.state.messages[msgID])
.sort((msg1, msg2) => msg1.id < msg2.id ? -1 : 1);
return messages;
}
get thread() {
const activeThreadID = this.props.activeThreadID;
const threads = this.env.store.messaging.state.threads;
return threads[activeThreadID];
}
get timeElapsed() {
return mailUtils.timeFromNow(this.props.message.date);
}
_onClick(ev) {
this.updateState(Object.assign({}, this.state, { toggledClick: !this.state.toggledClick }));
}
_onClickCommandStar(ev) {
ev.stopPropagation();
this.env.store.messaging.dispatch({
type: 'TOGGLE_MESSAGE_STAR_STATUS',
data: { messageID: this.props.message.id },
});
}
}

return Message;

});
Oops, something went wrong.

0 comments on commit 6a8cfd8

Please sign in to comment.
You can’t perform that action at this time.