[IMP] web: add always_range option to daterange widget

always_range option on the daterange widget allows to always display this
widget as a range (two inputs separated by an arrow) even if both
start/end date are empty and not required.

task-3628069

Part-of: odoo/odoo#145167
This commit is contained in:
Hugo Carlier (Huca)
2024-01-03 10:58:02 +00:00
parent c04d667912
commit bc98aad620
3 changed files with 76 additions and 8 deletions
@@ -40,6 +40,7 @@ export class DateTimeField extends Component {
endDateField: { type: String, optional: true },
maxDate: { type: String, optional: true },
minDate: { type: String, optional: true },
alwaysRange: { type: Boolean, optional: true },
placeholder: { type: String, optional: true },
required: { type: Boolean, optional: true },
rounding: { type: Number, optional: true },
@@ -198,7 +199,11 @@ export class DateTimeField extends Component {
if (!this.relatedField) {
return false;
}
return this.props.required || ensureArray(value).filter(Boolean).length === 2;
return (
this.props.alwaysRange ||
this.props.required ||
ensureArray(value).filter(Boolean).length === 2
);
}
/**
@@ -216,9 +221,10 @@ export class DateTimeField extends Component {
*/
shouldShowSeparator() {
return (
this.state.range &&
(this.props.required ||
(!this.isEmpty(this.startDateField) && !this.isEmpty(this.endDateField)))
this.props.alwaysRange ||
(this.state.range &&
(this.props.required ||
(!this.isEmpty(this.startDateField) && !this.isEmpty(this.endDateField))))
);
}
@@ -275,6 +281,7 @@ export const dateField = {
endDateField: options[END_DATE_FIELD_OPTION],
maxDate: options.max_date,
minDate: options.min_date,
alwaysRange: archParseBoolean(options.always_range),
placeholder: attrs.placeholder,
required: dynamicInfo.required,
rounding: options.rounding && parseInt(options.rounding, 10),
@@ -342,6 +349,15 @@ export const dateRangeField = {
type: "field",
availableTypes: ["date", "datetime"],
},
{
label: _t("Always range"),
name: "always_range",
type: "boolean",
default: false,
help: _t(
`Set to true the full range input has to be display by default, even if empty.`
),
},
],
supportedTypes: ["date", "datetime"],
};
@@ -7,7 +7,7 @@
<t t-if="props.readonly">
<span class="text-truncate" t-esc="getFormattedValue(0)" />
</t>
<t t-elif="!props.required and isEmpty(startDateField) and !isEmpty(endDateField)">
<t t-elif="!props.required and !props.alwaysRange and isEmpty(startDateField) and !isEmpty(endDateField)">
<button
class="o_add_date o_add_start_date btn btn-secondary btn-sm w-100"
t-on-click="() => this.addDate(0)"
@@ -16,7 +16,7 @@
Add start date
</button>
</t>
<t t-elif="props.required or !isEmpty(startDateField) or startDateField === props.name">
<t t-elif="props.required or props.alwaysRange or !isEmpty(startDateField) or startDateField === props.name">
<input
t-ref="start-date"
type="text"
@@ -44,7 +44,7 @@
<t t-if="props.readonly">
<span class="text-truncate" t-esc="getFormattedValue(1)" />
</t>
<t t-elif="!props.required and !isEmpty(startDateField) and isEmpty(endDateField)">
<t t-elif="!props.required and !props.alwaysRange and !isEmpty(startDateField) and isEmpty(endDateField)">
<button
class="o_add_date o_add_end_date btn btn-secondary btn-sm w-100"
t-on-click="() => this.addDate(1)"
@@ -53,7 +53,7 @@
Add end date
</button>
</t>
<t t-elif="props.required or !isEmpty(endDateField) or endDateField === props.name">
<t t-elif="props.required or props.alwaysRange or !isEmpty(endDateField) or endDateField === props.name">
<input
t-ref="end-date"
type="text"
@@ -1167,4 +1167,56 @@ QUnit.module("Fields", (hooks) => {
assert.deepEqual(textSiblings, ["->", "02/03/2017"]);
});
QUnit.test(
"always range: related end date, both start date and end date empty",
async (assert) => {
serverData.models.partner.records[0].datetime = false;
await makeView({
type: "form",
resModel: "partner",
serverData,
arch: /* xml */ `
<form>
<field name="datetime" widget="daterange" options="{'end_date_field': 'datetime_end', 'always_range': '1'}"/>
</form>`,
resId: 1,
});
assert.strictEqual(getInputs().length, 2);
assert.hasAttrValue(getInputs()[0], "data-field", "datetime");
assert.strictEqual(getInputs()[0].value, "");
assert.hasAttrValue(getInputs()[1], "data-field", "datetime_end");
assert.strictEqual(getInputs()[1].value, "");
assert.containsNone(target, ".o_add_date");
await editInput(getInputs()[0], null, "06/06/2023 12:00:00");
assert.strictEqual(getInputs().length, 2);
assert.hasAttrValue(getInputs()[0], "data-field", "datetime");
assert.strictEqual(getInputs()[0].value, "06/06/2023 12:00:00");
assert.hasAttrValue(getInputs()[1], "data-field", "datetime_end");
assert.strictEqual(getInputs()[1].value, "");
assert.containsNone(target, ".o_add_date");
await editInput(getInputs()[1], null, "07/07/2023 13:00:00");
assert.strictEqual(getInputs().length, 2);
assert.hasAttrValue(getInputs()[0], "data-field", "datetime");
assert.strictEqual(getInputs()[0].value, "06/06/2023 12:00:00");
assert.hasAttrValue(getInputs()[1], "data-field", "datetime_end");
assert.strictEqual(getInputs()[1].value, "07/07/2023 13:00:00");
assert.containsNone(target, ".o_add_date");
await editInput(getInputs()[0], null, "");
assert.strictEqual(getInputs().length, 2);
assert.hasAttrValue(getInputs()[0], "data-field", "datetime");
assert.strictEqual(getInputs()[0].value, "");
assert.hasAttrValue(getInputs()[1], "data-field", "datetime_end");
assert.strictEqual(getInputs()[1].value, "07/07/2023 13:00:00");
assert.containsNone(target, ".o_add_date");
}
);
});