[IMP] mail: introduce WebClientViewAttachmentView
This will allow using the component directly into the new Owl form. task-2886642 closes odoo/odoo#95436 Related: odoo/enterprise#29182 Signed-off-by: Louis Wicket (wil) <wil@odoo.com>
This commit is contained in:
@@ -77,6 +77,9 @@
|
||||
'web/static/src/webclient/webclient.scss',
|
||||
'web/static/src/webclient/webclient_extra.scss',
|
||||
'web/static/src/core/utils/*.scss',
|
||||
# depends on BS variables, can't be loaded in assets_primary or assets_secondary
|
||||
'mail/static/src/scss/variables/derived_variables.scss',
|
||||
'mail/static/src/scss/composer.scss',
|
||||
# Dependency of notification_group, notification_request, thread_needaction_preview and thread_preview
|
||||
'mail/static/src/components/notification_list/notification_list_item.scss',
|
||||
'mail/static/src/component_hooks/*.js',
|
||||
@@ -162,7 +165,6 @@
|
||||
'web.assets_qweb': [
|
||||
'mail/static/src/xml/*.xml',
|
||||
'mail/static/src/components/*/*.xml',
|
||||
'mail/static/src/widgets/*/*.xml',
|
||||
],
|
||||
},
|
||||
'license': 'LGPL-3',
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import { useComponentToModel } from '@mail/component_hooks/use_component_to_model';
|
||||
import { useRefToModel } from '@mail/component_hooks/use_ref_to_model';
|
||||
import { useUpdate } from '@mail/component_hooks/use_update';
|
||||
import { registerMessagingComponent } from '@mail/utils/messaging_component';
|
||||
import { LegacyComponent } from '@web/legacy/legacy_component';
|
||||
|
||||
@@ -13,15 +12,10 @@ export class Chatter extends LegacyComponent {
|
||||
*/
|
||||
setup() {
|
||||
super.setup();
|
||||
useUpdate({ func: () => this._update() });
|
||||
useComponentToModel({ fieldName: 'component' });
|
||||
useRefToModel({ fieldName: 'scrollPanelRef', refName: 'scrollPanel' });
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @returns {Chatter}
|
||||
*/
|
||||
@@ -29,26 +23,6 @@ export class Chatter extends LegacyComponent {
|
||||
return this.props.record;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_notifyRendered() {
|
||||
this.trigger('o-chatter-rendered');
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_update() {
|
||||
if (this.chatter.thread) {
|
||||
this._notifyRendered();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Object.assign(Chatter, {
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { useComponentToModel } from '@mail/component_hooks/use_component_to_model';
|
||||
import { useRefToModel } from '@mail/component_hooks/use_ref_to_model';
|
||||
import { useUpdateToModel } from '@mail/component_hooks/use_update_to_model';
|
||||
import { registerMessagingComponent } from '@mail/utils/messaging_component';
|
||||
|
||||
import { LegacyComponent } from '@web/legacy/legacy_component';
|
||||
|
||||
export class WebClientViewAttachmentView extends LegacyComponent {
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
setup() {
|
||||
useComponentToModel({ fieldName: 'component' });
|
||||
useRefToModel({ fieldName: 'iframeViewerPdfRef', refName: 'iframeViewerPdf' });
|
||||
useUpdateToModel({ methodName: 'onComponentUpdate' });
|
||||
}
|
||||
/**
|
||||
* @returns {WebClientViewAttachmentView}
|
||||
*/
|
||||
get webClientViewAttachmentView() {
|
||||
return this.props.record;
|
||||
}
|
||||
}
|
||||
|
||||
Object.assign(WebClientViewAttachmentView, {
|
||||
props: { record: Object },
|
||||
template: 'mail.WebClientViewAttachmentView',
|
||||
});
|
||||
|
||||
registerMessagingComponent(WebClientViewAttachmentView);
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates>
|
||||
|
||||
<t t-name="mail.WebClientViewAttachmentView" owl="1">
|
||||
<t t-if="webClientViewAttachmentView.thread.mainAttachment">
|
||||
<t t-if="!webClientViewAttachmentView.thread.mainAttachment.isPdf">
|
||||
<h3 class="mt0 mb8 ps-2 text-muted float-end"><t t-esc="webClientViewAttachmentView.thread.mainAttachment.filename"/></h3>
|
||||
</t>
|
||||
<div t-if="webClientViewAttachmentView.thread.mainAttachment.isImage" class="o_attachment_preview_img">
|
||||
<img id="attachment_img" class="img img-fluid d-block" t-attf-src="/web/image/#{webClientViewAttachmentView.thread.mainAttachment.id}?unique=1"/>
|
||||
</div>
|
||||
<iframe t-if="webClientViewAttachmentView.thread.mainAttachment.isPdf" class="mb48" t-attf-src="/web/static/lib/pdfjs/web/viewer.html?file=/web/content/#{webClientViewAttachmentView.thread.mainAttachment.id}?filename%3D#{window.encodeURIComponent(webClientViewAttachmentView.thread.mainAttachment.name)}" t-ref="iframeViewerPdf"/>
|
||||
<t t-if="webClientViewAttachmentView.thread.attachmentsInWebClientView.length > 1">
|
||||
<a class="arrow o_move_previous text-center" href="#" t-on-click="webClientViewAttachmentView.onClickPrevious">
|
||||
<span class="fa fa-chevron-left"/>
|
||||
</a>
|
||||
<a class="arrow o_move_next text-center" href="#" t-on-click="webClientViewAttachmentView.onClickNext">
|
||||
<span class="fa fa-chevron-right"/>
|
||||
</a>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { useModels } from '@mail/component_hooks/use_models';
|
||||
// ensure components are registered beforehand.
|
||||
import '@mail/components/web_client_view_attachment_view/web_client_view_attachment_view';
|
||||
import { replace } from '@mail/model/model_field_command';
|
||||
import { getMessagingComponent } from '@mail/utils/messaging_component';
|
||||
|
||||
const { Component, onWillDestroy, onWillUpdateProps } = owl;
|
||||
|
||||
const getNextId = (function () {
|
||||
let tmpId = 0;
|
||||
return () => {
|
||||
tmpId += 1;
|
||||
return tmpId;
|
||||
};
|
||||
})();
|
||||
|
||||
/**
|
||||
* This component abstracts attachment view component to its parent, so that it
|
||||
* can be mounted and receive messaging data even when an attachment view
|
||||
* component cannot be created. Indeed, in order to create an attachment view
|
||||
* component, we must create an attachment view record, the latter requiring
|
||||
* messaging to be initialized. The view may attempt to create an attachment
|
||||
* view before messaging has been initialized, so this component delays the
|
||||
* mounting of attachment view until it becomes initialized.
|
||||
*/
|
||||
export class WebClientViewAttachmentViewContainer extends Component {
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
setup() {
|
||||
useModels();
|
||||
super.setup();
|
||||
this.webClientViewAttachmentView = undefined;
|
||||
this.webClientViewAttachmentViewId = getNextId();
|
||||
this._insertFromProps(this.props);
|
||||
onWillUpdateProps(nextProps => this._insertFromProps(nextProps));
|
||||
onWillDestroy(() => this._deleteRecord());
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_deleteRecord() {
|
||||
if (this.webClientViewAttachmentView) {
|
||||
if (this.webClientViewAttachmentView.exists()) {
|
||||
this.webClientViewAttachmentView.delete();
|
||||
}
|
||||
this.webClientViewAttachmentView = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
async _insertFromProps(props) {
|
||||
const messaging = await this.env.services.messaging.get();
|
||||
if (this.__owl__.status === 5 /* destroyed */) {
|
||||
this._deleteRecord();
|
||||
return;
|
||||
}
|
||||
if (!props.threadId) {
|
||||
this._deleteRecord();
|
||||
return;
|
||||
}
|
||||
const thread = messaging.models['Thread'].insert({
|
||||
id: props.threadId,
|
||||
model: props.threadModel,
|
||||
});
|
||||
this.webClientViewAttachmentView = messaging.models['WebClientViewAttachmentView'].insert({
|
||||
id: this.webClientViewAttachmentViewId,
|
||||
thread: replace(thread),
|
||||
});
|
||||
this.render();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Object.assign(WebClientViewAttachmentViewContainer, {
|
||||
components: { WebClientViewAttachmentView: getMessagingComponent('WebClientViewAttachmentView') },
|
||||
props: {
|
||||
threadId: {
|
||||
type: Number,
|
||||
optional: true,
|
||||
},
|
||||
threadModel: String,
|
||||
},
|
||||
template: 'mail.WebClientViewAttachmentViewContainer',
|
||||
});
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="mail.WebClientViewAttachmentViewContainer" owl="1">
|
||||
<t t-if="webClientViewAttachmentView and webClientViewAttachmentView.thread.attachmentsInWebClientView.length > 0">
|
||||
<div class="o_attachment_preview_container">
|
||||
<WebClientViewAttachmentView record="webClientViewAttachmentView"/>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
@@ -579,6 +579,7 @@ registerModel({
|
||||
});
|
||||
}
|
||||
this.update(values);
|
||||
this.messaging.messagingBus.trigger('o-thread-loaded-data', { thread: this });
|
||||
},
|
||||
/**
|
||||
* Add current user to provided thread's followers.
|
||||
@@ -949,6 +950,17 @@ registerModel({
|
||||
kwargs: { name: newName },
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @param {Attachment} attachment
|
||||
*/
|
||||
async setMainAttachment(attachment) {
|
||||
this.update({ mainAttachment: replace(attachment) });
|
||||
await this.messaging.rpc({
|
||||
model: 'ir.attachment',
|
||||
method: 'register_as_main_attachment',
|
||||
args: [[this.mainAttachment.id]],
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Unfollow current partner from this thread.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerModel } from '@mail/model/model_core';
|
||||
import { attr, one } from '@mail/model/model_field';
|
||||
import { OnChange } from '@mail/model/model_onchange';
|
||||
|
||||
import { hidePDFJSButtons } from '@web/legacy/js/libs/pdfjs';
|
||||
|
||||
registerModel({
|
||||
name: 'WebClientViewAttachmentView',
|
||||
identifyingFields: ['id'],
|
||||
recordMethods: {
|
||||
/**
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
onClickNext(ev) {
|
||||
ev.preventDefault();
|
||||
const index = this.thread.attachmentsInWebClientView.findIndex(attachment => attachment === this.thread.mainAttachment);
|
||||
this.setMainAttachmentFromIndex(index === this.thread.attachmentsInWebClientView.length - 1 ? 0 : index + 1);
|
||||
},
|
||||
/**
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
onClickPrevious(ev) {
|
||||
ev.preventDefault();
|
||||
const index = this.thread.attachmentsInWebClientView.findIndex(attachment => attachment === this.thread.mainAttachment);
|
||||
this.setMainAttachmentFromIndex(index === 0 ? this.thread.attachmentsInWebClientView.length - 1 : index - 1);
|
||||
},
|
||||
onComponentUpdate() {
|
||||
if (this.iframeViewerPdfRef.el) {
|
||||
hidePDFJSButtons(this.iframeViewerPdfRef.el);
|
||||
}
|
||||
this.component.trigger('preview_attachment_validation');
|
||||
},
|
||||
async setMainAttachmentFromIndex(index) {
|
||||
await this.thread.setMainAttachment(this.thread.attachmentsInWebClientView[index]);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onChangeThreadAttachmentsInWebClientView() {
|
||||
if (!this.thread.mainAttachment && this.thread.attachmentsInWebClientView.length > 0) {
|
||||
this.setMainAttachmentFromIndex(0);
|
||||
}
|
||||
},
|
||||
},
|
||||
fields: {
|
||||
component: attr(),
|
||||
id: attr({
|
||||
readonly: true,
|
||||
required: true,
|
||||
}),
|
||||
iframeViewerPdfRef: attr(),
|
||||
thread: one('Thread', {
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
onChanges: [
|
||||
new OnChange({
|
||||
dependencies: ['thread.attachmentsInWebClientView'],
|
||||
methodName: '_onChangeThreadAttachmentsInWebClientView',
|
||||
}),
|
||||
],
|
||||
});
|
||||
@@ -1,123 +0,0 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { replace } from '@mail/model/model_field_command';
|
||||
|
||||
import core from 'web.core';
|
||||
import Widget from 'web.Widget';
|
||||
import { hidePDFJSButtons } from '@web/legacy/js/libs/pdfjs';
|
||||
|
||||
const QWeb = core.qweb;
|
||||
|
||||
export const AttachmentViewer = Widget.extend({
|
||||
className: 'o_attachment_preview_container',
|
||||
events: {
|
||||
'click .arrow.o_move_next': '_onClickNext',
|
||||
'click .arrow.o_move_previous': '_onClickPrevious',
|
||||
},
|
||||
/**
|
||||
* @constructor
|
||||
* @override
|
||||
* @param {Widget} parent
|
||||
* @param {Thread} thread
|
||||
*/
|
||||
init(parent, thread) {
|
||||
this._super.apply(this, arguments);
|
||||
this.thread = thread;
|
||||
this.attachments = this.thread.attachmentsInWebClientView;
|
||||
this._setActive();
|
||||
},
|
||||
/**
|
||||
* Render attachment.
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
start() {
|
||||
this._renderAttachment();
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Update attachments list and activeAttachment.
|
||||
|
||||
* @param {Thread} thread
|
||||
*/
|
||||
updateContents(thread) {
|
||||
this.thread = thread;
|
||||
this.attachments = this.thread.attachmentsInWebClientView;
|
||||
this._setActive();
|
||||
this._renderAttachment();
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Render template
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_renderAttachment() {
|
||||
this.$el.empty();
|
||||
this.$el.append(QWeb.render('mail.widgets.AttachmentViewer', { thread: this.thread }));
|
||||
if (this.thread.mainAttachment && this.thread.mainAttachment.isPdf) {
|
||||
hidePDFJSButtons(this.el);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_setActive() {
|
||||
if (!this.thread.mainAttachment && this.thread.attachmentsInWebClientView.length > 0) {
|
||||
this._switch_main_attachment(0);
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Sets the attachment at position index as the new main attachment of
|
||||
* the related model, and display it.
|
||||
**/
|
||||
async _switch_main_attachment(index) {
|
||||
this.thread.update({ mainAttachment: replace(this.thread.attachmentsInWebClientView[index]) });
|
||||
await this._rpc({
|
||||
model: 'ir.attachment',
|
||||
method: 'register_as_main_attachment',
|
||||
args: [[this.thread.mainAttachment['id']]],
|
||||
});
|
||||
this._renderAttachment();
|
||||
},
|
||||
|
||||
/**
|
||||
* On click move to next attachment.
|
||||
*
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onClickNext(ev) {
|
||||
ev.preventDefault();
|
||||
var index = _.findIndex(this.thread.attachmentsInWebClientView, this.thread.mainAttachment);
|
||||
index = index === this.thread.attachmentsInWebClientView.length - 1 ? 0 : index + 1;
|
||||
this._switch_main_attachment(index);
|
||||
},
|
||||
/**
|
||||
* On click move to previous attachment.
|
||||
*
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onClickPrevious(ev) {
|
||||
ev.preventDefault();
|
||||
var index = _.findIndex(this.thread.attachmentsInWebClientView, this.thread.mainAttachment);
|
||||
index = index === 0 ? this.thread.attachmentsInWebClientView.length - 1 : index - 1;
|
||||
this._switch_main_attachment(index);
|
||||
},
|
||||
});
|
||||
@@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates>
|
||||
|
||||
<t t-name="mail.widgets.AttachmentViewer">
|
||||
<t t-if="thread.mainAttachment">
|
||||
<t t-if="!thread.mainAttachment.isPdf">
|
||||
<h3 class="mt0 mb8 ps-2 text-muted float-end"><t t-esc="thread.mainAttachment.filename"/></h3>
|
||||
</t>
|
||||
<div t-if="thread.mainAttachment.isImage" class="o_attachment_preview_img">
|
||||
<img id="attachment_img" class="img img-fluid d-block" t-attf-src="/web/image/#{thread.mainAttachment.id}?unique=1"/>
|
||||
</div>
|
||||
<iframe t-if="thread.mainAttachment.isPdf" class="mb48" t-attf-src="/web/static/lib/pdfjs/web/viewer.html?file=/web/content/#{thread.mainAttachment.id}?filename%3D#{window.encodeURIComponent(thread.mainAttachment.name)}"/>
|
||||
<t t-if="thread.attachmentsInWebClientView.length > 1">
|
||||
<a class="arrow o_move_previous text-center" href="#">
|
||||
<span class="fa fa-chevron-left"/>
|
||||
</a>
|
||||
<a class="arrow o_move_next text-center" href="#">
|
||||
<span class="fa fa-chevron-right"/>
|
||||
</a>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
@@ -1,7 +1,8 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { ChatterContainer } from '@mail/components/chatter_container/chatter_container';
|
||||
import { AttachmentViewer } from '@mail/widgets/attachment_viewer/attachment_viewer';
|
||||
import { WebClientViewAttachmentViewContainer } from '@mail/components/web_client_view_attachment_view_container/web_client_view_attachment_view_container';
|
||||
import { Listener } from '@mail/model/model_listener';
|
||||
|
||||
import dom from 'web.dom';
|
||||
import FormRenderer from 'web.FormRenderer';
|
||||
@@ -23,6 +24,10 @@ FormRenderer.include({
|
||||
*/
|
||||
init(parent, state, params) {
|
||||
this._super(...arguments);
|
||||
this.modelsListener = new Listener({
|
||||
name: 'interchangeChatter',
|
||||
onChange: () => this._interchangeChatter(),
|
||||
});
|
||||
this.hasChatter = params.hasChatter && !params.isFromFormViewDialog;
|
||||
this.isChatterInSheet = false;
|
||||
this.hasAttachmentViewerFeature = params.hasAttachmentViewerFeature;
|
||||
@@ -49,14 +54,15 @@ FormRenderer.include({
|
||||
* when applying the rendering into the DOM.
|
||||
*/
|
||||
this.chatterContainerTargetPlaceholder = undefined;
|
||||
this.attachmentViewer = undefined;
|
||||
this.webClientViewAttachmentViewContainer = undefined;
|
||||
this.attachmentViewerTarget = undefined;
|
||||
if (this.hasAttachmentViewerFeature) {
|
||||
this.attachmentViewerTarget = document.createElement("div");
|
||||
this.attachmentViewerTarget.classList.add("o_attachment_preview");
|
||||
this.webClientViewAttachmentViewContainer = new ComponentWrapper(this, WebClientViewAttachmentViewContainer, this._makeWebClientViewAttachmentViewContainerProps());
|
||||
this.webClientViewAttachmentViewContainer.mount(this.attachmentViewerTarget);
|
||||
}
|
||||
this.attachmentViewerTargetPlaceholder = undefined;
|
||||
this.on('o_chatter_rendered', this, ev => this._onChatterRendered(ev));
|
||||
},
|
||||
async initChatter() {
|
||||
this._chatterContainerComponent = new ChatterContainerWrapperComponent(
|
||||
@@ -99,6 +105,9 @@ FormRenderer.include({
|
||||
if (this.hasChatter) {
|
||||
await this._updateChatterContainerComponent();
|
||||
}
|
||||
if (this.hasAttachmentViewer()) {
|
||||
await this._updateWebClientViewAttachmentViewContainer();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* The last rendering of the form view has just been applied into the DOM,
|
||||
@@ -135,8 +144,10 @@ FormRenderer.include({
|
||||
*/
|
||||
destroy() {
|
||||
this._super(...arguments);
|
||||
if (owl.Component.env.services.messaging) {
|
||||
owl.Component.env.services.messaging.modelManager.removeListener(this.modelsListener);
|
||||
}
|
||||
this._chatterContainerComponent = undefined;
|
||||
this.off('o_chatter_rendered', this);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -176,10 +187,13 @@ FormRenderer.include({
|
||||
}
|
||||
$(this._chatterContainerTarget).insertAfter($sheetBg);
|
||||
}
|
||||
if (this.hasAttachmentViewer()) {
|
||||
$(this.attachmentViewerTarget).insertAfter($sheetBg);
|
||||
} else {
|
||||
dom.append($sheetBg, $(this.attachmentViewerTarget));
|
||||
if (this.hasAttachmentViewerFeature) {
|
||||
if (this.hasAttachmentViewer()) {
|
||||
$(this.attachmentViewerTarget).insertAfter($sheetBg);
|
||||
this._updateWebClientViewAttachmentViewContainer();
|
||||
} else {
|
||||
this.attachmentViewerTarget.remove();
|
||||
}
|
||||
}
|
||||
this._updateChatterContainerComponent();
|
||||
},
|
||||
@@ -211,55 +225,24 @@ FormRenderer.include({
|
||||
threadModel: this.state.model,
|
||||
};
|
||||
},
|
||||
_makeWebClientViewAttachmentViewContainerProps() {
|
||||
return {
|
||||
threadId: this.state.res_id,
|
||||
threadModel: this.state.model,
|
||||
};
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
async _updateChatterContainerComponent() {
|
||||
const props = this._makeChatterContainerProps();
|
||||
try {
|
||||
await this._chatterContainerComponent.update(props);
|
||||
} catch (error) {
|
||||
if (error.message !== "Mounting operation cancelled") {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
await this._chatterContainerComponent.update(props);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {OdooEvent} ev
|
||||
* @param {Object} ev.data
|
||||
* @param {Attachment[]} ev.data.attachments
|
||||
* @param {Thread} ev.data.thread
|
||||
*/
|
||||
_onChatterRendered(ev) {
|
||||
if (!this.hasAttachmentViewer()) {
|
||||
if (this.attachmentViewer) {
|
||||
this.attachmentViewer.destroy();
|
||||
this.attachmentViewer = undefined;
|
||||
this._interchangeChatter();
|
||||
}
|
||||
return;
|
||||
}
|
||||
var self = this;
|
||||
const thread = this.messaging.models['Thread'].insert({
|
||||
id: this.state.res_id,
|
||||
model: this.state.model,
|
||||
});
|
||||
if (this.attachmentViewer) {
|
||||
// FIXME should be improved : what if somehow an attachment is replaced in a thread ?
|
||||
if (
|
||||
this.attachmentViewer.thread !== thread ||
|
||||
this.attachmentViewer.attachments.length !== thread.attachmentsInWebClientView.length
|
||||
) {
|
||||
this.attachmentViewer.updateContents(thread);
|
||||
}
|
||||
this.trigger_up('preview_attachment_validation');
|
||||
} else {
|
||||
this.attachmentViewer = new AttachmentViewer(this, thread);
|
||||
this.attachmentViewer.appendTo($(this.attachmentViewerTarget)).then(function () {
|
||||
self.trigger_up('preview_attachment_validation');
|
||||
self._interchangeChatter();
|
||||
});
|
||||
}
|
||||
async _updateWebClientViewAttachmentViewContainer() {
|
||||
const props = this._makeWebClientViewAttachmentViewContainerProps();
|
||||
await this.webClientViewAttachmentViewContainer.update(props);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -125,6 +125,10 @@ patch(MockServer.prototype, 'mail', {
|
||||
if (new RegExp('/mail/channel/\\d+/partner/\\d+/avatar_128').test(route)) {
|
||||
return;
|
||||
}
|
||||
if (args.model === 'ir.attachment' && args.method === 'register_as_main_attachment') {
|
||||
const ids = args.args[0];
|
||||
return this._mockIrAttachmentRegisterAsMainAttachment(ids);
|
||||
}
|
||||
// mail.activity methods
|
||||
if (args.model === 'mail.activity' && args.method === 'action_feedback') {
|
||||
const ids = args.args[0];
|
||||
@@ -528,7 +532,7 @@ patch(MockServer.prototype, 'mail', {
|
||||
[['res_id', '=', thread.id], ['res_model', '=', thread_model]],
|
||||
); // order not done for simplicity
|
||||
res['attachments'] = this._mockIrAttachment_attachmentFormat(attachments.map(attachment => attachment.id));
|
||||
res['mainAttachment'] = thread.message_main_attachment_id ? [['insert-and-replace', { 'id': thread.message_main_attachment_id }]] : [['clear']];
|
||||
res['mainAttachment'] = thread.message_main_attachment_id ? [['insert-and-replace', { 'id': thread.message_main_attachment_id[0] }]] : [['clear']];
|
||||
}
|
||||
if (request_list.includes('followers')) {
|
||||
const followers = this.pyEnv['mail.followers'].searchRead([['id', 'in', thread.message_follower_ids || []]]);
|
||||
@@ -613,6 +617,31 @@ patch(MockServer.prototype, 'mail', {
|
||||
return res;
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Simulates `register_as_main_attachment` on `ir.attachment`.
|
||||
*
|
||||
* @private
|
||||
* @param {integer} ids
|
||||
* @param {boolean} [force=true]
|
||||
* @returns {boolean} dummy value for mock server
|
||||
*/
|
||||
_mockIrAttachmentRegisterAsMainAttachment(ids, force = true) {
|
||||
const [attachment] = this.getRecords('ir.attachment', [['id', 'in', ids]]);
|
||||
if (!attachment.res_model) {
|
||||
return true; // dummy value for mock server
|
||||
}
|
||||
if (!this.models[attachment.res_model].fields['message_main_attachment_id']) {
|
||||
return true; // dummy value for mock server
|
||||
}
|
||||
const [record] = this.pyEnv[attachment.res_model].searchRead([['id', '=', attachment.res_id]]);
|
||||
if (force || !record.message_main_attachment_id) {
|
||||
this.pyEnv[attachment.res_model].write(
|
||||
[record.id],
|
||||
{ message_main_attachment_id: attachment.id },
|
||||
);
|
||||
}
|
||||
return true; // dummy value for mock server
|
||||
},
|
||||
/**
|
||||
* Simulates `_action_done` on `mail.activity`.
|
||||
*
|
||||
|
||||
@@ -446,25 +446,44 @@ function getOpenDiscuss(afterEvent, webClient, { context = {}, params, ...props
|
||||
}
|
||||
|
||||
function getOpenFormView(afterEvent, openView) {
|
||||
return async function openFormView(action, { props, waitUntilMessagesLoaded = true } = {}) {
|
||||
return async function openFormView(action, { props, waitUntilDataLoaded = true, waitUntilMessagesLoaded = true } = {}) {
|
||||
action['views'] = [[false, 'form']];
|
||||
if (waitUntilMessagesLoaded) {
|
||||
return afterNextRender(() => afterEvent({
|
||||
eventName: 'o-thread-view-hint-processed',
|
||||
func: () => openView(action, props),
|
||||
message: "should wait until chatter loaded its messages",
|
||||
predicate: ({ hint, threadViewer }) => {
|
||||
return (
|
||||
hint.type === 'messages-loaded' &&
|
||||
threadViewer &&
|
||||
threadViewer.thread.model === action.res_model &&
|
||||
threadViewer.thread.id === action.res_id
|
||||
)
|
||||
},
|
||||
}));
|
||||
const func = () => openView(action, props);
|
||||
const waitData = func => afterNextRender(() => afterEvent({
|
||||
eventName: 'o-thread-loaded-data',
|
||||
func,
|
||||
message: "should wait until chatter loaded its data",
|
||||
predicate: ({ thread }) => {
|
||||
return (
|
||||
thread.model === action.res_model &&
|
||||
thread.id === action.res_id
|
||||
);
|
||||
},
|
||||
}));
|
||||
const waitMessages = func => afterNextRender(() => afterEvent({
|
||||
eventName: 'o-thread-view-hint-processed',
|
||||
func,
|
||||
message: "should wait until chatter loaded its messages",
|
||||
predicate: ({ hint, threadViewer }) => {
|
||||
return (
|
||||
hint.type === 'messages-loaded' &&
|
||||
threadViewer &&
|
||||
threadViewer.thread.model === action.res_model &&
|
||||
threadViewer.thread.id === action.res_id
|
||||
);
|
||||
},
|
||||
}));
|
||||
if (waitUntilDataLoaded && waitUntilMessagesLoaded) {
|
||||
return waitData(() => waitMessages(func));
|
||||
}
|
||||
return openView(action, props);
|
||||
}
|
||||
if (waitUntilDataLoaded) {
|
||||
return waitData(func);
|
||||
}
|
||||
if (waitUntilMessagesLoaded) {
|
||||
return waitMessages(func);
|
||||
}
|
||||
return func();
|
||||
};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user