[IMP] web: improve datetime picker support for time
This commit improves the support for time in the datetime picker by doing two things: - allow to pick seconds by giving a rounding value of 0 - check minDate and maxDate by accounting for the time when the picker is in datetime mode instead of only checking the date Part-of: odoo/odoo#133349
This commit is contained in:
@@ -37,7 +37,8 @@ import { ensureArray } from "../utils/arrays";
|
||||
* @property {PrecisionLevel} [minPrecision="days"]
|
||||
* @property {(value: DateTime) => any} [onSelect]
|
||||
* @property {boolean} [range]
|
||||
* @property {number} [rounding=5]
|
||||
* @property {number} [rounding=5] the rounding in minutes, pass 0 to show seconds, pass 1 to avoid
|
||||
* rounding minutes without displaying seconds.
|
||||
* @property {{ buttons?: any }} [slots]
|
||||
* @property {"date" | "datetime"} [type]
|
||||
* @property {NullableDateTime | NullableDateRange} value
|
||||
@@ -143,6 +144,7 @@ const toWeekItem = (weekDayItems) => ({
|
||||
// Time constants
|
||||
const HOURS = numberRange(0, 24).map((hour) => [hour, String(hour)]);
|
||||
const MINUTES = numberRange(0, 60).map((minute) => [minute, String(minute || 0).padStart(2, "0")]);
|
||||
const SECONDS = [...MINUTES];
|
||||
const MERIDIEMS = ["AM", "PM"];
|
||||
|
||||
/**
|
||||
@@ -380,14 +382,19 @@ export class DateTimePicker extends Component {
|
||||
);
|
||||
this.availableHours = HOURS;
|
||||
this.availableMinutes = MINUTES.filter((minute) => !(minute[0] % props.rounding));
|
||||
this.availableSeconds = props.rounding ? [] : SECONDS;
|
||||
this.allowedPrecisionLevels = this.filterPrecisionLevels(
|
||||
props.minPrecision,
|
||||
props.maxPrecision
|
||||
);
|
||||
|
||||
this.additionalMonth = props.range && !this.env.isSmall;
|
||||
this.maxDate = parseLimitDate(props.maxDate, MAX_VALID_DATE).endOf("day");
|
||||
this.minDate = parseLimitDate(props.minDate, MIN_VALID_DATE).startOf("day");
|
||||
this.maxDate = parseLimitDate(props.maxDate, MAX_VALID_DATE);
|
||||
this.minDate = parseLimitDate(props.minDate, MIN_VALID_DATE);
|
||||
if (this.props.type === "date") {
|
||||
this.maxDate = this.maxDate.endOf("day");
|
||||
this.minDate = this.minDate.startOf("day");
|
||||
}
|
||||
|
||||
if (this.maxDate < this.minDate) {
|
||||
throw new Error(`DateTimePicker error: given "maxDate" comes before "minDate".`);
|
||||
|
||||
@@ -66,6 +66,13 @@
|
||||
<t t-set="unitIndex" t-value="1" />
|
||||
<t t-set="unitList" t-value="availableMinutes" />
|
||||
</t>
|
||||
<t t-if="availableSeconds.length">
|
||||
<span>:</span>
|
||||
<t t-call="web.DateTimePicker.Select">
|
||||
<t t-set="unitIndex" t-value="2" />
|
||||
<t t-set="unitList" t-value="availableSeconds" />
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="meridiems">
|
||||
<t t-call="web.DateTimePicker.Select">
|
||||
<t t-set="unitIndex" t-value="3" />
|
||||
|
||||
@@ -872,6 +872,23 @@ QUnit.module("Components", ({ beforeEach }) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("rounding=0 enables seconds picker", async (assert) => {
|
||||
await mountPicker({
|
||||
rounding: 0,
|
||||
});
|
||||
|
||||
const [hourSelect, minuteSelect, secondsSelect] = getTimePickers().at(0);
|
||||
assert.deepEqual(getTexts(hourSelect, "option"), range(24, String));
|
||||
assert.deepEqual(
|
||||
getTexts(minuteSelect, "option"),
|
||||
range(60, (i) => pad2(i))
|
||||
);
|
||||
assert.deepEqual(
|
||||
getTexts(secondsSelect, "option"),
|
||||
range(60, (i) => pad2(i))
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("no value, select date without handler", async (assert) => {
|
||||
await mountPicker();
|
||||
|
||||
@@ -903,6 +920,86 @@ QUnit.module("Components", ({ beforeEach }) => {
|
||||
assert.verifySteps(["2023-04-25T18:00:00", "2023-04-25T18:05:00"]);
|
||||
});
|
||||
|
||||
QUnit.test("minDate with time: selecting out-of-range and in-range times", async (assert) => {
|
||||
await mountPicker({
|
||||
onSelect: (value) => assert.step(formatForStep(value)),
|
||||
minDate: DateTime.fromISO("2023-04-25T16:00:00.000"),
|
||||
});
|
||||
|
||||
const [hourSelect] = getTimePickers().at(0);
|
||||
await editSelect(hourSelect, null, "15");
|
||||
assert.verifySteps([]);
|
||||
await editSelect(hourSelect, null, "16");
|
||||
assert.verifySteps(["2023-04-25T16:00:00"]);
|
||||
});
|
||||
|
||||
QUnit.test("maxDate with time: selecting out-of-range and in-range times", async (assert) => {
|
||||
await mountPicker({
|
||||
onSelect: (value) => assert.step(formatForStep(value)),
|
||||
maxDate: DateTime.fromISO("2023-04-25T16:00:00.000"),
|
||||
});
|
||||
|
||||
const [hourSelect] = getTimePickers().at(0);
|
||||
await editSelect(hourSelect, null, "17");
|
||||
assert.verifySteps([]);
|
||||
await editSelect(hourSelect, null, "16");
|
||||
assert.verifySteps(["2023-04-25T16:00:00"]);
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"max and min date with time: selecting out-of-range and in-range times",
|
||||
async (assert) => {
|
||||
await mountPicker({
|
||||
onSelect: (value) => assert.step(formatForStep(value)),
|
||||
minDate: DateTime.fromISO("2023-04-25T16:00:00.000"),
|
||||
maxDate: DateTime.fromISO("2023-04-25T16:00:00.000"),
|
||||
});
|
||||
|
||||
const [hourSelect] = getTimePickers().at(0);
|
||||
await editSelect(hourSelect, null, "15");
|
||||
await editSelect(hourSelect, null, "17");
|
||||
assert.verifySteps([]);
|
||||
await editSelect(hourSelect, null, "16");
|
||||
assert.verifySteps(["2023-04-25T16:00:00"]);
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test(
|
||||
"max and min date with time: selecting invalid minutes and making it valid by selecting hours",
|
||||
async (assert) => {
|
||||
await mountPicker({
|
||||
onSelect: (value) => assert.step(formatForStep(value)),
|
||||
minDate: DateTime.fromISO("2023-04-25T16:10:00.000"),
|
||||
maxDate: DateTime.fromISO("2023-04-25T16:50:00.000"),
|
||||
});
|
||||
|
||||
const [hourSelect, minuteSelect] = getTimePickers().at(0);
|
||||
await editSelect(hourSelect, null, "13");
|
||||
await editSelect(minuteSelect, null, "30");
|
||||
assert.verifySteps([]);
|
||||
await editSelect(hourSelect, null, "16");
|
||||
assert.verifySteps(["2023-04-25T16:30:00"]);
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test(
|
||||
"max and min date with time: valid time on invalid day becomes valid when selecting day",
|
||||
async (assert) => {
|
||||
await mountPicker({
|
||||
onSelect: (value) => assert.step(formatForStep(value)),
|
||||
minDate: DateTime.fromISO("2023-04-24T16:10:00.000"),
|
||||
maxDate: DateTime.fromISO("2023-04-24T16:50:00.000"),
|
||||
});
|
||||
|
||||
const [hourSelect, minuteSelect] = getTimePickers().at(0);
|
||||
await editSelect(hourSelect, null, "16");
|
||||
await editSelect(minuteSelect, null, "30");
|
||||
assert.verifySteps([]);
|
||||
await click(getPickerCell("24"));
|
||||
assert.verifySteps(["2023-04-24T16:30:00"]);
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test("single value, select date", async (assert) => {
|
||||
await mountPicker({
|
||||
value: DateTime.fromObject({ day: 30, hour: 8, minute: 43 }),
|
||||
|
||||
Reference in New Issue
Block a user