[IMP] web,*: better classes handling in view archs

**Before this commit**
- The optional "class" attribute set on the root node of a view arch
  is ignored, except for the kanban view which has a custom
  way of using it.
- The optional "js_class" attribute set on the root node of a view arch
  does not have any impact on the class names passed to its controller.

**After this commit**
The content of the optional attribute "class" set on the root node of an
arch like in

<list class="o_custom_class">
    ...
</list>

as well as an additionnal class derived [1] from the value of the
"js_class" attribute set on the root node of an arch like in

<list js_class="extended_list">
    ...
</list>

will both be found in the prop "className" of any view controller.

[1] a js_class value of "xyz" yields to the class "o_xyz_view"

**Note on this commit**
The kanban view was already appending the root node class attribute
to its renderer element. This is no longer the case and some styling
rules has been adapted.

closes odoo/odoo#113014

Related: odoo/enterprise#37265
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
Co-authored-by: Mathieu Duckerts-Antoine <dam@odoo.com>
Co-authored-by: Bruno Boi <boi@odoo.com>
This commit is contained in:
Bruno Boi
2023-03-01 17:01:03 +01:00
co-authored by Mathieu Duckerts-Antoine
parent af00a92b3e
commit d19037e141
46 changed files with 121 additions and 104 deletions
@@ -1,4 +1,4 @@
.o_kanban_dashboard.o_account_kanban {
.o_kanban_dashboard.o_account_kanban .o_kanban_renderer {
&.o_kanban_ungrouped .o_account_dashboard_header {
margin: (0 - $o-kanban-record-margin) ($o-kanban-record-margin - $o-horizontal-padding) $o-kanban-record-margin;
@@ -1,4 +1,4 @@
.o_kanban_dashboard.o_account_kanban {
.o_kanban_dashboard.o_account_kanban .o_kanban_renderer {
.o_kanban_record {
@include media-breakpoint-up(sm) {
+1 -1
View File
@@ -6,7 +6,7 @@
}
}
.o_opportunity_kanban {
.o_opportunity_kanban .o_kanban_renderer {
.ribbon {
&::before, &::after {
display: none;
@@ -1,4 +1,4 @@
.o_crm_team_member_kanban {
.o_crm_team_member_kanban .o_kanban_renderer {
.o_member_assignment div.oe_gauge {
width: 100px;
height: 80px;
+2 -2
View File
@@ -1,4 +1,4 @@
.o_kanban_view .o_event_kanban_view {
.o_kanban_view.o_event_kanban_view .o_kanban_renderer {
.o_kanban_record > div {
min-height: 140px;
}
@@ -17,7 +17,7 @@
}
}
.o_kanban_view .o_event_attendee_kanban_view {
.o_kanban_view.o_event_attendee_kanban_view .o_kanban_renderer {
@media (max-width: 768px) {
.o_event_registration_kanban {
min-height: 80px;
@@ -113,7 +113,7 @@
<field name="name">Badge Kanban View</field>
<field name="model">gamification.badge</field>
<field name="arch" type="xml">
<kanban class="o_kanban_badge">
<kanban>
<field name="id"/>
<field name="name"/>
<field name="description"/>
+2 -2
View File
@@ -1,4 +1,4 @@
.o_kanban_dashboard.o_hr_department_kanban {
.o_kanban_dashboard.o_hr_department_kanban .o_kanban_renderer {
--KanbanRecord-width: 450px;
--KanbanRecord-width-small: 350px;
}
@@ -40,7 +40,7 @@
}
}
.o_hr_employee_kanban {
.o_hr_employee_kanban .o_kanban_renderer {
.o_employee_availability {
margin: 0 1px;
}
@@ -98,7 +98,7 @@
<field name="model">hr.employee</field>
<field name="priority">99</field>
<field name="arch" type="xml">
<kanban class="o_hr_employee_attendance_kanban" create="false" action="action_employee_kiosk_confirm" type="object">
<kanban create="false" action="action_employee_kiosk_confirm" type="object">
<field name="attendance_state"/>
<field name="hours_today"/>
<field name="total_overtime"/>
@@ -1,6 +1,6 @@
.hr_expense {
@include media-breakpoint-up(md) {
&.o_list_view, &.o_kanban_renderer {
&.o_list_view, &.o_kanban_view .o_kanban_renderer {
min-height: auto;
}
}
@@ -1,6 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="hr_expense.KanbanRenderer" t-inherit="web.KanbanRenderer" t-inherit-mode="primary" owl="1">
<xpath expr="//div[hasclass('o_kanban_renderer')]" position="attributes">
<attribute name="class" add="position-relative h-auto" separator=" "/>
</xpath>
<xpath expr="//div[hasclass('o_kanban_renderer')]" position="before">
<div t-if="dragState.showDragZone" class="o_dropzone">
<i class="fa fa-upload fa-10x"></i>
+1 -1
View File
@@ -245,7 +245,7 @@
<field name="name">hr.expense.kanban</field>
<field name="model">hr.expense</field>
<field name="arch" type="xml">
<kanban class="o_kanban_mobile hr_expense position-relative h-auto" sample="1" js_class="hr_expense_kanban">
<kanban class="o_kanban_mobile hr_expense" sample="1" js_class="hr_expense_kanban">
<field name="name"/>
<field name="employee_id"/>
<field name="total_amount"/>
@@ -1,5 +1,5 @@
.o_kanban_renderer.o_kanban_dashboard {
&.o_hr_recruitment_kanban {
.o_kanban_dashboard.o_hr_recruitment_kanban {
.o_kanban_renderer {
&.o_kanban_ungrouped .o_kanban_record {
width: 450px;
&:not(.o_kanban_ghost) {
@@ -62,8 +62,8 @@
}
}
.o_kanban_renderer {
&.o_kanban_applicant {
.o_kanban_applicant {
.o_kanban_renderer {
.ribbon {
&::before, &::after {
display: none;
@@ -1,3 +1,3 @@
.o_project_kanban .oe_kanban_align.badge {
.o_project_kanban .o_kanban_renderer .oe_kanban_align.badge {
color: inherit;
}
@@ -1,3 +1,3 @@
.o_kanban_renderer.o_maintenance_team_kanban {
.o_maintenance_team_kanban .o_kanban_renderer {
--KanbanRecord-width: 420px;
}
@@ -107,7 +107,10 @@
margin-bottom: 8px;
}
}
&.o_kanban_mailing_list {
}
.o_kanban_mailing_list {
.o_kanban_renderer {
.o_kanban_group:not(.o_column_folded) {
flex-basis: 380px
}
@@ -1,5 +1,5 @@
.o_kanban_dashboard{
&.o_mrp_workorder_kanban {
&.o_mrp_workorder_kanban .o_kanban_renderer {
.o_kanban_group:not(.o_column_folded) {
width: 400px + $o-kanban-group-padding;
}
@@ -17,14 +17,12 @@
.o_kanban_workorder_title {
flex-basis: 40%;
}
.o_kanban_workorder_date {
}
.o_kanban_workorder_status {
flex-basis: 20%;
}
}
}
&.o_workcenter_kanban {
&.o_workcenter_kanban .o_kanban_renderer {
.o_kanban_group:not(.o_column_folded) {
width: 400px + $o-kanban-group-padding;
}
+1 -1
View File
@@ -5,7 +5,7 @@
<field name="name">mrp.document kanban.mrp</field>
<field name="model">mrp.document</field>
<field name="arch" type="xml">
<kanban js_class="mrp_documents_kanban" class="o_mrp_documents_kanban_view" create="false">
<kanban js_class="mrp_documents_kanban" create="false">
<field name="ir_attachment_id"/>
<field name="mimetype"/>
<field name="type"/>
+1 -1
View File
@@ -76,7 +76,7 @@
<field name="name">note.note.kanban</field>
<field name="model">note.note</field>
<field name="arch" type="xml">
<kanban default_group_by="stage_id" class="oe_notes oe_kanban_quickcreate_textarea o_kanban_small_column">
<kanban default_group_by="stage_id" class="o_kanban_small_column">
<field name="color"/>
<field name="sequence"/>
<field name="name"/>
@@ -1,4 +1,4 @@
.o_kanban_renderer.o_kanban_dashboard.o_pos_kanban.o_kanban_ungrouped {
.o_kanban_dashboard.o_pos_kanban .o_kanban_renderer.o_kanban_ungrouped {
.o_kanban_record {
width: 500px;
}
@@ -81,7 +81,7 @@
<field name="name">Product.template.product.kanban</field>
<field name="model">product.template</field>
<field name="arch" type="xml">
<kanban sample="1" class="o_kanban_product_template">
<kanban sample="1">
<field name="id"/>
<field name="product_variant_count"/>
<field name="currency_id"/>
@@ -1,4 +1,4 @@
.o_kanban_renderer.o_kanban_dashboard.o_project_kanban {
.o_kanban_dashboard.o_project_kanban .o_kanban_renderer {
.o_project_kanban_main {
max-width: 300px;
@@ -37,7 +37,7 @@
cursor: pointer;
}
.o_kanban_project_tasks .o_field_many2manytags, .o_kanban_tags{
.o_kanban_project_tasks .o_kanban_renderer .o_field_many2manytags, .o_kanban_tags{
margin: 0px;
}
@@ -1,4 +1,4 @@
.o_kanban_project_tasks {
.o_kanban_project_tasks .o_kanban_renderer {
div.o_field_many2many_avatar_user[name="user_ids"] {
margin-left: 6px;
}
@@ -1,4 +1,4 @@
.o_pupdate_kanban {
.o_project_update_kanban_view .o_kanban_renderer {
overflow: auto;
&.o_kanban_ungrouped {
padding:0px;
@@ -12,7 +12,7 @@ function openProjectUpdateAndReturnToTasks(view, viewClass) {
}, {
trigger: ".o-kanban-button-new",
content: "Create a new update from project task view : " + view,
extra_trigger: '.o_pupdate_kanban',
extra_trigger: '.o_project_update_kanban_view',
}, {
trigger: "button.o_form_button_cancel",
content: "Discard project update from project task view : " + view,
@@ -66,7 +66,7 @@
<field name="name">project.update.view.kanban</field>
<field name="model">project.update</field>
<field name="arch" type="xml">
<kanban class="o_pupdate_kanban" sample="1" js_class="project_update_kanban">
<kanban sample="1" js_class="project_update_kanban">
<field name="color"/>
<templates>
<t t-name="kanban-box">
@@ -1,4 +1,4 @@
.o_kanban_renderer .o_rating_rating_kanban {
.o_rating_rating_kanban .o_kanban_renderer {
.o_kanban_record {
width: 350px;
}
@@ -1,8 +1,8 @@
.o_kanban_renderer.o_crm_team_kanban {
.o_crm_team_kanban .o_kanban_renderer {
--KanbanRecord-width: 400px;
}
.o_kanban_renderer.o_crm_team_member_kanban {
.o_crm_team_member_kanban .o_kanban_renderer {
--KanbanRecord-width: 350px;
.o_kanban_group:not(.o_column_folded) {
@@ -129,7 +129,7 @@
<field name="name">stock.picking.type.kanban</field>
<field name="model">stock.picking.type</field>
<field name="arch" type="xml">
<kanban class="o_kanban_dashboard o_emphasize_colors o_stock_kanban" create="0" group_create="false">
<kanban class="o_kanban_dashboard o_emphasize_colors" create="0" group_create="false">
<field name="color"/>
<field name="code" readonly="1"/>
<field name="count_picking_ready"/>
@@ -1,5 +1,5 @@
// KANBAN VIEW
.o_survey_survey_view_kanban {
.o_survey_view_kanban_view .o_kanban_renderer {
// Common: left semi-trophy icon for certifications
.o_survey_kanban_card_certification {
background-image:
+1 -1
View File
@@ -209,7 +209,7 @@
<field name="name">survey.survey.view.kanban</field>
<field name="model">survey.survey</field>
<field name="arch" type="xml">
<kanban class="o_survey_survey_view_kanban" js_class="survey_view_kanban">
<kanban js_class="survey_view_kanban">
<field name="active"/>
<field name="certification"/>
<field name="color"/>
+1 -1
View File
@@ -1,4 +1,4 @@
.o_kanban_renderer.o_utm_kanban {
.o_utm_kanban .o_kanban_renderer {
--KanbanRecord-width: #{380px - 2 * ($grid-gutter-width * .25)};
--KanbanGroup-padding-h: #{$grid-gutter-width * .25};
--KanbanGroup-padding-bottom: #{$grid-gutter-width};
@@ -35,7 +35,6 @@ export class KanbanArchParser extends XMLParser {
parse(arch, models, modelName) {
const fields = models[modelName];
const xmlDoc = this.parseXML(arch);
const className = xmlDoc.getAttribute("class") || null;
let defaultOrder = stringToOrderBy(xmlDoc.getAttribute("default_order") || null);
const defaultGroupBy = xmlDoc.getAttribute("default_group_by");
const limit = xmlDoc.getAttribute("limit");
@@ -171,7 +170,6 @@ export class KanbanArchParser extends XMLParser {
arch,
activeActions,
activeFields,
className,
creates,
defaultGroupBy,
fieldNodes,
@@ -455,10 +455,6 @@
@include media-breakpoint-up(md) {
--KanbanGroup-width: calc(var(--KanbanRecord-width) + (2 * var(--KanbanGroup-padding-h)));
&.o_kanban_small_column {
--KanbanGroup-width: calc(var(--KanbanRecord--small-width) + (2 * var(--KanbanGroup-padding-h)));
}
}
.o_kanban_group,
@@ -596,12 +592,6 @@
}
}
&.o_kanban_mobile .o_kanban_record {
div.label {
@include o-text-overflow;
}
}
// Records colours
@include o-kanban-record-color;
@@ -612,6 +602,19 @@
}
}
.o_kanban_mobile .o_kanban_renderer .o_kanban_record {
div.label {
@include o-text-overflow;
}
}
.o_kanban_small_column .o_kanban_renderer.o_kanban_grouped {
@include media-breakpoint-up(md) {
--KanbanGroup-width: calc(var(--KanbanRecord--small-width) + (2 * var(--KanbanGroup-padding-h)));
}
}
// ------- Sample mode -------
.o_kanban_view .o_view_sample_data {
// all records
@@ -1,4 +1,4 @@
.o_kanban_dashboard {
.o_kanban_dashboard .o_kanban_renderer {
// ----------------------------------------------------------------------------
// Customize kanbanView default values
@@ -193,9 +193,11 @@
);
padding: $o-kanban-record-margin;
}
}
.o_kanban_dashboard.o_emphasize_colors .o_kanban_renderer {
// Emphasize records' colors when necessary
&.o_emphasize_colors .o_kanban_record::after {
.o_kanban_record::after {
width: $o-kanban-color-border-width * 2;
}
}
@@ -3,7 +3,7 @@
<t t-name="web.KanbanRenderer" owl="1">
<div class="o_kanban_renderer o_renderer d-flex"
t-attf-class="{{ props.list.isGrouped ? 'o_kanban_grouped align-content-stretch' : 'o_kanban_ungrouped align-content-start flex-wrap justify-content-start' }} {{ props.archInfo.className or '' }}"
t-attf-class="{{ props.list.isGrouped ? 'o_kanban_grouped align-content-stretch' : 'o_kanban_ungrouped align-content-start flex-wrap justify-content-start' }}"
t-ref="root"
>
<t t-foreach="getGroupsOrRecords()" t-as="groupOrRecord" t-key="groupOrRecord.key">
+8 -1
View File
@@ -268,11 +268,18 @@ export class View extends Component {
let subType = rootNode.getAttribute("js_class");
const bannerRoute = rootNode.getAttribute("banner_route");
const sample = rootNode.getAttribute("sample");
const classList = [
"o_view_controller",
`o_${type}_view`,
...(props.className || "").split(" "),
...(rootNode.getAttribute("class") || "").split(" "),
];
// determine ViewClass to instantiate (if not already done)
if (subType) {
if (viewRegistry.contains(subType)) {
descr = viewRegistry.get(subType);
classList.push(`o_${subType}_view`);
} else {
subType = null;
}
@@ -304,7 +311,7 @@ export class View extends Component {
relatedModels,
resModel,
useSampleModel: false,
className: `${props.className} o_view_controller o_${this.env.config.viewType}_view`,
className: [...new Set(classList)].filter((c) => c).join(" "),
};
if (viewDescription.custom_view_id) {
// for dashboard
@@ -357,8 +357,8 @@ QUnit.module("Views", (hooks) => {
},
});
assert.hasClass(target.querySelector(".o_kanban_view"), "o_kanban_test");
assert.hasClass(target.querySelector(".o_kanban_renderer"), "o_kanban_ungrouped");
assert.hasClass(target.querySelector(".o_kanban_renderer"), "o_kanban_test");
assert.containsN(target, ".o_kanban_record:not(.o_kanban_ghost)", 4);
assert.containsN(target, ".o_kanban_ghost", 6);
assert.containsOnce(target, ".o_kanban_record:contains(gnap)");
@@ -432,8 +432,8 @@ QUnit.module("Views", (hooks) => {
"bg-100",
"o_kanban_group should have a background"
);
assert.hasClass(target.querySelector(".o_kanban_view"), "o_kanban_test");
assert.hasClass(target.querySelector(".o_kanban_renderer"), "o_kanban_grouped");
assert.hasClass(target.querySelector(".o_kanban_renderer"), "o_kanban_test");
assert.containsN(target, ".o_kanban_group", 2);
assert.containsOnce(target, ".o_kanban_group:first-child .o_kanban_record");
assert.containsN(target, ".o_kanban_group:nth-child(2) .o_kanban_record", 3);
+37 -34
View File
@@ -479,12 +479,8 @@ QUnit.module("Views", (hooks) => {
patchWithCleanup(ToyController.prototype, {
setup() {
this._super();
const {
irFilters,
searchViewArch,
searchViewFields,
searchViewId,
} = this.props.info;
const { irFilters, searchViewArch, searchViewFields, searchViewId } =
this.props.info;
assert.strictEqual(searchViewArch, serverData.views["animal,false,search"]);
assert.deepEqual(searchViewFields, serverData.models.animal.fields);
assert.strictEqual(searchViewId, false);
@@ -527,12 +523,8 @@ QUnit.module("Views", (hooks) => {
patchWithCleanup(ToyController.prototype, {
setup() {
this._super();
const {
irFilters,
searchViewArch,
searchViewFields,
searchViewId,
} = this.props.info;
const { irFilters, searchViewArch, searchViewFields, searchViewId } =
this.props.info;
assert.strictEqual(searchViewArch, `<search/>`);
assert.deepEqual(searchViewFields, {});
assert.strictEqual(searchViewId, false);
@@ -571,12 +563,8 @@ QUnit.module("Views", (hooks) => {
patchWithCleanup(ToyController.prototype, {
setup() {
this._super();
const {
irFilters,
searchViewArch,
searchViewFields,
searchViewId,
} = this.props.info;
const { irFilters, searchViewArch, searchViewFields, searchViewId } =
this.props.info;
assert.strictEqual(searchViewArch, `<search/>`);
assert.deepEqual(searchViewFields, {});
assert.strictEqual(searchViewId, undefined);
@@ -614,12 +602,8 @@ QUnit.module("Views", (hooks) => {
patchWithCleanup(ToyController.prototype, {
setup() {
this._super();
const {
irFilters,
searchViewArch,
searchViewFields,
searchViewId,
} = this.props.info;
const { irFilters, searchViewArch, searchViewFields, searchViewId } =
this.props.info;
assert.strictEqual(searchViewArch, `<search/>`);
assert.deepEqual(searchViewFields, {});
assert.strictEqual(searchViewId, false);
@@ -679,12 +663,8 @@ QUnit.module("Views", (hooks) => {
patchWithCleanup(ToyController.prototype, {
setup() {
this._super();
const {
irFilters,
searchViewArch,
searchViewFields,
searchViewId,
} = this.props.info;
const { irFilters, searchViewArch, searchViewFields, searchViewId } =
this.props.info;
assert.strictEqual(searchViewArch, `<search/>`);
assert.deepEqual(searchViewFields, {});
assert.strictEqual(searchViewId, undefined);
@@ -1425,7 +1405,7 @@ QUnit.module("Views", (hooks) => {
});
assert.deepEqual(domain, [[0, "=", 1]]);
assert.deepEqual(groupBy, ["birthday"]);
assert.deepEqual(orderBy, [{name: "bar", asc: true}]);
assert.deepEqual(orderBy, [{ name: "bar", asc: true }]);
}
}
ToyController.template = xml`<div/>`;
@@ -1439,7 +1419,7 @@ QUnit.module("Views", (hooks) => {
domain: [[0, "=", 1]],
groupBy: ["birthday"],
context: { key: "val" },
orderBy: [{name: "bar", asc: true}],
orderBy: [{ name: "bar", asc: true }],
};
await mount(View, target, { env, props });
}
@@ -1593,7 +1573,7 @@ QUnit.module("Views", (hooks) => {
});
assert.deepEqual(domain, ["&", [0, "=", 1], [1, "=", 1]]);
assert.deepEqual(groupBy, ["name"]);
assert.deepEqual(orderBy, [{name: "bar", asc: true}]);
assert.deepEqual(orderBy, [{ name: "bar", asc: true }]);
}
}
ToyController.template = xml`<div/>`;
@@ -1607,12 +1587,35 @@ QUnit.module("Views", (hooks) => {
domain: [[0, "=", 1]],
groupBy: ["birthday"],
context: { search_default_filter: 1, search_default_group_by: 1 },
orderBy: [{name: "bar", asc: true}],
orderBy: [{ name: "bar", asc: true }],
};
await mount(View, target, { env, props });
}
);
QUnit.test("multiple ways to pass classes for styling", async (assert) => {
const env = await makeTestEnv({ serverData });
const props = {
resModel: "animal",
type: "toy",
className: "o_custom_class_from_props_1 o_custom_class_from_props_2",
arch: `
<toy
js_class="toy_imp"
class="o_custom_class_from_arch_1 o_custom_class_from_arch_2"
/>
`,
fields: {},
};
await mount(View, target, { env, props });
const view = target.querySelector(".o_toy_view");
assert.hasClass(view, "o_toy_imp_view", "should have the class from js_class attribute");
assert.hasClass(view, "o_custom_class_from_props_1", "should have the class from props");
assert.hasClass(view, "o_custom_class_from_props_2", "should have the class from props");
assert.hasClass(view, "o_custom_class_from_arch_1", "should have the class from arch");
assert.hasClass(view, "o_custom_class_from_arch_2", "should have the class from arch");
});
////////////////////////////////////////////////////////////////////////////
// update props
////////////////////////////////////////////////////////////////////////////
@@ -195,7 +195,7 @@
display: contents;
}
.o_kanban_renderer.o_theme_kanban {
.o_theme_preview_kanban_view .o_kanban_renderer {
$o-theme-kanban-gray: #fcfcfc;
/// Un-grouped Layout (default)
@@ -1,4 +1,4 @@
.o_wvisitor_kanban {
.o_wvisitor_kanban .o_kanban_renderer {
&.o_kanban_ungrouped {
padding:0px;
.o_kanban_record {
+1 -1
View File
@@ -228,7 +228,7 @@
<field name="name">Themes Kanban</field>
<field name="model">ir.module.module</field>
<field name="arch" type="xml">
<kanban create="false" class="o_theme_kanban" default_order="state,sequence,name" js_class="theme_preview_kanban">
<kanban create="false" default_order="state,sequence,name" js_class="theme_preview_kanban">
<field name="icon"/>
<field name="summary"/>
<field name="name"/>
@@ -1,4 +1,4 @@
.o_kanban_view .o_slide_kanban {
.o_kanban_view.o_slide_kanban .o_kanban_renderer {
--KanbanRecord-width: 400px;
.o_kanban_slides_card_manage_pane {
@@ -236,7 +236,7 @@
<field name="name">slide.channel.view.kanban</field>
<field name="model">slide.channel</field>
<field name="arch" type="xml">
<kanban string="eLearning Overview" class="o_emphasize_colors o_kanban_dashboard o_slide_kanban breadcrumb_item active" edit="false" sample="1">
<kanban string="eLearning Overview" class="o_emphasize_colors o_kanban_dashboard o_slide_kanban" edit="false" sample="1">
<field name="color"/>
<field name="enroll"/>
<field name="website_published"/>
+6 -6
View File
@@ -12,24 +12,24 @@
width: 77%;
}
.o_kanban_view .o_modules_kanban .oe_module_vignette,
.o_kanban_view.o_modules_kanban .o_kanban_renderer .oe_module_vignette,
.o_modules_field .o_modules_kanban .oe_module_vignette {
align-items: center;
display: flex;
}
.o_kanban_view .o_modules_kanban .o_kanban_record .o_dropdown_kanban,
.o_modules_field .o_modules_kanban .o_kanban_record .o_dropdown_kanban {
.o_kanban_view.o_modules_kanban .o_kanban_renderer .o_kanban_record .o_dropdown_kanban,
.o_modules_field .o_modules_kanban .o_kanban_renderer .o_kanban_record .o_dropdown_kanban {
visibility: visible;
opacity: 0.5;
}
.o_kanban_view .o_modules_kanban .o_kanban_record:hover .o_dropdown_kanban,
.o_kanban_view .o_modules_kanban .o_kanban_record .o_dropdown_kanban.show {
.o_kanban_view.o_modules_kanban .o_kanban_renderer .o_kanban_record:hover .o_dropdown_kanban,
.o_kanban_view.o_modules_kanban .o_kanban_renderer .o_kanban_record .o_dropdown_kanban.show {
opacity: 1;
}
.o_modules_field .o_modules_kanban {
.o_modules_field .o_modules_kanban .o_kanban_renderer {
--KanbanRecord-width: 280px;
--KanbanRecord-width-small: 280px;
}
+1 -1
View File
@@ -456,7 +456,7 @@
<field name="name">res.partner.kanban</field>
<field name="model">res.partner</field>
<field name="arch" type="xml">
<kanban class="o_res_partner_kanban" sample="1">
<kanban sample="1">
<field name="id"/>
<field name="color"/>
<field name="display_name"/>