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 9ebf1de1c9f742d6ea056b64b4d1c0a9709468e8
Showing with 10,780 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. +1,205 −0 addons/mail/static/src/js/wip/rui/rui.js
  44. +100 −0 addons/mail/static/src/js/wip/rui/rui_component.js
  45. +108 −0 addons/mail/static/src/js/wip/rui/rui_element.js
  46. +75 −0 addons/mail/static/src/js/wip/rui/rui_fiber.js
  47. +30 −0 addons/mail/static/src/js/wip/rui/rui_ref.js
  48. +720 −0 addons/mail/static/src/js/wip/services/chat_window_manager.js
  49. +42 −0 addons/mail/static/src/js/wip/services/chat_window_service.js
  50. +50 −0 addons/mail/static/src/js/wip/services/messaging_service.js
  51. +3,254 −0 addons/mail/static/src/js/wip/services/messaging_store.js
  52. +113 −0 addons/mail/static/src/js/wip/test_app/test_app.js
  53. +11 −0 addons/mail/static/src/js/wip/test_app/test_app_root.js
  54. +37 −0 addons/mail/static/src/scss/wip/discuss/content/composer/discuss_content_composer.scss
  55. +39 −0 addons/mail/static/src/scss/wip/discuss/content/composer/discuss_content_composer_commands.scss
  56. +23 −0 ...c/scss/wip/discuss/content/composer/discuss_content_composer_commands_emojis_popover_content.scss
  57. +18 −0 addons/mail/static/src/scss/wip/discuss/content/composer/discuss_content_composer_input.scss
  58. +16 −0 addons/mail/static/src/scss/wip/discuss/content/discuss_content.scss
  59. +33 −0 addons/mail/static/src/scss/wip/discuss/content/thread_view/discuss_content_thread_view.scss
  60. +106 −0 addons/mail/static/src/scss/wip/discuss/content/thread_view/discuss_content_thread_view_message.scss
  61. +27 −0 addons/mail/static/src/scss/wip/discuss/discuss.scss
  62. +12 −0 addons/mail/static/src/scss/wip/discuss/discuss_root.scss
  63. +13 −0 addons/mail/static/src/scss/wip/discuss/sidebar/channel/discuss_sidebar_channel.scss
  64. +18 −0 addons/mail/static/src/scss/wip/discuss/sidebar/channel/discuss_sidebar_channel_add_item.scss
  65. +44 −0 addons/mail/static/src/scss/wip/discuss/sidebar/channel/discuss_sidebar_channel_header.scss
  66. +66 −0 addons/mail/static/src/scss/wip/discuss/sidebar/channel/discuss_sidebar_channel_item.scss
  67. +31 −0 addons/mail/static/src/scss/wip/discuss/sidebar/channel/discuss_sidebar_channel_item_commands.scss
  68. +17 −0 addons/mail/static/src/scss/wip/discuss/sidebar/channel/discuss_sidebar_channel_item_type.scss
  69. +12 −0 addons/mail/static/src/scss/wip/discuss/sidebar/channel/discuss_sidebar_channel_list.scss
  70. +33 −0 addons/mail/static/src/scss/wip/discuss/sidebar/discuss_sidebar.scss
  71. +13 −0 addons/mail/static/src/scss/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat.scss
  72. +18 −0 addons/mail/static/src/scss/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat_add_item.scss
  73. +39 −0 addons/mail/static/src/scss/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat_header.scss
  74. +64 −0 addons/mail/static/src/scss/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat_item.scss
  75. +30 −0 addons/mail/static/src/scss/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat_item_commands.scss
  76. +17 −0 .../mail/static/src/scss/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat_item_editable_name.scss
  77. +77 −0 addons/mail/static/src/scss/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat_item_status.scss
  78. +12 −0 addons/mail/static/src/scss/wip/discuss/sidebar/dm_chat/discuss_sidebar_dm_chat_list.scss
  79. +13 −0 addons/mail/static/src/scss/wip/discuss/sidebar/mailbox/discuss_sidebar_mailbox.scss
  80. +54 −0 addons/mail/static/src/scss/wip/discuss/sidebar/mailbox/discuss_sidebar_mailbox_item.scss
  81. +15 −0 addons/mail/static/src/xml/wip/component.xml
  82. +25 −0 addons/mail/static/src/xml/wip/discuss.xml
  83. +10 −0 addons/mail/static/src/xml/wip/test_app.xml
  84. +28 −0 addons/mail/views/mail_channel_views.xml
  85. +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 9ebf1de

Please sign in to comment.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.