[REF] survey: convert question_page_one2many
This commit converts the old one2many field to display survey questions and sections to the new WOWL field API. Part-of: odoo/odoo#97984
This commit is contained in:
committed by
Mathieu Duckerts-Antoine
parent
1870b49d31
commit
eac5022455
@@ -88,6 +88,7 @@ sent mails with personal token for the invitation of the survey.
|
||||
'survey/static/src/scss/survey_reports.scss',
|
||||
],
|
||||
'web.assets_backend': [
|
||||
'survey/static/src/question_page/*.js',
|
||||
'survey/static/src/js/fields_section_one2many.js',
|
||||
'survey/static/src/js/fields_form_page_description.js',
|
||||
'survey/static/src/js/survey_renderers.js',
|
||||
@@ -97,7 +98,10 @@ sent mails with personal token for the invitation of the survey.
|
||||
'survey/static/src/scss/survey_templates_results.scss',
|
||||
],
|
||||
'web.assets_tests': [
|
||||
'survey/static/tests/**/*',
|
||||
'survey/static/tests/tours/*.js',
|
||||
],
|
||||
'web.qunit_suite_tests': [
|
||||
'survey/static/tests/components/*.js',
|
||||
],
|
||||
'web.assets_common': [
|
||||
'survey/static/src/js/tours/survey_tour.js',
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import { makeContext } from "@web/core/context";
|
||||
import { ListRenderer } from "@web/views/list/list_renderer";
|
||||
|
||||
const { useEffect } = owl;
|
||||
|
||||
export class QuestionPageListRenderer extends ListRenderer {
|
||||
setup() {
|
||||
super.setup();
|
||||
|
||||
this.discriminant = "is_page";
|
||||
this.fieldsToShow = ["random_questions_count"];
|
||||
this.titleField = "title";
|
||||
|
||||
useEffect(
|
||||
(table) => {
|
||||
if (table) {
|
||||
table.classList.add("o_section_list_view");
|
||||
}
|
||||
},
|
||||
() => [this.tableRef.el]
|
||||
);
|
||||
}
|
||||
|
||||
add(params) {
|
||||
let editable = false;
|
||||
if (params.context && !this.env.isSmall) {
|
||||
const evaluatedContext = makeContext([params.context]);
|
||||
if (evaluatedContext[`default_${this.discriminant}`]) {
|
||||
editable = this.props.editable;
|
||||
}
|
||||
}
|
||||
super.add({ ...params, editable });
|
||||
}
|
||||
|
||||
getColumns(record) {
|
||||
const columns = super.getColumns(record);
|
||||
if (this.isSection(record)) {
|
||||
return this.getSectionColumns(columns);
|
||||
}
|
||||
return columns;
|
||||
}
|
||||
|
||||
getRowClass(record) {
|
||||
const classNames = super.getRowClass(record).split(" ");
|
||||
if (this.isSection(record)) {
|
||||
classNames.push(`o_is_section`, `fw-bold`);
|
||||
}
|
||||
return classNames.join(" ");
|
||||
}
|
||||
|
||||
getSectionColumns(columns) {
|
||||
const sectionColumns = [];
|
||||
|
||||
let titleColumnIndex = 0;
|
||||
for (const col of columns) {
|
||||
if (col.type !== "field") {
|
||||
continue;
|
||||
}
|
||||
if (col.widget === "handle") {
|
||||
titleColumnIndex = 1;
|
||||
sectionColumns.push(col);
|
||||
continue;
|
||||
}
|
||||
if (this.fieldsToShow.includes(col.name) && col.name !== this.titleField) {
|
||||
sectionColumns.push(col);
|
||||
}
|
||||
}
|
||||
|
||||
const colspan = columns.length - sectionColumns.length;
|
||||
const titleCol = columns.find(
|
||||
(col) => col.type === "field" && col.name === this.titleField
|
||||
);
|
||||
sectionColumns.splice(titleColumnIndex, 0, { ...titleCol, colspan });
|
||||
|
||||
return sectionColumns;
|
||||
}
|
||||
|
||||
isInlineEditable(record) {
|
||||
return this.isSection(record) && this.props.editable;
|
||||
}
|
||||
|
||||
isSection(record) {
|
||||
return record.data[this.discriminant];
|
||||
}
|
||||
|
||||
onCellKeydownEditMode(hotkey) {
|
||||
switch (hotkey) {
|
||||
case "enter":
|
||||
case "tab":
|
||||
case "shift+tab": {
|
||||
this.props.list.unselectRecord(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.onCellKeydownEditMode(...arguments);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import { QuestionPageListRenderer } from "./question_page_list_renderer";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { X2ManyField } from "@web/views/fields/x2many/x2many_field";
|
||||
|
||||
class QuestionPageOneToManyField extends X2ManyField {}
|
||||
QuestionPageOneToManyField.components = {
|
||||
...X2ManyField.components,
|
||||
ListRenderer: QuestionPageListRenderer,
|
||||
};
|
||||
QuestionPageOneToManyField.defaultProps = {
|
||||
...X2ManyField.defaultProps,
|
||||
editable: "bottom",
|
||||
};
|
||||
|
||||
registry.category("fields").add("question_page_one2many", QuestionPageOneToManyField);
|
||||
@@ -0,0 +1,257 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import {
|
||||
click,
|
||||
clickEdit,
|
||||
editInput,
|
||||
getFixture,
|
||||
nextTick,
|
||||
triggerHotkey,
|
||||
} from "@web/../tests/helpers/utils";
|
||||
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
|
||||
|
||||
QUnit.module("QuestionPageOneToManyField", (hooks) => {
|
||||
let serverData;
|
||||
let target;
|
||||
|
||||
hooks.beforeEach(() => {
|
||||
target = getFixture();
|
||||
|
||||
serverData = {
|
||||
models: {
|
||||
partner: {
|
||||
fields: { lines: { type: "one2many", relation: "lines_sections" } },
|
||||
records: [
|
||||
{
|
||||
id: 1,
|
||||
lines: [1, 2],
|
||||
},
|
||||
],
|
||||
},
|
||||
lines_sections: {
|
||||
fields: {
|
||||
is_page: { type: "boolean" },
|
||||
title: { type: "char", string: "Title" },
|
||||
random_questions_count: { type: "number", string: "Question Count" },
|
||||
},
|
||||
records: [
|
||||
{
|
||||
id: 1,
|
||||
is_page: true,
|
||||
title: "firstSectionTitle",
|
||||
random_questions_count: 4,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
is_page: false,
|
||||
title: "recordTitle",
|
||||
random_questions_count: 5,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
views: {
|
||||
"lines_sections,false,form": `
|
||||
<form>
|
||||
<field name="title" />
|
||||
</form>
|
||||
`,
|
||||
},
|
||||
};
|
||||
|
||||
setupViewRegistries();
|
||||
});
|
||||
|
||||
QUnit.test("basic rendering", async (assert) => {
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
resId: 1,
|
||||
serverData,
|
||||
arch: `
|
||||
<form>
|
||||
<field name="lines" widget="question_page_one2many">
|
||||
<tree>
|
||||
<field name="is_page" invisible="1" />
|
||||
<field name="title" />
|
||||
<field name="random_questions_count" />
|
||||
</tree>
|
||||
</field>
|
||||
</form>
|
||||
`,
|
||||
});
|
||||
assert.containsOnce(target, ".o_field_x2many .o_list_renderer table.o_section_list_view");
|
||||
assert.containsN(target, ".o_data_row", 2);
|
||||
const rows = target.querySelectorAll(".o_data_row");
|
||||
assert.hasClass(rows[0], "o_is_section");
|
||||
assert.hasClass(rows[0], "fw-bold");
|
||||
assert.strictEqual(rows[0].textContent, "firstSectionTitle4");
|
||||
assert.strictEqual(rows[1].textContent, "recordTitle5");
|
||||
assert.strictEqual(rows[0].querySelector("td[name=title]").getAttribute("colspan"), "1");
|
||||
assert.strictEqual(rows[1].querySelector("td[name=title]").getAttribute("colspan"), null);
|
||||
});
|
||||
|
||||
QUnit.test("click on section behaves as usual in readonly mode", async (assert) => {
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
resId: 1,
|
||||
serverData,
|
||||
arch: `
|
||||
<form>
|
||||
<field name="lines" widget="question_page_one2many">
|
||||
<tree>
|
||||
<field name="is_page" invisible="1" />
|
||||
<field name="title" />
|
||||
<field name="random_questions_count" />
|
||||
</tree>
|
||||
</field>
|
||||
</form>
|
||||
`,
|
||||
});
|
||||
await click(target.querySelector(".o_data_cell"));
|
||||
assert.containsNone(target, ".o_selected_row");
|
||||
assert.containsOnce(target, ".modal .o_form_view_dialog");
|
||||
});
|
||||
|
||||
QUnit.test("click on section edit the section in place", async (assert) => {
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
resId: 1,
|
||||
serverData,
|
||||
arch: `
|
||||
<form>
|
||||
<field name="lines" widget="question_page_one2many">
|
||||
<tree>
|
||||
<field name="is_page" invisible="1" />
|
||||
<field name="title" />
|
||||
<field name="random_questions_count" />
|
||||
</tree>
|
||||
</field>
|
||||
</form>`,
|
||||
});
|
||||
await clickEdit(target);
|
||||
await click(target.querySelector(".o_data_cell"));
|
||||
assert.hasClass(target.querySelector(".o_is_section"), "o_selected_row");
|
||||
assert.containsNone(target, ".modal .o_form_view_dialog");
|
||||
});
|
||||
|
||||
QUnit.test("click on real line opens a dialog", async (assert) => {
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
resId: 1,
|
||||
serverData,
|
||||
arch: `
|
||||
<form>
|
||||
<field name="lines" widget="question_page_one2many">
|
||||
<tree>
|
||||
<field name="is_page" invisible="1" />
|
||||
<field name="title" />
|
||||
<field name="random_questions_count" />
|
||||
</tree>
|
||||
</field>
|
||||
</form>
|
||||
`,
|
||||
});
|
||||
await clickEdit(target);
|
||||
await click(target.querySelector(".o_data_row:nth-child(2) .o_data_cell"));
|
||||
assert.containsNone(target, ".o_selected_row");
|
||||
assert.containsOnce(target, ".modal .o_form_view_dialog");
|
||||
});
|
||||
|
||||
QUnit.test("can create section inline", async (assert) => {
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
resId: 1,
|
||||
serverData,
|
||||
arch: `
|
||||
<form>
|
||||
<field name="lines" widget="question_page_one2many">
|
||||
<tree>
|
||||
<field name="is_page" invisible="1" />
|
||||
<field name="title" />
|
||||
<field name="random_questions_count" />
|
||||
<control>
|
||||
<create string="add line" />
|
||||
<create string="add section" context="{'default_is_page': true}" />
|
||||
</control>
|
||||
</tree>
|
||||
</field>
|
||||
</form>
|
||||
`,
|
||||
});
|
||||
|
||||
await clickEdit(target);
|
||||
assert.containsNone(target, ".o_selected_row");
|
||||
|
||||
await click(target.querySelectorAll(".o_field_x2many_list_row_add a")[1]);
|
||||
assert.containsOnce(target, ".o_selected_row.o_is_section");
|
||||
assert.containsNone(target, ".modal .o_form_view_dialog");
|
||||
});
|
||||
|
||||
QUnit.test("creates real record in form dialog", async (assert) => {
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
resId: 1,
|
||||
serverData,
|
||||
arch: `
|
||||
<form>
|
||||
<field name="lines" widget="question_page_one2many">
|
||||
<tree>
|
||||
<field name="is_page" invisible="1" />
|
||||
<field name="title" />
|
||||
<field name="random_questions_count" />
|
||||
<control>
|
||||
<create string="add line" />
|
||||
<create string="add section" context="{'default_is_page': true}" />
|
||||
</control>
|
||||
</tree>
|
||||
</field>
|
||||
</form>
|
||||
`,
|
||||
});
|
||||
|
||||
await clickEdit(target);
|
||||
await click(target.querySelector(".o_field_x2many_list_row_add a"));
|
||||
assert.containsNone(target, ".o_selected_row");
|
||||
assert.containsOnce(target, ".modal .o_form_view_dialog");
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"press enter with focus in a edited section pass the section in readonly mode",
|
||||
async (assert) => {
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
resId: 1,
|
||||
serverData,
|
||||
arch: `
|
||||
<form>
|
||||
<field name="lines" widget="question_page_one2many">
|
||||
<tree>
|
||||
<field name="is_page" invisible="1" />
|
||||
<field name="title" />
|
||||
<field name="random_questions_count" />
|
||||
</tree>
|
||||
</field>
|
||||
</form>
|
||||
`,
|
||||
});
|
||||
await clickEdit(target);
|
||||
await click(target.querySelector(".o_data_row .o_data_cell"));
|
||||
assert.containsOnce(target, ".o_selected_row.o_is_section");
|
||||
|
||||
await editInput(target, "[name='title'] input", "a");
|
||||
|
||||
triggerHotkey("Enter");
|
||||
await nextTick();
|
||||
|
||||
assert.containsNone(target, ".o_selected_row.o_is_section");
|
||||
assert.strictEqual(target.querySelector(".o_is_section [name=title]").innerText, "a");
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -5,7 +5,7 @@
|
||||
<field name="name">survey.survey.view.form</field>
|
||||
<field name="model">survey.survey</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Survey" class="o_survey_form" js_class="legacy_form">
|
||||
<form string="Survey" class="o_survey_form">
|
||||
<field name="id" invisible="1"/>
|
||||
<field name="session_state" invisible="1"/>
|
||||
<field name="question_ids" invisible="1"/>
|
||||
|
||||
Reference in New Issue
Block a user