[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:
Lucas Perais
2022-08-29 13:49:10 +02:00
committed by Mathieu Duckerts-Antoine
parent 1870b49d31
commit eac5022455
5 changed files with 379 additions and 2 deletions
+5 -1
View File
@@ -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");
}
);
});
+1 -1
View File
@@ -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"/>