diff --git a/addons/mail/static/src/views/fields/assign_user_command_hook.js b/addons/mail/static/src/views/fields/assign_user_command_hook.js
index 6e8a97fac0c..a6e2f5d5b3c 100644
--- a/addons/mail/static/src/views/fields/assign_user_command_hook.js
+++ b/addons/mail/static/src/views/fields/assign_user_command_hook.js
@@ -16,10 +16,7 @@ export function useAssignUserCommand() {
const orm = useService("orm");
const user = useService("user");
const type = component.props.record.fields[component.props.name].type;
- if (
- component.relation !== "res.users" ||
- component.props.record.activeFields[component.props.name].viewType !== "form"
- ) {
+ if (component.relation !== "res.users") {
return;
}
diff --git a/addons/mail/static/src/views/fields/many2many_avatar_user_field/many2many_avatar_user_field.js b/addons/mail/static/src/views/fields/many2many_avatar_user_field/many2many_avatar_user_field.js
index ae6ef298c4a..cbd88dd5211 100644
--- a/addons/mail/static/src/views/fields/many2many_avatar_user_field/many2many_avatar_user_field.js
+++ b/addons/mail/static/src/views/fields/many2many_avatar_user_field/many2many_avatar_user_field.js
@@ -18,7 +18,9 @@ export class Many2ManyTagsAvatarUserField extends Many2ManyTagsAvatarField {
setup() {
super.setup();
this.openChat = useOpenChat(this.relation);
- useAssignUserCommand();
+ if (this.props.withCommand) {
+ useAssignUserCommand();
+ }
}
get tags() {
@@ -44,15 +46,24 @@ export const many2ManyTagsAvatarUserField = {
registry.category("fields").add("many2many_avatar_user", many2ManyTagsAvatarUserField);
export class KanbanMany2ManyTagsAvatarUserField extends ListKanbanMany2ManyTagsAvatarField {
+ static props = {
+ ...ListKanbanMany2ManyTagsAvatarField.props,
+ displayText: { type: Boolean, optional: true },
+ };
+
setup() {
super.setup();
this.openChat = useOpenChat(this.relation);
- useAssignUserCommand();
+ if (this.props.withCommand) {
+ useAssignUserCommand();
+ }
}
get displayText() {
- const isList = this.props.record.activeFields[this.props.name].viewType === "list";
- return (isList && this.props.value.records.length === 1) || !this.props.readonly;
+ return (
+ (this.props.displayText && this.props.value.records.length === 1) ||
+ !this.props.readonly
+ );
}
get tags() {
@@ -75,6 +86,10 @@ export const kanbanMany2ManyTagsAvatarUserField = {
...listKanbanMany2ManyTagsAvatarField,
component: KanbanMany2ManyTagsAvatarUserField,
additionalClasses: ["o_field_many2many_tags_avatar"],
+ extractProps: (fieldInfo) => ({
+ ...listKanbanMany2ManyTagsAvatarField.extractProps(fieldInfo),
+ displayText: fieldInfo.viewType === "list",
+ }),
};
registry.category("fields").add("kanban.many2many_avatar_user", kanbanMany2ManyTagsAvatarUserField);
diff --git a/addons/mail/static/src/views/fields/many2one_avatar_user_field/many2one_avatar_user_field.js b/addons/mail/static/src/views/fields/many2one_avatar_user_field/many2one_avatar_user_field.js
index 7ea2f78989e..117c642eaa9 100644
--- a/addons/mail/static/src/views/fields/many2one_avatar_user_field/many2one_avatar_user_field.js
+++ b/addons/mail/static/src/views/fields/many2one_avatar_user_field/many2one_avatar_user_field.js
@@ -9,11 +9,18 @@ import { useOpenChat } from "@mail/views/open_chat_hook";
import { useAssignUserCommand } from "@mail/views/fields/assign_user_command_hook";
export class Many2OneAvatarUserField extends Many2OneAvatarField {
+ static props = {
+ ...Many2OneAvatarField.props,
+ withCommand: { type: Boolean, optional: true },
+ };
+
setup() {
super.setup();
const relation = this.props.record.fields[this.props.name].relation;
this.openChat = useOpenChat(relation);
- useAssignUserCommand();
+ if (this.props.withCommand) {
+ useAssignUserCommand();
+ }
}
onClickAvatar() {
@@ -26,21 +33,15 @@ export const many2OneAvatarUserField = {
...many2OneAvatarField,
component: Many2OneAvatarUserField,
additionalClasses: ["o_field_many2one_avatar"],
+ extractProps: (fieldInfo) => ({
+ ...many2OneAvatarField.extractProps(fieldInfo),
+ withCommand: fieldInfo.viewType === "form",
+ }),
};
registry.category("fields").add("many2one_avatar_user", many2OneAvatarUserField);
-export class KanbanMany2OneAvatarUserField extends Many2OneAvatarUserField {
- /**
- * All props are normally passed to the Many2OneField however since
- * we add a new one, we need to filter it out.
- */
- get m2oFieldProps() {
- return Object.fromEntries(
- Object.entries(this.props).filter(([key, _val]) => key in Many2OneAvatarField.props)
- );
- }
-}
+export class KanbanMany2OneAvatarUserField extends Many2OneAvatarUserField {}
KanbanMany2OneAvatarUserField.template = "mail.KanbanMany2OneAvatarUserField";
KanbanMany2OneAvatarUserField.props = {
...Many2OneAvatarUserField.props,
diff --git a/addons/mail/static/src/views/fields/many2one_avatar_user_field/many2one_avatar_user_field.xml b/addons/mail/static/src/views/fields/many2one_avatar_user_field/many2one_avatar_user_field.xml
index 3a7c4db0b44..2be39a3990a 100644
--- a/addons/mail/static/src/views/fields/many2one_avatar_user_field/many2one_avatar_user_field.xml
+++ b/addons/mail/static/src/views/fields/many2one_avatar_user_field/many2one_avatar_user_field.xml
@@ -9,7 +9,6 @@
props.readonly and props.displayAvatarName
- m2oFieldProps
diff --git a/addons/project/static/src/components/project_state_selection/project_state_selection.js b/addons/project/static/src/components/project_state_selection/project_state_selection.js
index 0be3a7aef74..cffef1e1fb7 100644
--- a/addons/project/static/src/components/project_state_selection/project_state_selection.js
+++ b/addons/project/static/src/components/project_state_selection/project_state_selection.js
@@ -15,13 +15,6 @@ export class ProjectStateSelectionField extends StateSelectionField {
this.colors = STATUS_COLORS;
}
- /**
- * @override
- */
- get showLabel() {
- return !this.props.hideLabel;
- }
-
/**
* @override
*/
@@ -33,6 +26,10 @@ export class ProjectStateSelectionField extends StateSelectionField {
export const projectStateSelectionField = {
...stateSelectionField,
component: ProjectStateSelectionField,
+ extractProps: (fieldInfo) => ({
+ ...stateSelectionField.extractProps(fieldInfo),
+ hideLabel: !!fieldInfo.options.hideLabel,
+ }),
};
registry.category("fields").add("kanban.project_state_selection", projectStateSelectionField);
diff --git a/addons/project/static/src/views/fields/project_task_priority_switch_field.js b/addons/project/static/src/views/fields/project_task_priority_switch_field.js
index f18494167a5..9d4e0094e21 100644
--- a/addons/project/static/src/views/fields/project_task_priority_switch_field.js
+++ b/addons/project/static/src/views/fields/project_task_priority_switch_field.js
@@ -3,35 +3,28 @@
import { sprintf } from "@web/core/utils/strings";
import { registry } from "@web/core/registry";
import { PriorityField, priorityField } from "@web/views/fields/priority/priority_field";
-import { useCommand } from "@web/core/commands/command_hook";
-import { useState } from "@odoo/owl";
export class PrioritySwitchField extends PriorityField {
- setup() {
- this.state = useState({
- index: -1,
- });
- if (this.props.record.activeFields[this.props.name].viewType !== "form") {
- return;
- }
-
- for (const [id, name] of this.options) {
- useCommand(
- sprintf(this.env._t("Set priority as %s"), name),
- () => this.props.update(id),
- {
- category: "smart_action",
- hotkey: "alt+r",
- isAvailable: () => this.props.value !== id,
- }
- );
- }
+ get commands() {
+ return this.options.map(([id, name]) => [
+ sprintf(this.env._t("Set priority as %s"), name),
+ () => this.updateRecord(id),
+ {
+ category: "smart_action",
+ hotkey: "alt+r",
+ isAvailable: () => this.props.value !== id,
+ },
+ ]);
}
}
export const prioritySwitchField = {
...priorityField,
component: PrioritySwitchField,
+ extractProps: (fieldInfo) => ({
+ ...priorityField.extractProps(fieldInfo),
+ withCommand: fieldInfo.viewType === "form",
+ }),
};
registry.category("fields").add("priority_switch", prioritySwitchField);
diff --git a/addons/purchase_requisition/static/src/widgets/purchase_order_alternatives_widget.js b/addons/purchase_requisition/static/src/widgets/purchase_order_alternatives_widget.js
index 31afa394b5d..e02ec9b3589 100644
--- a/addons/purchase_requisition/static/src/widgets/purchase_order_alternatives_widget.js
+++ b/addons/purchase_requisition/static/src/widgets/purchase_order_alternatives_widget.js
@@ -16,11 +16,13 @@ FieldMany2ManyAltPOsRenderer.recordRowTemplate = "purchase_requisition.AltPOsLis
export class FieldMany2ManyAltPOs extends X2ManyField {
setup() {
+ super.setup();
this.orm = useService("orm");
this.action = useService("action");
- // TODO: this is a terrible hack, make this a proper extension of many2many if/when possible
- this.props.record.activeFields[this.props.name].widget = "many2many";
- super.setup();
+ }
+
+ get isMany2Many() {
+ return true;
}
/**
diff --git a/addons/web/static/src/views/fields/boolean_icon/boolean_icon_field.js b/addons/web/static/src/views/fields/boolean_icon/boolean_icon_field.js
index 338c688d994..3fdf54b0760 100644
--- a/addons/web/static/src/views/fields/boolean_icon/boolean_icon_field.js
+++ b/addons/web/static/src/views/fields/boolean_icon/boolean_icon_field.js
@@ -10,15 +10,12 @@ export class BooleanIconField extends Component {
static props = {
...standardFieldProps,
icon: { type: String, optional: true },
+ label: { type: String, optional: true },
};
static defaultProps = {
icon: "fa-check-square-o",
};
- get label() {
- return this.props.record.activeFields[this.props.name].string;
- }
-
update() {
this.props.record.update({ [this.props.name]: !this.props.value });
}
@@ -28,8 +25,9 @@ export const booleanIconField = {
component: BooleanIconField,
displayName: _lt("Boolean Icon"),
supportedTypes: ["boolean"],
- extractProps: ({ options }) => ({
+ extractProps: ({ options, string }) => ({
icon: options.icon,
+ label: string,
}),
};
diff --git a/addons/web/static/src/views/fields/boolean_icon/boolean_icon_field.xml b/addons/web/static/src/views/fields/boolean_icon/boolean_icon_field.xml
index c16feb215a5..d3b9e5c9cae 100644
--- a/addons/web/static/src/views/fields/boolean_icon/boolean_icon_field.xml
+++ b/addons/web/static/src/views/fields/boolean_icon/boolean_icon_field.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/addons/web/static/src/views/fields/color_picker/color_picker_field.js b/addons/web/static/src/views/fields/color_picker/color_picker_field.js
index 6f7a61db791..df1e146fc54 100644
--- a/addons/web/static/src/views/fields/color_picker/color_picker_field.js
+++ b/addons/web/static/src/views/fields/color_picker/color_picker_field.js
@@ -13,16 +13,13 @@ export class ColorPickerField extends Component {
};
static props = {
...standardFieldProps,
+ canToggle: { type: Boolean },
};
static RECORD_COLORS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
- get canToggle() {
- return this.props.record.activeFields[this.props.name].viewType !== "list";
- }
-
get isExpanded() {
- return !this.canToggle && !this.props.readonly;
+ return !this.props.canToggle && !this.props.readonly;
}
switchColor(colorIndex) {
@@ -33,6 +30,9 @@ export class ColorPickerField extends Component {
export const colorPickerField = {
component: ColorPickerField,
supportedTypes: ["integer"],
+ extractProps: ({ viewType }) => ({
+ canToggle: viewType !== "list",
+ }),
};
registry.category("fields").add("color_picker", colorPickerField);
diff --git a/addons/web/static/src/views/fields/color_picker/color_picker_field.xml b/addons/web/static/src/views/fields/color_picker/color_picker_field.xml
index d7d76139473..3ac645263d5 100644
--- a/addons/web/static/src/views/fields/color_picker/color_picker_field.xml
+++ b/addons/web/static/src/views/fields/color_picker/color_picker_field.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/addons/web/static/src/views/fields/many2many_tags/many2many_tags_field.js b/addons/web/static/src/views/fields/many2many_tags/many2many_tags_field.js
index c1f3530fd4a..1ae1248bbaf 100644
--- a/addons/web/static/src/views/fields/many2many_tags/many2many_tags_field.js
+++ b/addons/web/static/src/views/fields/many2many_tags/many2many_tags_field.js
@@ -41,6 +41,7 @@ export class Many2ManyTagsField extends Component {
createDomain: { type: [Array, Boolean], optional: true },
placeholder: { type: String, optional: true },
nameCreateField: { type: String, optional: true },
+ string: { type: String, optional: true },
};
static defaultProps = {
canCreate: true,
@@ -112,7 +113,7 @@ export class Many2ManyTagsField extends Component {
return this.props.record.evalContext;
}
get string() {
- return this.props.record.activeFields[this.props.name].string;
+ return this.props.string || this.props.record.fields[this.props.name].string || "";
}
getTagProps(record) {
@@ -257,7 +258,7 @@ export const many2ManyTagsField = {
}
return relatedFields;
},
- extractProps: ({ attrs, options }) => {
+ extractProps: ({ attrs, options, string }) => {
const noCreate = Boolean(options.no_create);
const canCreate = attrs.can_create && Boolean(JSON.parse(attrs.can_create)) && !noCreate;
const noQuickCreate = Boolean(options.no_quick_create);
@@ -270,6 +271,7 @@ export const many2ManyTagsField = {
canCreateEdit: canCreate && !noCreateEdit,
createDomain: options.create,
placeholder: attrs.placeholder,
+ string,
};
},
};
diff --git a/addons/web/static/src/views/fields/many2many_tags_avatar/many2many_tags_avatar_field.js b/addons/web/static/src/views/fields/many2many_tags_avatar/many2many_tags_avatar_field.js
index b238a67fa1d..54697cb3ef4 100644
--- a/addons/web/static/src/views/fields/many2many_tags_avatar/many2many_tags_avatar_field.js
+++ b/addons/web/static/src/views/fields/many2many_tags_avatar/many2many_tags_avatar_field.js
@@ -14,6 +14,10 @@ export class Many2ManyTagsAvatarField extends Many2ManyTagsField {
Many2XAutocomplete,
TagsList,
};
+ static props = {
+ ...Many2ManyTagsField.props,
+ withCommand: { type: Boolean, optional: true },
+ };
get tags() {
return super.tags.map((tag) => ({
@@ -27,14 +31,23 @@ export class Many2ManyTagsAvatarField extends Many2ManyTagsField {
export const many2ManyTagsAvatarField = {
...many2ManyTagsField,
component: Many2ManyTagsAvatarField,
+ extractProps: (fieldInfo) => ({
+ ...many2ManyTagsField.extractProps(fieldInfo),
+ withCommand: fieldInfo.viewType === "form",
+ }),
};
registry.category("fields").add("many2many_tags_avatar", many2ManyTagsAvatarField);
export class ListKanbanMany2ManyTagsAvatarField extends Many2ManyTagsAvatarField {
- get itemsVisible() {
- return this.props.record.activeFields[this.props.name].viewType === "list" ? 5 : 3;
- }
+ static props = {
+ ...Many2ManyTagsAvatarField.props,
+ itemsVisible: { type: Number, optional: true },
+ };
+ static defaultProps = {
+ ...Many2ManyTagsAvatarField.defaultProps,
+ itemsVisible: 3,
+ };
getTagProps(record) {
return {
@@ -47,6 +60,10 @@ export class ListKanbanMany2ManyTagsAvatarField extends Many2ManyTagsAvatarField
export const listKanbanMany2ManyTagsAvatarField = {
...many2ManyTagsAvatarField,
component: ListKanbanMany2ManyTagsAvatarField,
+ extractProps: (fieldInfo) => ({
+ ...many2ManyTagsAvatarField.extractProps(fieldInfo),
+ itemsVisible: fieldInfo.viewType === "list" ? 5 : 3,
+ }),
};
registry.category("fields").add("list.many2many_tags_avatar", listKanbanMany2ManyTagsAvatarField);
diff --git a/addons/web/static/src/views/fields/many2many_tags_avatar/many2many_tags_avatar_field.xml b/addons/web/static/src/views/fields/many2many_tags_avatar/many2many_tags_avatar_field.xml
index cc7ca8b9871..03aa3388858 100644
--- a/addons/web/static/src/views/fields/many2many_tags_avatar/many2many_tags_avatar_field.xml
+++ b/addons/web/static/src/views/fields/many2many_tags_avatar/many2many_tags_avatar_field.xml
@@ -6,7 +6,7 @@
class="o_field_tags d-inline-flex flex-wrap mw-100"
t-att-class="{'o_tags_input o_input': !props.readonly}"
>
-
+
key in this.constructor.components.Many2OneField.props
+ )
+ );
+ }
}
export const many2OneAvatarField = {
diff --git a/addons/web/static/src/views/fields/many2one_avatar/many2one_avatar_field.xml b/addons/web/static/src/views/fields/many2one_avatar/many2one_avatar_field.xml
index 3a664202bdf..a7df28e1417 100644
--- a/addons/web/static/src/views/fields/many2one_avatar/many2one_avatar_field.xml
+++ b/addons/web/static/src/views/fields/many2one_avatar/many2one_avatar_field.xml
@@ -7,7 +7,7 @@
-
+
diff --git a/addons/web/static/src/views/fields/priority/priority_field.js b/addons/web/static/src/views/fields/priority/priority_field.js
index 37127192829..9b80ed782c0 100644
--- a/addons/web/static/src/views/fields/priority/priority_field.js
+++ b/addons/web/static/src/views/fields/priority/priority_field.js
@@ -11,15 +11,24 @@ export class PriorityField extends Component {
static template = "web.PriorityField";
static props = {
...standardFieldProps,
+ withCommand: { type: Boolean, optional: true },
};
setup() {
this.state = useState({
index: -1,
});
- if (this.props.record.activeFields[this.props.name].viewType === "form") {
- const commandName = this.env._t("Set priority...");
- useCommand(
+ if (this.props.withCommand) {
+ for (const command of this.commands) {
+ useCommand(...command);
+ }
+ }
+ }
+
+ get commands() {
+ const commandName = this.env._t("Set priority...");
+ return [
+ [
commandName,
() => {
return {
@@ -37,9 +46,9 @@ export class PriorityField extends Component {
],
};
},
- { category: "smart_action", hotkey: "alt+r" }
- );
- }
+ { category: "smart_action", hotkey: "alt+r" },
+ ],
+ ];
}
get tooltipLabel() {
@@ -91,6 +100,9 @@ export const priorityField = {
component: PriorityField,
displayName: _lt("Priority"),
supportedTypes: ["selection"],
+ extractProps: ({ viewType }) => ({
+ withCommand: viewType === "form",
+ }),
};
registry.category("fields").add("priority", priorityField);
diff --git a/addons/web/static/src/views/fields/radio/radio_field.js b/addons/web/static/src/views/fields/radio/radio_field.js
index 4edab220a11..672b59f0a1d 100644
--- a/addons/web/static/src/views/fields/radio/radio_field.js
+++ b/addons/web/static/src/views/fields/radio/radio_field.js
@@ -11,6 +11,7 @@ export class RadioField extends Component {
static props = {
...standardFieldProps,
orientation: { type: String, optional: true },
+ label: { type: String, optional: true },
};
static defaultProps = {
orientation: "vertical",
@@ -38,9 +39,6 @@ export class RadioField extends Component {
get items() {
return RadioField.getItems(this.props.name, this.props.record);
}
- get string() {
- return this.props.record.activeFields[this.props.name].string;
- }
get value() {
switch (this.props.record.fields[this.props.name].type) {
case "selection":
@@ -72,8 +70,9 @@ export const radioField = {
displayName: _lt("Radio"),
supportedTypes: ["many2one", "selection"],
isEmpty: (record, fieldName) => record.data[fieldName] === false,
- extractProps: ({ options }) => ({
+ extractProps: ({ options, string }) => ({
orientation: options.horizontal ? "horizontal" : "vertical",
+ label: string,
}),
legacySpecialData: "_fetchSpecialMany2ones",
};
diff --git a/addons/web/static/src/views/fields/radio/radio_field.xml b/addons/web/static/src/views/fields/radio/radio_field.xml
index ef3db657c32..a74d660f459 100644
--- a/addons/web/static/src/views/fields/radio/radio_field.xml
+++ b/addons/web/static/src/views/fields/radio/radio_field.xml
@@ -5,7 +5,7 @@
diff --git a/addons/web/static/src/views/fields/stat_info/stat_info_field.js b/addons/web/static/src/views/fields/stat_info/stat_info_field.js
index 7f350a08756..5d0e6380249 100644
--- a/addons/web/static/src/views/fields/stat_info/stat_info_field.js
+++ b/addons/web/static/src/views/fields/stat_info/stat_info_field.js
@@ -15,6 +15,7 @@ export class StatInfoField extends Component {
labelField: { type: String, optional: true },
noLabel: { type: Boolean, optional: true },
digits: { type: Array, optional: true },
+ string: { type: String, optional: true },
};
get digits() {
@@ -28,7 +29,7 @@ export class StatInfoField extends Component {
get label() {
return this.props.labelField
? this.props.record.data[this.props.labelField]
- : this.props.record.activeFields[this.props.name].string;
+ : this.props.string;
}
}
@@ -37,7 +38,7 @@ export const statInfoField = {
displayName: _lt("Stat Info"),
supportedTypes: ["float", "integer", "monetary"],
isEmpty: () => false,
- extractProps: ({ attrs, options }) => {
+ extractProps: ({ attrs, options, string }) => {
// Sadly, digits param was available as an option and an attr.
// The option version could be removed with some xml refactoring.
let digits;
@@ -51,6 +52,7 @@ export const statInfoField = {
digits,
labelField: options.label_field,
noLabel: archParseBoolean(attrs.nolabel),
+ string,
};
},
};
diff --git a/addons/web/static/src/views/fields/state_selection/state_selection_field.js b/addons/web/static/src/views/fields/state_selection/state_selection_field.js
index 30827b56f24..ab32f8a6af2 100644
--- a/addons/web/static/src/views/fields/state_selection/state_selection_field.js
+++ b/addons/web/static/src/views/fields/state_selection/state_selection_field.js
@@ -19,6 +19,7 @@ export class StateSelectionField extends Component {
static props = {
...standardFieldProps,
hideLabel: { type: Boolean, optional: true },
+ withCommand: { type: Boolean, optional: true },
};
static defaultProps = {
hideLabel: false,
@@ -30,20 +31,19 @@ export class StateSelectionField extends Component {
blocked: "red",
done: "green",
};
- if (this.props.record.activeFields[this.props.name].viewType !== "form") {
- return;
- }
- const hotkeys = ["D", "F", "G"];
- for (const [index, [value, label]] of this.options.entries()) {
- useCommand(
- sprintf(this.env._t("Set kanban state as %s"), label),
- () => this.updateRecord(value),
- {
- category: "smart_action",
- hotkey: "alt+" + hotkeys[index],
- isAvailable: () => this.props.value !== value,
- }
- );
+ if (this.props.withCommand) {
+ const hotkeys = ["D", "F", "G"];
+ for (const [index, [value, label]] of this.options.entries()) {
+ useCommand(
+ sprintf(this.env._t("Set kanban state as %s"), label),
+ () => this.updateRecord(value),
+ {
+ category: "smart_action",
+ hotkey: "alt+" + hotkeys[index],
+ isAvailable: () => this.props.value !== value,
+ }
+ );
+ }
}
}
get options() {
@@ -61,10 +61,7 @@ export class StateSelectionField extends Component {
return formatSelection(this.currentValue, { selection: this.options });
}
get showLabel() {
- return (
- this.props.record.activeFields[this.props.name].viewType === "list" &&
- !this.props.hideLabel
- );
+ return !this.props.hideLabel;
}
get isReadonly() {
return this.props.record.isReadonly(this.props.name);
@@ -91,8 +88,9 @@ export const stateSelectionField = {
component: StateSelectionField,
displayName: _lt("Label Selection"),
supportedTypes: ["selection"],
- extractProps: ({ options }) => ({
- hideLabel: !!options.hide_label,
+ extractProps: ({ options, viewType }) => ({
+ hideLabel: !!options.hide_label && viewType === "list",
+ withCommand: viewType === "form",
}),
};
diff --git a/addons/web/static/src/views/fields/statusbar/statusbar_field.js b/addons/web/static/src/views/fields/statusbar/statusbar_field.js
index 31b0abf3b2f..95b25ce146a 100644
--- a/addons/web/static/src/views/fields/statusbar/statusbar_field.js
+++ b/addons/web/static/src/views/fields/statusbar/statusbar_field.js
@@ -24,13 +24,14 @@ export class StatusBarField extends Component {
displayName: { type: String, optional: true },
isDisabled: { type: Boolean, optional: true },
visibleSelection: { type: Array, optional: true },
+ withCommand: { type: Boolean, optional: true },
};
static defaultProps = {
visibleSelection: [],
};
setup() {
- if (this.props.record.activeFields[this.props.name].viewType === "form") {
+ if (this.props.withCommand) {
const commandName = sprintf(this.env._t(`Move to %s...`), escape(this.displayName));
useCommand(
commandName,
@@ -225,12 +226,13 @@ export const statusBarField = {
supportedTypes: ["many2one", "selection"],
isEmpty: (record, fieldName) => record.model.env.isSmall && !record.data[fieldName],
legacySpecialData: "_fetchSpecialStatus",
- extractProps: ({ attrs, options }) => ({
+ extractProps: ({ attrs, options, viewType }) => ({
canCreate: Boolean(attrs.can_create),
canWrite: Boolean(attrs.can_write),
isDisabled: !options.clickable,
visibleSelection:
attrs.statusbar_visible && attrs.statusbar_visible.trim().split(/\s*,\s*/g),
+ withCommand: viewType === "form",
}),
};
diff --git a/addons/web/static/src/views/fields/x2many/x2many_field.js b/addons/web/static/src/views/fields/x2many/x2many_field.js
index 94525578ad2..742bdb0c3a7 100644
--- a/addons/web/static/src/views/fields/x2many/x2many_field.js
+++ b/addons/web/static/src/views/fields/x2many/x2many_field.js
@@ -27,31 +27,29 @@ export class X2ManyField extends Component {
...standardFieldProps,
addLabel: { type: String, optional: true },
editable: { type: String, optional: true },
+ viewMode: { type: String, optional: true },
+ widget: { type: String, optional: true },
+ crudOptions: { type: Object, optional: true },
+ string: { type: String, optional: true },
+ views: { type: Object, optional: true },
+ };
+ static defaultProps = {
+ archInfo: {},
};
setup() {
- this.activeField = this.props.record.activeFields[this.props.name];
this.field = this.props.record.fields[this.props.name];
-
- this.isMany2Many =
- this.field.type === "many2many" || this.activeField.widget === "many2many";
-
- this.viewMode = this.activeField.viewMode;
-
const { saveRecord, updateRecord, removeRecord } = useX2ManyCrud(
() => this.list,
this.isMany2Many
);
- let archInfo;
- if (this.viewMode) {
- archInfo = this.activeField.views[this.viewMode];
- } else {
- archInfo = {};
- }
- if (this.viewMode === "kanban") {
- this.creates = archInfo.creates.length
- ? archInfo.creates
+ this.archInfo = this.props.views[this.props.viewMode] || {};
+
+ const { activeActions, creates } = this.archInfo;
+ if (this.props.viewMode === "kanban") {
+ this.creates = creates.length
+ ? creates
: [
{
type: "create",
@@ -60,9 +58,9 @@ export class X2ManyField extends Component {
},
];
}
- const subViewActiveActions = archInfo.activeActions;
+ const subViewActiveActions = activeActions;
this.activeActions = useActiveActions({
- crudOptions: Object.assign({}, this.activeField.options, {
+ crudOptions: Object.assign({}, this.props.crudOptions, {
onDelete: removeRecord,
}),
fieldType: this.isMany2Many ? "many2many" : "one2many",
@@ -86,7 +84,7 @@ export class X2ManyField extends Component {
getList: () => this.list,
saveRecord,
updateRecord,
- withParentId: this.activeField.widget !== "many2many",
+ withParentId: this.props.widget !== "many2many",
});
this._openRecord = (params) => {
const activeElement = document.activeElement;
@@ -100,7 +98,9 @@ export class X2ManyField extends Component {
});
};
this.canOpenRecord =
- this.viewMode === "list" ? !(archInfo.editable || this.props.editable) : true;
+ this.props.viewMode === "list"
+ ? !(this.archInfo.editable || this.props.editable)
+ : true;
const selectCreate = useSelectCreate({
resModel: this.props.value.resModel,
@@ -117,14 +117,26 @@ export class X2ManyField extends Component {
};
}
+ get activeField() {
+ return {
+ views: this.props.views,
+ viewMode: this.props.viewMode,
+ string: this.props.string,
+ };
+ }
+
get displayControlPanelButtons() {
return (
- this.viewMode === "kanban" &&
+ this.props.viewMode === "kanban" &&
("link" in this.activeActions ? this.activeActions.link : this.activeActions.create) &&
!this.props.readonly
);
}
+ get isMany2Many() {
+ return this.field.type === "many2many" || this.props.widget === "many2many";
+ }
+
get list() {
return this.props.value;
}
@@ -165,14 +177,14 @@ export class X2ManyField extends Component {
}
get rendererProps() {
- const archInfo = this.activeField.views[this.viewMode];
+ const { archInfo } = this;
const props = {
archInfo,
list: this.list,
openRecord: this.openRecord.bind(this),
};
- if (this.viewMode === "kanban") {
+ if (this.props.viewMode === "kanban") {
const recordsDraggable = !this.props.readonly && archInfo.recordsDraggable;
props.archInfo = { ...archInfo, recordsDraggable };
props.readonly = this.props.readonly;
@@ -227,7 +239,7 @@ export class X2ManyField extends Component {
const domain = record.getFieldDomain(this.props.name).toList();
context = makeContext([record.getFieldContext(this.props.name), context]);
if (this.isMany2Many) {
- const { string } = this.props.record.activeFields[this.props.name];
+ const { string } = this.props;
const title = sprintf(this.env._t("Add: %s"), string);
return this.selectCreate({ domain, context, title });
}
@@ -258,9 +270,19 @@ export const x2ManyField = {
displayName: _lt("Relational table"),
supportedTypes: ["one2many", "many2many"],
useSubView: true,
- extractProps: ({ attrs }) => ({
- addLabel: attrs["add-label"],
- }),
+ extractProps: ({ attrs, viewMode, views, widget, options, string }) => {
+ const props = {
+ addLabel: attrs["add-label"],
+ viewMode,
+ views,
+ crudOptions: options,
+ string,
+ };
+ if (widget) {
+ props.widget = widget;
+ }
+ return props;
+ },
};
registry.category("fields").add("one2many", x2ManyField);
diff --git a/addons/web/static/src/views/fields/x2many/x2many_field.xml b/addons/web/static/src/views/fields/x2many/x2many_field.xml
index 9669dc42899..03a0a0252ce 100644
--- a/addons/web/static/src/views/fields/x2many/x2many_field.xml
+++ b/addons/web/static/src/views/fields/x2many/x2many_field.xml
@@ -2,7 +2,7 @@
-