[IMP] *: improve documentation of options in fields metadata
*: analytic, base_automation, loyalty, mass_mailing, project, web, web_editor, website This commit adds many new documentation of options and their usage for fields. This makes them more usable and customizable in Studio, and adds documentation for developers to know the type of expected option. Some options that might lead to issues or that are too technical have been removed, as they are not relevant and not required in most use cases. task-3469741 closes odoo/odoo#134858 Related: odoo/enterprise#47148 Signed-off-by: Lucas Perais (lpe) <lpe@odoo.com>
This commit is contained in:
@@ -686,6 +686,35 @@ export const analyticDistribution = {
|
||||
component: AnalyticDistribution,
|
||||
supportedTypes: ["char", "text"],
|
||||
fieldDependencies: [{ name:"analytic_precision", type: "integer" }],
|
||||
supportedOptions: [
|
||||
{
|
||||
label: _t("Disable save"),
|
||||
name: "disable_save",
|
||||
type: "boolean",
|
||||
},
|
||||
{
|
||||
label: _t("Force applicability"),
|
||||
name: "force_applicability",
|
||||
type: "boolean",
|
||||
},
|
||||
{
|
||||
label: _t("Business domain"),
|
||||
name: "business_domain",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
label: _t("Product field"),
|
||||
name: "product_field",
|
||||
type: "field",
|
||||
availableTypes: ["many2one"],
|
||||
},
|
||||
{
|
||||
label: _t("Account field"),
|
||||
name: "account_field",
|
||||
type: "field",
|
||||
availableTypes: ["many2one"],
|
||||
}
|
||||
],
|
||||
extractProps: ({ attrs, options }) => ({
|
||||
business_domain: options.business_domain,
|
||||
account_field: options.account_field,
|
||||
|
||||
@@ -48,6 +48,7 @@ export class TriggerReferenceField extends Component {
|
||||
export const triggerReferenceField = {
|
||||
supportedTypes: ["char"],
|
||||
component: TriggerReferenceField,
|
||||
supportedOptions: many2OneField.supportedOptions,
|
||||
extractProps: many2OneField.extractProps,
|
||||
};
|
||||
registry.category("fields").add("base_automation_trigger_reference", triggerReferenceField);
|
||||
|
||||
@@ -36,6 +36,18 @@ FilterableSelectionField.props = {
|
||||
export const filterableSelectionField = {
|
||||
...selectionField,
|
||||
component: FilterableSelectionField,
|
||||
supportedOptions: [
|
||||
{
|
||||
label: "Whitelisted Values",
|
||||
name: "whitelisted_values",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
label: "Blacklisted Values",
|
||||
name: "blacklisted_values",
|
||||
type: "string",
|
||||
}
|
||||
],
|
||||
extractProps({ options }) {
|
||||
const props = selectionField.extractProps(...arguments);
|
||||
props.whitelisted_values = options.whitelisted_values;
|
||||
|
||||
@@ -168,6 +168,21 @@ FieldMany2OneMailingFilter.defaultProps = {
|
||||
export const fieldMany2OneMailingFilter = {
|
||||
...many2OneField,
|
||||
component: FieldMany2OneMailingFilter,
|
||||
supportedOptions: [
|
||||
...many2OneField.supportedOptions,
|
||||
{
|
||||
label: _t("Domain field"),
|
||||
name: "domain_field",
|
||||
type: "field",
|
||||
supportedTypes: ["char"]
|
||||
},
|
||||
{
|
||||
label: _t("Model field"),
|
||||
name: "model_field",
|
||||
type: "field",
|
||||
supportedTypes: ["char"]
|
||||
}
|
||||
],
|
||||
extractProps({ options }) {
|
||||
const props = many2OneField.extractProps(...arguments);
|
||||
props.domain_field = options.domain_field;
|
||||
|
||||
@@ -627,6 +627,10 @@ export const massMailingHtmlField = {
|
||||
label: _t("Filter templates"),
|
||||
name: "filterTemplates",
|
||||
type: "boolean"
|
||||
}, {
|
||||
label: _t("Inline field"),
|
||||
name: "inline-field",
|
||||
type: "field"
|
||||
}],
|
||||
extractProps({ attrs, options }) {
|
||||
const props = htmlField.extractProps(...arguments);
|
||||
|
||||
+7
-1
@@ -177,11 +177,17 @@ ProjectTaskStateSelection.props = {
|
||||
viewType: { type: String },
|
||||
}
|
||||
|
||||
|
||||
export const projectTaskStateSelection = {
|
||||
...stateSelectionField,
|
||||
component: ProjectTaskStateSelection,
|
||||
fieldDependencies: [{ name: "project_id", type: "many2one" }],
|
||||
supportedOptions: [
|
||||
...stateSelectionField.supportedOptions, {
|
||||
label: _t("Is toggle mode"),
|
||||
name: "is_toggle_mode",
|
||||
type: "boolean"
|
||||
}
|
||||
],
|
||||
extractProps({ options, viewType }) {
|
||||
const props = stateSelectionField.extractProps(...arguments);
|
||||
props.isToggleMode = Boolean(options.is_toggle_mode);
|
||||
|
||||
@@ -29,6 +29,17 @@ export const booleanFavoriteField = {
|
||||
displayName: _t("Favorite"),
|
||||
supportedTypes: ["boolean"],
|
||||
isEmpty: () => false,
|
||||
supportedOptions: [
|
||||
{
|
||||
label: _t("Autosave"),
|
||||
name: "autosave",
|
||||
type: "boolean",
|
||||
default: true,
|
||||
help: _t(
|
||||
"If checked, the record will be saved immediately when the field is modified."
|
||||
),
|
||||
},
|
||||
],
|
||||
extractProps: ({ attrs, options }) => ({
|
||||
noLabel: archParseBoolean(attrs.nolabel),
|
||||
autosave: "autosave" in options ? Boolean(options.autosave) : true,
|
||||
|
||||
@@ -21,6 +21,17 @@ export const booleanToggleField = {
|
||||
...booleanField,
|
||||
component: BooleanToggleField,
|
||||
displayName: _t("Toggle"),
|
||||
supportedOptions: [
|
||||
{
|
||||
label: _t("Autosave"),
|
||||
name: "autosave",
|
||||
type: "boolean",
|
||||
default: true,
|
||||
help: _t(
|
||||
"If checked, the record will be saved immediately when the field is modified."
|
||||
),
|
||||
},
|
||||
],
|
||||
extractProps({ options }, dynamicInfo) {
|
||||
return {
|
||||
autosave: "autosave" in options ? Boolean(options.autosave) : true,
|
||||
|
||||
@@ -68,6 +68,20 @@ export const charField = {
|
||||
component: CharField,
|
||||
displayName: _t("Text"),
|
||||
supportedTypes: ["char"],
|
||||
supportedOptions: [
|
||||
{
|
||||
label: _t("Dynamic placeholder"),
|
||||
name: "dynamic_placeholder",
|
||||
type: "boolean",
|
||||
help: _t("Enable this option to allow the input to display a dynamic placeholder."),
|
||||
},
|
||||
{
|
||||
label: _t("Model reference field"),
|
||||
name: "dynamic_placeholder_model_reference_field",
|
||||
type: "field",
|
||||
supportedTypes: ["char"],
|
||||
},
|
||||
],
|
||||
extractProps: ({ attrs, options }) => ({
|
||||
isPassword: archParseBoolean(attrs.password),
|
||||
dynamicPlaceholder: options.dynamic_placeholder || false,
|
||||
|
||||
@@ -309,11 +309,13 @@ export const dateTimeField = {
|
||||
supportedOptions: [
|
||||
...dateField.supportedOptions,
|
||||
{
|
||||
label: _t("Rounding"),
|
||||
label: _t("Time interval"),
|
||||
name: "rounding",
|
||||
type: "number",
|
||||
default: 5,
|
||||
help: _t(`Increment used in the minutes selection dropdown.`),
|
||||
help: _t(
|
||||
`Control the number of minutes in the time selection. E.g. set it to 15 to work in quarters.`
|
||||
),
|
||||
},
|
||||
],
|
||||
supportedTypes: ["datetime"],
|
||||
|
||||
@@ -247,6 +247,12 @@ export const domainField = {
|
||||
name: "in_dialog",
|
||||
type: "boolean",
|
||||
},
|
||||
{
|
||||
label: _t("Foldable"),
|
||||
name: "foldable",
|
||||
type: "boolean",
|
||||
help: _t("Display the domain using facets"),
|
||||
},
|
||||
{
|
||||
label: _t("Model"),
|
||||
name: "model",
|
||||
|
||||
+24
-5
@@ -4,20 +4,21 @@ import { CharField, charField } from "@web/views/fields/char/char_field";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { archParseBoolean } from "@web/views/utils";
|
||||
|
||||
import { DynamicModelFieldSelector } from "./dynamic_model_field_selector";
|
||||
import { DynamicModelFieldSelector } from "./dynamic_model_field_selector";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
|
||||
export class DynamicModelFieldSelectorChar extends CharField {
|
||||
static components = {
|
||||
...CharField.components,
|
||||
DynamicModelFieldSelector
|
||||
DynamicModelFieldSelector,
|
||||
};
|
||||
|
||||
static props = {
|
||||
...CharField.props,
|
||||
resModel : { type: String, optional: true },
|
||||
resModel: { type: String, optional: true },
|
||||
onlySearchable: { type: Boolean, optional: true },
|
||||
followRelations: { type: Boolean, optional: true },
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Update record
|
||||
@@ -26,7 +27,7 @@ export class DynamicModelFieldSelectorChar extends CharField {
|
||||
* @private
|
||||
*/
|
||||
async _onRecordUpdate(value) {
|
||||
await this.props.record.update({[this.props.name]: value});
|
||||
await this.props.record.update({ [this.props.name]: value });
|
||||
}
|
||||
|
||||
//---- Getters ----
|
||||
@@ -62,6 +63,24 @@ DynamicModelFieldSelectorChar.template = "web.DynamicModelFieldSelectorChar";
|
||||
export const dynamicModelFieldSelectorChar = {
|
||||
...charField,
|
||||
component: DynamicModelFieldSelectorChar,
|
||||
supportedOptions: [
|
||||
{
|
||||
label: _t("Follow relations"),
|
||||
name: "follow_relations",
|
||||
type: "boolean",
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
label: _t("Model"),
|
||||
name: "model",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
label: _t("Only searchable"),
|
||||
name: "only_searchable",
|
||||
type: "string",
|
||||
},
|
||||
],
|
||||
extractProps({ options }, dynamicInfo) {
|
||||
return {
|
||||
followRelations: options.follow_relations ?? true,
|
||||
|
||||
@@ -26,13 +26,13 @@ export class FloatField extends Component {
|
||||
formatNumber: true,
|
||||
inputType: "text",
|
||||
humanReadable: false,
|
||||
decimals:0,
|
||||
decimals: 0,
|
||||
};
|
||||
|
||||
setup() {
|
||||
this.state = useState({
|
||||
hasFocus: false,
|
||||
})
|
||||
});
|
||||
this.inputRef = useInputField({
|
||||
getValue: () => this.formattedValue,
|
||||
refName: "numpadDecimal",
|
||||
@@ -42,11 +42,11 @@ export class FloatField extends Component {
|
||||
}
|
||||
|
||||
onFocusIn() {
|
||||
this.state.hasFocus = true
|
||||
this.state.hasFocus = true;
|
||||
}
|
||||
|
||||
onFocusOut() {
|
||||
this.state.hasFocus = false
|
||||
this.state.hasFocus = false;
|
||||
}
|
||||
|
||||
parse(value) {
|
||||
@@ -65,9 +65,13 @@ export class FloatField extends Component {
|
||||
return this.value;
|
||||
}
|
||||
if (this.props.humanReadable && !this.state.hasFocus) {
|
||||
return formatFloat(this.value, { digits: this.digits, humanReadable: true, decimals: this.props.decimals });
|
||||
return formatFloat(this.value, {
|
||||
digits: this.digits,
|
||||
humanReadable: true,
|
||||
decimals: this.props.decimals,
|
||||
});
|
||||
} else {
|
||||
return formatFloat(this.value, { digits: this.digits, humanReadable: false});
|
||||
return formatFloat(this.value, { digits: this.digits, humanReadable: false });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +88,9 @@ export const floatField = {
|
||||
label: _t("Format number"),
|
||||
name: "enable_formatting",
|
||||
type: "boolean",
|
||||
help: _t("Format the value according to your language setup - e.g. thousand separators, rounding, etc."),
|
||||
help: _t(
|
||||
"Format the value according to your language setup - e.g. thousand separators, rounding, etc."
|
||||
),
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
@@ -102,6 +108,19 @@ export const floatField = {
|
||||
name: "step",
|
||||
type: "number",
|
||||
},
|
||||
{
|
||||
label: _t("User-friendly format"),
|
||||
name: "human_readable",
|
||||
type: "boolean",
|
||||
help: _t("Use a human readable format (e.g.: 500G instead of 500,000,000,000)."),
|
||||
},
|
||||
{
|
||||
label: _t("Decimals"),
|
||||
name: "decimals",
|
||||
type: "number",
|
||||
default: 0,
|
||||
help: _t("Use it with the 'User-friendly format' option to customize the formatting."),
|
||||
},
|
||||
],
|
||||
supportedTypes: ["float"],
|
||||
isEmpty: () => false,
|
||||
|
||||
@@ -42,10 +42,16 @@ export const floatTimeField = {
|
||||
component: FloatTimeField,
|
||||
displayName: _t("Time"),
|
||||
supportedOptions: [
|
||||
{
|
||||
label: _t("Display seconds"),
|
||||
name: "display_seconds",
|
||||
type: "boolean",
|
||||
},
|
||||
{
|
||||
label: _t("Type"),
|
||||
name: "type",
|
||||
type: "string",
|
||||
default: "text",
|
||||
},
|
||||
],
|
||||
supportedTypes: ["float"],
|
||||
|
||||
@@ -199,6 +199,12 @@ export const imageField = {
|
||||
component: ImageField,
|
||||
displayName: _t("Image"),
|
||||
supportedOptions: [
|
||||
{
|
||||
label: _t("Reload"),
|
||||
name: "reload",
|
||||
type: "boolean",
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
label: _t("Enable zoom"),
|
||||
name: "zoom",
|
||||
|
||||
@@ -25,13 +25,13 @@ export class IntegerField extends Component {
|
||||
formatNumber: true,
|
||||
humanReadable: false,
|
||||
inputType: "text",
|
||||
decimals: 0,
|
||||
decimals: 0,
|
||||
};
|
||||
|
||||
setup() {
|
||||
this.state = useState({
|
||||
hasFocus: false,
|
||||
})
|
||||
hasFocus: false,
|
||||
});
|
||||
useInputField({
|
||||
getValue: () => this.formattedValue,
|
||||
refName: "numpadDecimal",
|
||||
@@ -41,11 +41,11 @@ export class IntegerField extends Component {
|
||||
}
|
||||
|
||||
onFocusIn() {
|
||||
this.state.hasFocus = true
|
||||
this.state.hasFocus = true;
|
||||
}
|
||||
|
||||
onFocusOut() {
|
||||
this.state.hasFocus = false
|
||||
this.state.hasFocus = false;
|
||||
}
|
||||
|
||||
get formattedValue() {
|
||||
@@ -56,9 +56,12 @@ export class IntegerField extends Component {
|
||||
return this.value;
|
||||
}
|
||||
if (this.props.humanReadable && !this.state.hasFocus) {
|
||||
return formatInteger(this.value, { humanReadable: true, decimals: this.props.decimals });
|
||||
return formatInteger(this.value, {
|
||||
humanReadable: true,
|
||||
decimals: this.props.decimals,
|
||||
});
|
||||
} else {
|
||||
return formatInteger(this.value, { humanReadable: false});
|
||||
return formatInteger(this.value, { humanReadable: false });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +78,9 @@ export const integerField = {
|
||||
label: _t("Format number"),
|
||||
name: "enable_formatting",
|
||||
type: "boolean",
|
||||
help: _t("Format the value according to your language setup - e.g. thousand separators, rounding, etc."),
|
||||
help: _t(
|
||||
"Format the value according to your language setup - e.g. thousand separators, rounding, etc."
|
||||
),
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
@@ -88,6 +93,19 @@ export const integerField = {
|
||||
name: "step",
|
||||
type: "number",
|
||||
},
|
||||
{
|
||||
label: _t("User-friendly format"),
|
||||
name: "human_readable",
|
||||
type: "boolean",
|
||||
help: _t("Use a human readable format (e.g.: 500G instead of 500,000,000,000)."),
|
||||
},
|
||||
{
|
||||
label: _t("Decimals"),
|
||||
name: "decimals",
|
||||
type: "number",
|
||||
default: 0,
|
||||
help: _t("Use it with the 'User-friendly format' option to customize the formatting."),
|
||||
},
|
||||
],
|
||||
supportedTypes: ["integer"],
|
||||
isEmpty: (record, fieldName) => record.data[fieldName] === false,
|
||||
|
||||
@@ -30,6 +30,13 @@ export class LabelSelectionField extends Component {
|
||||
export const labelSelectionField = {
|
||||
component: LabelSelectionField,
|
||||
displayName: _t("Label Selection"),
|
||||
supportedOptions: [
|
||||
{
|
||||
label: _t("Classes"),
|
||||
name: "classes",
|
||||
type: "string",
|
||||
},
|
||||
],
|
||||
supportedTypes: ["selection"],
|
||||
extractProps: ({ options }) => ({
|
||||
classesObj: options.classes,
|
||||
|
||||
@@ -264,11 +264,38 @@ export const many2ManyTagsField = {
|
||||
label: _t("Disable creation"),
|
||||
name: "no_create",
|
||||
type: "boolean",
|
||||
help: _t(
|
||||
"If checked, users won't be able to create records through the autocomplete dropdown at all."
|
||||
),
|
||||
},
|
||||
{
|
||||
label: _t("Use colors"),
|
||||
name: "color_field",
|
||||
label: _t("Disable 'Create' option"),
|
||||
name: "no_quick_create",
|
||||
type: "boolean",
|
||||
help: _t(
|
||||
"If checked, users will not be able to create records based on the text input; they will still be able to create records via a popup form."
|
||||
),
|
||||
},
|
||||
{
|
||||
label: _t("Disable 'Create and Edit' option"),
|
||||
name: "no_create_edit",
|
||||
type: "boolean",
|
||||
help: _t(
|
||||
"If checked, users will not be able to create records based through a popup form; they will still be able to create records based on the text input."
|
||||
),
|
||||
},
|
||||
{
|
||||
label: _t("Can create"),
|
||||
name: "create",
|
||||
type: "string",
|
||||
help: _t("Write a domain to allow the creation of records conditionnally."),
|
||||
},
|
||||
{
|
||||
label: _t("Color field"),
|
||||
name: "color_field",
|
||||
type: "field",
|
||||
availableTypes: ["integer"],
|
||||
help: _t("Set an integer field to use colors with the tags."),
|
||||
},
|
||||
],
|
||||
supportedTypes: ["many2many"],
|
||||
|
||||
@@ -328,25 +328,34 @@ export const many2OneField = {
|
||||
component: Many2OneField,
|
||||
displayName: _t("Many2one"),
|
||||
supportedOptions: [
|
||||
{
|
||||
label: _t("Disable creation"),
|
||||
name: "no_create",
|
||||
type: "boolean",
|
||||
},
|
||||
{
|
||||
label: _t("Disable opening"),
|
||||
name: "no_open",
|
||||
type: "boolean",
|
||||
},
|
||||
{
|
||||
label: _t("No quick create"),
|
||||
name: "no_quick_create",
|
||||
label: _t("Disable creation"),
|
||||
name: "no_create",
|
||||
type: "boolean",
|
||||
help: _t(
|
||||
"If checked, users won't be able to create records through the autocomplete dropdown at all."
|
||||
),
|
||||
},
|
||||
{
|
||||
label: _t("No create edit"),
|
||||
label: _t("Disable 'Create' option"),
|
||||
name: "no_quick_create",
|
||||
type: "boolean",
|
||||
help: _t(
|
||||
"If checked, users will not be able to create records based on the text input; they will still be able to create records via a popup form."
|
||||
),
|
||||
},
|
||||
{
|
||||
label: _t("Disable 'Create and Edit' option"),
|
||||
name: "no_create_edit",
|
||||
type: "boolean",
|
||||
help: _t(
|
||||
"If checked, users will not be able to create records based through a popup form; they will still be able to create records based on the text input."
|
||||
),
|
||||
},
|
||||
],
|
||||
supportedTypes: ["many2one"],
|
||||
|
||||
@@ -31,12 +31,12 @@ export class MonetaryField extends Component {
|
||||
useNumpadDecimal();
|
||||
}
|
||||
|
||||
get inputOptions(){
|
||||
get inputOptions() {
|
||||
return {
|
||||
getValue: () => this.formattedValue,
|
||||
refName: "numpadDecimal",
|
||||
parse: parseMonetary,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
get currencyId() {
|
||||
@@ -73,11 +73,7 @@ export class MonetaryField extends Component {
|
||||
}
|
||||
|
||||
get formattedValue() {
|
||||
if (
|
||||
this.props.inputType === "number" &&
|
||||
!this.props.readonly &&
|
||||
this.value
|
||||
) {
|
||||
if (this.props.inputType === "number" && !this.props.readonly && this.value) {
|
||||
return this.value;
|
||||
}
|
||||
return formatMonetary(this.value, {
|
||||
@@ -92,8 +88,13 @@ export const monetaryField = {
|
||||
component: MonetaryField,
|
||||
supportedOptions: [
|
||||
{
|
||||
name: "currency_field",
|
||||
label: _t("Hide symbol"),
|
||||
name: "no_symbol",
|
||||
type: "boolean",
|
||||
},
|
||||
{
|
||||
label: _t("Currency"),
|
||||
name: "currency_field",
|
||||
type: "field",
|
||||
availableTypes: ["many2one"],
|
||||
},
|
||||
|
||||
@@ -74,6 +74,14 @@ export class PdfViewerField extends Component {
|
||||
export const pdfViewerField = {
|
||||
component: PdfViewerField,
|
||||
displayName: _t("PDF Viewer"),
|
||||
supportedOptions: [
|
||||
{
|
||||
label: _t("Preview image"),
|
||||
name: "preview_image",
|
||||
type: "field",
|
||||
availableTypes: ["binary"],
|
||||
},
|
||||
],
|
||||
supportedTypes: ["binary"],
|
||||
};
|
||||
|
||||
|
||||
@@ -89,6 +89,17 @@ export class PriorityField extends Component {
|
||||
export const priorityField = {
|
||||
component: PriorityField,
|
||||
displayName: _t("Priority"),
|
||||
supportedOptions: [
|
||||
{
|
||||
label: _t("Autosave"),
|
||||
name: "autosave",
|
||||
type: "boolean",
|
||||
default: true,
|
||||
help: _t(
|
||||
"If checked, the record will be saved immediately when the field is modified."
|
||||
),
|
||||
},
|
||||
],
|
||||
supportedTypes: ["selection"],
|
||||
extractProps({ options, viewType }, dynamicInfo) {
|
||||
return {
|
||||
|
||||
@@ -102,12 +102,12 @@ export const progressBarField = {
|
||||
displayName: _t("Progress Bar"),
|
||||
supportedOptions: [
|
||||
{
|
||||
label: _t("Editable"),
|
||||
label: _t("Can edit value"),
|
||||
name: "editable",
|
||||
type: "boolean",
|
||||
},
|
||||
{
|
||||
label: _t("Edit max value"),
|
||||
label: _t("Can edit max value"),
|
||||
name: "edit_max_value",
|
||||
type: "boolean",
|
||||
},
|
||||
@@ -116,12 +116,18 @@ export const progressBarField = {
|
||||
name: "current_value",
|
||||
type: "field",
|
||||
availableTypes: ["integer", "float"],
|
||||
help: _t(
|
||||
"Use to override the display value (e.g. if your progress bar is a computed percentage but you want to display the actual field value instead)."
|
||||
),
|
||||
},
|
||||
{
|
||||
label: _t("Max value field"),
|
||||
name: "max_value",
|
||||
type: "field",
|
||||
availableTypes: ["integer", "float"],
|
||||
help: _t(
|
||||
"Field that holds the maximum value of the progress bar. If set, will be displayed next to the progress bar (e.g. 10 / 200)."
|
||||
),
|
||||
},
|
||||
{
|
||||
label: _t("Overflow style"),
|
||||
|
||||
@@ -229,6 +229,19 @@ export class ReferenceField extends Component {
|
||||
export const referenceField = {
|
||||
component: ReferenceField,
|
||||
displayName: _t("Reference"),
|
||||
supportedOptions: [
|
||||
{
|
||||
label: _t("Hide model"),
|
||||
name: "hide_model",
|
||||
type: "boolean",
|
||||
},
|
||||
{
|
||||
label: _t("Model field"),
|
||||
name: "model_field",
|
||||
type: "field",
|
||||
availableTypes: ["many2one"],
|
||||
},
|
||||
],
|
||||
supportedTypes: ["reference", "char"],
|
||||
extractProps({ options }) {
|
||||
/*
|
||||
|
||||
@@ -36,6 +36,14 @@ export class StatInfoField extends Component {
|
||||
export const statInfoField = {
|
||||
component: StatInfoField,
|
||||
displayName: _t("Stat Info"),
|
||||
supportedOptions: [
|
||||
{
|
||||
label: _t("Label field"),
|
||||
name: "label_field",
|
||||
type: "field",
|
||||
availableTypes: ["char"],
|
||||
},
|
||||
],
|
||||
supportedTypes: ["float", "integer", "monetary"],
|
||||
isEmpty: () => false,
|
||||
extractProps: ({ attrs, options, string }) => {
|
||||
|
||||
@@ -78,6 +78,23 @@ export class StateSelectionField extends Component {
|
||||
export const stateSelectionField = {
|
||||
component: StateSelectionField,
|
||||
displayName: _t("Label Selection"),
|
||||
supportedOptions: [
|
||||
{
|
||||
label: _t("Autosave"),
|
||||
name: "autosave",
|
||||
type: "boolean",
|
||||
default: true,
|
||||
help: _t(
|
||||
"If checked, the record will be saved immediately when the field is modified."
|
||||
),
|
||||
},
|
||||
{
|
||||
label: _t("Hide label"),
|
||||
name: "hide_label",
|
||||
type: "boolean",
|
||||
viewTypes: ["list"],
|
||||
},
|
||||
],
|
||||
supportedTypes: ["selection"],
|
||||
extractProps({ options, viewType }, dynamicInfo) {
|
||||
return {
|
||||
|
||||
@@ -247,11 +247,13 @@ export const statusBarField = {
|
||||
label: _t("Clickable"),
|
||||
name: "clickable",
|
||||
type: "boolean",
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
label: _t("Fold field"),
|
||||
name: "fold_field",
|
||||
type: "string",
|
||||
type: "field",
|
||||
availableTypes: ["boolean"],
|
||||
},
|
||||
],
|
||||
supportedTypes: ["many2one", "selection"],
|
||||
|
||||
@@ -78,6 +78,20 @@ export const timezoneMismatchField = {
|
||||
...selectionField,
|
||||
component: TimezoneMismatchField,
|
||||
additionalClasses: ["d-flex"],
|
||||
supportedOptions: [
|
||||
...(selectionField.supportedOptions || []),
|
||||
{
|
||||
label: _t("Mismatch title"),
|
||||
name: "mismatch_title",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
label: _t("Timezone offset field"),
|
||||
name: "tz_offset_field",
|
||||
type: "field",
|
||||
availableTypes: ["char"],
|
||||
},
|
||||
],
|
||||
extractProps({ options }) {
|
||||
const props = selectionField.extractProps(...arguments);
|
||||
props.tzOffsetField = options.tz_offset_field;
|
||||
|
||||
@@ -39,6 +39,14 @@ export class UrlField extends Component {
|
||||
export const urlField = {
|
||||
component: UrlField,
|
||||
displayName: _t("URL"),
|
||||
supportedOptions: [
|
||||
{
|
||||
label: _t("Is a website path"),
|
||||
name: "website_path",
|
||||
type: "boolean",
|
||||
help: _t("If True, the url will be used as it is, without any prefix added to it."),
|
||||
},
|
||||
],
|
||||
supportedTypes: ["char"],
|
||||
extractProps: ({ attrs, options }) => ({
|
||||
text: attrs.text,
|
||||
|
||||
@@ -367,15 +367,15 @@ QUnit.module("Fields", (hooks) => {
|
||||
type: "kanban",
|
||||
resModel: "partner",
|
||||
arch: /* xml */ `
|
||||
<kanban>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div>
|
||||
<field name="int_field" widget="progressbar" options="{'editable': true, 'max_value': 'float_field', 'readonly': True}" />
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>`,
|
||||
<kanban>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div>
|
||||
<field name="int_field" widget="progressbar" options="{'editable': true, 'max_value': 'float_field', 'readonly': True}" />
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>`,
|
||||
resId: 1,
|
||||
mockRPC(route, { method, args }) {
|
||||
if (method === "web_save") {
|
||||
|
||||
@@ -639,17 +639,29 @@ export const htmlField = {
|
||||
name: "resizable",
|
||||
type: "boolean",
|
||||
}, {
|
||||
label: _t("Dynamic placeholder"),
|
||||
name: "dynamic_placeholder",
|
||||
label: _t("Sandboxed preview"),
|
||||
name: "sandboxedPreview",
|
||||
type: "boolean",
|
||||
help: _t("With the option enabled, all content can only be viewed in a sandboxed iframe or in the code editor."),
|
||||
}, {
|
||||
label: _t("Collaborative"),
|
||||
label: _t("Collaborative edition"),
|
||||
name: "collaborative",
|
||||
type: "boolean",
|
||||
},{
|
||||
label: _t("Collaborative trigger"),
|
||||
name: "collaborative_trigger",
|
||||
type: "selection",
|
||||
choices: [
|
||||
{ label: _t("Focus"), value: "focus" },
|
||||
{ label: _t("Start"), value: "start" },
|
||||
],
|
||||
default: "focus",
|
||||
help: _t("Specify when the collaboration starts. 'Focus' will start the collaboration session when the user clicks inside the text field (default), 'Start' when the record is loaded (could impact performance if set)."),
|
||||
}, {
|
||||
label: _t("Codeview"),
|
||||
name: "codeview",
|
||||
type: "boolean",
|
||||
help: _t("Allow users to view and edit the field in HTML.")
|
||||
}],
|
||||
supportedTypes: ["html"],
|
||||
extractProps({ attrs, options }, dynamicInfo) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import {useInputField} from '@web/views/fields/input_field_hook';
|
||||
import {useService} from '@web/core/utils/hooks';
|
||||
import {Switch} from '@website/components/switch/switch';
|
||||
import {registry} from '@web/core/registry';
|
||||
import { _t } from '@web/core/l10n/translation';
|
||||
|
||||
const {Component, useState} = owl;
|
||||
|
||||
@@ -98,6 +99,14 @@ ImageRadioField.props = {
|
||||
|
||||
export const imageRadioField = {
|
||||
component: ImageRadioField,
|
||||
supportedOptions: [
|
||||
{
|
||||
label: _t("Images"),
|
||||
name: "images",
|
||||
type: "string",
|
||||
help: _t("Use an array to list the images to use in the radio selection.")
|
||||
}
|
||||
],
|
||||
supportedTypes: ['selection'],
|
||||
extractProps: ({ options }) => ({
|
||||
images: options.images,
|
||||
|
||||
Reference in New Issue
Block a user