[IMP] website, *: adapt code to work on "pages" kanban views

*: website_blog

The goal of this commit is to update JS code to have the same behaviour
from the 'website content' list view (trigger the 'new content' dialogs
on "CREATE", add a website selector to filter content) on kanban views
too.

The blog post kanban view has been adapted to use this. Other "website
content" related records will receive a kanban view in a further update.
This is is also important so that the mobile UX is nicer.

task-2889981

X-original-commit: ed09db19c372da8d8be541f365117d1ce8e965ba
Part-of: odoo/odoo#101215
This commit is contained in:
xO-Tx
2022-09-27 11:41:52 +02:00
committed by qsm-odoo
parent 9d9fe23c33
commit b60db0df9b
6 changed files with 170 additions and 78 deletions
@@ -0,0 +1,31 @@
/** @odoo-module **/
import {PageControllerMixin, PageRendererMixin} from "./page_views_mixin";
import {registry} from '@web/core/registry';
import {kanbanView} from "@web/views/kanban/kanban_view";
export class PageKanbanController extends PageControllerMixin(kanbanView.Controller) {
/**
* @override
*/
async createRecord() {
return this.createWebsiteContent();
}
}
PageKanbanController.template = 'website.PageKanbanView';
export class PageKanbanRenderer extends PageRendererMixin(kanbanView.Renderer) {}
PageKanbanRenderer.props = [
...kanbanView.Renderer.props,
"activeWebsite",
];
PageKanbanRenderer.template = 'website.PageKanbanRenderer';
export const PageKanbanView = {
...kanbanView,
Renderer: PageKanbanRenderer,
Controller: PageKanbanController,
};
registry.category("views").add("website_pages_kanban", PageKanbanView);
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="website.PageKanbanRenderer" t-inherit="web.KanbanRenderer" owl="1">
<xpath expr="//t[@t-if='groupOrRecord.group']//KanbanRecord" position="attributes">
<attribute name="t-if">recordFilter(record, props.list.records)</attribute>
</xpath>
<xpath expr="//div/t/t[2]/KanbanRecord" position="attributes">
<attribute name="t-if">recordFilter(groupOrRecord.record, props.list.records)</attribute>
</xpath>
</t>
<t t-name="website.PageKanbanView" t-inherit="web.KanbanView" owl="1">
<xpath expr="//t[@t-component='props.Renderer']" position="attributes">
<attribute name="activeWebsite">state.activeWebsite</attribute>
</xpath>
<xpath expr="//Layout" position="inside">
<t t-set-slot="control-panel-website-extra-actions">
<t t-call="website.RecordFilter"/>
</t>
</xpath>
</t>
</templates>
@@ -1,78 +1,21 @@
/** @odoo-module **/
import {AddPageDialog} from "../dialog/dialog";
import {PageControllerMixin, PageRendererMixin} from "./page_views_mixin";
import {registry} from '@web/core/registry';
import {listView} from '@web/views/list/list_view';
import {useService} from "@web/core/utils/hooks";
const {onWillStart, useState} = owl;
export class PageListController extends listView.Controller {
/**
* @override
*/
setup() {
super.setup();
this.website = useService('website');
this.websiteSelection = [{id: 0, name: this.env._t("All Websites")}];
this.state = useState({
activeWebsite: this.websiteSelection[0],
});
onWillStart(async () => {
await this.website.fetchWebsites();
this.websiteSelection.push(...this.website.websites);
});
}
export class PageListController extends PageControllerMixin(listView.Controller) {
/**
* @override
*/
onClickCreate() {
if (this.props.resModel === 'website.page') {
return this.dialogService.add(AddPageDialog, {selectWebsite: true});
}
const action = this.props.context.create_action;
if (action) {
if (/^\//.test(action)) {
window.location.replace(action);
return;
}
this.actionService.doAction(action, {
onClose: (data) => {
if (data) {
this.website.goToWebsite({path: data.path});
}
},
});
}
}
onSelectWebsite(website) {
this.state.activeWebsite = website;
return this.createWebsiteContent();
}
}
PageListController.template = `website.PageListView`;
export class PageListRenderer extends listView.Renderer {
/**
* The goal here is to tweak the renderer to display records following some
* rules:
* - All websites (props.activeWebsite.id === 0):
* -> Show all generic/specific records.
* - A website is selected:
* -> Display website-specific records & generic ones (only those without
* specific clones).
*/
recordFilter(record, records) {
return !this.props.activeWebsite.id
|| this.props.activeWebsite.id === record.data.website_id[0]
|| !record.data.website_id[0] && records.filter(rec => rec.data.website_url === record.data.website_url).length === 1;
}
}
export class PageListRenderer extends PageRendererMixin(listView.Renderer) {}
PageListRenderer.props = [
...listView.Renderer.props,
"activeWebsite",
@@ -18,17 +18,7 @@
</xpath>
<xpath expr="//Layout" position="inside">
<t t-set-slot="control-panel-website-extra-actions">
<div class="btn-group" role="toolbar" aria-label="Main actions">
<button class="btn btn-light dropdown-toggle o-no-caret" data-bs-toggle="dropdown" aria-expanded="false">
<i class="me-1 fa fa-globe"/><span t-esc="state.activeWebsite.name"/>
</button>
<div class="dropdown-menu">
<t t-foreach="websiteSelection" t-as="website" t-key="website">
<a role="menuitem" href="#" class="dropdown-item" t-on-click="() => this.onSelectWebsite(website)"><t t-esc="website.name"/></a>
<div t-if="!website.id" class="dropdown-divider"/>
</t>
</div>
</div>
<t t-call="website.RecordFilter"/>
</t>
</xpath>
</t>
@@ -45,4 +35,18 @@
</xpath>
</t>
<t t-name="website.RecordFilter" owl="1">
<div class="btn-group" role="toolbar" aria-label="Main actions" t-if="'website_id' in props.archInfo.fieldNodes">
<button class="btn btn-light dropdown-toggle o-no-caret" data-bs-toggle="dropdown" aria-expanded="false">
<i class="me-1 fa fa-globe"/><span t-esc="state.activeWebsite.name"/>
</button>
<div class="dropdown-menu">
<t t-foreach="websiteSelection" t-as="website" t-key="website">
<a role="menuitem" href="#" class="dropdown-item" t-on-click="() => this.onSelectWebsite(website)"><t t-esc="website.name"/></a>
<div t-if="!website.id" class="dropdown-divider"/>
</t>
</div>
</div>
</t>
</templates>
@@ -0,0 +1,80 @@
/** @odoo-module **/
import {AddPageDialog} from "../dialog/dialog";
import {useService} from "@web/core/utils/hooks";
const {onWillStart, useState} = owl;
/**
* Used to share code and keep the same behaviour on different types of 'website
* content' views:
* - Trigger the 'new content' dialogs when 'CREATE' button is clicked.
* - Add a website selector on ControlPanel (that will be used by the renderer
* to filter content).
*/
export const PageControllerMixin = (component) => class extends component {
/**
* @override
*/
setup() {
super.setup();
this.website = useService('website');
this.dialog = useService('dialog');
this.websiteSelection = [{id: 0, name: this.env._t("All Websites")}];
this.state = useState({
activeWebsite: this.websiteSelection[0],
});
onWillStart(async () => {
await this.website.fetchWebsites();
this.websiteSelection.push(...this.website.websites);
});
}
/**
* Adds the new 'website content' record depending on the targeted model and
* 'create_action' passed in context.
*/
createWebsiteContent() {
if (this.props.resModel === 'website.page') {
return this.dialog.add(AddPageDialog, {selectWebsite: true});
}
const action = this.props.context.create_action;
if (action) {
if (/^\//.test(action)) {
window.location.replace(action);
return;
}
this.actionService.doAction(action, {
onClose: (data) => {
if (data) {
this.website.goToWebsite({path: data.path});
}
},
});
}
}
onSelectWebsite(website) {
this.state.activeWebsite = website;
}
};
export const PageRendererMixin = (component) => class extends component {
/**
* The goal here is to tweak the renderer to display records following some
* rules:
* - All websites (props.activeWebsite.id === 0):
* -> Show all generic/specific records.
* - A website is selected:
* -> Display website-specific records & generic ones (only those without
* specific clones).
*/
recordFilter(record, records) {
return !this.props.activeWebsite.id
|| this.props.activeWebsite.id === record.data.website_id[0]
|| !record.data.website_id[0] && records.filter(rec => rec.data.website_url === record.data.website_url).length === 1;
}
};
@@ -49,32 +49,42 @@
<field name="name">blog.post.kanban</field>
<field name="model">blog.post</field>
<field name="arch" type="xml">
<kanban class="o_kanban_mobile" sample="1">
<kanban js_class="website_pages_kanban" class="o_kanban_mobile" action="open_website_url" type="object" sample="1">
<field name="name"/>
<field name="blog_id"/>
<field name="author_id"/>
<field name="post_date"/>
<field name="website_url"/>
<templates>
<t t-name="kanban-box">
<div class="oe_kanban_global_click">
<div class="row mb4">
<div class="oe_kanban_global_click d-flex flex-column">
<div class="row mb-auto">
<strong class="col-8">
<span t-esc="record.name.value"/>
<span class="o_text_overflow" t-esc="record.name.value"/>
<div class="text-muted" t-if="record.website_id.value">
<i class="fa fa-globe me-1" title="Website"/>
<field name="website_id" groups="website.group_multi_website"/>
</div>
</strong>
<strong class="col-4 text-end">
<span t-esc="record.blog_id.value"/>
</strong>
<div class="col-8">
<i class="fa fa-clock-o" role="img" aria-label="Post date" title="Post date"/><span t-esc="record.post_date.value"/>
<i class="fa fa-clock-o me-1" role="img" aria-label="Post date" title="Post date"/><span t-esc="record.post_date.value"/>
</div>
<div class="col-4 text-end">
<img t-if="record.author_id.raw_value"
t-att-title="record.author_id.value"
t-att-alt="record.author_id.value"
class="oe_kanban_avatar o_image_24_cover"
class="oe_kanban_avatar o_image_24_cover rounded-circle"
t-att-src="kanban_image('res.partner', 'avatar_128', record.author_id.raw_value)"/>
</div>
</div>
<div class="border-top mt-2 pt-2">
<field name="is_published" widget="boolean_toggle"/>
<t t-if="record.is_published.raw_value">Published</t>
<t t-else="">Not Published</t>
</div>
</div>
</t>
</templates>