[REF] *: register field descriptors instead of components

Before this commit, the field's description was stored on the
component and this component was then registered.

Now, an object describing the field is used on registration the same way
as it is done for views since https://github.com/odoo/odoo/commit/b828cfc72c587d0b73fcc5459695705640437671.
This split the component's description (props, template, ...) of
the field's description (displayName, supportedTypes, ...) and makes
it clearer.

closes odoo/odoo#112498

Task: 3171520
Related: odoo/enterprise#37105
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
Michael (mcm)
2023-02-16 14:13:32 +01:00
parent d645518638
commit 9f4622492c
174 changed files with 2365 additions and 1693 deletions
@@ -88,6 +88,10 @@ export class AccountPaymentField extends Component {
}
}
AccountPaymentField.template = "account.AccountPaymentField";
AccountPaymentField.supportedTypes = ["char"];
registry.category("fields").add("payment", AccountPaymentField);
export const accountPaymentField = {
component: AccountPaymentField,
supportedTypes: ["char"],
};
registry.category("fields").add("payment", accountPaymentField);
@@ -21,4 +21,6 @@ class ShowResequenceRenderer extends Component {
ShowResequenceRenderer.template = "account.ResequenceRenderer";
ShowResequenceRenderer.components = { ChangeLine };
registry.category("fields").add("account_resequence_widget", ShowResequenceRenderer);
registry.category("fields").add("account_resequence_widget", {
component: ShowResequenceRenderer,
});
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { SelectionField } from "@web/views/fields/selection/selection_field";
import { SelectionField, selectionField } from "@web/views/fields/selection/selection_field";
export class AccountTypeSelection extends SelectionField {
get hierarchyOptions() {
@@ -20,4 +20,9 @@ export class AccountTypeSelection extends SelectionField {
}
AccountTypeSelection.template = "account.AccountTypeSelection";
registry.category("fields").add("account_type_selection", AccountTypeSelection);
export const accountTypeSelection = {
...selectionField,
component: AccountTypeSelection,
};
registry.category("fields").add("account_type_selection", accountTypeSelection);
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { Many2ManyTagsField } from "@web/views/fields/many2many_tags/many2many_tags_field";
import { Many2ManyTagsField, many2ManyTagsField } from "@web/views/fields/many2many_tags/many2many_tags_field";
const { onWillUpdateProps } = owl;
@@ -46,4 +46,9 @@ export class AutosaveMany2ManyTagsField extends Many2ManyTagsField {
}
}
registry.category("fields").add("autosave_many2many_tags", AutosaveMany2ManyTagsField);
export const autosaveMany2ManyTagsField = {
...many2ManyTagsField,
component: AutosaveMany2ManyTagsField,
};
registry.category("fields").add("autosave_many2many_tags", autosaveMany2ManyTagsField);
@@ -28,4 +28,6 @@ class ShowGroupedList extends Component {
ShowGroupedList.template = "account.GroupedListTemplate";
ShowGroupedList.components = { ListGroup };
registry.category("fields").add("grouped_view_widget", ShowGroupedList);
registry.category("fields").add("grouped_view_widget", {
component: ShowGroupedList,
});
@@ -45,4 +45,8 @@ export class JournalDashboardActivity extends Component {
}
JournalDashboardActivity.template = "account.JournalDashboardActivity";
registry.category("fields").add("kanban_vat_activity", JournalDashboardActivity);
export const journalDashboardActivity = {
component: JournalDashboardActivity,
};
registry.category("fields").add("kanban_vat_activity", journalDashboardActivity);
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { Many2OneField } from "@web/views/fields/many2one/many2one_field";
import { Many2OneField, many2OneField } from "@web/views/fields/many2one/many2one_field";
class LineOpenMoveWidget extends Many2OneField {
async openAction() {
@@ -10,4 +10,9 @@ class LineOpenMoveWidget extends Many2OneField {
}
}
registry.category("fields").add("line_open_move_widget", LineOpenMoveWidget);
export const lineOpenMoveWidget = {
...many2OneField,
component: LineOpenMoveWidget,
};
registry.category("fields").add("line_open_move_widget", lineOpenMoveWidget);
@@ -19,4 +19,6 @@ class OpenMoveWidget extends Component {
}
OpenMoveWidget.template = "account.OpenMoveWidget";
registry.category("fields").add("open_move_widget", OpenMoveWidget);
registry.category("fields").add("open_move_widget", {
component: OpenMoveWidget,
});
@@ -2,7 +2,7 @@
import { registry } from "@web/core/registry";
import { ListRenderer } from "@web/views/list/list_renderer";
import { X2ManyField } from "@web/views/fields/x2many/x2many_field";
import { X2ManyField, x2ManyField } from "@web/views/fields/x2many/x2many_field";
import { TextField, ListTextField } from "@web/views/fields/text/text_field";
import { CharField } from "@web/views/fields/char/char_field";
@@ -82,7 +82,6 @@ export class SectionAndNoteText extends Component {
}
}
SectionAndNoteText.template = "account.SectionAndNoteText";
SectionAndNoteText.additionalClasses = ["o_field_text"];
export class ListSectionAndNoteText extends SectionAndNoteText {
get componentToUse() {
@@ -92,6 +91,21 @@ export class ListSectionAndNoteText extends SectionAndNoteText {
}
}
registry.category("fields").add("section_and_note_one2many", SectionAndNoteFieldOne2Many);
registry.category("fields").add("section_and_note_text", SectionAndNoteText);
registry.category("fields").add("list.section_and_note_text", ListSectionAndNoteText);
export const sectionAndNoteFieldOne2Many = {
...x2ManyField,
component: SectionAndNoteFieldOne2Many,
};
export const sectionAndNoteText = {
component: SectionAndNoteText,
additionalClasses: ["o_field_text"],
};
export const listSectionAndNoteText = {
...sectionAndNoteText,
component: ListSectionAndNoteText,
};
registry.category("fields").add("section_and_note_one2many", sectionAndNoteFieldOne2Many);
registry.category("fields").add("section_and_note_text", sectionAndNoteText);
registry.category("fields").add("list.section_and_note_text", listSectionAndNoteText);
@@ -186,4 +186,8 @@ TaxTotalsComponent.props = {
...standardFieldProps,
};
registry.category("fields").add("account-tax-totals-field", TaxTotalsComponent);
export const taxTotalsComponent = {
component: TaxTotalsComponent,
};
registry.category("fields").add("account-tax-totals-field", taxTotalsComponent);
@@ -573,15 +573,11 @@ export class AnalyticDistribution extends Component {
}
}
AnalyticDistribution.template = "analytic.AnalyticDistribution";
AnalyticDistribution.supportedTypes = ["char", "text"];
AnalyticDistribution.components = {
AnalyticAutoComplete,
TagsList,
}
AnalyticDistribution.fieldDependencies = {
analytic_precision: { type: 'integer' },
}
AnalyticDistribution.props = {
...standardFieldProps,
business_domain: { type: String, optional: true },
@@ -591,15 +587,21 @@ AnalyticDistribution.props = {
force_applicability: { type: String, optional: true },
allow_save: { type: Boolean },
}
AnalyticDistribution.extractProps = ({ field, attrs }) => {
return {
export const analyticDistribution = {
component: AnalyticDistribution,
supportedTypes: ["char", "text"],
fieldDependencies: {
analytic_precision: { type: "integer" },
},
extractProps: ({ attrs }) => ({
business_domain: attrs.options.business_domain,
account_field: attrs.options.account_field,
product_field: attrs.options.product_field,
business_domain_compute: attrs.business_domain_compute,
force_applicability: attrs.options.force_applicability,
allow_save: !Boolean(attrs.options.disable_save),
};
allow_save: !attrs.options.disable_save,
}),
};
registry.category("fields").add("analytic_distribution", AnalyticDistribution);
registry.category("fields").add("analytic_distribution", analyticDistribution);
@@ -30,8 +30,6 @@ export class PasswordField extends Component {
this.recommendations = recommendations;
}
}
PasswordField.displayName = _lt("Password");
PasswordField.supportedTypes = ["char"];
PasswordField.props = standardFieldProps;
PasswordField.components = { Meter };
PasswordField.template = xml`
@@ -46,4 +44,10 @@ PasswordField.template = xml`
</t>
`;
registry.category("fields").add("password_meter", PasswordField);
export const passwordField = {
component: PasswordField,
displayName: _lt("Password"),
supportedTypes: ["char"],
};
registry.category("fields").add("password_meter", passwordField);
@@ -20,4 +20,8 @@ export class BarcodeHandlerField extends Component {
BarcodeHandlerField.template = xml``;
BarcodeHandlerField.props = { ...standardFieldProps };
registry.category("fields").add("barcode_handler", BarcodeHandlerField);
export const barcodeHandlerField = {
component: BarcodeHandlerField,
};
registry.category("fields").add("barcode_handler", barcodeHandlerField);
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { FloatField } from "@web/views/fields/float/float_field";
import { FloatField, floatField } from "@web/views/fields/float/float_field";
export class FloatScannableField extends FloatField {
onBarcodeScanned() {
@@ -10,4 +10,9 @@ export class FloatScannableField extends FloatField {
}
FloatScannableField.template = "barcodes.FloatScannableField";
registry.category("fields").add("field_float_scannable", FloatScannableField);
export const floatScannableField = {
...floatField,
component: FloatScannableField,
};
registry.category("fields").add("field_float_scannable", floatScannableField);
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { CharField } from "@web/views/fields/char/char_field";
import { CharField, charField } from "@web/views/fields/char/char_field";
import { useDebounced } from "@web/core/utils/timing";
import { useService } from "@web/core/utils/hooks";
@@ -27,4 +27,9 @@ export class IbanWidget extends CharField {
}
IbanWidget.template = "base_iban.iban";
registry.category("fields").add("iban", IbanWidget);
export const ibanWidget = {
...charField,
component: IbanWidget,
};
registry.category("fields").add("iban", ibanWidget);
@@ -1,7 +1,10 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { Many2ManyTagsAvatarField } from "@web/views/fields/many2many_tags_avatar/many2many_tags_avatar_field";
import {
Many2ManyTagsAvatarField,
many2ManyTagsAvatarField,
} from "@web/views/fields/many2many_tags_avatar/many2many_tags_avatar_field";
export class Many2ManyAttendee extends Many2ManyTagsAvatarField {
get tags() {
@@ -26,10 +29,15 @@ export class Many2ManyAttendee extends Many2ManyTagsAvatarField {
return tags;
}
}
Many2ManyAttendee.additionalClasses = ["o_field_many2many_tags_avatar"];
Many2ManyAttendee.legacySpecialData = "_fetchSpecialAttendeeStatus";
registry.category("fields").add("many2manyattendee", Many2ManyAttendee);
export const many2ManyAttendee = {
...many2ManyTagsAvatarField,
component: Many2ManyAttendee,
additionalClasses: ["o_field_many2many_tags_avatar"],
legacySpecialData: "_fetchSpecialAttendeeStatus",
};
registry.category("fields").add("many2manyattendee", many2ManyAttendee);
export function preloadMany2ManyAttendee(orm, record, fieldName) {
const context = record.getFieldContext(fieldName);
@@ -88,4 +88,8 @@ export class MondialRelayField extends Component {
}
MondialRelayField.template = xml`<div t-if="enabled" t-ref="root"/>`;
registry.category("fields").add("mondialrelay_relay", MondialRelayField);
export const mondialRelayField = {
component: MondialRelayField,
};
registry.category("fields").add("mondialrelay_relay", mondialRelayField);
@@ -20,11 +20,13 @@ IconSelectionField.props = {
icons: Object,
};
IconSelectionField.displayName = _lt("Icon Selection");
IconSelectionField.supportedTypes = ["char", "text", "selection"];
export const iconSelectionField = {
component: IconSelectionField,
displayName: _lt("Icon Selection"),
supportedTypes: ["char", "text", "selection"],
extractProps: ({ attrs }) => ({
icons: attrs.options,
}),
};
IconSelectionField.extractProps = ({ attrs }) => ({
icons: attrs.options,
});
registry.category("fields").add("event_icon_selection", IconSelectionField);
registry.category("fields").add("event_icon_selection", iconSelectionField);
@@ -2,9 +2,14 @@
import { registry } from '@web/core/registry';
import { ImageField } from '@web/views/fields/image/image_field';
import { ImageField, imageField } from '@web/views/fields/image/image_field';
export class BackgroundImageField extends ImageField {}
BackgroundImageField.template = 'hr.BackgroundImage';
registry.category("fields").add("background_image", BackgroundImageField);
export const backgroundImageField = {
...imageField,
component: BackgroundImageField,
};
registry.category("fields").add("background_image", backgroundImageField);
@@ -1,9 +1,14 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { BinaryField } from "@web/views/fields/binary/binary_field";
import { BinaryField, binaryField } from "@web/views/fields/binary/binary_field";
export class WorkPermitUploadField extends BinaryField {}
WorkPermitUploadField.template = "hr.WorkPermitUploadField";
registry.category("fields").add("work_permit_upload", WorkPermitUploadField);
export const workPermitUploadField = {
...binaryField,
component: WorkPermitUploadField,
};
registry.category("fields").add("work_permit_upload", workPermitUploadField);
@@ -1,15 +1,40 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { Many2ManyTagsAvatarUserField, KanbanMany2ManyTagsAvatarUserField } from "@mail/views/fields/many2many_avatar_user_field/many2many_avatar_user_field";
import {
Many2ManyTagsAvatarUserField,
KanbanMany2ManyTagsAvatarUserField,
many2ManyTagsAvatarUserField,
kanbanMany2ManyTagsAvatarUserField,
} from "@mail/views/fields/many2many_avatar_user_field/many2many_avatar_user_field";
export class Many2ManyTagsAvatarEmployeeField extends Many2ManyTagsAvatarUserField {}
Many2ManyTagsAvatarEmployeeField.additionalClasses = [...Many2ManyTagsAvatarUserField.additionalClasses, "o_field_many2many_avatar_user"];
registry.category("fields").add("many2many_avatar_employee", Many2ManyTagsAvatarEmployeeField);
export const many2ManyTagsAvatarEmployeeField = {
...many2ManyTagsAvatarUserField,
component: Many2ManyTagsAvatarEmployeeField,
additionalClasses: [
...many2ManyTagsAvatarUserField.additionalClasses,
"o_field_many2many_avatar_user",
],
};
registry.category("fields").add("many2many_avatar_employee", many2ManyTagsAvatarEmployeeField);
export class KanbanMany2ManyTagsAvatarEmployeeField extends KanbanMany2ManyTagsAvatarUserField {}
KanbanMany2ManyTagsAvatarEmployeeField.additionalClasses = [...KanbanMany2ManyTagsAvatarUserField.additionalClasses, "o_field_many2many_avatar_user"];
registry.category("fields").add("kanban.many2many_avatar_employee", KanbanMany2ManyTagsAvatarEmployeeField);
registry.category("fields").add("list.many2many_avatar_employee", KanbanMany2ManyTagsAvatarEmployeeField);
export const kanbanMany2ManyTagsAvatarEmployeeField = {
...kanbanMany2ManyTagsAvatarUserField,
component: KanbanMany2ManyTagsAvatarEmployeeField,
additionalClasses: [
...kanbanMany2ManyTagsAvatarUserField.additionalClasses,
"o_field_many2many_avatar_user",
],
};
registry
.category("fields")
.add("kanban.many2many_avatar_employee", kanbanMany2ManyTagsAvatarEmployeeField);
registry
.category("fields")
.add("list.many2many_avatar_employee", kanbanMany2ManyTagsAvatarEmployeeField);
@@ -1,13 +1,33 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { Many2OneAvatarUserField, KanbanMany2OneAvatarUserField } from "@mail/views/fields/many2one_avatar_user_field/many2one_avatar_user_field";
import {
Many2OneAvatarUserField,
KanbanMany2OneAvatarUserField,
many2OneAvatarUserField,
kanbanMany2OneAvatarUserField,
} from "@mail/views/fields/many2one_avatar_user_field/many2one_avatar_user_field";
export class Many2OneAvatarEmployeeField extends Many2OneAvatarUserField {}
Many2OneAvatarEmployeeField.additionalClasses = [...Many2OneAvatarUserField.additionalClasses, "o_field_many2one_avatar_user"];
registry.category("fields").add("many2one_avatar_employee", Many2OneAvatarEmployeeField);
export const many2OneAvatarEmployeeField = {
...many2OneAvatarUserField,
component: Many2OneAvatarEmployeeField,
additionalClasses: [
...many2OneAvatarUserField.additionalClasses,
"o_field_many2one_avatar_user",
],
};
registry.category("fields").add("many2one_avatar_employee", many2OneAvatarEmployeeField);
export class KanbanMany2OneAvatarEmployeeField extends KanbanMany2OneAvatarUserField {}
registry.category("fields").add("kanban.many2one_avatar_employee", KanbanMany2OneAvatarEmployeeField);
export const kanbanMany2OneAvatarEmployeeField = {
...kanbanMany2OneAvatarUserField,
component: KanbanMany2OneAvatarEmployeeField,
};
registry
.category("fields")
.add("kanban.many2one_avatar_employee", kanbanMany2OneAvatarEmployeeField);
@@ -1,12 +1,15 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { RadioField, preloadRadio } from "@web/views/fields/radio/radio_field";
import { RadioField, preloadRadio, radioField } from "@web/views/fields/radio/radio_field";
class RadioImageField extends RadioField {}
RadioImageField.template = "hr_holidays.RadioImageField";
registry.category("fields").add("hr_holidays_radio_image", RadioImageField);
registry.category("fields").add("hr_holidays_radio_image", {
...radioField,
component: RadioImageField,
});
registry.category("preloadedData").add("hr_holidays_radio_image", {
loadOnTypes: ["many2one"],
@@ -1,6 +1,5 @@
/** @odoo-module */
import {Field} from '@web/views/fields/field';
import { registry } from "@web/core/registry";
import { useService } from "@web/core/utils/hooks";
import { usePopover } from "@web/core/popover/popover_hook";
@@ -49,7 +48,7 @@ class HrOrgChartPopover extends Component {
}
HrOrgChartPopover.template = 'hr_org_chart.hr_orgchart_emp_popover';
export class HrOrgChart extends Field {
export class HrOrgChart extends Component {
async setup() {
super.setup();
@@ -143,4 +142,8 @@ HrOrgChart.components = {
HrOrgChart.template = 'hr_org_chart.hr_org_chart';
registry.category("fields").add("hr_org_chart", HrOrgChart);
export const hrOrgChart = {
component: HrOrgChart,
};
registry.category("fields").add("hr_org_chart", hrOrgChart);
@@ -1,6 +1,6 @@
/** @odoo-module */
import { CharField } from "@web/views/fields/char/char_field";
import { CharField, charField } from "@web/views/fields/char/char_field";
import { registry } from "@web/core/registry";
import { useService } from "@web/core/utils/hooks";
@@ -27,4 +27,10 @@ export class ApplicantCharField extends CharField {
}
}
ApplicantCharField.template = "hr_recruitment.ApplicantCharField";
registry.category("fields").add("applicant_char", ApplicantCharField);
export const applicantCharField = {
...charField,
component: ApplicantCharField,
};
registry.category("fields").add("applicant_char", applicantCharField);
@@ -4,7 +4,7 @@ import { registry } from "@web/core/registry";
import { formatDate } from "@web/core/l10n/dates";
import { SkillsX2ManyField } from "./skills_one2many";
import { SkillsX2ManyField, skillsX2ManyField } from "./skills_one2many";
import { CommonSkillsListRenderer } from "../views/skills_list_renderer";
export class ResumeListRenderer extends CommonSkillsListRenderer {
@@ -36,5 +36,9 @@ ResumeX2ManyField.components = {
ListRenderer: ResumeListRenderer,
};
registry.category("fields")
.add("resume_one2many", ResumeX2ManyField);
export const resumeX2ManyField = {
...skillsX2ManyField,
component: ResumeX2ManyField,
};
registry.category("fields").add("resume_one2many", resumeX2ManyField);
@@ -1,6 +1,6 @@
/** @odoo-module */
import { X2ManyField } from "@web/views/fields/x2many/x2many_field";
import { X2ManyField, x2ManyField } from "@web/views/fields/x2many/x2many_field";
import { registry } from "@web/core/registry";
import { CommonSkillsListRenderer } from "../views/skills_list_renderer";
@@ -41,4 +41,9 @@ SkillsX2ManyField.components = {
ListRenderer: SkillsListRenderer,
};
registry.category("fields").add("skills_one2many", SkillsX2ManyField);
export const skillsX2ManyField = {
...x2ManyField,
component: SkillsX2ManyField,
};
registry.category("fields").add("skills_one2many", skillsX2ManyField);
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { Many2OneField } from "@web/views/fields/many2one/many2one_field";
import { Many2OneField, many2OneField } from "@web/views/fields/many2one/many2one_field";
class TaskWithHours extends Many2OneField {
@@ -48,4 +48,7 @@ class TaskWithHours extends Many2OneField {
}
registry.category("fields").add("task_with_hours", TaskWithHours);
registry.category("fields").add("task_with_hours", {
...many2OneField,
component: TaskWithHours,
});
@@ -30,7 +30,7 @@ export class TimesheetUOM extends Component {
}
get timesheetComponent() {
return registry.category("fields").get(this.timesheetWidget, FloatFactorField);
return registry.category("fields").get(this.timesheetWidget, { component: FloatFactorField }).component;
}
get timesheetComponentProps() {
@@ -53,4 +53,8 @@ TimesheetUOM.template = "hr_timesheet.TimesheetUOM";
TimesheetUOM.components = { FloatFactorField, FloatToggleField, FloatTimeField };
registry.category("fields").add("timesheet_uom", TimesheetUOM);
export const timesheetUOM = {
component: TimesheetUOM,
};
registry.category("fields").add("timesheet_uom", timesheetUOM);
@@ -2,7 +2,7 @@
import { registry } from "@web/core/registry";
import { TimesheetUOM } from "../timesheet_uom/timesheet_uom";
import { TimesheetUOM, timesheetUOM } from "../timesheet_uom/timesheet_uom";
export class TimesheetUOMNoToggle extends TimesheetUOM {
@@ -17,4 +17,9 @@ export class TimesheetUOMNoToggle extends TimesheetUOM {
// As FloatToggleField won't be used by TimesheetUOMNoToggle, we remove it from the components that we get from TimesheetUOM.
delete TimesheetUOMNoToggle.components.FloatToggleField;
registry.category("fields").add("timesheet_uom_no_toggle", TimesheetUOMNoToggle);
export const timesheetUOMNoToggle = {
...timesheetUOM,
component: TimesheetUOMNoToggle,
};
registry.category("fields").add("timesheet_uom_no_toggle", timesheetUOMNoToggle);
@@ -2,7 +2,10 @@
import { registry } from "@web/core/registry";
import { Many2ManyTagsField } from "@web/views/fields/many2many_tags/many2many_tags_field";
import {
Many2ManyTagsField,
many2ManyTagsField,
} from "@web/views/fields/many2many_tags/many2many_tags_field";
const fieldRegistry = registry.category("fields");
@@ -22,4 +25,9 @@ export class ChatbotScriptTriggeringAnswersMany2Many extends Many2ManyTagsField
}
};
fieldRegistry.add("chatbot_triggering_answers_widget", ChatbotScriptTriggeringAnswersMany2Many);
export const chatbotScriptTriggeringAnswersMany2Many = {
...many2ManyTagsField,
component: ChatbotScriptTriggeringAnswersMany2Many,
};
fieldRegistry.add("chatbot_triggering_answers_widget", chatbotScriptTriggeringAnswersMany2Many);
@@ -4,7 +4,7 @@ import { ListRenderer } from "@web/views/list/list_renderer";
import { registry } from "@web/core/registry";
import { patch } from '@web/core/utils/patch';
import { useX2ManyCrud, useOpenX2ManyRecord, X2ManyFieldDialog } from "@web/views/fields/relational_utils";
import { X2ManyField } from "@web/views/fields/x2many/x2many_field";
import { X2ManyField, x2ManyField } from "@web/views/fields/x2many/x2many_field";
const fieldRegistry = registry.category("fields");
@@ -96,7 +96,12 @@ export class ChatbotStepsOne2many extends X2ManyField {
}
};
fieldRegistry.add("chatbot_steps_one2many", ChatbotStepsOne2many);
export const chatbotStepsOne2many = {
...x2ManyField,
component: ChatbotStepsOne2many,
};
fieldRegistry.add("chatbot_steps_one2many", chatbotStepsOne2many);
ChatbotStepsOne2many.components = {
...X2ManyField.components,
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { SelectionField } from "@web/views/fields/selection/selection_field";
import { SelectionField, selectionField } from "@web/views/fields/selection/selection_field";
/**
* The purpose of this field is to be able to define some values which should not be
@@ -33,12 +33,14 @@ FilterableSelectionField.props = {
blacklisted_values: { type: Array, optional: true },
};
FilterableSelectionField.extractProps = ({ attrs }) => {
return {
...SelectionField.extractProps({ attrs }),
whitelisted_values: attrs.options.whitelisted_values,
blacklisted_values: attrs.options.blacklisted_values,
};
export const filterableSelectionField = {
...selectionField,
component: FilterableSelectionField,
extractProps: (params) => ({
...selectionField.extractProps(params),
whitelisted_values: params.attrs.options.whitelisted_values,
blacklisted_values: params.attrs.options.blacklisted_values,
}),
};
registry.category("fields").add("filterable_selection", FilterableSelectionField);
registry.category("fields").add("filterable_selection", filterableSelectionField);
@@ -1,9 +1,14 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { X2ManyField } from "@web/views/fields/x2many/x2many_field";
import { X2ManyField, x2ManyField } from "@web/views/fields/x2many/x2many_field";
export class LoyaltyX2ManyField extends X2ManyField {};
LoyaltyX2ManyField.template = "loyalty.LoyaltyX2ManyField";
registry.category("fields").add("loyalty_one2many", LoyaltyX2ManyField);
export const loyaltyX2ManyField = {
...x2ManyField,
component: LoyaltyX2ManyField,
};
registry.category("fields").add("loyalty_one2many", loyaltyX2ManyField);
@@ -19,10 +19,12 @@ class ActivityException extends Component {
Object.assign(ActivityException, {
props: standardFieldProps,
template: "mail.ActivityException",
});
registry.category("fields").add("activity_exception", {
component: ActivityException,
fieldDependencies: {
activity_exception_icon: { type: "char" },
},
noLabel: true,
});
registry.category("fields").add("activity_exception", ActivityException);
@@ -78,6 +78,14 @@ export class KanbanFieldActivityViewContainer extends Component {
}
Object.assign(KanbanFieldActivityViewContainer, {
props: {
...standardFieldProps,
},
template: "mail.KanbanFieldActivityViewContainer",
});
export const kanbanFieldActivityViewContainer = {
component: KanbanFieldActivityViewContainer,
fieldDependencies: {
activity_exception_decoration: { type: "selection" },
activity_exception_icon: { type: "char" },
@@ -86,10 +94,6 @@ Object.assign(KanbanFieldActivityViewContainer, {
activity_type_icon: { type: "char" },
activity_type_id: { type: "many2one", relation: "mail.activity.type" },
},
props: {
...standardFieldProps,
},
template: "mail.KanbanFieldActivityViewContainer",
});
};
registry.category("fields").add("kanban_activity", KanbanFieldActivityViewContainer);
registry.category("fields").add("kanban_activity", kanbanFieldActivityViewContainer);
@@ -78,6 +78,14 @@ export class ListFieldActivityViewContainer extends Component {
}
Object.assign(ListFieldActivityViewContainer, {
props: {
...standardFieldProps,
},
template: "mail.ListFieldActivityViewContainer",
});
export const listFieldActivityViewContainer = {
component: ListFieldActivityViewContainer,
fieldDependencies: {
activity_exception_decoration: { type: "selection" },
activity_exception_icon: { type: "char" },
@@ -86,10 +94,6 @@ Object.assign(ListFieldActivityViewContainer, {
activity_type_icon: { type: "char" },
activity_type_id: { type: "many2one", relation: "mail.activity.type" },
},
props: {
...standardFieldProps,
},
template: "mail.ListFieldActivityViewContainer",
});
};
registry.category("fields").add("list_activity", ListFieldActivityViewContainer);
registry.category("fields").add("list_activity", listFieldActivityViewContainer);
@@ -2,8 +2,8 @@
import { patch } from "@web/core/utils/patch";
import { debounce } from "@web/core/utils/timing";
import { CharField } from "@web/views/fields/char/char_field";
import { TextField } from '@web/views/fields/text/text_field';
import { CharField, charField } from "@web/views/fields/char/char_field";
import { TextField, textField } from "@web/views/fields/text/text_field";
import { archParseBoolean } from "@web/views/utils";
const { useEffect } = owl;
@@ -24,7 +24,7 @@ const onchangeOnKeydownMixin = {
const triggerOnChange = debounce(this.triggerOnChange, this.props.keydownDebounceDelay);
useEffect(() => {
if (input.el) {
input.el.addEventListener('keydown', triggerOnChange.bind(this));
input.el.addEventListener("keydown", triggerOnChange.bind(this));
}
});
}
@@ -32,12 +32,12 @@ const onchangeOnKeydownMixin = {
triggerOnChange() {
const input = this.input || this.textareaRef;
input.el.dispatchEvent(new Event('change'));
}
input.el.dispatchEvent(new Event("change"));
},
};
patch(CharField.prototype, 'char_field_onchange_on_keydown', onchangeOnKeydownMixin);
patch(TextField.prototype, 'text_field_onchange_on_keydown', onchangeOnKeydownMixin);
patch(CharField.prototype, "char_field_onchange_on_keydown", onchangeOnKeydownMixin);
patch(TextField.prototype, "text_field_onchange_on_keydown", onchangeOnKeydownMixin);
CharField.props = {
...CharField.props,
@@ -51,18 +51,22 @@ TextField.props = {
keydownDebounceDelay: { type: Number, optional: true },
};
const charExtractProps = CharField.extractProps;
CharField.extractProps = ({ attrs, field }) => {
return Object.assign(charExtractProps({ attrs, field }), {
const charExtractProps = charField.extractProps;
charField.extractProps = (attrs) => {
return Object.assign(charExtractProps(attrs), {
onchangeOnKeydown: archParseBoolean(attrs.onchange_on_keydown),
keydownDebounceDelay: attrs.keydown_debounce_delay ? Number(attrs.keydown_debounce_delay) : 2000,
keydownDebounceDelay: attrs.keydown_debounce_delay
? Number(attrs.keydown_debounce_delay)
: 2000,
});
};
const textExtractProps = TextField.extractProps;
TextField.extractProps = ({ attrs, field }) => {
return Object.assign(textExtractProps({ attrs, field }), {
onchangeOnKeydown: archParseBoolean(attrs.onchange_on_keydown),
keydownDebounceDelay: attrs.keydown_debounce_delay ? Number(attrs.keydown_debounce_delay) : 2000,
const textExtractProps = textField.extractProps;
textField.extractProps = (params) => {
return Object.assign(textExtractProps(params), {
onchangeOnKeydown: archParseBoolean(params.attrs.onchange_on_keydown),
keydownDebounceDelay: params.attrs.keydown_debounce_delay
? Number(params.attrs.keydown_debounce_delay)
: 2000,
});
};
@@ -35,7 +35,7 @@ export class ActivityArchParser extends XMLParser {
addFieldDependencies(
activeFields,
models[modelName],
fieldInfo.FieldComponent.fieldDependencies
fieldInfo.field.fieldDependencies
);
}
@@ -1,6 +1,6 @@
/** @odoo-module **/
import { CharField } from "@web/views/fields/char/char_field";
import { CharField, charField } from "@web/views/fields/char/char_field";
import { patch } from "@web/core/utils/patch";
import MailEmojisMixin from "@mail/js/emojis_mixin";
import { EmojisFieldCommon } from "@mail/views/fields/emojis_field_common/emojis_field_common";
@@ -23,5 +23,11 @@ patch(EmojisCharField.prototype, "emojis_char_field_mail_mixin", MailEmojisMixin
patch(EmojisCharField.prototype, "emojis_char_field_field_mixin", EmojisFieldCommon);
EmojisCharField.template = "mail.EmojisCharField";
EmojisCharField.components = { ...CharField.components };
EmojisCharField.additionalClasses = [...(CharField.additionalClasses || []), "o_field_text"];
registry.category("fields").add("char_emojis", EmojisCharField);
export const emojisCharField = {
...charField,
component: EmojisCharField,
additionalClasses: [...(charField.additionalClasses || []), "o_field_text"],
};
registry.category("fields").add("char_emojis", emojisCharField);
@@ -1,6 +1,6 @@
/** @odoo-module **/
import { TextField } from "@web/views/fields/text/text_field";
import { TextField, textField } from "@web/views/fields/text/text_field";
import { patch } from "@web/core/utils/patch";
import MailEmojisMixin from "@mail/js/emojis_mixin";
import { EmojisFieldCommon } from "@mail/views/fields/emojis_field_common/emojis_field_common";
@@ -21,5 +21,11 @@ patch(EmojisTextField.prototype, "emojis_char_field_mail_mixin", MailEmojisMixin
patch(EmojisTextField.prototype, "emojis_text_field_field_mixin", EmojisFieldCommon);
EmojisTextField.template = "mail.EmojisTextField";
EmojisTextField.components = { ...TextField.components };
EmojisTextField.additionalClasses = [...(TextField.additionalClasses || []), "o_field_text"];
registry.category("fields").add("text_emojis", EmojisTextField);
export const emojisTextField = {
...textField,
component: EmojisTextField,
additionalClasses: [...(textField.additionalClasses || []), "o_field_text"],
};
registry.category("fields").add("text_emojis", emojisTextField);
@@ -5,6 +5,8 @@ import { TagsList } from "@web/views/fields/many2many_tags/tags_list";
import {
Many2ManyTagsAvatarField,
ListKanbanMany2ManyTagsAvatarField,
many2ManyTagsAvatarField,
listKanbanMany2ManyTagsAvatarField,
} from "@web/views/fields/many2many_tags_avatar/many2many_tags_avatar_field";
import { useOpenChat } from "@mail/views/open_chat_hook";
import { useAssignUserCommand } from "@mail/views/fields/assign_user_command_hook";
@@ -32,9 +34,14 @@ Many2ManyTagsAvatarUserField.components = {
...Many2ManyTagsAvatarField.components,
TagsList: Many2ManyAvatarUserTagsList,
};
Many2ManyTagsAvatarUserField.additionalClasses = ["o_field_many2many_tags_avatar"];
registry.category("fields").add("many2many_avatar_user", Many2ManyTagsAvatarUserField);
export const many2ManyTagsAvatarUserField = {
...many2ManyTagsAvatarField,
component: Many2ManyTagsAvatarUserField,
additionalClasses: ["o_field_many2many_tags_avatar"],
};
registry.category("fields").add("many2many_avatar_user", many2ManyTagsAvatarUserField);
export class KanbanMany2ManyTagsAvatarUserField extends ListKanbanMany2ManyTagsAvatarField {
setup() {
@@ -63,8 +70,15 @@ KanbanMany2ManyTagsAvatarUserField.components = {
...ListKanbanMany2ManyTagsAvatarField.components,
TagsList: Many2ManyAvatarUserTagsList,
};
KanbanMany2ManyTagsAvatarUserField.additionalClasses = ["o_field_many2many_tags_avatar"];
registry.category("fields").add("kanban.many2many_avatar_user", KanbanMany2ManyTagsAvatarUserField);
registry.category("fields").add("list.many2many_avatar_user", KanbanMany2ManyTagsAvatarUserField);
registry.category("fields").add("activity.many2many_avatar_user", KanbanMany2ManyTagsAvatarUserField);
export const kanbanMany2ManyTagsAvatarUserField = {
...listKanbanMany2ManyTagsAvatarField,
component: ListKanbanMany2ManyTagsAvatarField,
additionalClasses: ["o_field_many2many_tags_avatar"],
};
registry.category("fields").add("kanban.many2many_avatar_user", kanbanMany2ManyTagsAvatarUserField);
registry.category("fields").add("list.many2many_avatar_user", kanbanMany2ManyTagsAvatarUserField);
registry
.category("fields")
.add("activity.many2many_avatar_user", kanbanMany2ManyTagsAvatarUserField);
@@ -4,7 +4,10 @@ import { registry } from "@web/core/registry";
import { useOpenMany2XRecord } from "@web/views/fields/relational_utils";
import { sprintf } from "@web/core/utils/strings";
import { Many2ManyTagsField } from "@web/views/fields/many2many_tags/many2many_tags_field";
import {
Many2ManyTagsField,
many2ManyTagsField,
} from "@web/views/fields/many2many_tags/many2many_tags_field";
import { TagsList } from "@web/views/fields/many2many_tags/tags_list";
import { onMounted, onWillUpdateProps } from "@odoo/owl";
@@ -87,10 +90,13 @@ FieldMany2ManyTagsEmail.components = {
TagsList: FieldMany2ManyTagsEmailTagsList,
};
FieldMany2ManyTagsEmail.fieldsToFetch = (fieldInfo) => {
return [...Many2ManyTagsField.fieldsToFetch(fieldInfo), { name: "email", type: "char" }];
export const fieldMany2ManyTagsEmail = {
...many2ManyTagsField,
component: FieldMany2ManyTagsEmail,
fieldsToFetch: (fieldInfo) => {
return [...many2ManyTagsField.fieldsToFetch(fieldInfo), { name: "email", type: "char" }];
},
additionalClasses: ["o_field_many2many_tags"],
};
FieldMany2ManyTagsEmail.additionalClasses = ["o_field_many2many_tags"];
registry.category("fields").add("many2many_tags_email", FieldMany2ManyTagsEmail);
registry.category("fields").add("many2many_tags_email", fieldMany2ManyTagsEmail);
@@ -1,7 +1,10 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { Many2OneAvatarField } from "@web/views/fields/many2one_avatar/many2one_avatar_field";
import {
Many2OneAvatarField,
many2OneAvatarField,
} from "@web/views/fields/many2one_avatar/many2one_avatar_field";
import { useOpenChat } from "@mail/views/open_chat_hook";
import { useAssignUserCommand } from "@mail/views/fields/assign_user_command_hook";
@@ -17,9 +20,14 @@ export class Many2OneAvatarUserField extends Many2OneAvatarField {
}
}
Many2OneAvatarUserField.template = "mail.Many2OneAvatarUserField";
Many2OneAvatarUserField.additionalClasses = ["o_field_many2one_avatar"];
registry.category("fields").add("many2one_avatar_user", Many2OneAvatarUserField);
export const many2OneAvatarUserField = {
...many2OneAvatarField,
component: Many2OneAvatarUserField,
additionalClasses: ["o_field_many2one_avatar"],
};
registry.category("fields").add("many2one_avatar_user", many2OneAvatarUserField);
export class KanbanMany2OneAvatarUserField extends Many2OneAvatarUserField {
/**
@@ -37,12 +45,15 @@ KanbanMany2OneAvatarUserField.props = {
...Many2OneAvatarUserField.props,
displayAvatarName: { type: Boolean, optional: true },
};
KanbanMany2OneAvatarUserField.extractProps = ({ attrs, field }) => {
return {
...Many2OneAvatarUserField.extractProps({ attrs, field }),
displayAvatarName: attrs.options.display_avatar_name || false,
};
export const kanbanMany2OneAvatarUserField = {
...many2OneAvatarUserField,
component: KanbanMany2OneAvatarUserField,
extractProps: (params) => ({
...many2OneAvatarUserField.extractProps(params),
displayAvatarName: params.attrs.options.display_avatar_name || false,
}),
};
registry.category("fields").add("kanban.many2one_avatar_user", KanbanMany2OneAvatarUserField);
registry.category("fields").add("activity.many2one_avatar_user", KanbanMany2OneAvatarUserField);
registry.category("fields").add("kanban.many2one_avatar_user", kanbanMany2OneAvatarUserField);
registry.category("fields").add("activity.many2one_avatar_user", kanbanMany2OneAvatarUserField);
@@ -3,7 +3,7 @@
import { registry } from '@web/core/registry';
import { Dropdown } from "@web/core/dropdown/dropdown";
import { useService } from "@web/core/utils/hooks";
import { Many2OneField } from '@web/views/fields/many2one/many2one_field';
import { Many2OneField, many2OneField } from '@web/views/fields/many2one/many2one_field';
import Domain from 'web.Domain';
const { useState, useEffect } = owl;
@@ -149,12 +149,15 @@ FieldMany2OneMailingFilter.defaultProps = {
domain_field: "mailing_domain",
model_field: "mailing_model_id",
};
FieldMany2OneMailingFilter.extractProps = ({ field, attrs }) => {
return {
...Many2OneField.extractProps({ field, attrs }),
domain_field: attrs.options.domain_field,
model_field: attrs.options.model_field,
}
export const fieldMany2OneMailingFilter = {
...many2OneField,
component: FieldMany2OneMailingFilter,
extractProps: (params) => ({
...many2OneField.extractProps(params),
domain_field: params.attrs.options.domain_field,
model_field: params.attrs.options.model_field,
}),
};
registry.category('fields').add('mailing_filter', FieldMany2OneMailingFilter);
registry.category("fields").add("mailing_filter", fieldMany2OneMailingFilter);
@@ -9,7 +9,7 @@ import { loadBundle, loadJS } from "@web/core/assets";
import { qweb } from 'web.core';
import { useService } from "@web/core/utils/hooks";
import { buildQuery } from "web.rpc";
import { HtmlField } from "@web_editor/js/backend/html_field";
import { HtmlField, htmlField } from "@web_editor/js/backend/html_field";
import { getWysiwygClass } from 'web_editor.loader';
import { device } from 'web.config';
import { MassMailingMobilePreviewDialog } from "./mass_mailing_mobile_preview";
@@ -584,16 +584,16 @@ MassMailingHtmlField.props = {
iframeHtmlClass: { type: String, optional: true },
};
MassMailingHtmlField.displayName = _lt("Email");
MassMailingHtmlField.extractProps = (...args) => {
const [{ attrs }] = args;
const htmlProps = HtmlField.extractProps(...args);
return {
...htmlProps,
filterTemplates: attrs.options.filterTemplates,
inlineField: attrs.options['inline-field'],
iframeHtmlClass: attrs['iframeHtmlClass'],
};
export const massMailingHtmlField = {
...htmlField,
component: MassMailingHtmlField,
displayName: _lt("Email"),
extractProps: (params) => ({
...htmlField.extractProps(params),
filterTemplates: params.attrs.options.filterTemplates,
inlineField: params.attrs.options['inline-field'],
iframeHtmlClass: params.attrs['iframeHtmlClass'],
}),
};
registry.category("fields").add("mass_mailing_html", MassMailingHtmlField);
registry.category("fields").add("mass_mailing_html", massMailingHtmlField);
@@ -3,7 +3,7 @@
import { _lt } from "@web/core/l10n/translation";
import { registry } from "@web/core/registry";
import { useService } from "@web/core/utils/hooks";
import { CharField } from "@web/views/fields/char/char_field";
import { CharField, charField } from "@web/views/fields/char/char_field";
const { useState } = owl;
@@ -48,6 +48,11 @@ export class SlidesViewer extends CharField {
}
SlidesViewer.template = "mrp.SlidesViewer";
SlidesViewer.displayName = _lt("Google Slides Viewer");
registry.category("fields").add("embed_viewer", SlidesViewer);
export const slidesViewer = {
...charField,
component: SlidesViewer,
displayName: _lt("Google Slides Viewer"),
};
registry.category("fields").add("embed_viewer", slidesViewer);
@@ -1,6 +1,6 @@
/** @odoo-module **/
import { FloatField } from "@web/views/fields/float/float_field";
import { FloatField, floatField } from "@web/views/fields/float/float_field";
import { registry } from "@web/core/registry";
import { formatFloat } from "@web/views/fields/formatters";
@@ -44,6 +44,11 @@ export class MrpShouldConsumeOwl extends FloatField {
}
MrpShouldConsumeOwl.template = "mrp.ShouldConsume";
MrpShouldConsumeOwl.displayName = "MRP Should Consume";
registry.category("fields").add("mrp_should_consume", MrpShouldConsumeOwl);
export const mrpShouldConsumeOwl = {
...floatField,
component: MrpShouldConsumeOwl,
displayName: "MRP Should Consume",
};
registry.category("fields").add("mrp_should_consume", mrpShouldConsumeOwl);
@@ -1,7 +1,11 @@
/** @odoo-module */
import { useService } from "@web/core/utils/hooks";
import { registry } from "@web/core/registry";
import { PopoverComponent, PopoverWidgetField } from '@stock/widgets/popover_widget';
import {
PopoverComponent,
PopoverWidgetField,
popoverWidgetField,
} from "@stock/widgets/popover_widget";
/**
* Link to a Char field representing a JSON:
@@ -36,4 +40,7 @@ WorkOrderPopoverField.components = {
Popover: WorkOrderPopover
};
registry.category("fields").add("mrp_workorder_popover", WorkOrderPopoverField);
registry.category("fields").add("mrp_workorder_popover", {
...popoverWidgetField,
component: WorkOrderPopoverField,
});
+6 -2
View File
@@ -84,7 +84,6 @@ export class MrpTimer extends Component {
}
}
MrpTimer.supportedTypes = ["float"];
MrpTimer.props = {
...standardFieldProps,
duration: { type: Number, optional: true },
@@ -93,5 +92,10 @@ MrpTimer.props = {
};
MrpTimer.template = "mrp.MrpTimer";
registry.category("fields").add("mrp_timer", MrpTimer);
export const mrpTimer = {
component: MrpTimer,
supportedTypes: ["float"],
};
registry.category("fields").add("mrp_timer", mrpTimer);
registry.category("formatters").add("mrp_timer", formatMinutes);
@@ -5,7 +5,7 @@ import { AutoComplete } from "@web/core/autocomplete/autocomplete";
import { useChildRef } from "@web/core/utils/hooks";
import { registry } from "@web/core/registry";
import { _t } from "@web/core/l10n/translation";
import { CharField } from "@web/views/fields/char/char_field";
import { CharField, charField } from "@web/views/fields/char/char_field";
import { useInputField } from "@web/views/fields/input_field_hook";
import { loadJS } from "@web/core/assets";
@@ -97,4 +97,9 @@ PartnerAutoCompleteCharField.components = {
AutoComplete,
};
registry.category("fields").add("field_partner_autocomplete", PartnerAutoCompleteCharField);
export const partnerAutoCompleteCharField = {
...charField,
component: PartnerAutoCompleteCharField,
};
registry.category("fields").add("field_partner_autocomplete", partnerAutoCompleteCharField);
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { Many2XAutocomplete } from '@web/views/fields/relational_utils';
import { Many2OneField } from '@web/views/fields/many2one/many2one_field';
import { Many2OneField, many2OneField } from '@web/views/fields/many2one/many2one_field';
import { _t } from "@web/core/l10n/translation";
import { registry } from "@web/core/registry";
@@ -68,4 +68,9 @@ PartnerAutoCompleteMany2one.components = {
Many2XAutocomplete: PartnerMany2XAutocomplete,
}
registry.category("fields").add("res_partner_many2one", PartnerAutoCompleteMany2one);
export const partnerAutoCompleteMany2one = {
...many2OneField,
component: PartnerAutoCompleteMany2one,
};
registry.category("fields").add("res_partner_many2one", partnerAutoCompleteMany2one);
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { PortalWizardUserListController } from "../list/portal_wizard_user_list_controller";
import { X2ManyField } from "@web/views/fields/x2many/x2many_field";
import { X2ManyField, x2ManyField } from "@web/views/fields/x2many/x2many_field";
import { registry } from "@web/core/registry";
export class PortalUserX2ManyField extends X2ManyField {}
@@ -10,4 +10,9 @@ PortalUserX2ManyField.components = {
Controller: PortalWizardUserListController,
};
registry.category("fields").add("portal_wizard_user_one2many", PortalUserX2ManyField);
export const portalUserX2ManyField = {
...x2ManyField,
component: PortalUserX2ManyField,
};
registry.category("fields").add("portal_wizard_user_one2many", portalUserX2ManyField);
@@ -1,9 +1,14 @@
/** @odoo-module */
import { registry } from '@web/core/registry';
import { Many2OneField } from '@web/views/fields/many2one/many2one_field';
import { Many2OneField, many2OneField } from '@web/views/fields/many2one/many2one_field';
export class ProjectPrivateTaskMany2OneField extends Many2OneField { }
ProjectPrivateTaskMany2OneField.template = 'project.ProjectPrivateTaskMany2OneField';
registry.category('fields').add('project_private_task', ProjectPrivateTaskMany2OneField);
export const projectPrivateTaskMany2OneField = {
...many2OneField,
component: ProjectPrivateTaskMany2OneField,
};
registry.category("fields").add("project_private_task", projectPrivateTaskMany2OneField);
@@ -1,7 +1,10 @@
/** @odoo-module */
import { registry } from '@web/core/registry';
import { StateSelectionField } from '@web/views/fields/state_selection/state_selection_field';
import {
StateSelectionField,
stateSelectionField,
} from "@web/views/fields/state_selection/state_selection_field";
import { STATUS_COLORS, STATUS_COLOR_PREFIX } from '../../utils/project_utils';
@@ -27,4 +30,9 @@ export class ProjectStateSelectionField extends StateSelectionField {
}
}
registry.category('fields').add('kanban.project_state_selection', ProjectStateSelectionField);
export const projectStateSelectionField = {
...stateSelectionField,
component: ProjectStateSelectionField,
};
registry.category("fields").add("kanban.project_state_selection", projectStateSelectionField);
@@ -1,6 +1,6 @@
/** @odoo-module */
import { SelectionField } from '@web/views/fields/selection/selection_field';
import { SelectionField, selectionField } from '@web/views/fields/selection/selection_field';
import { registry } from '@web/core/registry';
import { STATUS_COLORS, STATUS_COLOR_PREFIX } from '../../utils/project_utils';
@@ -22,4 +22,9 @@ export class ProjectStatusWithColorSelectionField extends SelectionField {
}
ProjectStatusWithColorSelectionField.template = 'project.ProjectStatusWithColorSelectionField';
registry.category('fields').add('status_with_color', ProjectStatusWithColorSelectionField);
export const projectStatusWithColorSelectionField = {
...selectionField,
component: ProjectStatusWithColorSelectionField,
};
registry.category("fields").add("status_with_color", projectStatusWithColorSelectionField);
@@ -1,7 +1,7 @@
/** @odoo-module */
import { registry } from '@web/core/registry';
import { CharField } from '@web/views/fields/char/char_field';
import { CharField, charField } from '@web/views/fields/char/char_field';
import { formatChar } from '@web/views/fields/formatters';
class ProjectTaskNameWithSubtaskCountCharField extends CharField {
@@ -12,4 +12,7 @@ class ProjectTaskNameWithSubtaskCountCharField extends CharField {
ProjectTaskNameWithSubtaskCountCharField.template = 'project.ProjectTaskNameWithSubtaskCountCharField';
registry.category('fields').add('name_with_subtask_count', ProjectTaskNameWithSubtaskCountCharField);
registry.category("fields").add("name_with_subtask_count", {
...charField,
component: ProjectTaskNameWithSubtaskCountCharField,
});
@@ -2,7 +2,7 @@
import { sprintf } from "@web/core/utils/strings";
import { registry } from "@web/core/registry";
import { PriorityField } from "@web/views/fields/priority/priority_field";
import { PriorityField, priorityField } from "@web/views/fields/priority/priority_field";
import { useCommand } from "@web/core/commands/command_hook";
import { useState } from "@odoo/owl";
@@ -29,4 +29,9 @@ export class PrioritySwitchField extends PriorityField {
}
}
registry.category("fields").add("priority_switch", PrioritySwitchField);
export const prioritySwitchField = {
...priorityField,
component: PrioritySwitchField,
};
registry.category("fields").add("priority_switch", prioritySwitchField);
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { registry } from '@web/core/registry';
import { Many2OneField } from '@web/views/fields/many2one/many2one_field';
import { Many2OneField, many2OneField } from '@web/views/fields/many2one/many2one_field';
import { ProductMatrixDialog } from "@product_matrix/js/product_matrix_dialog";
import { useService } from "@web/core/utils/hooks";
@@ -107,4 +107,9 @@ export class PurchaseOrderLineProductField extends Many2OneField {
PurchaseOrderLineProductField.template = "purchase.PurchaseProductField";
registry.category("fields").add("pol_product_many2one", PurchaseOrderLineProductField);
export const purchaseOrderLineProductField = {
...many2OneField,
component: PurchaseOrderLineProductField,
};
registry.category("fields").add("pol_product_many2one", purchaseOrderLineProductField);
@@ -2,7 +2,7 @@
import { registry } from "@web/core/registry";
import { useService } from "@web/core/utils/hooks";
import { X2ManyField } from "@web/views/fields/x2many/x2many_field";
import { X2ManyField, x2ManyField } from "@web/views/fields/x2many/x2many_field";
import { ListRenderer } from "@web/views/list/list_renderer";
@@ -43,4 +43,9 @@ FieldMany2ManyAltPOs.components = {
ListRenderer: FieldMany2ManyAltPOsRenderer,
};
registry.category("fields").add("many2many_alt_pos", FieldMany2ManyAltPOs);
export const fieldMany2ManyAltPOs = {
...x2ManyField,
component: FieldMany2ManyAltPOs,
};
registry.category("fields").add("many2many_alt_pos", fieldMany2ManyAltPOs);
@@ -2,7 +2,7 @@
import { SectionListRenderer } from "./section_list_renderer";
import { registry } from "@web/core/registry";
import { X2ManyField } from "@web/views/fields/x2many/x2many_field";
import { X2ManyField, x2ManyField } from "@web/views/fields/x2many/x2many_field";
class SectionOneToManyField extends X2ManyField {}
SectionOneToManyField.components = {
@@ -14,4 +14,7 @@ SectionOneToManyField.defaultProps = {
editable: "bottom",
};
registry.category("fields").add("section_one2many", SectionOneToManyField);
registry.category("fields").add("section_one2many", {
...x2ManyField,
component: SectionOneToManyField,
});
@@ -2,7 +2,7 @@
import { registry } from "@web/core/registry";
import { useService } from "@web/core/utils/hooks";
import { FloatField } from "@web/views/fields/float/float_field";
import { FloatField, floatField } from "@web/views/fields/float/float_field";
import { _lt } from "@web/core/l10n/translation";
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
@@ -57,6 +57,11 @@ export function sameValue(orderLines) {
ProductDiscountField.components = { ConfirmationDialog };
ProductDiscountField.template = "sale.ProductDiscountField";
ProductDiscountField.displayName = _lt("Disc.%");
registry.category("fields").add("sol_discount", ProductDiscountField)
export const productDiscountField = {
...floatField,
component: ProductDiscountField,
displayName: _lt("Disc.%"),
};
registry.category("fields").add("sol_discount", productDiscountField)
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { registry } from '@web/core/registry';
import { Many2OneField } from '@web/views/fields/many2one/many2one_field';
import { Many2OneField, many2OneField } from '@web/views/fields/many2one/many2one_field';
export class SaleOrderLineProductField extends Many2OneField {
@@ -109,4 +109,9 @@ export class SaleOrderLineProductField extends Many2OneField {
SaleOrderLineProductField.template = "sale.SaleProductField";
registry.category("fields").add("sol_product_many2one", SaleOrderLineProductField);
export const saleOrderLineProductField = {
...many2OneField,
component: SaleOrderLineProductField,
};
registry.category("fields").add("sol_product_many2one", saleOrderLineProductField);
@@ -2,7 +2,10 @@
import { registry } from "@web/core/registry";
import { useService } from "@web/core/utils/hooks";
import { KanbanProgressBarField } from "@web/views/fields/progress_bar/kanban_progress_bar_field";
import {
KanbanProgressBarField,
kanbanProgressBarField,
} from "@web/views/fields/progress_bar/kanban_progress_bar_field";
const { useEffect } = owl;
@@ -42,4 +45,9 @@ export class SaleProgressBarField extends KanbanProgressBarField {
*/
SaleProgressBarField.template = "sale.SaleProgressBarField";
registry.category("fields").add("sales_team_progressbar", SaleProgressBarField);
export const saleProgressBarField = {
...kanbanProgressBarField,
component: SaleProgressBarField,
};
registry.category("fields").add("sales_team_progressbar", saleProgressBarField);
@@ -1,6 +1,6 @@
/** @odoo-module alias=sale_expense.sale_order_many2one **/
import { Many2OneField } from '@web/views/fields/many2one/many2one_field';
import { Many2OneField, many2OneField } from '@web/views/fields/many2one/many2one_field';
import { registry } from "@web/core/registry";
@@ -21,5 +21,10 @@ export class OrderField extends Many2OneField {
}
}
registry.category('fields').add('sale_order_many2one', OrderField)
export const orderField = {
...many2OneField,
component: OrderField,
};
registry.category("fields").add("sale_order_many2one", orderField);
registry.add('sale_order_many2one', OrderField);
@@ -1,8 +1,8 @@
/** @odoo-module */
import { registry } from "@web/core/registry";
import { Many2OneField } from "@web/views/fields/many2one/many2one_field";
import { X2ManyField } from "@web/views/fields/x2many/x2many_field";
import { Many2OneField, many2OneField } from "@web/views/fields/many2one/many2one_field";
import { X2ManyField, x2ManyField } from "@web/views/fields/x2many/x2many_field";
export class SoLineField extends Many2OneField {
setup() {
@@ -18,8 +18,17 @@ export class SoLineField extends Many2OneField {
}
}
export class TimesheetsOne2ManyField extends X2ManyField {}
TimesheetsOne2ManyField.additionalClasses = ['o_field_one2many'];
registry.category("fields").add('so_line_one2many', TimesheetsOne2ManyField); // TODO: Remove me when the gantt view is converted in OWL
export const soLineField = {
...many2OneField,
component: SoLineField,
};
registry.category("fields").add("so_line_field", soLineField);
registry.category("fields").add("so_line_field", SoLineField);
export class TimesheetsOne2ManyField extends X2ManyField {}
export const timesheetsOne2ManyField = {
...x2ManyField,
component: TimesheetsOne2ManyField,
additionalClasses: ['o_field_one2many'],
};
registry.category("fields").add('so_line_one2many', timesheetsOne2ManyField); // TODO: Remove me when the gantt view is converted in OWL
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { patch } from "@web/core/utils/patch";
import { PhoneField } from "@web/views/fields/phone/phone_field";
import { PhoneField, phoneField, formPhoneField } from "@web/views/fields/phone/phone_field";
import { SendSMSButton } from '@sms/components/sms_button/sms_button';
patch(PhoneField, "sms.PhoneField", {
@@ -17,10 +17,16 @@ patch(PhoneField, "sms.PhoneField", {
...PhoneField.props,
enableButton: { type: Boolean, optional: true },
},
extractProps: ({ attrs }) => {
});
const patchDescr = {
extractProps({ attrs }) {
return {
...this._super({ attrs }),
enableButton: attrs.options.enable_sms,
placeholder: attrs.placeholder,
};
},
});
};
patch(phoneField, "sms.PhoneField", patchDescr);
patch(formPhoneField, "sms.PhoneField", patchDescr);
@@ -34,3 +34,4 @@ export class SendSMSButton extends Component {
}
};
SendSMSButton.template = "sms.SendSMSButton";
SendSMSButton.props = ["*"];
@@ -1,6 +1,9 @@
/** @odoo-module **/
import { EmojisTextField} from '@mail/views/fields/emojis_text_field/emojis_text_field';
import {
EmojisTextField,
emojisTextField,
} from "@mail/views/fields/emojis_text_field/emojis_text_field";
import { useService } from "@web/core/utils/hooks";
import { registry } from "@web/core/registry";
@@ -94,5 +97,15 @@ export class SmsWidget extends EmojisTextField {
}
}
SmsWidget.template = 'sms.SmsWidget';
SmsWidget.additionalClasses = [...(EmojisTextField.additionalClasses || []), 'o_field_text', 'o_field_text_emojis'];
registry.category("fields").add("sms_widget", SmsWidget);
export const smsWidget = {
...emojisTextField,
component: SmsWidget,
additionalClasses: [
...(emojisTextField.additionalClasses || []),
"o_field_text",
"o_field_text_emojis",
],
};
registry.category("fields").add("sms_widget", smsWidget);
@@ -2,7 +2,7 @@
import { registry } from "@web/core/registry";
import { ListRenderer } from "@web/views/list/list_renderer";
import { X2ManyField } from "@web/views/fields/x2many/x2many_field";
import { X2ManyField, x2ManyField } from "@web/views/fields/x2many/x2many_field";
import { ViewButton } from "@web/views/view_button/view_button";
class MoveViewButton extends ViewButton {
@@ -30,4 +30,9 @@ MovesListRenderer.components = { ...ListRenderer.components, ViewButton: MoveVie
export class StockMoveX2ManyField extends X2ManyField {}
StockMoveX2ManyField.components = { ...X2ManyField.components, ListRenderer: MovesListRenderer };
registry.category("fields").add("stock_move_one2many", StockMoveX2ManyField);
export const stockMoveX2ManyField = {
...x2ManyField,
component: StockMoveX2ManyField,
};
registry.category("fields").add("stock_move_one2many", stockMoveX2ManyField);
@@ -1,6 +1,6 @@
/** @odoo-module **/
import { FloatField } from "@web/views/fields/float/float_field";
import { FloatField, floatField } from "@web/views/fields/float/float_field";
import { registry } from "@web/core/registry";
const { useEffect, useRef } = owl;
@@ -41,4 +41,9 @@ export class CountedQuantityWidgetField extends FloatField {
}
}
registry.category("fields").add("counted_quantity_widget", CountedQuantityWidgetField);
export const countedQuantityWidgetField = {
...floatField,
component: CountedQuantityWidgetField,
};
registry.category("fields").add("counted_quantity_widget", countedQuantityWidgetField);
@@ -1,6 +1,6 @@
/** @odoo-module */
import { FloatField } from "@web/views/fields/float/float_field";
import { FloatField, floatField } from "@web/views/fields/float/float_field";
import { formatDate } from "@web/core/l10n/dates";
import { formatFloat } from "@web/views/fields/formatters";
import { registry } from "@web/core/registry";
@@ -49,4 +49,9 @@ export class ForecastWidgetField extends FloatField {
}
ForecastWidgetField.template = "stock.ForecastWidget";
registry.category("fields").add("forecast_widget", ForecastWidgetField);
export const forecastWidgetField = {
...floatField,
component: ForecastWidgetField,
};
registry.category("fields").add("forecast_widget", forecastWidgetField);
+17 -4
View File
@@ -16,8 +16,11 @@ export class JsonPopOver extends Component {
}
}
JsonPopOver.displayName = _lt("Json Popup");
JsonPopOver.supportedTypes = ["char"];
export const jsonPopOver = {
component: JsonPopOver,
displayName: _lt("Json Popup"),
supportedTypes: ["char"],
};
export class PopOverLeadDays extends JsonPopOver {
setup() {
@@ -50,8 +53,18 @@ export class PopOverLeadDays extends JsonPopOver {
PopOverLeadDays.template = "stock.leadDays";
export const popOverLeadDays = {
...jsonPopOver,
component: PopOverLeadDays,
};
registry.category("fields").add("lead_days_widget", popOverLeadDays);
export class ReplenishmentHistoryWidget extends JsonPopOver {}
ReplenishmentHistoryWidget.template = "stock.replenishmentHistory";
registry.category("fields").add("lead_days_widget", PopOverLeadDays);
registry.category("fields").add("replenishment_history_widget", ReplenishmentHistoryWidget);
export const replenishmentHistoryWidget = {
...jsonPopOver,
component: ReplenishmentHistoryWidget,
};
registry.category("fields").add("replenishment_history_widget", replenishmentHistoryWidget);
@@ -46,7 +46,12 @@ export class PopoverWidgetField extends Component {
}
}
PopoverWidgetField.supportedTypes = ['char'];
PopoverWidgetField.template = 'stock.popoverButton';
PopoverWidgetField.components = { Popover: PopoverComponent }
registry.category("fields").add("popover_widget", PopoverWidgetField);
export const popoverWidgetField = {
component: PopoverWidgetField,
supportedTypes: ['char'],
};
registry.category("fields").add("popover_widget", popoverWidgetField);
@@ -1,7 +1,11 @@
/** @odoo-module */
import { useService } from "@web/core/utils/hooks";
import { registry } from "@web/core/registry";
import { PopoverComponent, PopoverWidgetField } from '@stock/widgets/popover_widget';
import {
PopoverComponent,
PopoverWidgetField,
popoverWidgetField,
} from "@stock/widgets/popover_widget";
class StockRescheculingPopoverComponent extends PopoverComponent {
setup(){
@@ -37,4 +41,7 @@ StockRescheculingPopover.components = {
Popover: StockRescheculingPopoverComponent
}
registry.category("fields").add("stock_rescheduling_popover", StockRescheculingPopover);
registry.category("fields").add("stock_rescheduling_popover", {
...popoverWidgetField,
component: StockRescheculingPopover,
});
@@ -1,6 +1,6 @@
/** @odoo-module */
import { CharField } from "@web/views/fields/char/char_field";
import { CharField, charField } from "@web/views/fields/char/char_field";
import { registry } from "@web/core/registry";
const { useEffect, useRef } = owl;
@@ -24,4 +24,7 @@ class DescriptionPageField extends CharField {
}
DescriptionPageField.template = "survey.DescriptionPageField";
registry.category("fields").add("survey_description_page", DescriptionPageField);
registry.category("fields").add("survey_description_page", {
...charField,
component: DescriptionPageField,
});
@@ -5,7 +5,7 @@ import { registry } from "@web/core/registry";
import { useOpenX2ManyRecord, useX2ManyCrud, X2ManyFieldDialog } from "@web/views/fields/relational_utils";
import { patch } from '@web/core/utils/patch';
import { useService } from "@web/core/utils/hooks";
import { X2ManyField } from "@web/views/fields/x2many/x2many_field";
import { X2ManyField, x2ManyField } from "@web/views/fields/x2many/x2many_field";
const { useSubEnv } = owl;
@@ -127,4 +127,9 @@ QuestionPageOneToManyField.defaultProps = {
editable: "bottom",
};
registry.category("fields").add("question_page_one2many", QuestionPageOneToManyField);
export const questionPageOneToManyField = {
...x2ManyField,
component: QuestionPageOneToManyField,
};
registry.category("fields").add("question_page_one2many", questionPageOneToManyField);
@@ -8,14 +8,18 @@ import { useDebounced } from "@web/core/utils/timing";
import { Component, useState, useRef, onWillStart, onMounted, onWillUnmount } from "@odoo/owl";
class MenuItem extends Component {}
MenuItem.template = "web.ProfilingQwebView.menuitem";
class MenuItem extends Component {
static template = "web.ProfilingQwebView.menuitem";
}
/**
* This widget is intended to be used on Text fields. It will provide Ace Editor
* for display XML and Python profiling.
*/
export class ProfilingQwebView extends Component {
static template = "web.ProfilingQwebView";
static components = { MenuItem };
setup() {
super.setup();
@@ -36,11 +40,11 @@ export class ProfilingQwebView extends Component {
onWillStart(async () => {
await loadBundle({
jsLibs: [
'/web/static/lib/ace/ace.js',
"/web/static/lib/ace/ace.js",
[
'/web/static/lib/ace/mode-python.js',
'/web/static/lib/ace/mode-xml.js',
'/web/static/lib/ace/mode-qweb.js'
"/web/static/lib/ace/mode-python.js",
"/web/static/lib/ace/mode-xml.js",
"/web/static/lib/ace/mode-qweb.js",
],
],
});
@@ -81,7 +85,7 @@ export class ProfilingQwebView extends Component {
* @private
* @returns {Promise<viewObjects>}
*/
async _fetchViewData () {
async _fetchViewData() {
const viewIDs = Array.from(new Set(this.profile.data.map((line) => line.view_id)));
const viewObjects = await this.orm.call("ir.ui.view", "search_read", [], {
fields: ["id", "display_name", "key"],
@@ -111,7 +115,7 @@ export class ProfilingQwebView extends Component {
* @param {number} delay
* @returns {string}
*/
_formatDelay (delay) {
_formatDelay(delay) {
return delay ? _.str.sprintf("%.1f", Math.ceil(delay * 10) / 10) : ".";
}
@@ -122,7 +126,7 @@ export class ProfilingQwebView extends Component {
* @private
* @param {Node} node - the DOM element the ace library must initialize on
*/
_startAce (node) {
_startAce(node) {
this.aceEditor = window.ace.edit(node);
this.aceEditor.setOptions({
maxLines: Infinity,
@@ -150,20 +154,22 @@ export class ProfilingQwebView extends Component {
this.aceEditor.renderer.on("afterRender", this.renderProfilingInformation.bind(this));
}
renderProfilingInformation () {
renderProfilingInformation() {
this._unmoutInfo();
let flat = {};
let arch = [{ xpath: "", children: [] }];
const flat = {};
const arch = [{ xpath: "", children: [] }];
const rows = this.ace.el.querySelectorAll(".ace_gutter .ace_gutter-cell");
const elems = this.ace.el.querySelectorAll(".ace_tag-open, .ace_end-tag-close, .ace_end-tag-open, .ace_qweb");
elems.forEach(node => {
const elems = this.ace.el.querySelectorAll(
".ace_tag-open, .ace_end-tag-close, .ace_end-tag-open, .ace_qweb"
);
elems.forEach((node) => {
const parent = arch[arch.length - 1];
let xpath = parent.xpath;
if (node.classList.contains("ace_end-tag-close")) {
// Close tag.
let previous = node;
while (previous = previous.previousElementSibling) {
while ((previous = previous.previousElementSibling)) {
if (previous && previous.classList.contains("ace_tag-name")) {
break;
}
@@ -220,7 +226,12 @@ export class ProfilingQwebView extends Component {
i++;
}
xpath += "[" + i + "]";
flat[xpath] = { xpath: xpath, tag: nodeTagName.textContent, children: [], directive: [] };
flat[xpath] = {
xpath: xpath,
tag: nodeTagName.textContent,
children: [],
directive: [],
};
arch.push(flat[xpath]);
parent.children.push(flat[xpath]);
@@ -278,32 +289,32 @@ export class ProfilingQwebView extends Component {
}
_unmoutInfo() {
if (this.hover) {
if (this.ace.el.querySelector('.o_ace_hover')) {
this.ace.el.querySelector('.o_ace_hover').remove();
if (this.ace.el.querySelector(".o_ace_hover")) {
this.ace.el.querySelector(".o_ace_hover").remove();
}
}
if (this.info) {
if (this.ace.el.querySelector('.o_ace_info')) {
this.ace.el.querySelector('.o_ace_info').remove();
if (this.ace.el.querySelector(".o_ace_info")) {
this.ace.el.querySelector(".o_ace_info").remove();
}
}
}
_renderHover(delay, query, node) {
const xml = renderToString('web.ProfilingQwebView.hover', {
const xml = renderToString("web.ProfilingQwebView.hover", {
delay: this._formatDelay(delay),
query: query,
});
const div = new DOMParser().parseFromString(xml, "text/html").querySelector('div');
const div = new DOMParser().parseFromString(xml, "text/html").querySelector("div");
node.insertBefore(div, node.firstChild);
}
_renderInfo(delays, querys, displayDetail, groups, node) {
const xml = renderToString('web.ProfilingQwebView.info', {
const xml = renderToString("web.ProfilingQwebView.info", {
delay: this._formatDelay(delays.reduce((a, b) => a + b, 0)),
query: querys.reduce((a, b) => a + b, 0) || ".",
displayDetail: displayDetail,
groups: groups,
});
const div = new DOMParser().parseFromString(xml, "text/html").querySelector('div');
const div = new DOMParser().parseFromString(xml, "text/html").querySelector("div");
node.insertBefore(div, node.firstChild);
}
@@ -315,12 +326,14 @@ export class ProfilingQwebView extends Component {
* @private
* @param {MouseEvent} ev
*/
_onSelectView (ev) {
_onSelectView(ev) {
this.state.viewID = +ev.currentTarget.dataset.id;
this._renderView();
}
}
ProfilingQwebView.template = "web.ProfilingQwebView";
ProfilingQwebView.components = { MenuItem };
registry.category("fields").add("profiling_qweb_view", ProfilingQwebView);
export const profilingQwebView = {
component: ProfilingQwebView,
};
registry.category("fields").add("profiling_qweb_view", profilingQwebView);
@@ -232,8 +232,7 @@ export class Record extends DataPoint {
}
}
const isSet =
activeField && activeField.FieldComponent && activeField.FieldComponent.isSet;
const isSet = activeField && activeField.field && activeField.field.isSet;
if (this.isRequired(fieldName) && isSet && !isSet(this.data[fieldName])) {
this.setInvalidField(fieldName);
@@ -11,6 +11,15 @@ import { standardFieldProps } from "../standard_field_props";
import { Component, onWillStart, onWillUpdateProps, useEffect, useRef } from "@odoo/owl";
export class AceField extends Component {
static template = "web.AceField";
static props = {
...standardFieldProps,
mode: { type: String, optional: true },
};
static defaultProps = {
mode: "qweb",
};
setup() {
this.aceEditor = null;
this.editorRef = useRef("editor");
@@ -110,22 +119,13 @@ export class AceField extends Component {
}
}
AceField.template = "web.AceField";
AceField.props = {
...standardFieldProps,
mode: { type: String, optional: true },
};
AceField.defaultProps = {
mode: "qweb",
};
AceField.displayName = _lt("Ace Editor");
AceField.supportedTypes = ["text"];
AceField.extractProps = ({ attrs }) => {
return {
export const aceField = {
component: AceField,
displayName: _lt("Ace Editor"),
supportedTypes: ["text"],
extractProps: ({ attrs }) => ({
mode: attrs.options.mode,
};
}),
};
registry.category("fields").add("ace", AceField);
registry.category("fields").add("ace", aceField);
@@ -5,11 +5,14 @@ import { registry } from "@web/core/registry";
import { Component } from "@odoo/owl";
export class AttachmentImageField extends Component {}
export class AttachmentImageField extends Component {
static template = "web.AttachmentImageField";
}
AttachmentImageField.template = "web.AttachmentImageField";
export const attachmentImageField = {
component: AttachmentImageField,
displayName: _lt("Attachment Image"),
supportedTypes: ["many2one"],
};
AttachmentImageField.displayName = _lt("Attachment Image");
AttachmentImageField.supportedTypes = ["many2one"];
registry.category("fields").add("attachment_image", AttachmentImageField);
registry.category("fields").add("attachment_image", attachmentImageField);
@@ -8,6 +8,11 @@ import { Component } from "@odoo/owl";
const formatters = registry.category("formatters");
export class BadgeField extends Component {
static template = "web.BadgeField";
static props = {
...standardFieldProps,
};
get formattedValue() {
const formatter = formatters.get(this.props.type);
return formatter(this.props.value, {
@@ -25,12 +30,10 @@ export class BadgeField extends Component {
}
}
BadgeField.template = "web.BadgeField";
BadgeField.props = {
...standardFieldProps,
export const badgeField = {
component: BadgeField,
displayName: _lt("Badge"),
supportedTypes: ["selection", "many2one", "char"],
};
BadgeField.displayName = _lt("Badge");
BadgeField.supportedTypes = ["selection", "many2one", "char"];
registry.category("fields").add("badge", BadgeField);
registry.category("fields").add("badge", badgeField);
@@ -7,6 +7,11 @@ import { standardFieldProps } from "../standard_field_props";
import { Component } from "@odoo/owl";
export class BadgeSelectionField extends Component {
static template = "web.BadgeSelectionField";
static props = {
...standardFieldProps,
};
get options() {
switch (this.props.record.fields[this.props.name].type) {
case "many2one":
@@ -61,18 +66,15 @@ export class BadgeSelectionField extends Component {
}
}
BadgeSelectionField.template = "web.BadgeSelectionField";
BadgeSelectionField.props = {
...standardFieldProps,
export const badgeSelectionField = {
component: BadgeSelectionField,
displayName: _lt("Badges"),
supportedTypes: ["many2one", "selection"],
isEmpty: (record, fieldName) => record.data[fieldName] === false,
legacySpecialData: "_fetchSpecialMany2ones",
};
BadgeSelectionField.displayName = _lt("Badges");
BadgeSelectionField.supportedTypes = ["many2one", "selection"];
BadgeSelectionField.legacySpecialData = "_fetchSpecialMany2ones";
BadgeSelectionField.isEmpty = (record, fieldName) => record.data[fieldName] === false;
registry.category("fields").add("selection_badge", BadgeSelectionField);
registry.category("fields").add("selection_badge", badgeSelectionField);
export function preloadSelection(orm, record, fieldName) {
const field = record.fields[fieldName];
@@ -10,6 +10,19 @@ import { _lt } from "@web/core/l10n/translation";
import { Component, onWillUpdateProps, useState } from "@odoo/owl";
export class BinaryField extends Component {
static template = "web.BinaryField";
static components = {
FileUploader,
};
static props = {
...standardFieldProps,
acceptedFileExtensions: { type: String, optional: true },
fileNameField: { type: String, optional: true },
};
static defaultProps = {
acceptedFileExtensions: "*",
};
setup() {
this.notification = useService("notification");
this.state = useState({
@@ -52,27 +65,14 @@ export class BinaryField extends Component {
}
}
BinaryField.template = "web.BinaryField";
BinaryField.components = {
FileUploader,
};
BinaryField.props = {
...standardFieldProps,
acceptedFileExtensions: { type: String, optional: true },
fileNameField: { type: String, optional: true },
};
BinaryField.defaultProps = {
acceptedFileExtensions: "*",
};
BinaryField.displayName = _lt("File");
BinaryField.supportedTypes = ["binary"];
BinaryField.extractProps = ({ attrs }) => {
return {
export const binaryField = {
component: BinaryField,
displayName: _lt("File"),
supportedTypes: ["binary"],
extractProps: ({ attrs }) => ({
acceptedFileExtensions: attrs.options.accepted_file_extensions,
fileNameField: attrs.filename,
};
}),
};
registry.category("fields").add("binary", BinaryField);
registry.category("fields").add("binary", binaryField);
@@ -8,6 +8,12 @@ import { CheckBox } from "@web/core/checkbox/checkbox";
import { Component } from "@odoo/owl";
export class BooleanField extends Component {
static template = "web.BooleanField";
static components = { CheckBox };
static props = {
...standardFieldProps,
};
get isReadonly() {
return !(this.props.record.isInEdition && !this.props.record.isReadonly(this.props.name));
}
@@ -20,15 +26,11 @@ export class BooleanField extends Component {
}
}
BooleanField.template = "web.BooleanField";
BooleanField.components = { CheckBox };
BooleanField.props = {
...standardFieldProps,
export const booleanField = {
component: BooleanField,
displayName: _lt("Checkbox"),
supportedTypes: ["boolean"],
isEmpty: () => false,
};
BooleanField.displayName = _lt("Checkbox");
BooleanField.supportedTypes = ["boolean"];
BooleanField.isEmpty = () => false;
registry.category("fields").add("boolean", BooleanField);
registry.category("fields").add("boolean", booleanField);
@@ -7,25 +7,25 @@ import { standardFieldProps } from "../standard_field_props";
import { Component } from "@odoo/owl";
export class BooleanFavoriteField extends Component {}
BooleanFavoriteField.template = "web.BooleanFavoriteField";
BooleanFavoriteField.props = {
...standardFieldProps,
noLabel: { type: Boolean, optional: true },
};
BooleanFavoriteField.defaultProps = {
noLabel: false,
};
BooleanFavoriteField.displayName = _lt("Favorite");
BooleanFavoriteField.supportedTypes = ["boolean"];
BooleanFavoriteField.isEmpty = () => false;
BooleanFavoriteField.extractProps = ({ attrs }) => {
return {
noLabel: archParseBoolean(attrs.nolabel),
export class BooleanFavoriteField extends Component {
static template = "web.BooleanFavoriteField";
static props = {
...standardFieldProps,
noLabel: { type: Boolean, optional: true },
};
static defaultProps = {
noLabel: false,
};
}
export const booleanFavoriteField = {
component: BooleanFavoriteField,
displayName: _lt("Favorite"),
supportedTypes: ["boolean"],
isEmpty: () => false,
extractProps: ({ attrs }) => ({
noLabel: archParseBoolean(attrs.nolabel),
}),
};
registry.category("fields").add("boolean_favorite", BooleanFavoriteField);
registry.category("fields").add("boolean_favorite", booleanFavoriteField);
@@ -6,24 +6,27 @@ import { _lt } from "@web/core/l10n/translation";
import { standardFieldProps } from "../standard_field_props";
export class BooleanIconField extends Component {
static defaultProps = {
icon: "fa-check-square-o",
};
static extractProps = ({ attrs }) => {
return {
icon: attrs.options.icon,
};
};
static template = "web.BooleanIconField";
static props = {
...standardFieldProps,
icon: { type: String, optional: true },
};
static displayName = _lt("Boolean Icon");
static supportedTypes = ["boolean"];
static defaultProps = {
icon: "fa-check-square-o",
};
get label() {
return this.props.record.activeFields[this.props.name].string;
}
}
registry.category("fields").add("boolean_icon", BooleanIconField);
export const booleanIconField = {
component: BooleanIconField,
displayName: _lt("Boolean Icon"),
supportedTypes: ["boolean"],
extractProps: ({ attrs }) => ({
icon: attrs.options.icon,
}),
};
registry.category("fields").add("boolean_icon", booleanIconField);
@@ -2,16 +2,20 @@
import { registry } from "@web/core/registry";
import { _lt } from "@web/core/l10n/translation";
import { BooleanField } from "../boolean/boolean_field";
import { booleanField, BooleanField } from "../boolean/boolean_field";
export class BooleanToggleField extends BooleanField {
static template = "web.BooleanToggleField";
get isReadonly() {
return this.props.record.isReadonly(this.props.name);
}
}
BooleanToggleField.template = "web.BooleanToggleField";
export const booleanToggleField = {
...booleanField,
component: BooleanToggleField,
displayName: _lt("Toggle"),
};
BooleanToggleField.displayName = _lt("Toggle");
registry.category("fields").add("boolean_toggle", BooleanToggleField);
registry.category("fields").add("boolean_toggle", booleanToggleField);
@@ -1,9 +1,11 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { BooleanToggleField } from "./boolean_toggle_field";
import { booleanToggleField, BooleanToggleField } from "./boolean_toggle_field";
export class ListBooleanToggleField extends BooleanToggleField {
static template = "web.ListBooleanToggleField";
onClick() {
if (!this.props.readonly) {
this.props.update(!this.props.value);
@@ -11,6 +13,9 @@ export class ListBooleanToggleField extends BooleanToggleField {
}
}
ListBooleanToggleField.template = "web.ListBooleanToggleField";
export const listBooleanToggleField = {
...booleanToggleField,
component: ListBooleanToggleField,
};
registry.category("fields").add("list.boolean_toggle", ListBooleanToggleField);
registry.category("fields").add("list.boolean_toggle", listBooleanToggleField);
@@ -12,6 +12,22 @@ import { useDynamicPlaceholder } from "../dynamicplaceholder_hook";
import { Component, onMounted, onWillUnmount, useRef } from "@odoo/owl";
export class CharField extends Component {
static template = "web.CharField";
static components = {
TranslationButton,
};
static props = {
...standardFieldProps,
autocomplete: { type: String, optional: true },
isPassword: { type: Boolean, optional: true },
placeholder: { type: String, optional: true },
dynamicPlaceholder: { type: Boolean, optional: true },
shouldTrim: { type: Boolean, optional: true },
maxLength: { type: Number, optional: true },
isTranslatable: { type: Boolean, optional: true },
};
static defaultProps = { dynamicPlaceholder: false };
setup() {
if (this.props.dynamicPlaceholder) {
this.dynamicPlaceholder = useDynamicPlaceholder();
@@ -26,34 +42,33 @@ export class CharField extends Component {
if (ev.key === this.dynamicPlaceholder.TRIGGER_KEY && ev.target === this.input.el) {
const baseModel = this.props.record.data.mailing_model_real;
if (baseModel) {
await this.dynamicPlaceholder.open(
this.input.el,
baseModel,
{
validateCallback: this.onDynamicPlaceholderValidate.bind(this),
closeCallback: this.onDynamicPlaceholderClose.bind(this)
}
);
await this.dynamicPlaceholder.open(this.input.el, baseModel, {
validateCallback: this.onDynamicPlaceholderValidate.bind(this),
closeCallback: this.onDynamicPlaceholderClose.bind(this),
});
}
}
}
onMounted() {
if (this.props.dynamicPlaceholder) {
this.keydownListenerCallback = this.onKeydownListener.bind(this);
document.addEventListener('keydown', this.keydownListenerCallback);
document.addEventListener("keydown", this.keydownListenerCallback);
}
}
onWillUnmount() {
if (this.props.dynamicPlaceholder) {
document.removeEventListener('keydown', this.keydownListenerCallback);
document.removeEventListener("keydown", this.keydownListenerCallback);
}
}
onDynamicPlaceholderValidate(chain, defaultValue) {
if (chain) {
const triggerKeyReplaceRegex = new RegExp(`${this.dynamicPlaceholder.TRIGGER_KEY}$`);
let dynamicPlaceholder = "{{object." + chain.join('.');
dynamicPlaceholder += defaultValue && defaultValue !== '' ? ` or '''${defaultValue}'''}}` : '}}';
this.props.update(this.input.el.value.replace(triggerKeyReplaceRegex, '') + dynamicPlaceholder);
let dynamicPlaceholder = "{{object." + chain.join(".");
dynamicPlaceholder +=
defaultValue && defaultValue !== "" ? ` or '''${defaultValue}'''}}` : "}}";
this.props.update(
this.input.el.value.replace(triggerKeyReplaceRegex, "") + dynamicPlaceholder
);
}
}
onDynamicPlaceholderClose() {
@@ -72,35 +87,20 @@ export class CharField extends Component {
}
}
CharField.template = "web.CharField";
CharField.components = {
TranslationButton,
};
CharField.defaultProps = { dynamicPlaceholder: false };
CharField.props = {
...standardFieldProps,
autocomplete: { type: String, optional: true },
isPassword: { type: Boolean, optional: true },
placeholder: { type: String, optional: true },
dynamicPlaceholder: { type: Boolean, optional: true},
shouldTrim: { type: Boolean, optional: true },
maxLength: { type: Number, optional: true },
isTranslatable: { type: Boolean, optional: true },
};
export const charField = {
component: CharField,
displayName: _lt("Text"),
supportedTypes: ["char"],
extractProps: ({ attrs, field }) => ({
isPassword: archParseBoolean(attrs.password),
dynamicPlaceholder: attrs.options.dynamic_placeholder,
autocomplete: attrs.autocomplete,
placeholder: attrs.placeholder,
CharField.displayName = _lt("Text");
CharField.supportedTypes = ["char"];
CharField.extractProps = ({ attrs, field }) => {
return {
shouldTrim: field.trim && !archParseBoolean(attrs.password), // passwords shouldn't be trimmed
maxLength: field.size,
isTranslatable: field.translate,
dynamicPlaceholder: attrs.options.dynamic_placeholder,
autocomplete: attrs.autocomplete,
isPassword: archParseBoolean(attrs.password),
placeholder: attrs.placeholder,
};
}),
};
registry.category("fields").add("char", CharField);
registry.category("fields").add("char", charField);
@@ -6,13 +6,18 @@ import { standardFieldProps } from "../standard_field_props";
import { Component, useState, onWillUpdateProps } from "@odoo/owl";
export class ColorField extends Component {
static template = "web.ColorField";
static props = {
...standardFieldProps,
};
setup() {
this.state = useState({
color: this.props.value || '',
color: this.props.value || "",
});
onWillUpdateProps((nextProps) => {
this.state.color = nextProps.value || '';
this.state.color = nextProps.value || "";
});
}
@@ -21,11 +26,9 @@ export class ColorField extends Component {
}
}
ColorField.template = "web.ColorField";
ColorField.props = {
...standardFieldProps,
export const colorField = {
component: ColorField,
supportedTypes: ["char"],
};
ColorField.supportedTypes = ["char"];
registry.category("fields").add("color", ColorField);
registry.category("fields").add("color", colorField);
@@ -7,6 +7,16 @@ import { standardFieldProps } from "../standard_field_props";
import { Component } from "@odoo/owl";
export class ColorPickerField extends Component {
static template = "web.ColorPickerField";
static components = {
ColorList,
};
static props = {
...standardFieldProps,
};
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";
}
@@ -20,15 +30,9 @@ export class ColorPickerField extends Component {
}
}
ColorPickerField.template = "web.ColorPickerField";
ColorPickerField.components = {
ColorList,
};
ColorPickerField.props = {
...standardFieldProps,
export const colorPickerField = {
component: ColorPickerField,
supportedTypes: ["integer"],
};
ColorPickerField.supportedTypes = ["integer"];
ColorPickerField.RECORD_COLORS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
registry.category("fields").add("color_picker", ColorPickerField);
registry.category("fields").add("color_picker", colorPickerField);
@@ -6,6 +6,15 @@ import { useService } from "@web/core/utils/hooks";
import { Component, useRef } from "@odoo/owl";
export class CopyButton extends Component {
static template = "web.CopyButton";
static props = {
className: { type: String, optional: true },
copyText: { type: String, optional: true },
disabled: { type: Boolean, optional: true },
successText: { type: String, optional: true },
content: { type: [String, Object], optional: true },
};
setup() {
this.button = useRef("button");
this.popover = useService("popover");
@@ -40,11 +49,3 @@ export class CopyButton extends Component {
this.showTooltip();
}
}
CopyButton.template = "web.CopyButton";
CopyButton.props = {
className: { type: String, optional: true },
copyText: { type: String, optional: true },
disabled: { type: Boolean, optional: true },
successText: { type: String, optional: true },
content: { type: [String, Object], optional: true },
};
@@ -15,10 +15,18 @@ import { standardFieldProps } from "../standard_field_props";
import { Component } from "@odoo/owl";
class CopyClipboardField extends Component {
static template = "web.CopyClipboardField";
static props = {
...standardFieldProps,
string: { type: String, optional: true },
disabledExpr: { type: String, optional: true },
};
setup() {
this.copyText = this.props.string || this.env._t("Copy");
this.successText = this.env._t("Copied");
}
get copyButtonClassName() {
return `o_btn_${this.props.type}_copy btn-sm`;
}
@@ -34,47 +42,68 @@ class CopyClipboardField extends Component {
return Boolean(evaluated);
}
}
CopyClipboardField.template = "web.CopyClipboardField";
CopyClipboardField.props = {
...standardFieldProps,
string: { type: String, optional: true },
disabledExpr: { type: String, optional: true },
};
CopyClipboardField.extractProps = ({ attrs }) => {
return {
string: attrs.string,
disabledExpr: attrs.disabled,
};
};
export class CopyClipboardButtonField extends CopyClipboardField {
static template = "web.CopyClipboardButtonField";
static components = { CopyButton };
get copyButtonClassName() {
return `o_btn_${this.props.type}_copy rounded-2`;
}
}
CopyClipboardButtonField.template = "web.CopyClipboardButtonField";
CopyClipboardButtonField.components = { CopyButton };
CopyClipboardButtonField.displayName = _lt("Copy to Clipboard");
registry.category("fields").add("CopyClipboardButton", CopyClipboardButtonField);
export class CopyClipboardCharField extends CopyClipboardField {
static components = { Field: CharField, CopyButton };
}
export class CopyClipboardCharField extends CopyClipboardField {}
CopyClipboardCharField.components = { Field: CharField, CopyButton };
CopyClipboardCharField.displayName = _lt("Copy Text to Clipboard");
CopyClipboardCharField.supportedTypes = ["char"];
export class CopyClipboardTextField extends CopyClipboardField {
static components = { Field: TextField, CopyButton };
}
registry.category("fields").add("CopyClipboardChar", CopyClipboardCharField);
export class CopyClipboardURLField extends CopyClipboardField {
static components = { Field: UrlField, CopyButton };
}
export class CopyClipboardTextField extends CopyClipboardField {}
CopyClipboardTextField.components = { Field: TextField, CopyButton };
CopyClipboardTextField.displayName = _lt("Copy Multiline Text to Clipboard");
CopyClipboardTextField.supportedTypes = ["text"];
// ----------------------------------------------------------------------------
registry.category("fields").add("CopyClipboardText", CopyClipboardTextField);
function extractProps({ attrs }) {
return {
string: attrs.string,
disabledExpr: attrs.disabled,
};
}
export class CopyClipboardURLField extends CopyClipboardField {}
CopyClipboardURLField.components = { Field: UrlField, CopyButton };
CopyClipboardURLField.displayName = _lt("Copy URL to Clipboard");
CopyClipboardURLField.supportedTypes = ["char"];
export const copyClipboardButtonField = {
component: CopyClipboardButtonField,
displayName: _lt("Copy to Clipboard"),
extractProps,
};
registry.category("fields").add("CopyClipboardURL", CopyClipboardURLField);
registry.category("fields").add("CopyClipboardButton", copyClipboardButtonField);
export const copyClipboardCharField = {
component: CopyClipboardCharField,
displayName: _lt("Copy Text to Clipboard"),
supportedTypes: ["char"],
extractProps,
};
registry.category("fields").add("CopyClipboardChar", copyClipboardCharField);
export const copyClipboardTextField = {
component: CopyClipboardTextField,
displayName: _lt("Copy Multiline Text to Clipboard"),
supportedTypes: ["text"],
extractProps,
};
registry.category("fields").add("CopyClipboardText", copyClipboardTextField);
export const copyClipboardURLField = {
component: CopyClipboardURLField,
displayName: _lt("Copy URL to Clipboard"),
supportedTypes: ["char"],
extractProps,
};
registry.category("fields").add("CopyClipboardURL", copyClipboardURLField);
@@ -10,6 +10,19 @@ import { standardFieldProps } from "../standard_field_props";
import { Component } from "@odoo/owl";
export class DateField extends Component {
static template = "web.DateField";
static components = {
DatePicker,
};
static props = {
...standardFieldProps,
pickerOptions: { type: Object, optional: true },
placeholder: { type: String, optional: true },
};
static defaultProps = {
pickerOptions: {},
};
setup() {
/**
* The last value that has been commited to the model.
@@ -17,6 +30,7 @@ export class DateField extends Component {
*/
this.lastSetValue = null;
}
get isDateTime() {
return this.props.record.fields[this.props.name].type === "datetime";
}
@@ -44,27 +58,14 @@ export class DateField extends Component {
}
}
DateField.template = "web.DateField";
DateField.components = {
DatePicker,
};
DateField.props = {
...standardFieldProps,
pickerOptions: { type: Object, optional: true },
placeholder: { type: String, optional: true },
};
DateField.defaultProps = {
pickerOptions: {},
};
DateField.displayName = _lt("Date");
DateField.supportedTypes = ["date", "datetime"];
DateField.extractProps = ({ attrs }) => {
return {
export const dateField = {
component: DateField,
displayName: _lt("Date"),
supportedTypes: ["date", "datetime"],
extractProps: ({ attrs }) => ({
pickerOptions: attrs.options.datepicker,
placeholder: attrs.placeholder,
};
}),
};
registry.category("fields").add("date", DateField);
registry.category("fields").add("date", dateField);
@@ -11,6 +11,15 @@ const formatters = registry.category("formatters");
const parsers = registry.category("parsers");
export class DateRangeField extends Component {
static template = "web.DateRangeField";
static props = {
...standardFieldProps,
relatedEndDateField: { type: String, optional: true },
relatedStartDateField: { type: String, optional: true },
formatType: { type: String, optional: true },
placeholder: { type: String, optional: true },
};
setup() {
this.notification = useService("notification");
this.root = useRef("root");
@@ -138,24 +147,17 @@ export class DateRangeField extends Component {
this.isPickerShown = false;
}
}
DateRangeField.template = "web.DateRangeField";
DateRangeField.props = {
...standardFieldProps,
relatedEndDateField: { type: String, optional: true },
relatedStartDateField: { type: String, optional: true },
formatType: { type: String, optional: true },
placeholder: { type: String, optional: true },
};
DateRangeField.supportedTypes = ["date", "datetime"];
DateRangeField.extractProps = ({ attrs, field }) => {
return {
export const dateRangeField = {
component: DateRangeField,
supportedTypes: ["date", "datetime"],
extractProps: ({ attrs, field }) => ({
relatedEndDateField: attrs.options.related_end_date,
relatedStartDateField: attrs.options.related_start_date,
formatType: attrs.options.format_type || field.type,
placeholder: attrs.placeholder,
};
formatType: attrs.options.format_type || field.type,
}),
};
registry.category("fields").add("daterange", DateRangeField);
registry.category("fields").add("daterange", dateRangeField);
@@ -9,6 +9,19 @@ import { standardFieldProps } from "../standard_field_props";
import { Component } from "@odoo/owl";
export class DateTimeField extends Component {
static template = "web.DateTimeField";
static components = {
DateTimePicker,
};
static props = {
...standardFieldProps,
pickerOptions: { type: Object, optional: true },
placeholder: { type: String, optional: true },
};
static defaultProps = {
pickerOptions: {},
};
setup() {
/**
* The last value that has been commited to the model.
@@ -16,6 +29,7 @@ export class DateTimeField extends Component {
*/
this.lastSetValue = null;
}
get formattedValue() {
return formatDateTime(this.props.value);
}
@@ -34,27 +48,14 @@ export class DateTimeField extends Component {
}
}
DateTimeField.template = "web.DateTimeField";
DateTimeField.components = {
DateTimePicker,
};
DateTimeField.props = {
...standardFieldProps,
pickerOptions: { type: Object, optional: true },
placeholder: { type: String, optional: true },
};
DateTimeField.defaultProps = {
pickerOptions: {},
};
DateTimeField.displayName = _lt("Date & Time");
DateTimeField.supportedTypes = ["datetime"];
DateTimeField.extractProps = ({ attrs }) => {
return {
export const dateTimeField = {
component: DateTimeField,
displayName: _lt("Date & Time"),
supportedTypes: ["datetime"],
extractProps: ({ attrs }) => ({
pickerOptions: attrs.options.datepicker,
placeholder: attrs.placeholder,
};
}),
};
registry.category("fields").add("datetime", DateTimeField);
registry.category("fields").add("datetime", dateTimeField);
@@ -12,6 +12,19 @@ import { standardFieldProps } from "../standard_field_props";
import { Component, onWillStart, onWillUpdateProps, useState } from "@odoo/owl";
export class DomainField extends Component {
static template = "web.DomainField";
static components = {
DomainSelector,
};
static props = {
...standardFieldProps,
editInDialog: { type: Boolean, optional: true },
resModel: { type: String, optional: true },
};
static defaultProps = {
editInDialog: false,
};
setup() {
this.orm = useService("orm");
this.state = useState({
@@ -126,28 +139,15 @@ export class DomainField extends Component {
}
}
DomainField.template = "web.DomainField";
DomainField.components = {
DomainSelector,
};
DomainField.props = {
...standardFieldProps,
editInDialog: { type: Boolean, optional: true },
resModel: { type: String, optional: true },
};
DomainField.defaultProps = {
editInDialog: false,
};
DomainField.displayName = _lt("Domain");
DomainField.supportedTypes = ["char"];
DomainField.isEmpty = () => false;
DomainField.extractProps = ({ attrs }) => {
return {
export const domainField = {
component: DomainField,
displayName: _lt("Domain"),
supportedTypes: ["char"],
isEmpty: () => false,
extractProps: ({ attrs }) => ({
editInDialog: attrs.options.in_dialog,
resModel: attrs.options.model,
};
}),
};
registry.category("fields").add("domain", DomainField);
registry.category("fields").add("domain", domainField);
@@ -8,27 +8,35 @@ import { standardFieldProps } from "../standard_field_props";
import { Component } from "@odoo/owl";
export class EmailField extends Component {
static template = "web.EmailField";
static props = {
...standardFieldProps,
placeholder: { type: String, optional: true },
};
setup() {
useInputField({ getValue: () => this.props.value || "" });
}
}
EmailField.template = "web.EmailField";
EmailField.props = {
...standardFieldProps,
placeholder: { type: String, optional: true },
};
EmailField.extractProps = ({ attrs }) => {
return {
export const emailField = {
component: EmailField,
displayName: _lt("Email"),
supportedTypes: ["char"],
extractProps: ({ attrs }) => ({
placeholder: attrs.placeholder,
};
}),
};
EmailField.displayName = _lt("Email");
EmailField.supportedTypes = ["char"];
registry.category("fields").add("email", emailField);
class FormEmailField extends EmailField {}
FormEmailField.template = "web.FormEmailField";
class FormEmailField extends EmailField {
static template = "web.FormEmailField";
}
registry.category("fields").add("email", EmailField);
registry.category("fields").add("form.email", FormEmailField);
export const formEmailField = {
...emailField,
component: FormEmailField,
};
registry.category("fields").add("form.email", formEmailField);
+25 -25
View File
@@ -50,17 +50,17 @@ function getFieldClassFromRegistry(fieldType, widget, viewType, jsClass) {
return fieldRegistry.get(fieldType);
}
return DefaultField;
return { component: DefaultField };
}
export function fieldVisualFeedback(FieldComponent, record, fieldName, fieldInfo) {
export function fieldVisualFeedback(field, record, fieldName, fieldInfo) {
const modifiers = fieldInfo.modifiers || {};
const readonly = evalDomain(modifiers.readonly, record.evalContext);
const inEdit = record.isInEdition;
let empty = !record.isVirtual;
if ("isEmpty" in FieldComponent) {
empty = empty && FieldComponent.isEmpty(record, fieldName);
if ("isEmpty" in field) {
empty = empty && field.isEmpty(record, fieldName);
} else {
empty = empty && !record.data[fieldName];
}
@@ -75,17 +75,17 @@ export function fieldVisualFeedback(FieldComponent, record, fieldName, fieldInfo
export class Field extends Component {
setup() {
this.FieldComponent = this.props.fieldInfo.FieldComponent;
if (!this.FieldComponent) {
this.field = this.props.fieldInfo.field;
if (!this.field) {
const fieldType = this.props.record.fields[this.props.name].type;
this.FieldComponent = getFieldClassFromRegistry(fieldType, this.props.type);
this.field = getFieldClassFromRegistry(fieldType, this.props.type);
}
}
get classNames() {
const { class: _class, fieldInfo, name, record } = this.props;
const { readonly, required, invalid, empty } = fieldVisualFeedback(
this.FieldComponent,
this.field,
record,
name,
fieldInfo
@@ -99,8 +99,8 @@ export class Field extends Component {
[`o_field_${this.type}`]: true,
[_class]: Boolean(_class),
};
if (this.FieldComponent.additionalClasses) {
for (const cls of this.FieldComponent.additionalClasses) {
if (this.field.additionalClasses) {
for (const cls of this.field.additionalClasses) {
classNames[cls] = true;
}
}
@@ -139,10 +139,10 @@ export class Field extends Component {
decorationMap[decoName] = value;
}
let propsFromAttrs = fieldInfo.propsFromAttrs;
let propsFromAttrs = fieldInfo.propsFromAttrs || {};
if (this.props.attrs) {
const extractProps = this.FieldComponent.extractProps || (() => ({}));
propsFromAttrs = extractProps({
const extractProps = this.field.extractProps || (() => ({}));
propsFromAttrs = extractProps.call(this.field, {
field,
attrs: {
...this.props.attrs,
@@ -202,18 +202,18 @@ Field.parseFieldNode = function (node, models, modelName, viewType, jsClass) {
const name = node.getAttribute("name");
const widget = node.getAttribute("widget");
const fields = models[modelName];
const field = fields[name];
const modifiers = JSON.parse(node.getAttribute("modifiers") || "{}");
const field = getFieldClassFromRegistry(fields[name].type, widget, viewType, jsClass);
const fieldInfo = {
name,
viewType,
context: node.getAttribute("context") || "{}",
string: node.getAttribute("string") || field.string,
string: node.getAttribute("string") || fields[name].string,
help: node.getAttribute("help"),
widget,
modifiers,
onChange: archParseBoolean(node.getAttribute("on_change")),
FieldComponent: getFieldClassFromRegistry(fields[name].type, widget, viewType, jsClass),
field,
forceSave: archParseBoolean(node.getAttribute("force_save")),
decorations: {}, // populated below
noLabel: archParseBoolean(node.getAttribute("nolabel")),
@@ -244,26 +244,26 @@ Field.parseFieldNode = function (node, models, modelName, viewType, jsClass) {
if (viewType !== "kanban") {
// FIXME WOWL: find a better solution
const extractProps = fieldInfo.FieldComponent.extractProps || (() => ({}));
fieldInfo.propsFromAttrs = extractProps({
field,
const extractProps = field.extractProps || (() => ({}));
fieldInfo.propsFromAttrs = extractProps.call(field, {
field: fields[name],
attrs: { ...fieldInfo.rawAttrs, options: fieldInfo.options },
});
}
if (X2M_TYPES.includes(field.type)) {
if (X2M_TYPES.includes(fields[name].type)) {
const views = {};
for (const child of node.children) {
const viewType = child.tagName === "tree" ? "list" : child.tagName;
const { ArchParser } = viewRegistry.get(viewType);
const xmlSerializer = new XMLSerializer();
const subArch = xmlSerializer.serializeToString(child);
const archInfo = new ArchParser().parse(subArch, models, field.relation);
const archInfo = new ArchParser().parse(subArch, models, fields[name].relation);
views[viewType] = {
...archInfo,
fields: models[field.relation],
fields: models[fields[name].relation],
};
fieldInfo.relatedFields = models[field.relation];
fieldInfo.relatedFields = models[fields[name].relation];
}
let viewMode = node.getAttribute("mode");
@@ -279,10 +279,10 @@ Field.parseFieldNode = function (node, models, modelName, viewType, jsClass) {
viewMode = viewMode.replace("tree", "list");
}
fieldInfo.viewMode = viewMode;
fieldInfo.relation = field.relation; // not really necessary
fieldInfo.relation = fields[name].relation; // not really necessary
fieldInfo.views = views;
let fieldsToFetch = fieldInfo.FieldComponent.fieldsToFetch;
let fieldsToFetch = field.fieldsToFetch;
if (fieldsToFetch) {
if (fieldsToFetch instanceof Function) {
fieldsToFetch = fieldsToFetch(fieldInfo);

Some files were not shown because too many files have changed in this diff Show More