[REF] web, *: simplify concrete fields API - remove value prop
This commit, is part of a series of commits that aim to simplifie the concrete fields API. In this commit we will remove value prop from concrete fields. Now each field will directly use this.props.record.data[this.props.name] to access their value, As a consequence of this, the name props need to be mandatory. task-id 3179751 closes odoo/odoo#113495 Related: odoo/enterprise#37464 Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
@@ -24,7 +24,7 @@ export class AccountPaymentField extends Component {
|
||||
}
|
||||
|
||||
formatData(props) {
|
||||
const info = props.value || {
|
||||
const info = props.record.data[props.name] || {
|
||||
content: [],
|
||||
outstanding: false,
|
||||
title: "",
|
||||
|
||||
@@ -15,7 +15,7 @@ class ShowResequenceRenderer extends Component {
|
||||
}
|
||||
|
||||
formatData(props) {
|
||||
this.data = props.value ? JSON.parse(props.value) : { changeLines: [], ordering: "date" };
|
||||
this.data = props.record.data[props.name] ? JSON.parse(props.record.data[props.name]) : { changeLines: [], ordering: "date" };
|
||||
}
|
||||
}
|
||||
ShowResequenceRenderer.template = "account.ResequenceRenderer";
|
||||
|
||||
@@ -20,8 +20,8 @@ class ShowGroupedList extends Component {
|
||||
}
|
||||
|
||||
formatData(props) {
|
||||
this.data = props.value
|
||||
? JSON.parse(props.value)
|
||||
this.data = props.record.data[props.name]
|
||||
? JSON.parse(props.record.data[props.name])
|
||||
: { groups_vals: [], options: { discarded_number: "", columns: [] } };
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ export class JournalDashboardActivity extends Component {
|
||||
}
|
||||
|
||||
formatData(props) {
|
||||
this.info = JSON.parse(this.props.value);
|
||||
this.info = JSON.parse(this.props.record.data[this.props.name]);
|
||||
this.info.more_activities = false;
|
||||
if (this.info.activities.length > this.MAX_ACTIVITY_DISPLAY) {
|
||||
this.info.more_activities = true;
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import { Many2OneField, many2OneField } from "@web/views/fields/many2one/many2on
|
||||
|
||||
class LineOpenMoveWidget extends Many2OneField {
|
||||
async openAction() {
|
||||
const action = await this.orm.call("account.move.line", "action_open_business_doc", [this.props.value[0]], {});
|
||||
const action = await this.orm.call("account.move.line", "action_open_business_doc", [this.props.record.data[this.props.name][0]], {});
|
||||
await this.action.doAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<templates>
|
||||
|
||||
<t t-name="account.OpenMoveWidget" owl="1">
|
||||
<a href="#" t-out="props.value" t-on-click.prevent.stop="(ev) => this.openMove()"/>
|
||||
<a href="#" t-out="props.record.data[props.name]" t-on-click.prevent.stop="(ev) => this.openMove()"/>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
||||
@@ -107,11 +107,11 @@ TaxGroupComponent.template = "account.TaxGroupComponent";
|
||||
export class TaxTotalsComponent extends Component {
|
||||
setup() {
|
||||
super.setup();
|
||||
this.totals = this.props.value;
|
||||
this.totals = this.props.record.data[this.props.name];
|
||||
this.readonly = this.props.readonly;
|
||||
onWillUpdateProps((nextProps) => {
|
||||
// We only reformat tax groups if there are changed
|
||||
this.totals = nextProps.value;
|
||||
this.totals = nextProps.record.data[nextProps.name];
|
||||
this.readonly = nextProps.readonly;
|
||||
this._computeTotalsFormat();
|
||||
});
|
||||
|
||||
+8
-3
@@ -47,6 +47,8 @@ export class AnalyticDistribution extends Component {
|
||||
this.focusSelector = false;
|
||||
this.activeGroup = false;
|
||||
|
||||
this.currentValue = this.props.record.data[this.props.name];
|
||||
|
||||
onWillStart(this.willStart);
|
||||
onWillUpdateProps(this.willUpdate);
|
||||
onPatched(this.patched);
|
||||
@@ -87,7 +89,9 @@ export class AnalyticDistribution extends Component {
|
||||
// and thus different applicabilities apply
|
||||
// or a model applies that contains unavailable plans
|
||||
// This should only execute when these fields have changed, therefore we use the `_field` props.
|
||||
const valueChanged = JSON.stringify(this.props.value) !== JSON.stringify(nextProps.value);
|
||||
const valueChanged =
|
||||
JSON.stringify(this.currentValue) !==
|
||||
JSON.stringify(nextProps.record.data[nextProps.name]);
|
||||
const currentAccount = this.props.account_field && this.props.record.data[this.props.account_field] || false;
|
||||
const currentProduct = this.props.product_field && this.props.record.data[this.props.product_field] || false;
|
||||
const accountChanged = !shallowEqual(this.lastAccount, currentAccount);
|
||||
@@ -100,6 +104,7 @@ export class AnalyticDistribution extends Component {
|
||||
this.lastProduct = productChanged && currentProduct || this.lastProduct;
|
||||
await this.formatData(nextProps);
|
||||
}
|
||||
this.currentValue = nextProps.record.data[nextProps.name];
|
||||
}
|
||||
|
||||
patched() {
|
||||
@@ -107,7 +112,7 @@ export class AnalyticDistribution extends Component {
|
||||
}
|
||||
|
||||
async formatData(nextProps) {
|
||||
const data = nextProps.value;
|
||||
const data = nextProps.record.data[nextProps.name];
|
||||
const analytic_account_ids = Object.keys(data).map((id) => parseInt(id));
|
||||
const records = analytic_account_ids.length ? await this.fetchAnalyticAccounts([["id", "in", analytic_account_ids]]) : [];
|
||||
if (records.length < data.length) {
|
||||
@@ -150,7 +155,7 @@ export class AnalyticDistribution extends Component {
|
||||
if (this.props.force_applicability) {
|
||||
args['applicability'] = this.props.force_applicability;
|
||||
}
|
||||
const existing_account_ids = Object.keys(nextProps.value).map((i) => parseInt(i));
|
||||
const existing_account_ids = Object.keys(nextProps.record.data[nextProps.name]).map((i) => parseInt(i));
|
||||
if (existing_account_ids.length) {
|
||||
args['existing_account_ids'] = existing_account_ids;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { useInputField } from "@web/views/fields/input_field_hook";
|
||||
import { recommendations, ConcretePolicy } from "./password_policy";
|
||||
import { Meter } from "./password_meter";
|
||||
|
||||
const { Component, xml, onWillStart, useState } = owl;
|
||||
const { Component, onWillStart, useState } = owl;
|
||||
|
||||
export class PasswordField extends Component {
|
||||
setup() {
|
||||
@@ -19,7 +19,7 @@ export class PasswordField extends Component {
|
||||
});
|
||||
|
||||
useInputField({
|
||||
getValue: () => this.props.value || "",
|
||||
getValue: () => this.props.record.data[this.props.name] || "",
|
||||
});
|
||||
|
||||
const orm = useService("orm");
|
||||
@@ -32,17 +32,7 @@ export class PasswordField extends Component {
|
||||
}
|
||||
PasswordField.props = standardFieldProps;
|
||||
PasswordField.components = { Meter };
|
||||
PasswordField.template = xml`
|
||||
<span t-if="props.readonly" t-out="props.value and '*'.repeat(props.value.length)"/>
|
||||
<t t-else="">
|
||||
<input class="o_input o_field_password" type="password"
|
||||
t-att-id="props.id" t-ref="input" placeholder=" "
|
||||
t-on-input="ev => this.state.value = ev.target.value"/>
|
||||
<Meter password="state.value"
|
||||
required="state.required"
|
||||
recommended="recommendations"/>
|
||||
</t>
|
||||
`;
|
||||
PasswordField.template = "auth_password_policy.PasswordField";
|
||||
|
||||
export const passwordField = {
|
||||
component: PasswordField,
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="auth_password_policy.PasswordField" owl="1">
|
||||
<span t-if="props.readonly" t-out="props.record.data[props.name] and '*'.repeat(props.record.data[props.name].length)"/>
|
||||
<t t-else="">
|
||||
<input class="o_input o_field_password" type="password"
|
||||
t-att-id="props.id" t-ref="input" placeholder=" "
|
||||
t-on-input="ev => this.state.value = ev.target.value"/>
|
||||
<Meter password="state.value"
|
||||
required="state.required"
|
||||
recommended="recommendations"/>
|
||||
</t>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -8,10 +8,13 @@ const { Component } = owl;
|
||||
|
||||
export class IconSelectionField extends Component {
|
||||
get icon() {
|
||||
return this.props.icons[this.props.value];
|
||||
return this.props.icons[this.props.record.data[this.props.name]];
|
||||
}
|
||||
get title() {
|
||||
return this.props.value.charAt(0).toUpperCase() + this.props.value.slice(1);
|
||||
return (
|
||||
this.props.record.data[this.props.name].charAt(0).toUpperCase() +
|
||||
this.props.record.data[this.props.name].slice(1)
|
||||
);
|
||||
}
|
||||
}
|
||||
IconSelectionField.template = "event.IconSelectionField";
|
||||
|
||||
+2
-2
@@ -16,11 +16,11 @@ export class FilterableSelectionField extends SelectionField {
|
||||
let options = super.options;
|
||||
if (this.props.whitelisted_values) {
|
||||
options = options.filter((option) => {
|
||||
return option[0] === this.props.value || this.props.whitelisted_values.includes(option[0])
|
||||
return option[0] === this.props.record.data[this.props.name] || this.props.whitelisted_values.includes(option[0])
|
||||
});
|
||||
} else if (this.props.blacklisted_values) {
|
||||
options = options.filter((option) => {
|
||||
return option[0] === this.props.value || !this.props.blacklisted_values.includes(option[0]);
|
||||
return option[0] === this.props.record.data[this.props.name] || !this.props.blacklisted_values.includes(option[0]);
|
||||
});
|
||||
}
|
||||
return options;
|
||||
|
||||
@@ -7,9 +7,12 @@ import { Component } from "@odoo/owl";
|
||||
|
||||
class ActivityException extends Component {
|
||||
get textClass() {
|
||||
if (this.props.value) {
|
||||
if (this.props.record.data[this.props.name]) {
|
||||
return (
|
||||
"text-" + this.props.value + " fa " + this.props.record.data.activity_exception_icon
|
||||
"text-" +
|
||||
this.props.record.data[this.props.name] +
|
||||
" fa " +
|
||||
this.props.record.data.activity_exception_icon
|
||||
);
|
||||
}
|
||||
return undefined;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<templates xml:space="preserve">
|
||||
<t t-name="mail.ActivityException" owl="1">
|
||||
<div
|
||||
t-if="props.value"
|
||||
t-if="props.record.data[props.name]"
|
||||
class="o_ActivityException float-end mt-1"
|
||||
t-att-class="textClass"
|
||||
title="This record has an exception activity."
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ export class KanbanFieldActivityViewContainer extends Component {
|
||||
const kanbanFieldActivityView = messaging.models["KanbanFieldActivityView"].insert({
|
||||
id: this.kanbanFieldActivityViewId,
|
||||
thread: {
|
||||
activities: props.value.records.map((activityData) => {
|
||||
activities: props.record.data[props.name].records.map((activityData) => {
|
||||
return {
|
||||
id: activityData.resId,
|
||||
};
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ export class ListFieldActivityViewContainer extends Component {
|
||||
const listFieldActivityView = messaging.models["ListFieldActivityView"].insert({
|
||||
id: this.listFieldActivityViewId,
|
||||
thread: {
|
||||
activities: props.value.records.map((activityData) => {
|
||||
activities: props.record.data[props.name].records.map((activityData) => {
|
||||
return {
|
||||
id: activityData.resId,
|
||||
};
|
||||
|
||||
@@ -21,10 +21,10 @@ export function useAssignUserCommand() {
|
||||
}
|
||||
|
||||
const getCurrentIds = () => {
|
||||
if (type === "many2one" && component.props.value) {
|
||||
return [component.props.value[0]];
|
||||
if (type === "many2one" && component.props.record.data[component.props.name]) {
|
||||
return [component.props.record.data[component.props.name][0]];
|
||||
} else if (type === "many2many") {
|
||||
return component.props.value.currentIds;
|
||||
return component.props.record.data[component.props.name].currentIds;
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
+3
-2
@@ -61,13 +61,14 @@ export class KanbanMany2ManyTagsAvatarUserField extends ListKanbanMany2ManyTagsA
|
||||
|
||||
get displayText() {
|
||||
return (
|
||||
(this.props.displayText && this.props.value.records.length === 1) ||
|
||||
(this.props.displayText && this.props.record.data[this.props.name].records.length === 1) ||
|
||||
!this.props.readonly
|
||||
);
|
||||
}
|
||||
|
||||
get tags() {
|
||||
const recordFromId = (id) => this.props.value.records.find((rec) => rec.id === id);
|
||||
const recordFromId = (id) =>
|
||||
this.props.record.data[this.props.name].records.find((rec) => rec.id === id);
|
||||
return super.tags.map((tag) => ({
|
||||
...tag,
|
||||
onImageClicked: () => {
|
||||
|
||||
@@ -44,7 +44,9 @@ export class FieldMany2ManyTagsEmail extends Many2ManyTagsField {
|
||||
}
|
||||
|
||||
async checkEmails(props) {
|
||||
const invalidRecords = props.value.records.filter((record) => !record.data.email);
|
||||
const invalidRecords = props.record.data[props.name].records.filter(
|
||||
(record) => !record.data.email
|
||||
);
|
||||
// Remove records with invalid data, open form view to edit those and readd them if they are updated correctly.
|
||||
const dialogDefs = [];
|
||||
for (const record of invalidRecords) {
|
||||
@@ -59,8 +61,10 @@ export class FieldMany2ManyTagsEmail extends Many2ManyTagsField {
|
||||
this.openedDialogs += invalidRecords.length;
|
||||
const invalidRecordIds = invalidRecords.map((rec) => rec.resId);
|
||||
if (invalidRecordIds.length) {
|
||||
this.props.value.replaceWith(
|
||||
props.value.currentIds.filter((id) => !invalidRecordIds.includes(id))
|
||||
this.props.record.data[this.props.name].replaceWith(
|
||||
props.record.data[props.name].currentIds.filter(
|
||||
(id) => !invalidRecordIds.includes(id)
|
||||
)
|
||||
);
|
||||
}
|
||||
return Promise.all(dialogDefs).then(() => {
|
||||
@@ -68,7 +72,7 @@ export class FieldMany2ManyTagsEmail extends Many2ManyTagsField {
|
||||
if (this.openedDialogs || !this.recordsIdsToAdd.length) {
|
||||
return;
|
||||
}
|
||||
props.value.add(this.recordsIdsToAdd, { isM2M: true });
|
||||
props.record.data[props.name].add(this.recordsIdsToAdd, { isM2M: true });
|
||||
this.recordsIdsToAdd = [];
|
||||
});
|
||||
}
|
||||
@@ -76,10 +80,13 @@ export class FieldMany2ManyTagsEmail extends Many2ManyTagsField {
|
||||
get tags() {
|
||||
// Add email to our tags
|
||||
const tags = super.tags;
|
||||
const emailByResId = this.props.value.records.reduce((acc, record) => {
|
||||
acc[record.resId] = record.data.email;
|
||||
return acc;
|
||||
}, {});
|
||||
const emailByResId = this.props.record.data[this.props.name].records.reduce(
|
||||
(acc, record) => {
|
||||
acc[record.resId] = record.data.email;
|
||||
return acc;
|
||||
},
|
||||
{}
|
||||
);
|
||||
tags.forEach((tag) => (tag.email = emailByResId[tag.resId]));
|
||||
return tags;
|
||||
}
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ export class Many2OneAvatarUserField extends Many2OneAvatarField {
|
||||
}
|
||||
|
||||
onClickAvatar() {
|
||||
this.openChat(this.props.value[0]);
|
||||
this.openChat(this.props.record.data[this.props.name][0]);
|
||||
}
|
||||
}
|
||||
Many2OneAvatarUserField.template = "mail.Many2OneAvatarUserField";
|
||||
|
||||
@@ -18,15 +18,15 @@ export class SlidesViewer extends CharField {
|
||||
}
|
||||
|
||||
get fileName() {
|
||||
return this.state.fileName || this.props.value || "";
|
||||
return this.state.fileName || this.props.record.data[this.props.name] || "";
|
||||
}
|
||||
|
||||
get url() {
|
||||
var src = false;
|
||||
if (this.props.value) {
|
||||
if (this.props.record.data[this.props.name]) {
|
||||
// check given google slide url is valid or not
|
||||
var googleRegExp = /(^https:\/\/docs.google.com).*(\/d\/e\/|\/d\/)([A-Za-z0-9-_]+)/;
|
||||
var google = this.props.value.match(googleRegExp);
|
||||
var google = this.props.record.data[this.props.name].match(googleRegExp);
|
||||
if (google && google[3]) {
|
||||
src =
|
||||
"https://docs.google.com/presentation" +
|
||||
|
||||
@@ -29,7 +29,7 @@ export class MrpTimer extends Component {
|
||||
this.state = useState({
|
||||
// duration is expected to be given in minutes
|
||||
duration:
|
||||
this.props.value !== undefined ? this.props.value : this.props.record.data.duration,
|
||||
this.props.record.data[this.props.name] !== undefined ? this.props.record.data[this.props.name] : this.props.record.data.duration,
|
||||
});
|
||||
this.lastDateTime = Date.now();
|
||||
useInputField({
|
||||
@@ -61,7 +61,7 @@ export class MrpTimer extends Component {
|
||||
const rerun = !this.ongoing && newOngoing;
|
||||
this.ongoing = newOngoing;
|
||||
if (rerun) {
|
||||
this.state.duration = nextProps.value;
|
||||
this.state.duration = nextProps.record.data[nextProps.name];
|
||||
this._runTimer();
|
||||
this._runSleepTimer()
|
||||
}
|
||||
@@ -70,8 +70,12 @@ export class MrpTimer extends Component {
|
||||
}
|
||||
|
||||
get durationFormatted() {
|
||||
if(this.props.value != this.state.duration && this.props.record && this.props.record.isDirty){
|
||||
this.state.duration = this.props.value;
|
||||
if (
|
||||
this.props.record.data[this.props.name] != this.state.duration &&
|
||||
this.props.record &&
|
||||
this.props.record.isDirty
|
||||
) {
|
||||
this.state.duration = this.props.record.data[this.props.name];
|
||||
}
|
||||
return formatMinutes(this.state.duration);
|
||||
}
|
||||
@@ -102,7 +106,6 @@ MrpTimer.props = {
|
||||
...standardFieldProps,
|
||||
duration: { type: Number, optional: true },
|
||||
ongoing: { type: Boolean, optional: true },
|
||||
value: { optional: true },
|
||||
};
|
||||
MrpTimer.template = "mrp.MrpTimer";
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ export class PartnerAutoCompleteCharField extends CharField {
|
||||
this.partner_autocomplete = usePartnerAutocomplete();
|
||||
|
||||
this.inputRef = useChildRef();
|
||||
useInputField({ getValue: () => this.props.value || "", parse: (v) => this.parse(v), ref: this.inputRef});
|
||||
useInputField({ getValue: () => this.props.record.data[this.props.name] || "", parse: (v) => this.parse(v), ref: this.inputRef});
|
||||
}
|
||||
|
||||
sanitizeVAT(request) {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<xpath expr="//t[@t-else='']" position="before">
|
||||
<t t-elif="props.record.resModel !== 'res.partner' || props.record.data.company_type === 'company'">
|
||||
<AutoComplete
|
||||
value="props.value || ''"
|
||||
value="props.record.data[props.name] || ''"
|
||||
sources="sources"
|
||||
onSelect.bind="onSelect"
|
||||
input="inputRef"
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
<t t-name="project.ProjectPrivateTaskMany2OneField" t-inherit="web.Many2OneField" t-inherit-mode="primary" owl="1">
|
||||
<xpath expr="//t[@t-if='!props.canOpen']/span" position="attributes">
|
||||
<attribute name="t-if">props.value</attribute>
|
||||
<attribute name="t-if">props.record.data[props.name]</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//t[@t-if='!props.canOpen']/span" position="after">
|
||||
<span t-else="" class="text-danger fst-italic text-muted"><i class="fa fa-lock"></i> Private</span>
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ export class ProjectStatusWithColorSelectionField extends SelectionField {
|
||||
}
|
||||
|
||||
get currentValue() {
|
||||
return this.props.value || this.options[0][0];
|
||||
return this.props.record.data[this.props.name] || this.options[0][0];
|
||||
}
|
||||
|
||||
statusColor(value) {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
style="color: inherit;"
|
||||
t-esc="subTask.data.display_name"
|
||||
t-on-click.prevent="() => this.goToSubtask(subTask.resId)"/>
|
||||
<Field value="subTask.data.user_ids"
|
||||
<Field
|
||||
class="`subtask_user_widget_col justify-content-end align-items-center`"
|
||||
name="'user_ids'"
|
||||
record="subTask"
|
||||
|
||||
@@ -12,7 +12,7 @@ export class PrioritySwitchField extends PriorityField {
|
||||
{
|
||||
category: "smart_action",
|
||||
hotkey: "alt+r",
|
||||
isAvailable: () => this.props.value !== id,
|
||||
isAvailable: () => this.props.record.data[this.props.name] !== id,
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -13,12 +13,13 @@ export class PurchaseOrderLineProductField extends Many2OneField {
|
||||
setup() {
|
||||
super.setup();
|
||||
this.dialog = useService("dialog");
|
||||
this.currentValue = this.value;
|
||||
|
||||
onWillUpdateProps(async (nextProps) => {
|
||||
if (nextProps.record.mode === 'edit' && nextProps.value) {
|
||||
if (nextProps.record.mode === 'edit' && nextProps.record.data[nextProps.name]) {
|
||||
if (
|
||||
!this.props.value ||
|
||||
this.props.value[0] != nextProps.value[0]
|
||||
!this.currentValue ||
|
||||
this.currentValue[0] != nextProps.record.data[nextProps.name][0]
|
||||
) {
|
||||
// Field was updated if line was open in edit mode,
|
||||
// field is not emptied,
|
||||
@@ -27,6 +28,7 @@ export class PurchaseOrderLineProductField extends Many2OneField {
|
||||
this._onProductTemplateUpdate();
|
||||
}
|
||||
}
|
||||
this.currentValue = nextProps.record.data[nextProps.name];
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ export class ProductDiscountField extends FloatField {
|
||||
return {
|
||||
operation: "UPDATE",
|
||||
record: line,
|
||||
data: {["discount"]: this.props.value},
|
||||
data: {["discount"]: this.props.record.data[this.props.name]},
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ export class SaleOrderLineProductField extends Many2OneField {
|
||||
// NB: quick creation doesn't go through here, but through quickCreate
|
||||
// below
|
||||
if (value) {
|
||||
if (Array.isArray(value[0]) && this.props.value != value[0]) {
|
||||
if (Array.isArray(value[0]) && this.props.record.data[this.props.name] != value[0]) {
|
||||
// product (existing)
|
||||
newValue = true;
|
||||
} else {
|
||||
@@ -61,7 +61,7 @@ export class SaleOrderLineProductField extends Many2OneField {
|
||||
// Keep external button, even if field is specified as 'no_open' so that the user is not
|
||||
// redirected to the product when clicking on the field content
|
||||
const res = super.hasExternalButton;
|
||||
return res || (!!this.props.value && !this.state.isFloating);
|
||||
return res || (!!this.props.record.data[this.props.name] && !this.state.isFloating);
|
||||
}
|
||||
get hasConfigurationButton() {
|
||||
return this.isConfigurableLine || this.isConfigurableTemplate;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<t t-inherit="web.PhoneField" t-inherit-mode="extension">
|
||||
<xpath expr="//div[hasclass('o_phone_content')]//a" position="after">
|
||||
<t t-if="props.enableButton and props.value.length > 0">
|
||||
<t t-if="props.enableButton and props.record.data[props.name].length > 0">
|
||||
<SendSMSButton t-props="props" />
|
||||
</t>
|
||||
</xpath>
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
<t t-inherit="web.FormPhoneField" t-inherit-mode="extension">
|
||||
<xpath expr="//div[hasclass('o_phone_content')]" position="inside">
|
||||
<t t-if="props.enableButton and props.value.length > 0">
|
||||
<t t-if="props.enableButton and props.record.data[props.name].length > 0">
|
||||
<SendSMSButton t-props="props" />
|
||||
</t>
|
||||
</xpath>
|
||||
|
||||
@@ -20,10 +20,10 @@ export class SmsWidget extends EmojisTextField {
|
||||
}
|
||||
|
||||
get encoding() {
|
||||
return this._extractEncoding(this.props.value || '');
|
||||
return this._extractEncoding(this.props.record.data[this.props.name] || '');
|
||||
}
|
||||
get nbrChar() {
|
||||
const content = this.props.value || '';
|
||||
const content = this.props.record.data[this.props.name] || '';
|
||||
return content.length + (content.match(/\n/g) || []).length;
|
||||
}
|
||||
get nbrSMS() {
|
||||
@@ -77,7 +77,7 @@ export class SmsWidget extends EmojisTextField {
|
||||
* @private
|
||||
*/
|
||||
async onBlur() {
|
||||
var content = this.props.value || '';
|
||||
var content = this.props.record.data[this.props.name] || '';
|
||||
if( !content.trim().length && content.length > 0) {
|
||||
this.notification.add(
|
||||
this.env._t("Your SMS Text Message must include at least one non-whitespace character"),
|
||||
|
||||
@@ -41,7 +41,7 @@ export class CountedQuantityWidgetField extends FloatField {
|
||||
get formattedValue() {
|
||||
if (
|
||||
this.props.readonly &&
|
||||
!this.props.value & !this.props.record.data.inventory_quantity_set
|
||||
!this.props.record.data[this.props.name] & !this.props.record.data.inventory_quantity_set
|
||||
) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ const { Component, onWillStart, onWillUpdateProps } = owl;
|
||||
export class JsonPopOver extends Component {
|
||||
|
||||
setup(){
|
||||
this.jsonValue = JSON.parse(this.props.value);
|
||||
this.jsonValue = JSON.parse(this.props.record.data[this.props.name]);
|
||||
onWillUpdateProps(nextProps => {
|
||||
this.jsonValue = JSON.parse(nextProps.value);
|
||||
this.jsonValue = JSON.parse(nextProps.record.data[nextProps.name]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,8 +69,8 @@ export class ProfilingQwebView extends Component {
|
||||
* @returns {archs, data: {template, xpath, directive, time, duration, query }[]}
|
||||
*/
|
||||
get profile() {
|
||||
if (this.props.value) {
|
||||
return JSON.parse(this.props.value)[0].results;
|
||||
if (this.props.record.data[this.props.name]) {
|
||||
return JSON.parse(this.props.record.data[this.props.name])[0].results;
|
||||
}
|
||||
return { archs: {}, data: [] };
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ export class AceField extends Component {
|
||||
this.aceEditor.on("blur", this.commitChanges.bind(this));
|
||||
}
|
||||
|
||||
updateAce({ mode, readonly, value }) {
|
||||
updateAce({ mode, readonly, record }) {
|
||||
if (!this.aceEditor) {
|
||||
return;
|
||||
}
|
||||
@@ -97,7 +97,7 @@ export class AceField extends Component {
|
||||
|
||||
this.aceEditor.renderer.$cursorLayer.element.style.display = readonly ? "none" : "block";
|
||||
|
||||
const formattedValue = formatText(value);
|
||||
const formattedValue = formatText(record.data[this.props.name]);
|
||||
if (this.aceSession.getValue() !== formattedValue) {
|
||||
this.aceSession.setValue(formattedValue);
|
||||
}
|
||||
@@ -112,7 +112,7 @@ export class AceField extends Component {
|
||||
commitChanges() {
|
||||
if (!this.props.readonly) {
|
||||
const value = this.aceSession.getValue();
|
||||
if (this.props.value !== value) {
|
||||
if (this.props.record.data[this.props.name] !== value) {
|
||||
return this.props.record.update({ [this.props.name]: value });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<t t-name="web.AttachmentImageField" owl="1">
|
||||
<div class="o_attachment_image">
|
||||
<img t-if="props.value" t-attf-src="/web/image/{{ props.value[0] }}?unique=1" t-att-title="props.value[1]" alt="Image" />
|
||||
<img t-if="props.record.data[props.name]" t-attf-src="/web/image/{{ props.record.data[props.name][0] }}?unique=1" t-att-title="props.record.data[props.name][1]" alt="Image" />
|
||||
</div>
|
||||
</t>
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ export class BadgeField extends Component {
|
||||
|
||||
get formattedValue() {
|
||||
const formatter = formatters.get(this.props.record.fields[this.props.name].type);
|
||||
return formatter(this.props.value, {
|
||||
return formatter(this.props.record.data[this.props.name], {
|
||||
selection: this.props.record.fields[this.props.name].selection,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<templates id="template" xml:space="preserve">
|
||||
|
||||
<t t-name="web.BadgeField" owl="1">
|
||||
<span t-if="props.value" class="badge rounded-pill" t-att-class="classFromDecoration" t-esc="formattedValue" />
|
||||
<span t-if="props.record.data[props.name]" class="badge rounded-pill" t-att-class="classFromDecoration" t-esc="formattedValue" />
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
||||
@@ -29,17 +29,19 @@ export class BadgeSelectionField extends Component {
|
||||
get string() {
|
||||
switch (this.props.record.fields[this.props.name].type) {
|
||||
case "many2one":
|
||||
return this.props.value ? this.props.value[1] : "";
|
||||
return this.props.record.data[this.props.name]
|
||||
? this.props.record.data[this.props.name][1]
|
||||
: "";
|
||||
case "selection":
|
||||
return this.props.value !== false
|
||||
? this.options.find((o) => o[0] === this.props.value)[1]
|
||||
return this.props.record.data[this.props.name] !== false
|
||||
? this.options.find((o) => o[0] === this.props.record.data[this.props.name])[1]
|
||||
: "";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
get value() {
|
||||
const rawValue = this.props.value;
|
||||
const rawValue = this.props.record.data[this.props.name];
|
||||
return this.props.record.fields[this.props.name].type === "many2one" && rawValue
|
||||
? rawValue[0]
|
||||
: rawValue;
|
||||
|
||||
@@ -36,7 +36,7 @@ export class BinaryField extends Component {
|
||||
}
|
||||
|
||||
get fileName() {
|
||||
return this.state.fileName || this.props.value || "";
|
||||
return this.state.fileName || this.props.record.data[this.props.name] || "";
|
||||
}
|
||||
|
||||
update({ data, name }) {
|
||||
@@ -58,7 +58,9 @@ export class BinaryField extends Component {
|
||||
filename_field: this.fileName,
|
||||
filename: this.fileName || "",
|
||||
download: true,
|
||||
data: isBinarySize(this.props.value) ? null : this.props.value,
|
||||
data: isBinarySize(this.props.record.data[this.props.name])
|
||||
? null
|
||||
: this.props.record.data[this.props.name],
|
||||
},
|
||||
url: "/web/content",
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<t t-name="web.BinaryField" owl="1">
|
||||
<t t-if="!props.readonly">
|
||||
<t t-if="props.value">
|
||||
<t t-if="props.record.data[props.name]">
|
||||
<div class="w-100 d-inline-flex">
|
||||
<FileUploader
|
||||
acceptedFileExtensions="props.acceptedFileExtensions"
|
||||
@@ -47,7 +47,7 @@
|
||||
</label>
|
||||
</t>
|
||||
</t>
|
||||
<t t-elif="props.record.resId and props.value">
|
||||
<t t-elif="props.record.resId and props.record.data[props.name]">
|
||||
<a class="o_form_uri" href="#" t-on-click.prevent="onFileDownload">
|
||||
<span class="fa fa-download me-2" />
|
||||
<t t-if="state.fileName" t-esc="state.fileName" />
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="web.BooleanField" owl="1">
|
||||
<CheckBox id="props.id" value="props.value or false" className="'d-inline-block me-2'" disabled="isReadonly" onChange.bind="onChange" />
|
||||
<CheckBox id="props.id" value="props.record.data[props.name] or false" className="'d-inline-block me-2'" disabled="isReadonly" onChange.bind="onChange" />
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
||||
@@ -18,7 +18,7 @@ export class BooleanFavoriteField extends Component {
|
||||
};
|
||||
|
||||
update() {
|
||||
this.props.record.update({ [this.props.name]: !this.props.value });
|
||||
this.props.record.update({ [this.props.name]: !this.props.record.data[this.props.name] });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
<i
|
||||
class="fa"
|
||||
role="img"
|
||||
t-att-class="props.value ? 'fa-star' : 'fa-star-o'"
|
||||
t-att-title="props.value ? 'Remove from Favorites' : 'Add to Favorites'"
|
||||
t-att-aria-label="props.value ? 'Remove from Favorites' : 'Add to Favorites'"
|
||||
t-att-class="props.record.data[props.name] ? 'fa-star' : 'fa-star-o'"
|
||||
t-att-title="props.record.data[props.name] ? 'Remove from Favorites' : 'Add to Favorites'"
|
||||
t-att-aria-label="props.record.data[props.name] ? 'Remove from Favorites' : 'Add to Favorites'"
|
||||
/>
|
||||
<t t-if="!props.noLabel"> <t t-esc="props.value ? 'Remove from Favorites' : 'Add to Favorites'" /></t>
|
||||
<t t-if="!props.noLabel"> <t t-esc="props.record.data[props.name] ? 'Remove from Favorites' : 'Add to Favorites'" /></t>
|
||||
</a>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
@@ -17,7 +17,7 @@ export class BooleanIconField extends Component {
|
||||
};
|
||||
|
||||
update() {
|
||||
this.props.record.update({ [this.props.name]: !this.props.value });
|
||||
this.props.record.update({ [this.props.name]: !this.props.record.data[this.props.name] });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="web.BooleanIconField" owl="1">
|
||||
<button t-attf-class="btn btn-sm btn-{{props.value ? 'primary' : 'outline-secondary'}} mx-2 py-1 fa {{props.icon}}" t-att-data-tooltip="props.label" t-on-click.prevent.stop="update" />
|
||||
<button t-attf-class="btn btn-sm btn-{{props.record.data[props.name] ? 'primary' : 'outline-secondary'}} mx-2 py-1 fa {{props.icon}}" t-att-data-tooltip="props.label" t-on-click.prevent.stop="update" />
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
||||
@@ -8,7 +8,9 @@ export class ListBooleanToggleField extends BooleanToggleField {
|
||||
|
||||
onClick() {
|
||||
if (!this.props.readonly) {
|
||||
this.props.record.update({ [this.props.name]: !this.props.value });
|
||||
this.props.record.update({
|
||||
[this.props.name]: !this.props.record.data[this.props.name],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,10 @@ export class CharField extends Component {
|
||||
dynamicPlaceholder.updateModel(this.props.dynamicPlaceholderModelReferenceField)
|
||||
);
|
||||
}
|
||||
useInputField({ getValue: () => this.props.value || "", parse: (v) => this.parse(v) });
|
||||
useInputField({
|
||||
getValue: () => this.props.record.data[this.props.name] || "",
|
||||
parse: (v) => this.parse(v),
|
||||
});
|
||||
}
|
||||
|
||||
get shouldTrim() {
|
||||
@@ -48,7 +51,9 @@ export class CharField extends Component {
|
||||
return this.props.record.fields[this.props.name].translate;
|
||||
}
|
||||
get formattedValue() {
|
||||
return formatChar(this.props.value, { isPassword: this.props.isPassword });
|
||||
return formatChar(this.props.record.data[this.props.name], {
|
||||
isPassword: this.props.isPassword,
|
||||
});
|
||||
}
|
||||
|
||||
parse(value) {
|
||||
|
||||
@@ -13,11 +13,11 @@ export class ColorField extends Component {
|
||||
|
||||
setup() {
|
||||
this.state = useState({
|
||||
color: this.props.value || "",
|
||||
color: this.props.record.data[this.props.name] || "",
|
||||
});
|
||||
|
||||
onWillUpdateProps((nextProps) => {
|
||||
this.state.color = nextProps.value || "";
|
||||
this.state.color = nextProps.record.data[nextProps.name] || "";
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="web.ColorPickerField" owl="1">
|
||||
<ColorList canToggle="props.canToggle" colors="constructor.RECORD_COLORS" forceExpanded="isExpanded" onColorSelected.bind="switchColor" selectedColor="props.value || 0"/>
|
||||
<ColorList canToggle="props.canToggle" colors="constructor.RECORD_COLORS" forceExpanded="isExpanded" onColorSelected.bind="switchColor" selectedColor="props.record.data[props.name] || 0"/>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
<t t-name="web.CopyClipboardField" owl="1">
|
||||
<div class="d-grid rounded-2 overflow-hidden">
|
||||
<Field t-props="fieldProps"/>
|
||||
<CopyButton className="copyButtonClassName" content="props.value" copyText="copyText" successText="successText"/>
|
||||
<CopyButton className="copyButtonClassName" content="props.record.data[props.name]" copyText="copyText" successText="successText"/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="web.CopyClipboardButtonField" owl="1">
|
||||
<CopyButton t-if="props.value" className="copyButtonClassName" content="props.value" copyText="copyText" disabled="disabled" successText="successText"/>
|
||||
<CopyButton t-if="props.record.data[props.name]" className="copyButtonClassName" content="props.record.data[props.name]" copyText="copyText" disabled="disabled" successText="successText"/>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
||||
@@ -35,13 +35,18 @@ export class DateField extends Component {
|
||||
return this.props.record.fields[this.props.name].type === "datetime";
|
||||
}
|
||||
get date() {
|
||||
return this.props.value && this.props.value.startOf("day");
|
||||
return (
|
||||
this.props.record.data[this.props.name] &&
|
||||
this.props.record.data[this.props.name].startOf("day")
|
||||
);
|
||||
}
|
||||
|
||||
get formattedValue() {
|
||||
return this.isDateTime
|
||||
? formatDateTime(this.props.value, { format: localization.dateFormat })
|
||||
: formatDate(this.props.value);
|
||||
? formatDateTime(this.props.record.data[this.props.name], {
|
||||
format: localization.dateFormat,
|
||||
})
|
||||
: formatDate(this.props.record.data[this.props.name]);
|
||||
}
|
||||
|
||||
onDateTimeChanged(date) {
|
||||
|
||||
@@ -59,7 +59,7 @@ export class DateRangeField extends Component {
|
||||
}
|
||||
};
|
||||
},
|
||||
() => [this.root.el, this.props.value]
|
||||
() => [this.root.el, this.props.record.data[this.props.name]]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ export class DateRangeField extends Component {
|
||||
return this.formatType === "datetime";
|
||||
}
|
||||
get formattedValue() {
|
||||
return this.formatValue(this.formatType, this.props.value);
|
||||
return this.formatValue(this.formatType, this.props.record.data[this.props.name]);
|
||||
}
|
||||
get formattedEndDate() {
|
||||
return this.formatValue(this.formatType, this.endDate);
|
||||
|
||||
@@ -31,11 +31,11 @@ export class DateTimeField extends Component {
|
||||
}
|
||||
|
||||
get formattedValue() {
|
||||
return formatDateTime(this.props.value);
|
||||
return formatDateTime(this.props.record.data[this.props.name]);
|
||||
}
|
||||
|
||||
onDateTimeChanged(date) {
|
||||
if (!areDateEquals(this.props.value || "", date)) {
|
||||
if (!areDateEquals(this.props.record.data[this.props.name] || "", date)) {
|
||||
this.props.record.update({ [this.props.name]: date });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<t t-else="">
|
||||
<DateTimePicker
|
||||
t-props="props.pickerOptions"
|
||||
date="props.value"
|
||||
date="props.record.data[props.name]"
|
||||
inputId="props.id"
|
||||
placeholder="props.placeholder"
|
||||
onDateTimeChanged="(datetime) => this.onDateTimeChanged(datetime)"
|
||||
|
||||
@@ -37,13 +37,13 @@ export class DomainField extends Component {
|
||||
this.isDebugEdited = false;
|
||||
|
||||
onWillStart(() => {
|
||||
this.displayedDomain = this.props.value;
|
||||
this.displayedDomain = this.props.record.data[this.props.name];
|
||||
this.loadCount(this.props);
|
||||
});
|
||||
onWillUpdateProps((nextProps) => {
|
||||
this.isDebugEdited = this.isDebugEdited && this.props.readonly === nextProps.readonly;
|
||||
if (!this.isDebugEdited) {
|
||||
this.displayedDomain = nextProps.value;
|
||||
this.displayedDomain = nextProps.record.data[nextProps.name];
|
||||
this.loadCount(nextProps);
|
||||
}
|
||||
});
|
||||
@@ -79,7 +79,10 @@ export class DomainField extends Component {
|
||||
noCreate: true,
|
||||
multiSelect: false,
|
||||
resModel: this.getResModel(this.props),
|
||||
domain: this.getDomain(this.props.value).toList(this.getContext(this.props)) || [],
|
||||
domain:
|
||||
this.getDomain(this.props.record.data[this.props.name]).toList(
|
||||
this.getContext(this.props)
|
||||
) || [],
|
||||
context: this.getContext(this.props) || {},
|
||||
},
|
||||
{
|
||||
@@ -90,7 +93,7 @@ export class DomainField extends Component {
|
||||
}
|
||||
get isValidDomain() {
|
||||
try {
|
||||
this.getDomain(this.props.value).toList();
|
||||
this.getDomain(this.props.record.data[this.props.name]).toList();
|
||||
return true;
|
||||
} catch {
|
||||
// WOWL TODO: rethrow error when not the expected type
|
||||
@@ -108,7 +111,9 @@ export class DomainField extends Component {
|
||||
|
||||
let recordCount;
|
||||
try {
|
||||
const domain = this.getDomain(props.value).toList(this.getContext(props));
|
||||
const domain = this.getDomain(props.record.data[props.name]).toList(
|
||||
this.getContext(props)
|
||||
);
|
||||
recordCount = await this.orm.silent.call(
|
||||
this.getResModel(props),
|
||||
"search_count",
|
||||
@@ -131,7 +136,7 @@ export class DomainField extends Component {
|
||||
onEditDialogBtnClick() {
|
||||
this.addDialog(DomainSelectorDialog, {
|
||||
resModel: this.getResModel(this.props),
|
||||
initialValue: this.props.value || "[]",
|
||||
initialValue: this.props.record.data[this.props.name] || "[]",
|
||||
readonly: this.props.readonly,
|
||||
isDebugMode: !!this.env.debug,
|
||||
onSelected: (value) => this.props.record.update({ [this.props.name]: value }),
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
readonly="props.readonly or props.editInDialog"
|
||||
update.bind="update"
|
||||
isDebugMode="!!env.debug"
|
||||
debugValue="props.value || '[]'"
|
||||
debugValue="props.record.data[props.name] || '[]'"
|
||||
className="props.readonly ? 'o_read_mode' : 'o_edit_mode'"
|
||||
/>
|
||||
<div class="o_field_domain_panel">
|
||||
|
||||
@@ -15,7 +15,7 @@ export class EmailField extends Component {
|
||||
};
|
||||
|
||||
setup() {
|
||||
useInputField({ getValue: () => this.props.value || "" });
|
||||
useInputField({ getValue: () => this.props.record.data[this.props.name] || "" });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<t t-name="web.EmailField" owl="1">
|
||||
<t t-if="props.readonly">
|
||||
<a class="o_form_uri o_text_overflow" t-on-click.stop="" t-att-href="props.value ? 'mailto:'+props.value : undefined" t-esc="props.value || ''"/>
|
||||
<a class="o_form_uri o_text_overflow" t-on-click.stop="" t-att-href="props.record.data[props.name] ? 'mailto:'+props.record.data[props.name] : undefined" t-esc="props.record.data[props.name] || ''"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div class="d-inline-flex w-100">
|
||||
@@ -22,8 +22,8 @@
|
||||
<t t-name="web.FormEmailField" t-inherit="web.EmailField" t-inherit-mode="primary">
|
||||
<xpath expr="//input" position="after">
|
||||
<a
|
||||
t-if="props.value"
|
||||
t-att-href="'mailto:'+props.value"
|
||||
t-if="props.record.data[props.name]"
|
||||
t-att-href="'mailto:'+props.record.data[props.name]"
|
||||
class="ms-3 d-inline-flex align-items-center"
|
||||
>
|
||||
<i class="fa fa-envelope" data-tooltip="Send Email" aria-label="Send Email"></i>
|
||||
|
||||
@@ -140,7 +140,6 @@ export class Field extends Component {
|
||||
delete props.type;
|
||||
|
||||
return {
|
||||
value: this.props.record.data[this.props.name],
|
||||
readonly: !record.isInEdition || readonlyFromModifiers || false,
|
||||
...propsFromNode,
|
||||
...props,
|
||||
|
||||
@@ -48,7 +48,7 @@ export class FloatField extends Component {
|
||||
}
|
||||
|
||||
get value() {
|
||||
return this.props.value;
|
||||
return this.props.record.data[this.props.name];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ export class FloatFactorField extends FloatField {
|
||||
}
|
||||
|
||||
get value() {
|
||||
return this.props.value * this.props.factor;
|
||||
return this.props.record.data[this.props.name] * this.props.factor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ export class FloatTimeField extends Component {
|
||||
}
|
||||
|
||||
get formattedValue() {
|
||||
return formatFloatTime(this.props.value);
|
||||
return formatFloatTime(this.props.record.data[this.props.name]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,9 @@ export class FloatToggleField extends Component {
|
||||
// TODO perf issue (because of update round trip)
|
||||
// we probably want to have a state and a useEffect or onWillUpateProps
|
||||
onChange() {
|
||||
let currentIndex = this.props.range.indexOf(this.props.value * this.factor);
|
||||
let currentIndex = this.props.range.indexOf(
|
||||
this.props.record.data[this.props.name] * this.factor
|
||||
);
|
||||
currentIndex++;
|
||||
if (currentIndex > this.props.range.length - 1) {
|
||||
currentIndex = 0;
|
||||
@@ -44,7 +46,7 @@ export class FloatToggleField extends Component {
|
||||
return !this.props.digits && Array.isArray(fieldDigits) ? fieldDigits : this.props.digits;
|
||||
}
|
||||
get formattedValue() {
|
||||
return formatFloat(this.props.value * this.factor, {
|
||||
return formatFloat(this.props.record.data[this.props.name] * this.factor, {
|
||||
digits: this.digits,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -23,7 +23,9 @@ export class FontSelectionField extends Component {
|
||||
return this.props.record.isRequired(this.props.name);
|
||||
}
|
||||
get string() {
|
||||
return formatSelection(this.props.value, { selection: this.options });
|
||||
return formatSelection(this.props.record.data[this.props.name], {
|
||||
selection: this.options,
|
||||
});
|
||||
}
|
||||
|
||||
stringify(value) {
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|
||||
<t t-name="web.FontSelectionField" owl="1">
|
||||
<t t-if="props.readonly">
|
||||
<span t-esc="string" t-att-raw-value="props.value" t-attf-style="font-family:{{ props.value }};"/>
|
||||
<span t-esc="string" t-att-raw-value="props.record.data[props.name]" t-attf-style="font-family:{{ props.record.data[props.name] }};"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<select class="o_input" t-on-change="onChange" t-attf-style="font-family:{{ props.value }};">
|
||||
<select class="o_input" t-on-change="onChange" t-attf-style="font-family:{{ props.record.data[props.name] }};">
|
||||
<option
|
||||
t-att-selected="false === value"
|
||||
t-att-value="stringify(false)"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<t t-name="web.HtmlField" owl="1">
|
||||
<t t-if="props.readonly">
|
||||
<span t-out="props.value or ''" />
|
||||
<span t-out="props.record.data[props.name] or ''" />
|
||||
</t>
|
||||
<t t-else="" t-call="web.TextField" />
|
||||
</t>
|
||||
|
||||
@@ -31,7 +31,7 @@ export class IframeWrapperField extends Component {
|
||||
iframeDoc.write(value);
|
||||
iframeDoc.close();
|
||||
},
|
||||
() => [this.props.value]
|
||||
() => [this.props.record.data[this.props.name]]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,9 @@ export class ImageField extends Component {
|
||||
return style;
|
||||
}
|
||||
get hasTooltip() {
|
||||
return this.props.enableZoom && this.props.readonly && this.props.value;
|
||||
return (
|
||||
this.props.enableZoom && this.props.readonly && this.props.record.data[this.props.name]
|
||||
);
|
||||
}
|
||||
get tooltipAttributes() {
|
||||
return {
|
||||
@@ -91,8 +93,8 @@ export class ImageField extends Component {
|
||||
}
|
||||
|
||||
getUrl(previewFieldName) {
|
||||
if (this.state.isValid && this.props.value) {
|
||||
if (isBinarySize(this.props.value)) {
|
||||
if (this.state.isValid && this.props.record.data[this.props.name]) {
|
||||
if (isBinarySize(this.props.record.data[this.props.name])) {
|
||||
if (!this.rawCacheKey) {
|
||||
this.rawCacheKey = this.props.record.data.write_date;
|
||||
}
|
||||
@@ -104,8 +106,9 @@ export class ImageField extends Component {
|
||||
});
|
||||
} else {
|
||||
// Use magic-word technique for detecting image type
|
||||
const magic = fileTypeMagicWordMap[this.props.value[0]] || "png";
|
||||
return `data:image/${magic};base64,${this.props.value}`;
|
||||
const magic =
|
||||
fileTypeMagicWordMap[this.props.record.data[this.props.name][0]] || "png";
|
||||
return `data:image/${magic};base64,${this.props.record.data[this.props.name]}`;
|
||||
}
|
||||
}
|
||||
return placeholder;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
</button>
|
||||
</t>
|
||||
<button
|
||||
t-if="props.value and state.isValid"
|
||||
t-if="props.record.data[props.name] and state.isValid"
|
||||
class="o_clear_file_button btn btn-light border-0 rounded-circle m-1 p-1"
|
||||
data-tooltip="Clear"
|
||||
aria-label="Clear"
|
||||
|
||||
@@ -20,12 +20,12 @@ export class ImageUrlField extends Component {
|
||||
setup() {
|
||||
this.notification = useService("notification");
|
||||
this.state = useState({
|
||||
src: this.props.value,
|
||||
src: this.props.record.data[this.props.name],
|
||||
});
|
||||
|
||||
onWillUpdateProps((nextProps) => {
|
||||
if (this.props.value !== nextProps.value) {
|
||||
this.state.value = nextProps.value;
|
||||
if (this.props.record.data[this.props.name] !== nextProps.record.data[nextProps.name]) {
|
||||
this.state.value = nextProps.record.data[nextProps.name];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<t t-name="web.ImageUrlField" owl="1">
|
||||
<img
|
||||
t-if="props.value"
|
||||
t-if="props.record.data[props.name]"
|
||||
class="img img-fluid"
|
||||
alt="Image"
|
||||
t-att-src="state.src"
|
||||
|
||||
@@ -154,7 +154,7 @@ export function useInputField(params) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((val || false) !== (component.props.value || false)) {
|
||||
if ((val || false) !== (component.props.record.data[component.props.name] || false)) {
|
||||
await component.props.record.update({ [component.props.name]: val });
|
||||
lastSetValue = inputRef.el.value;
|
||||
component.props.record.model.env.bus.trigger(
|
||||
|
||||
@@ -33,9 +33,9 @@ export class IntegerField extends Component {
|
||||
|
||||
get formattedValue() {
|
||||
if (!this.props.readonly && this.props.inputType === "number") {
|
||||
return this.props.value;
|
||||
return this.props.record.data[this.props.name];
|
||||
}
|
||||
return formatInteger(this.props.value);
|
||||
return formatInteger(this.props.record.data[this.props.name]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ export class JournalDashboardGraphField extends Component {
|
||||
this.chart = null;
|
||||
this.cookies = useService("cookie");
|
||||
this.canvasRef = useRef("canvas");
|
||||
this.data = JSON.parse(this.props.value);
|
||||
this.data = JSON.parse(this.props.record.data[this.props.name]);
|
||||
|
||||
onWillStart(() => loadJS("/web/static/lib/Chart/Chart.js"));
|
||||
|
||||
|
||||
@@ -18,10 +18,10 @@ export class LabelSelectionField extends Component {
|
||||
};
|
||||
|
||||
get className() {
|
||||
return this.props.classesObj[this.props.value] || "primary";
|
||||
return this.props.classesObj[this.props.record.data[this.props.name]] || "primary";
|
||||
}
|
||||
get string() {
|
||||
return formatSelection(this.props.value, {
|
||||
return formatSelection(this.props.record.data[this.props.name], {
|
||||
selection: Array.from(this.props.record.fields[this.props.name].selection),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="web.LabelSelectionField" owl="1">
|
||||
<span t-attf-class="badge text-bg-{{className}} " t-esc="string" t-att-raw-value="props.value"/>
|
||||
<span t-attf-class="badge text-bg-{{className}} " t-esc="string" t-att-raw-value="props.record.data[props.name]"/>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
||||
@@ -22,14 +22,14 @@ export class Many2ManyBinaryField extends Component {
|
||||
setup() {
|
||||
this.orm = useService("orm");
|
||||
this.notification = useService("notification");
|
||||
this.operations = useX2ManyCrud(() => this.props.value, true);
|
||||
this.operations = useX2ManyCrud(() => this.props.record.data[this.props.name], true);
|
||||
}
|
||||
|
||||
get uploadText() {
|
||||
return this.props.record.fields[this.props.name].string;
|
||||
}
|
||||
get files() {
|
||||
return this.props.value.records.map((record) => record.data);
|
||||
return this.props.record.data[this.props.name].records.map((record) => record.data);
|
||||
}
|
||||
|
||||
getUrl(id) {
|
||||
@@ -53,7 +53,9 @@ export class Many2ManyBinaryField extends Component {
|
||||
}
|
||||
|
||||
async onFileRemove(deleteId) {
|
||||
const record = this.props.value.records.find((record) => record.data.id === deleteId);
|
||||
const record = this.props.record.data[this.props.name].records.find(
|
||||
(record) => record.data.id === deleteId
|
||||
);
|
||||
this.operations.removeRecord(record);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-4
@@ -19,19 +19,22 @@ export class Many2ManyCheckboxesField extends Component {
|
||||
}
|
||||
|
||||
isSelected(item) {
|
||||
return this.props.value.currentIds.includes(item[0]);
|
||||
return this.props.record.data[this.props.name].currentIds.includes(item[0]);
|
||||
}
|
||||
|
||||
onChange(resId, checked) {
|
||||
if (checked) {
|
||||
this.props.value.replaceWith([...this.props.value.currentIds, resId]);
|
||||
this.props.record.data[this.props.name].replaceWith([
|
||||
...this.props.record.data[this.props.name].currentIds,
|
||||
resId,
|
||||
]);
|
||||
} else {
|
||||
const currentIds = [...this.props.value.currentIds];
|
||||
const currentIds = [...this.props.record.data[this.props.name].currentIds];
|
||||
const index = currentIds.indexOf(resId);
|
||||
if (index > -1) {
|
||||
currentIds.splice(index, 1);
|
||||
}
|
||||
this.props.value.replaceWith(currentIds);
|
||||
this.props.record.data[this.props.name].replaceWith(currentIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,10 @@ export class Many2ManyTagsField extends Component {
|
||||
|
||||
this.autoCompleteRef = useRef("autoComplete");
|
||||
|
||||
const { saveRecord, removeRecord } = useX2ManyCrud(() => this.props.value, true);
|
||||
const { saveRecord, removeRecord } = useX2ManyCrud(
|
||||
() => this.props.record.data[this.props.name],
|
||||
true
|
||||
);
|
||||
|
||||
this.activeActions = useActiveActions({
|
||||
fieldType: "many2many",
|
||||
@@ -128,7 +131,9 @@ export class Many2ManyTagsField extends Component {
|
||||
}
|
||||
|
||||
get tags() {
|
||||
return this.props.value.records.map((record) => this.getTagProps(record));
|
||||
return this.props.record.data[this.props.name].records.map((record) =>
|
||||
this.getTagProps(record)
|
||||
);
|
||||
}
|
||||
|
||||
get showM2OSelectionField() {
|
||||
@@ -136,15 +141,19 @@ export class Many2ManyTagsField extends Component {
|
||||
}
|
||||
|
||||
deleteTag(id) {
|
||||
const tagRecord = this.props.value.records.find((record) => record.id === id);
|
||||
const ids = this.props.value.currentIds.filter((id) => id !== tagRecord.resId);
|
||||
this.props.value.replaceWith(ids);
|
||||
const tagRecord = this.props.record.data[this.props.name].records.find(
|
||||
(record) => record.id === id
|
||||
);
|
||||
const ids = this.props.record.data[this.props.name].currentIds.filter(
|
||||
(id) => id !== tagRecord.resId
|
||||
);
|
||||
this.props.record.data[this.props.name].replaceWith(ids);
|
||||
}
|
||||
|
||||
getDomain() {
|
||||
return Domain.and([
|
||||
this.domain,
|
||||
Domain.not([["id", "in", this.props.value.currentIds]]),
|
||||
Domain.not([["id", "in", this.props.record.data[this.props.name].currentIds]]),
|
||||
]).toList(this.context);
|
||||
}
|
||||
|
||||
@@ -339,7 +348,9 @@ export class Many2ManyTagsFieldColorEditable extends Many2ManyTagsField {
|
||||
}
|
||||
|
||||
onTagVisibilityChange(isHidden, tag) {
|
||||
const tagRecord = this.props.value.records.find((record) => record.id === tag.id);
|
||||
const tagRecord = this.props.record.data[this.props.name].records.find(
|
||||
(record) => record.id === tag.id
|
||||
);
|
||||
if (tagRecord.data[this.props.colorField] != 0) {
|
||||
this.previousColorsMap[tagRecord.resId] = tagRecord.data[this.props.colorField];
|
||||
}
|
||||
@@ -351,7 +362,9 @@ export class Many2ManyTagsFieldColorEditable extends Many2ManyTagsField {
|
||||
}
|
||||
|
||||
switchTagColor(colorIndex, tag) {
|
||||
const tagRecord = this.props.value.records.find((record) => record.id === tag.id);
|
||||
const tagRecord = this.props.record.data[this.props.name].records.find(
|
||||
(record) => record.id === tag.id
|
||||
);
|
||||
tagRecord.update({ [this.props.colorField]: colorIndex });
|
||||
tagRecord.save();
|
||||
this.closePopover();
|
||||
|
||||
@@ -58,6 +58,7 @@ export class Many2OneField extends Component {
|
||||
string: { type: String, optional: true },
|
||||
canScanBarcode: { type: Boolean, optional: true },
|
||||
update: { type: Function, optional: true },
|
||||
value: { optional: true },
|
||||
};
|
||||
static defaultProps = {
|
||||
canOpen: true,
|
||||
@@ -86,7 +87,7 @@ export class Many2OneField extends Component {
|
||||
};
|
||||
|
||||
this.state = useState({
|
||||
isFloating: !this.props.value,
|
||||
isFloating: !this.value,
|
||||
});
|
||||
this.computeActiveActions(this.props);
|
||||
|
||||
@@ -95,7 +96,7 @@ export class Many2OneField extends Component {
|
||||
activeActions: this.state.activeActions,
|
||||
isToMany: false,
|
||||
onRecordSaved: async (record) => {
|
||||
const resId = this.props.value[0];
|
||||
const resId = this.value[0];
|
||||
const fields = ["display_name"];
|
||||
const context = this.props.record.getFieldContext(this.props.name);
|
||||
const records = await this.orm.read(this.relation, [resId], fields, { context });
|
||||
@@ -130,7 +131,8 @@ export class Many2OneField extends Component {
|
||||
};
|
||||
|
||||
onWillUpdateProps(async (nextProps) => {
|
||||
this.state.isFloating = !nextProps.value;
|
||||
this.state.isFloating =
|
||||
"value" in nextProps ? !nextProps.value : !nextProps.record.data[nextProps.name];
|
||||
this.computeActiveActions(nextProps);
|
||||
});
|
||||
}
|
||||
@@ -156,21 +158,24 @@ export class Many2OneField extends Component {
|
||||
return this.props.record.getFieldDomain(this.props.name);
|
||||
}
|
||||
get hasExternalButton() {
|
||||
return this.props.canOpen && !!this.props.value && !this.state.isFloating;
|
||||
return this.props.canOpen && !!this.value && !this.state.isFloating;
|
||||
}
|
||||
get displayName() {
|
||||
return this.props.value ? this.props.value[1].split("\n")[0] : "";
|
||||
return this.value ? this.value[1].split("\n")[0] : "";
|
||||
}
|
||||
get extraLines() {
|
||||
return this.props.value
|
||||
? this.props.value[1]
|
||||
return this.value
|
||||
? this.value[1]
|
||||
.split("\n")
|
||||
.map((line) => line.trim())
|
||||
.slice(1)
|
||||
: [];
|
||||
}
|
||||
get resId() {
|
||||
return this.props.value && this.props.value[0];
|
||||
return this.value && this.value[0];
|
||||
}
|
||||
get value() {
|
||||
return "value" in this.props ? this.props.value : this.props.record.data[this.props.name];
|
||||
}
|
||||
get Many2XAutocompleteProps() {
|
||||
return {
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
</t>
|
||||
<t t-else="">
|
||||
<a
|
||||
t-if="props.value"
|
||||
t-if="value"
|
||||
class="o_form_uri"
|
||||
t-att-href="props.value ? `#id=${props.value[0]}&model=${relation}` : '#'"
|
||||
t-att-href="value ? `#id=${value[0]}&model=${relation}` : '#'"
|
||||
t-on-click.prevent="onClick"
|
||||
>
|
||||
<span t-esc="displayName" />
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
<t t-name="web.Many2OneAvatarField" owl="1">
|
||||
<div class="d-flex">
|
||||
<span class="o_m2o_avatar">
|
||||
<span t-if="props.value === false and !props.readonly" class="o_m2o_avatar_empty"></span>
|
||||
<img t-if="props.value !== false" t-attf-src="/web/image/{{relation}}/{{props.value[0]}}/avatar_128" />
|
||||
<span t-if="props.record.data[props.name] === false and !props.readonly" class="o_m2o_avatar_empty"></span>
|
||||
<img t-if="props.record.data[props.name] !== false" t-attf-src="/web/image/{{relation}}/{{props.record.data[props.name][0]}}/avatar_128" />
|
||||
</span>
|
||||
<Many2OneField t-props="many2OneProps" canOpen="!props.readonly"/>
|
||||
</div>
|
||||
|
||||
@@ -65,10 +65,14 @@ export class MonetaryField extends Component {
|
||||
}
|
||||
|
||||
get formattedValue() {
|
||||
if (this.props.inputType === "number" && !this.props.readonly && this.props.value) {
|
||||
return this.props.value;
|
||||
if (
|
||||
this.props.inputType === "number" &&
|
||||
!this.props.readonly &&
|
||||
this.props.record.data[this.props.name]
|
||||
) {
|
||||
return this.props.record.data[this.props.name];
|
||||
}
|
||||
return formatMonetary(this.props.value, {
|
||||
return formatMonetary(this.props.record.data[this.props.name], {
|
||||
digits: this.currencyDigits,
|
||||
currencyId: this.currencyId,
|
||||
noSymbol: !this.props.readonly || this.props.hideSymbol,
|
||||
|
||||
@@ -36,11 +36,11 @@ export class PdfViewerField extends Component {
|
||||
}
|
||||
|
||||
get fileName() {
|
||||
return this.state.fileName || this.props.value || "";
|
||||
return this.state.fileName || this.props.record.data[this.props.name] || "";
|
||||
}
|
||||
|
||||
get url() {
|
||||
if (!this.state.isValid || !this.props.value) {
|
||||
if (!this.state.isValid || !this.props.record.data[this.props.name]) {
|
||||
return null;
|
||||
}
|
||||
const page = this.props.record.data[`${this.props.name}_page`] || 1;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<t t-name="web.PdfViewerField" owl="1">
|
||||
<t t-if="!props.readonly">
|
||||
<div class="o_form_pdf_controls">
|
||||
<t t-if="props.value">
|
||||
<t t-if="props.record.data[props.name]">
|
||||
<FileUploader
|
||||
acceptedFileExtensions="'.pdf'"
|
||||
onUploaded.bind="onFileUploaded"
|
||||
@@ -38,7 +38,7 @@
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="props.value">
|
||||
<t t-if="props.record.data[props.name]">
|
||||
<iframe class="o_pdfview_iframe"
|
||||
alt="PDF file"
|
||||
t-att-src="url"
|
||||
|
||||
@@ -14,7 +14,7 @@ export class PercentPieField extends Component {
|
||||
};
|
||||
|
||||
get transform() {
|
||||
const rotateDeg = (360 * this.props.value) / 100;
|
||||
const rotateDeg = (360 * this.props.record.data[this.props.name]) / 100;
|
||||
return {
|
||||
left: rotateDeg < 180 ? 180 : rotateDeg,
|
||||
right: rotateDeg < 180 ? rotateDeg : 0,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<div class="o_mask" t-attf-class="{{transform.value >= 360 ? 'o_full' : ''}}" t-attf-style="transform: rotate({{transform.left}}deg)"/>
|
||||
<div class="o_mask" t-attf-class="{{transform.value >= 180 ? 'o_full' : ''}}" t-attf-style="transform: rotate({{transform.right}}deg)"/>
|
||||
<div class="o_pie_value">
|
||||
<span t-esc="props.value + '%'"/>
|
||||
<span t-esc="props.record.data[props.name] + '%'"/>
|
||||
</div>
|
||||
</div>
|
||||
<span t-esc="props.string"/>
|
||||
|
||||
@@ -21,7 +21,7 @@ export class PercentageField extends Component {
|
||||
setup() {
|
||||
useInputField({
|
||||
getValue: () =>
|
||||
formatPercentage(this.props.value, {
|
||||
formatPercentage(this.props.record.data[this.props.name], {
|
||||
digits: this.digits,
|
||||
noSymbol: true,
|
||||
}),
|
||||
@@ -36,7 +36,7 @@ export class PercentageField extends Component {
|
||||
return !this.props.digits && Array.isArray(fieldDigits) ? fieldDigits : this.props.digits;
|
||||
}
|
||||
get formattedValue() {
|
||||
return formatPercentage(this.props.value, {
|
||||
return formatPercentage(this.props.record.data[this.props.name], {
|
||||
digits: this.digits,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ export class PhoneField extends Component {
|
||||
};
|
||||
|
||||
setup() {
|
||||
useInputField({ getValue: () => this.props.value || "" });
|
||||
useInputField({ getValue: () => this.props.record.data[this.props.name] || "" });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<t t-name="web.PhoneField" owl="1">
|
||||
<div class="o_phone_content d-inline-flex w-100">
|
||||
<t t-if="props.readonly">
|
||||
<a t-if="props.value" class="o_form_uri" t-att-href="'tel:'+props.value" t-esc="props.value"/>
|
||||
<a t-if="props.record.data[props.name]" class="o_form_uri" t-att-href="'tel:'+props.record.data[props.name]" t-esc="props.record.data[props.name]"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<input
|
||||
@@ -21,8 +21,8 @@
|
||||
<t t-name="web.FormPhoneField" t-inherit="web.PhoneField" t-inherit-mode="primary">
|
||||
<xpath expr="//input" position="after">
|
||||
<a
|
||||
t-if="props.value"
|
||||
t-att-href="'tel:'+props.value"
|
||||
t-if="props.record.data[props.name]"
|
||||
t-att-href="'tel:'+props.record.data[props.name]"
|
||||
class="o_phone_form_link ms-3 d-inline-flex align-items-center"
|
||||
>
|
||||
<i class="fa fa-phone"></i><small class="fw-bold ms-1">Call</small>
|
||||
|
||||
@@ -60,7 +60,7 @@ export class PriorityField extends Component {
|
||||
get index() {
|
||||
return this.state.index > -1
|
||||
? this.state.index
|
||||
: this.options.findIndex((o) => o[0] === this.props.value);
|
||||
: this.options.findIndex((o) => o[0] === this.props.record.data[this.props.name]);
|
||||
}
|
||||
get isReadonly() {
|
||||
return this.props.record.isReadonly(this.props.name);
|
||||
@@ -75,7 +75,7 @@ export class PriorityField extends Component {
|
||||
* @param {string} value
|
||||
*/
|
||||
onStarClicked(value) {
|
||||
if (this.props.value === value) {
|
||||
if (this.props.record.data[this.props.name] === value) {
|
||||
this.state.index = -1;
|
||||
this.updateRecord(this.options[0][0]);
|
||||
} else {
|
||||
|
||||
@@ -92,7 +92,9 @@ export class PropertiesField extends Component {
|
||||
* @returns {array}
|
||||
*/
|
||||
get propertiesList() {
|
||||
const propertiesValues = JSON.parse(JSON.stringify(this.props.value || []));
|
||||
const propertiesValues = JSON.parse(
|
||||
JSON.stringify(this.props.record.data[this.props.name] || [])
|
||||
);
|
||||
return propertiesValues.filter((definition) => !definition.definition_deleted);
|
||||
}
|
||||
|
||||
@@ -428,7 +430,7 @@ export class PropertiesField extends Component {
|
||||
// initial properties values, if the type or the model changed, the
|
||||
// name will be regenerated in order to reset the value on the children
|
||||
this.initialValues = {};
|
||||
for (const propertiesValues of this.props.value || []) {
|
||||
for (const propertiesValues of this.props.record.data[this.props.name] || []) {
|
||||
this.initialValues[propertiesValues.name] = {
|
||||
name: propertiesValues.name,
|
||||
type: propertiesValues.type,
|
||||
|
||||
@@ -312,7 +312,7 @@ export class PropertyTagsField extends Component {
|
||||
|
||||
get propertyTagsProps() {
|
||||
return {
|
||||
selectedTags: this.props.value || [],
|
||||
selectedTags: this.props.record.data[this.props.name] || [],
|
||||
tags: this.props.record.fields[this.props.name].tags || [],
|
||||
deleteAction: "value",
|
||||
readonly: this.props.readonly,
|
||||
|
||||
@@ -42,9 +42,11 @@ export class RadioField extends Component {
|
||||
get value() {
|
||||
switch (this.props.record.fields[this.props.name].type) {
|
||||
case "selection":
|
||||
return this.props.value;
|
||||
return this.props.record.data[this.props.name];
|
||||
case "many2one":
|
||||
return Array.isArray(this.props.value) ? this.props.value[0] : this.props.value;
|
||||
return Array.isArray(this.props.record.data[this.props.name])
|
||||
? this.props.record.data[this.props.name][0]
|
||||
: this.props.record.data[this.props.name];
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -28,14 +28,17 @@ export class ReferenceField extends Component {
|
||||
resModel: this.relation,
|
||||
});
|
||||
|
||||
this.currentValue = this.getValue(this.props);
|
||||
|
||||
onWillUpdateProps((nextProps) => {
|
||||
if (
|
||||
valuesEqual(this.getValue(this.props) || {}, this.getValue(nextProps) || {}) &&
|
||||
valuesEqual(this.currentValue || {}, this.getValue(nextProps) || {}) &&
|
||||
this.state.resModel &&
|
||||
this.getRelation(nextProps) !== this.state.resModel
|
||||
) {
|
||||
nextProps.record.update({ [this.props.name]: false });
|
||||
}
|
||||
this.currentValue = this.getValue(this.props);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -54,7 +57,7 @@ export class ReferenceField extends Component {
|
||||
displayName: pdata.data.display_name,
|
||||
};
|
||||
} else {
|
||||
return p.value;
|
||||
return p.record.data[p.name];
|
||||
}
|
||||
}
|
||||
get m2oProps() {
|
||||
|
||||
@@ -24,17 +24,21 @@ export class RemainingDaysField extends Component {
|
||||
}
|
||||
|
||||
get diffDays() {
|
||||
if (!this.props.value) {
|
||||
if (!this.props.record.data[this.props.name]) {
|
||||
return null;
|
||||
}
|
||||
const today = luxon.DateTime.local().startOf("day");
|
||||
return Math.floor(this.props.value.startOf("day").diff(today, "days").days);
|
||||
return Math.floor(
|
||||
this.props.record.data[this.props.name].startOf("day").diff(today, "days").days
|
||||
);
|
||||
}
|
||||
|
||||
get formattedValue() {
|
||||
return this.hasTime
|
||||
? formatDateTime(this.props.value, { format: localization.dateFormat })
|
||||
: formatDate(this.props.value);
|
||||
? formatDateTime(this.props.record.data[this.props.name], {
|
||||
format: localization.dateFormat,
|
||||
})
|
||||
: formatDate(this.props.record.data[this.props.name]);
|
||||
}
|
||||
|
||||
onDateTimeChanged(datetime) {
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div>
|
||||
<t t-component="pickerComponent" date="props.value or false" onDateTimeChanged.bind="onDateTimeChanged" />
|
||||
<t t-component="pickerComponent" date="props.record.data[props.name] or false" onDateTimeChanged.bind="onDateTimeChanged" />
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user