[IMP] website, *: improve the "edit in backend" button
*: base, mrp_account, product, mail, website_blog, website_event, website_forum This commit improves the button that allows to go to the backend view of an object when you are on its corresponding page on the website. The button is more visible and the user can see which object he is going to edit. Note that this commit also: - Changes the access key to translate a website page to ALT + T. - Adds a new access key to edit an object in backend with ALT + E. - Removes the possibility to duplicate a blog post (but this feature will be reintroduced later for all models, generically) **. **: Note that the duplication of blog posts actually had a mistake: The controller to create a new blog post has been added with [1] where it has been decided to not be a follower of the blog posts at their creation. A new controller has been added by [2] to be able to duplicate a blog post, to be consistent with [1], here also the user does not become a follower of the new blog post (the copy). So far, so good. Finally, [3] has changed the blog post creation controller so that the user who creates the blog post is a follower of the new blog post. Unfortunately the same change was not made for the duplicate controller, which is a mistake. There is no reason to be a follower of the newly created blog posts when you go through the add blog post controller but not when you go through the duplication controller. The behaviors should be consistent and there is no reason for there to be a difference. [1]: https://github.com/odoo/odoo/commit/4c3b516a7b988d758a67ff19242e8ed0837d756c [2]: https://github.com/odoo/odoo/commit/fe40538aff2b65f7719840c8e2d6e51e858f560f [3]: https://github.com/odoo/odoo/commit/4bf9dc4078a5ca413539a6fd16400fd5aad46907 task-2889929 closes odoo/odoo#97353 Related: odoo/enterprise#30075 Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com> Co-authored-by: qsm-odoo <qsm@odoo.com>
This commit is contained in:
committed by
qsm-odoo
co-authored by
qsm-odoo
parent
14408d6af5
commit
c2f394253e
@@ -16,7 +16,6 @@ class Users(models.Model):
|
||||
"""
|
||||
_name = 'res.users'
|
||||
_inherit = ['res.users']
|
||||
_description = 'Users'
|
||||
|
||||
notification_type = fields.Selection([
|
||||
('email', 'Handle by Emails'),
|
||||
|
||||
@@ -23,7 +23,6 @@ class ProductTemplate(models.Model):
|
||||
class ProductProduct(models.Model):
|
||||
_name = 'product.product'
|
||||
_inherit = 'product.product'
|
||||
_description = 'Product'
|
||||
|
||||
def button_bom_cost(self):
|
||||
self.ensure_one()
|
||||
|
||||
@@ -12,7 +12,7 @@ from odoo.tools import float_compare
|
||||
|
||||
class ProductProduct(models.Model):
|
||||
_name = "product.product"
|
||||
_description = "Product"
|
||||
_description = "Product Variant"
|
||||
_inherits = {'product.template': 'product_tmpl_id'}
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_order = 'priority desc, default_code, name, id'
|
||||
|
||||
@@ -15,7 +15,7 @@ _logger = logging.getLogger(__name__)
|
||||
class ProductTemplate(models.Model):
|
||||
_name = "product.template"
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin', 'image.mixin']
|
||||
_description = "Product Template"
|
||||
_description = "Product"
|
||||
_order = "priority desc, name"
|
||||
|
||||
@tools.ormcache()
|
||||
|
||||
@@ -42,6 +42,9 @@ export const websiteService = {
|
||||
let hasMultiWebsites;
|
||||
let actionJsId;
|
||||
let blockingProcesses = [];
|
||||
let modelNamesProm = null;
|
||||
const modelNames = {};
|
||||
|
||||
const context = reactive({
|
||||
showNewContentModal: false,
|
||||
showAceEditor: false,
|
||||
@@ -222,6 +225,34 @@ export const websiteService = {
|
||||
hideLoader() {
|
||||
bus.trigger('HIDE-WEBSITE-LOADER');
|
||||
},
|
||||
/**
|
||||
* Returns the (translated) "functional" name of a model
|
||||
* (_description) given its "technical" name (_name).
|
||||
*
|
||||
* @param {string} [model]
|
||||
* @returns {string}
|
||||
*/
|
||||
async getUserModelName(model = this.currentWebsite.metadata.mainObject.model) {
|
||||
if (!modelNamesProm) {
|
||||
// FIXME the `get_available_models` is to be removed/changed
|
||||
// in a near future. This code is to be adapted, probably
|
||||
// with another helper to map a model functional name from
|
||||
// its technical map without the need of the right access
|
||||
// rights (which is why I cannot use search_read here).
|
||||
modelNamesProm = orm.call("ir.model", "get_available_models")
|
||||
.then(modelsData => {
|
||||
for (const modelData of modelsData) {
|
||||
modelNames[modelData['model']] = modelData['display_name'];
|
||||
}
|
||||
})
|
||||
// Precaution in case the util is simply removed without
|
||||
// adapting this method: not critical, we can restore
|
||||
// later and use the fallback until the fix is made.
|
||||
.catch(() => {});
|
||||
}
|
||||
await modelNamesProm;
|
||||
return modelNames[model] || env._t("Data");
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,29 +1,25 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registry } from "@web/core/registry";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { Dropdown } from "@web/core/dropdown/dropdown";
|
||||
import { DropdownItem } from "@web/core/dropdown/dropdown_item";
|
||||
import { useService, useBus } from "@web/core/utils/hooks";
|
||||
|
||||
const { Component, onMounted } = owl;
|
||||
const { Component, onWillStart, onMounted } = owl;
|
||||
|
||||
const websiteSystrayRegistry = registry.category('website_systray');
|
||||
|
||||
export class EditInBackendSystray extends Component {
|
||||
setup() {
|
||||
this.websiteService = useService('website');
|
||||
this.actionService = useService('action');
|
||||
|
||||
onWillStart(this._updateMainObjectName);
|
||||
useBus(websiteSystrayRegistry, 'CONTENT-UPDATED', this._updateMainObjectName);
|
||||
|
||||
onMounted(() => {
|
||||
this.websiteService.editedObjectPath = null;
|
||||
});
|
||||
}
|
||||
|
||||
getElements() {
|
||||
return [{
|
||||
title: this.env._t("Settings"),
|
||||
callback: () => this.editInBackend(),
|
||||
}];
|
||||
}
|
||||
|
||||
editInBackend() {
|
||||
const { metadata: { mainObject } } = this.websiteService.currentWebsite;
|
||||
this.websiteService.editedObjectPath = this.websiteService.contentWindow.location.pathname;
|
||||
@@ -35,16 +31,16 @@ export class EditInBackendSystray extends Component {
|
||||
view_mode: "form",
|
||||
});
|
||||
}
|
||||
|
||||
async _updateMainObjectName() {
|
||||
this.mainObjectName = await this.websiteService.getUserModelName();
|
||||
}
|
||||
}
|
||||
EditInBackendSystray.template = "website.EditInBackendSystray";
|
||||
EditInBackendSystray.components = {
|
||||
Dropdown,
|
||||
DropdownItem
|
||||
};
|
||||
|
||||
export const systrayItem = {
|
||||
Component: EditInBackendSystray,
|
||||
isDisplayed: env => env.services.website.currentWebsite && env.services.website.currentWebsite.metadata.editableInBackend,
|
||||
};
|
||||
|
||||
registry.category("website_systray").add("EditInBackend", systrayItem, { sequence: 7 });
|
||||
registry.category("website_systray").add("EditInBackend", systrayItem, { sequence: 9 });
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
<t t-name="website.EditInBackendSystray" owl="1">
|
||||
<Dropdown class="'o_menu_systray_item o_website_edit_in_backend'" togglerClass="'p-2'">
|
||||
<t t-set-slot="toggler"><i class="fa fa-caret-down"/></t>
|
||||
<t t-foreach="getElements()" t-as="element" t-key="element_index">
|
||||
<DropdownItem
|
||||
t-esc="element.title"
|
||||
onSelected="element.callback"
|
||||
/>
|
||||
</t>
|
||||
</Dropdown>
|
||||
<div class="o_website_edit_in_backend">
|
||||
<a href="#" accesskey="e" t-on-click="editInBackend">
|
||||
<span class="fa fa-cog me-2"/>
|
||||
<t t-esc="mainObjectName"/>
|
||||
</a>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
|
||||
@@ -62,4 +62,4 @@ export const systrayItem = {
|
||||
isDisplayed: (env) => env.services.website.currentWebsite.metadata.editable,
|
||||
};
|
||||
|
||||
registry.category("website_systray").add("EditWebsite", systrayItem, { sequence: 8 });
|
||||
registry.category("website_systray").add("EditWebsite", systrayItem, { sequence: 7 });
|
||||
|
||||
@@ -96,7 +96,7 @@ export class NewContentModal extends Component {
|
||||
moduleXmlId: 'base.module_website_hr_recruitment',
|
||||
status: MODULE_STATUS.NOT_INSTALLED,
|
||||
icon: xml`<i class="fa fa-briefcase"/>`,
|
||||
title: this.env._t('Job Offer'),
|
||||
title: this.env._t('Job Position'),
|
||||
},
|
||||
{
|
||||
moduleXmlId: 'base.module_website_sale',
|
||||
|
||||
@@ -32,4 +32,4 @@ export const systrayItem = {
|
||||
isDisplayed: env => env.services.website.currentWebsite && env.services.website.currentWebsite.metadata.translatable,
|
||||
};
|
||||
|
||||
registry.category("website_systray").add("TranslateWebsiteSystray", systrayItem, { sequence: 9 });
|
||||
registry.category("website_systray").add("TranslateWebsiteSystray", systrayItem, { sequence: 8 });
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<t t-name="website.TranslateWebsiteSystray" owl="1">
|
||||
<div class="o_translate_website_container">
|
||||
<a href="#" accesskey="a" t-on-click="startTranslate">
|
||||
<a href="#" accesskey="t" t-on-click="startTranslate">
|
||||
<span t-if="websiteContext.translation" class="fa fa-refresh fa-spin me-2"/>
|
||||
TRANSLATE
|
||||
</a>
|
||||
|
||||
@@ -205,7 +205,6 @@ class WebsiteBlog(http.Controller):
|
||||
|
||||
if blog:
|
||||
values['main_object'] = blog
|
||||
values['edit_in_backend'] = True
|
||||
values['blog_url'] = QueryURL('', ['blog', 'tag'], blog=blog, tag=tag, date_begin=date_begin, date_end=date_end, search=search)
|
||||
else:
|
||||
values['blog_url'] = QueryURL('/blog', ['tag'], date_begin=date_begin, date_end=date_end, search=search)
|
||||
@@ -301,15 +300,3 @@ class WebsiteBlog(http.Controller):
|
||||
request.session['posts_viewed'].append(blog_post.id)
|
||||
request.session.modified = True
|
||||
return response
|
||||
|
||||
@http.route('/blog/post_duplicate', type='http', auth="user", website=True, methods=['POST'])
|
||||
def blog_post_copy(self, blog_post_id, **post):
|
||||
""" Duplicate a blog.
|
||||
|
||||
:param blog_post_id: id of the blog post currently browsed.
|
||||
|
||||
:return redirect to the new blog created
|
||||
"""
|
||||
new_blog_post = request.env['blog.post'].with_context(mail_create_nosubscribe=True).browse(int(blog_post_id)).copy()
|
||||
client_action_url = request.env["website"].get_client_action_url(f"/blog/{slug(new_blog_post.blog_id)}/{slug(new_blog_post)}", True)
|
||||
return request.redirect(client_action_url)
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { EditInBackendSystray } from '@website/systray_items/edit_in_backend';
|
||||
import { patch } from 'web.utils';
|
||||
import wUtils from 'website.utils';
|
||||
|
||||
patch(EditInBackendSystray.prototype, 'website_blog_edit_in_backend', {
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
getElements() {
|
||||
const elements = this._super();
|
||||
const { metadata: { mainObject } } = this.websiteService.currentWebsite;
|
||||
if (mainObject.model === 'blog.post') {
|
||||
return [...elements, {
|
||||
title: this.env._t("Duplicate"),
|
||||
callback: () => this.duplicate(),
|
||||
}];
|
||||
}
|
||||
return elements;
|
||||
},
|
||||
|
||||
async duplicate() {
|
||||
const { metadata: { mainObject } } = this.websiteService.currentWebsite;
|
||||
wUtils.sendRequest('/blog/post_duplicate', { blog_post_id: mainObject.id });
|
||||
}
|
||||
});
|
||||
@@ -40,11 +40,7 @@ EventAdditionalTourSteps.include({
|
||||
content: Markup(_t("Looking great! Let's now <b>publish</b> this page so that it becomes <b>visible</b> on your website!")),
|
||||
position: 'bottom',
|
||||
}, {
|
||||
trigger: '.o_menu_systray_item.o_website_edit_in_backend .dropdown-toggle',
|
||||
content: _t("Want to change your event configuration? Let's go back to the event form."),
|
||||
position: 'bottom',
|
||||
}, {
|
||||
trigger: '.o_menu_systray_item.o_website_edit_in_backend .dropdown-menu .dropdown-item',
|
||||
trigger: '.o_website_edit_in_backend > a',
|
||||
extra_trigger: 'iframe .o_wevent_event',
|
||||
content: _t("This shortcut will bring you right back to the event form."),
|
||||
position: 'bottom'
|
||||
|
||||
@@ -62,7 +62,7 @@ odoo.define("website_event.tour", function (require) {
|
||||
content: _t("Click to publish your event."),
|
||||
position: "top",
|
||||
}, {
|
||||
trigger: ".o_menu_systray_item.o_website_edit_in_backend",
|
||||
trigger: ".o_website_edit_in_backend > a",
|
||||
content: _t("Click here to customize your event further."),
|
||||
position: "bottom",
|
||||
}]);
|
||||
|
||||
@@ -155,7 +155,7 @@ class WebsiteForum(WebsiteProfile):
|
||||
values = self._prepare_user_values(forum=forum, searches=post, header={'ask_hide': not forum.active})
|
||||
values.update({
|
||||
'main_object': tag or forum,
|
||||
'edit_in_backend': not tag,
|
||||
'edit_in_backend': True,
|
||||
'question_ids': question_ids,
|
||||
'question_count': question_count,
|
||||
'search_count': question_count,
|
||||
@@ -258,6 +258,7 @@ class WebsiteForum(WebsiteProfile):
|
||||
values = self._prepare_user_values(forum=forum, searches=post)
|
||||
values.update({
|
||||
'main_object': question,
|
||||
'edit_in_backend': True,
|
||||
'question': question,
|
||||
'can_bump': (question.forum_id.allow_bump and not question.child_count and (datetime.today() - question.write_date).days > 9),
|
||||
'header': {'question_data': True},
|
||||
|
||||
@@ -244,7 +244,7 @@ class Users(models.Model):
|
||||
avatar, ... The user model is now dedicated to technical data.
|
||||
"""
|
||||
_name = "res.users"
|
||||
_description = 'Users'
|
||||
_description = 'User'
|
||||
_inherits = {'res.partner': 'partner_id'}
|
||||
_order = 'name, login'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user