Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
## [UNRELEASED]

### Fixed
- [#3425](https://github.com/plotly/dash/issues/3425) dcc.DatePicker: Fix `updatemode="bothdates"` not always respected
- [#3805](https://github.com/plotly/dash/pull/3805) Fix FastAPI POST routes deadlock caused by middleware consuming request body. Fixes [#3801](https://github.com/plotly/dash/issues/3801).

## [4.2.0] - 2026-06-01 - *The Freedom Update*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@
const containerRef = useRef<HTMLDivElement>(null);
const startInputRef = useRef<HTMLInputElement | null>(null);
const endInputRef = useRef<HTMLInputElement | null>(null);
const startAutosizeRef = useRef<any>(null);

Check warning on line 108 in components/dash-core-components/src/fragments/DatePickerRange.tsx

View workflow job for this annotation

GitHub Actions / DCC Lint Tests (Python 3.8)

Unexpected any. Specify a different type

Check warning on line 108 in components/dash-core-components/src/fragments/DatePickerRange.tsx

View workflow job for this annotation

GitHub Actions / DCC Lint Tests (Python 3.12)

Unexpected any. Specify a different type
const endAutosizeRef = useRef<any>(null);

Check warning on line 109 in components/dash-core-components/src/fragments/DatePickerRange.tsx

View workflow job for this annotation

GitHub Actions / DCC Lint Tests (Python 3.8)

Unexpected any. Specify a different type

Check warning on line 109 in components/dash-core-components/src/fragments/DatePickerRange.tsx

View workflow job for this annotation

GitHub Actions / DCC Lint Tests (Python 3.12)

Unexpected any. Specify a different type
const calendarRef = useRef<CalendarHandle>(null);
const isNewRangeRef = useRef(false);
const hasPortal = with_portal || with_full_screen_portal;
Expand Down Expand Up @@ -167,8 +167,14 @@
start_date: dateAsStr(internalStartDate),
end_date: dateAsStr(internalEndDate),
});
} else if (endChanged && !internalEndDate) {
// End date was cleared (user started a new range).
} else if (
updatemode === 'singledate' &&
endChanged &&
!internalEndDate
) {
// End date was cleared (user started a new range). Under
// 'bothdates' we wait for a complete range before updating props,
// so this partial update is only sent in 'singledate' mode.
setProps({
start_date: dateAsStr(internalStartDate) ?? null,
end_date: null,
Expand Down Expand Up @@ -358,7 +364,7 @@

return (
<div className="dash-datepicker" ref={containerRef}>
<ResizeDetector onResize={handleResize} targets={[containerRef]}/>
<ResizeDetector onResize={handleResize} targets={[containerRef]} />
<Popover.Root
open={!disabled && isCalendarOpen}
onOpenChange={disabled ? undefined : setIsCalendarOpen}
Expand Down Expand Up @@ -388,9 +394,7 @@
id={start_date_id || accessibleId}
inputClassName="dash-datepicker-input dash-datepicker-start-date"
value={startInputValue}
onChange={e =>
setStartInputValue(e.target?.value)
}
onChange={e => setStartInputValue(e.target?.value)}
onKeyDown={handleStartInputKeyDown}
onFocus={() => {
if (isCalendarOpen) {
Expand All @@ -412,9 +416,7 @@
id={end_date_id || accessibleId + '-end-date'}
inputClassName="dash-datepicker-input dash-datepicker-end-date"
value={endInputValue}
onChange={e =>
setEndInputValue(e.target?.value)
}
onChange={e => setEndInputValue(e.target?.value)}
onKeyDown={handleEndInputKeyDown}
onFocus={() => {
if (isCalendarOpen) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -534,3 +534,43 @@ def display_dates(start_date, end_date):
), "End input should display 2021-06-30"

assert dash_dcc.get_logs() == []


def test_dtpr031_bothdates_no_partial_update_on_new_start(dash_dcc):
"""Bug #3425: with updatemode='bothdates', picking a new start date (which
clears the end date) must not fire a partial update for the incomplete range."""
app = Dash(__name__)
app.layout = html.Div(
[
dcc.DatePickerRange(
id="dpr",
min_date_allowed=datetime(2021, 1, 1),
max_date_allowed=datetime(2021, 1, 31),
initial_visible_month=datetime(2021, 1, 1),
minimum_nights=0,
updatemode="bothdates",
display_format="MM/DD/YYYY",
),
html.Div(id="output"),
]
)

@app.callback(
Output("output", "children"),
Input("dpr", "start_date"),
Input("dpr", "end_date"),
prevent_initial_call=True,
)
def display_dates(start_date, end_date):
return f"Start: {start_date}, End: {end_date}"

dash_dcc.start_server(app)

dash_dcc.select_date_range("dpr", day_range=(2, 11))
dash_dcc.wait_for_text_to_equal("#output", "Start: 2021-01-02, End: 2021-01-11")

dash_dcc.select_date_range("dpr", day_range=(4,))
time.sleep(0.5)
assert dash_dcc.find_element("#output").text == "Start: 2021-01-02, End: 2021-01-11"

assert dash_dcc.get_logs() == []
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def test_dppt006_fullscreen_portal_close_button_keyboard(dash_dcc):
assert popover.is_displayed()

action = ActionChains(dash_dcc.driver)
action.move_to_element_with_offset(popover, 10, 10).click().perform()
action.move_by_offset(10, 10).click().perform()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated to the bug - this just addresses a flaky test when run locally.

sleep(0.2)

popover = dash_dcc.find_element(".dash-datepicker-content")
Expand Down
Loading