fields
forms
Progressbar
Odoo 19 fields — Progressbar (views)
Live preview
Interactive
Source excerpt
web/static/src/views/fields/progress_bar/progress_bar_field.js
import { _t } from "@web/core/l10n/translation";
import { registry } from "@web/core/registry";
import { useNumpadDecimal } from "../numpad_decimal_hook";
import { parseFloat } from "../parsers";
import { useInputField } from "@web/views/fields/input_field_hook";
import { standardFieldProps } from "../standard_field_props";
import { Component, useRef, useState } from "@odoo/owl";
const formatters = registry.category("formatters");
export class ProgressBarField extends Component {
static template = "web.ProgressBarField";
static props = {
...standardFieldProps,
maxValueField: { type: [String, Number], optional: true },
currentValueField: { type: String, optional: true },
isEditable: { type: Boolean, optional: true },
isCurrentValueEditable: { type: Boolean, optional: true },
isMaxValueEditable: { type: Boolean, optional: true },
title: { type: String, optional: true },
overflowClass: { type: String, optional: true },
};
setup() {
useNumpadDecimal();
this.root = useRef("numpadDecimal");
const { currentValueField, maxValueField, name } = this.props;
this.currentValueField = currentValueField ? currentValueField : name;
if (maxValueField) {
this.maxValueField = maxValueField;
}
this.currentValueRef = useInputField({
getValue: () => this.formatCurrentValue(),
parse: (v) => this.parseCurrentValue(v),
refName: "currentValue",
fieldName: this.currentValueField,
shouldSave: () => this.props.readonly,
});
this.maxValueRef = useInputField({
getValue: () => this.formatMaxValue(),
parse: (v) => this.parseMaxValue(v),
refName: "maxValue",
fieldName: this.maxValueField,
shouldSave: () => this.props.readonly,
});
this.state = useState({
isEditing: false,
});
}
get isEditable() {
return this.props.isEditable && !this.props.readonly;
}
get isPercentage() {
return !this.props.maxValueField || !isNaN(this.props.maxValueField);
}
get currentValue() {
return this.props.record.data[this.currentValueField] || 0;
}
get maxValue() {
return this.props.record.data[this.maxValueField] || 100;
}
get progressBarColorClass() {
return this.currentValue > this.maxValue ? this.props.overflowClass : "bg-primary";
}
formatCurrentValue(humanReadable = !this.state.isEditing) {
const formatter = formatters.get(this.props.record.fields[this.currentValueField].type);
return formatter(this.currentValue, { humanReadable });
}
formatMaxValue(humanReadable = !this.state.isEditing) {
const formatter = formatters.get(this.props.record.fields[this.maxValueField]?.type ?? "integer");
return formatter(this.maxValue, { humanReadable });
}
parseCurrentValue(value) {
let parsedValue = parseFloat(value);
if (this.props.record.fields[this.currentValueField].type === "integer") {
parsedValue = Math.floor(parsedValue);
}
return parsedValue;
}
parseMaxValue(value) {
let parsedValue = parseFloat(value);
if (this.props.record.fields[this.maxValueField].type === "integer") {
parsedValue = Math.floor(parsedValue);
}
return parsedValue;
}
onInputBlur() {
if (
document.activeElement !== this.maxValueRef.el &&
document.activeElement !== this.currentValueRef.el
) {
this.state.isEditing = false;
}
}
onInputFocus() {
this.state.isEditing = true;
}
}
export const progressBarField = {
component: ProgressBarField,
displayName: _t("Progress Bar"),
supportedOptions: [
{
label: _t("Can edit value"),
name: "editable",
type: "boolean",
},
{
Registry / API
- Registry name
progressbar- Category
fields- Module
web- Slug
progressbar- Nav group
forms