Skip to content

[scheduler] Fix the event dialog moving untouched dates across timezones - #23462

Merged
rita-codes merged 82 commits into
mui:masterfrom
rita-codes:scheduler-all-day-data-timezone
Sep 21, 2026
Merged

rita-codes merged 82 commits into
mui:masterfrom
rita-codes:scheduler-all-day-data-timezone

Conversation

@rita-codes

@rita-codes rita-codes commented Aug 31, 2026 •

Copy link
Copy Markdown
Member

Editing an event from another timezone breaks it in three ways.

How to reproduce

Take an all-day event stored as 2025-07-04T00:00:00Z → 2025-07-04T23:59:59Z (a UTC "July 4th") and show it with displayTimezone="America/New_York". New York is behind UTC, so the calendar shows it on July 3rd.

  1. Open the dialog, change only the title, save. The event is now stored as 2025-07-03T04:00:00Z → 2025-07-04T03:59:59Z. It moved one day back, and in UTC it now spans two days.
  2. Make the event weekly, then delete or drag one occurrence with "Only this event". The exception is written for July 3rd, but the series has no occurrence on July 3rd, so the wrong day is excluded, or none at all.
  3. Open the dialog and pick "Repeats weekly". The rule is stored as BYDAY=TH (the day shown in New York), but the series lives on Fridays in UTC, so the next occurrences land on Wednesday evenings. The same happens with the monthly presets ("on the 3rd", "first Thursday"), with the "Until" date, and when creating a new event.

Why it happens

The same instant is a different day depending on the timezone you ask in.

  1. The dialog fills its date fields with the days the user sees (July 3rd in New York) and, on save, sent start/end back even when the user did not touch them. Those days were then read as New York days, which is a different instant from what was stored.
  2. Every surface (dialog, toolbar, context menu, drag & drop) identified a recurring occurrence by the day it is displayed on. The recurrence engine identifies it by its start in the event's own timezone. For a cross-timezone all-day event those are different days.
  3. The recurrence presets are built on the weekday and day of month the user sees, and the rule was stored as is, in the event's timezone, where the start falls on another day.

What changes

The dialog only sends what the user edited.

  • start and end are sent only when the user changed a date or time field (the time fields only count while the event is not all-day). An untouched bound keeps its stored value byte for byte. On the recurring path each bound is checked on its own, so changing only the end date no longer moves the series start.
  • Exceptions: changing allDay resends both bounds; if the display timezone changed while the dialog was open, editing one bound resends both (the range was validated as a pair in the new timezone); with a dataSource, a resize made on the calendar and still being persisted is resent, or the next update would rebuild it from the stale model. The selection records the stored model's bounds when a committed change refreshes it, so a resize awaiting persistence is told apart from a bound the host moved while the dialog was open: the host's value is kept.
  • The submit checks run on the range the save writes, not on the form's re-read of it: an untouched bound is validated on its stored instant (the live event's on a non-recurring update), which the form can miss in a repeated DST hour or after a host update.

The recurrence rule is read and written in the event's timezone.

  • The rule is expressed in the timezone the series expands in, as RFC 5545 (the rule is evaluated as local time in the DTSTART timezone), Google Calendar and Bryntum do. There is no projection between the display and the data timezones anymore: a calendar position ("first Friday", "on the 1st") has no stable equivalent in another timezone, and a weekly rule only has one until DST gets involved.
  • The presets ("weekly", "monthly on day N", "first Friday") and the UNTIL day are built on the bounds the event ends up with, in the event's timezone: the edited bound when the save resends it (the tab and the save share the predicate), the occurrence's own otherwise, and the default timezone when creating an event. A picked preset re-anchors its weekday or day of month when the start moves; a custom rule is kept as picked. Enabling "Until" pre-fills the end of the event's last day in its own timezone, and the day typed there is read in that timezone too. The rule is then stored as is by edits, recurring scope changes and creation.
  • When the event's timezone is not the display one, the Recurrence tab names it under the selector ("Timezone: Pacific Time") and the read-only details append it to the recurrence label ("Repeats weekly on Friday (UTC)"), so a rule naming a weekday other than the one the occurrence is displayed on reads as intended. The name is the localized generic name from Intl.DateTimeFormat (timeZoneName: 'longGeneric'), falling back to the identifier when the runtime only has an offset for it (UTC); aliases of the same zone (US/Eastern, America/New_York) count as the same. The weekday token behind the ordinal aria-labels now reads the event's timezone instead of the browser's.
  • Breaking change (beta): displayTimezone.rrule is removed from the processed event and occurrence types; read occurrence.dataTimezone.rrule instead (behind isEventOccurrence for creation drafts). projectRRuleToTimezone is removed from the recurring-events plugin and applyDataTimezoneToEventUpdate only relabels the bounds and the exception dates. New recurrenceTimezoneLabel and recurrenceLabelTimezoneSuffix locale keys and eventDialogRecurrenceTimezoneLabel class.

Recurring occurrences are identified by their start in the event's timezone.

  • Dialog, toolbar, context menu and drag & drop all use occurrence.dataTimezone.start now. A drop only sends the bounds it moved: an untouched bound re-read from its display value can be another day in the event's timezone, which a recurring update would take for a day move. A drop that toggles all-day resends both, since the stored bounds belong to the other representation.
  • The grid primitives get the occurrence's dataTimezone as a prop (getOccurrenceDataTimezone, undefined for placeholders) and build the drag occurrence with a shared useOriginalOccurrence hook, so the drop knows which occurrence it started from.
  • A resize refreshes the armed snapshot with the committed bounds only, in both timezones, so a rule added right after is built on the real start and an end-only resize leaves the start untouched.

The selected occurrence stays correct after a scope change.

  • After "Only this event" or "This and following events", the selection moves onto the new event. After "All events", it stays selected only if the occurrence is still on the same day in the event's timezone and the rule was left alone. Otherwise the recurrence engine decides where the series lands, so the selection is dropped instead of guessing.
  • The selection keeps the occurrence's identity; when the editor opens from it, the rule is read from the store, so a split series shows its new count or weekday.
  • The three delete surfaces share one deleteOccurrence store method: recurring occurrences go to the scope dialog, the rest are deleted right away. It reads the rule from the store. An event the store does not hold yet (a split still being persisted through the dataSource, or one that left the loaded range) is neither deleted nor sent to the scope dialog: a transient error is surfaced, the same way a scheduling veto is, and confirming a scope whose event has gone is dropped with the same error instead of throwing.

Tests (all red/green)

  • Dialog: title-only edits keep the dates byte-identical in both timezone directions (single- and multi-day, all-day and timed, and with a snapshot sitting on a raw drop instant); end-only edits keep the series start (New York and Tokyo); untouched dates survive a display-timezone change during async validation, and an edited start pulls the untouched end along (plain and recurring paths); a pending resize survives a rename with a dataSource, a bound the host moved while the dialog is open is kept, and an edit conflicting with it is rejected; an untouched start in a repeated DST hour is validated on its stored instant; immediate delete.
  • Rule in the event's timezone: weekly, monthly day and ordinal presets stored as is from New York on an untouched start, on an edited start (labels, ordinal toggle and the checked weekday follow it; a custom pick does not), after an armed resize, when only the display timezone moved, and on creation; UNTIL pre-filled with the event's last day (untouched, edited timed end, edited all-day end), read back from Tokyo on the stored day, and stored at the end of the typed day in the event's timezone; the timezone label in the tab and in the read-only details, and its absence when both timezones match; unit tests on getRecurrenceRuleBound, getResentRangeBounds, getWeekdayToken and the timezone name (localized, default/system resolved to the system timezone, identifier fallback, aliases).
  • Identity: an end-only resize of a cross-timezone all-day series with "All events" keeps the start and the rule, and the same resize on an armed non-recurring occurrence keeps its start in the snapshot (store, drop target and a weekly rule added right after); a drop that toggles all-day off resends both bounds; cross-timezone deletes from dialog, toolbar and context menu; drags in the month view (checking where the detached event lands), the week view (a timed occurrence) and the timeline (including from a secondary resource row); a cross-timezone resize; the Nov 2025 DST transition; a cross-timezone "This and following" split.
  • Selection: same-day time or end-only change stays selected; a day move, a rule change or a removed rule drops it; the editor opens on the split series' new count and weekday; deleteOccurrence on both branches and with a selection that disagrees with the store; a delete or a scope confirmation on an event the store does not hold is rejected with the transient error.
  • Store: recurring scope changes store the submitted rule as is from a later occurrence, for "All events" and "This and following events"; a count-only change keeps the stored BYMONTHDAY.
  • Units: getEditedRangeBounds, getOccurrenceDataTimezone.

Depends on #23467 (exDates keyed in the wrong zone, now merged), which this review surfaced. Merging it also exposed a test-builder issue fixed here: EventBuilder now serializes its dates (including toOccurrence's round-tripped model) as UTC instants, since a date labeled with the event's timezone stringifies with an offset suffix that resolveEventDate reads as wall time.

The dialog built all-day bounds with the display timezone, so saving an
all-day event viewed from another timezone — even a plain rename —
shifted its stored day boundaries and stretched it across two data-zone
days. computeRange now takes the all-day anchor timezone and the submit
path passes the event's data timezone for edits; validation and the
placeholder keep the display timezone, where ordering and rendering
happen. Creations still anchor to the display timezone (the event has no
timezone of its own yet).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDEgka4iDRFrenWeWFhunq
@rita-codes rita-codes added type: bug It doesn't behave as expected. scope: scheduler Changes related to the scheduler. labels Aug 31, 2026
@rita-codes rita-codes self-assigned this Aug 31, 2026
@code-infra-dashboard

code-infra-dashboard Bot commented Aug 31, 2026 •

Copy link
Copy Markdown

Deploy preview

Bundle size

Bundle Parsed size Gzip size
@mui/x-data-grid 0B(0.00%) 0B(0.00%)
@mui/x-data-grid-pro 0B(0.00%) 0B(0.00%)
@mui/x-data-grid-premium 0B(0.00%) 0B(0.00%)
@mui/x-charts 0B(0.00%) 0B(0.00%)
@mui/x-charts-pro 0B(0.00%) 0B(0.00%)
@mui/x-charts-premium 0B(0.00%) 0B(0.00%)
@mui/x-date-pickers 0B(0.00%) 0B(0.00%)
@mui/x-date-pickers-pro 0B(0.00%) 0B(0.00%)
@mui/x-tree-view 0B(0.00%) 0B(0.00%)
@mui/x-tree-view-pro 0B(0.00%) 0B(0.00%)
@mui/x-scheduler 🔺+4.05KB(+1.02%) 🔺+1.39KB(+1.28%)
@mui/x-scheduler-premium 🔺+3.68KB(+0.65%) 🔺+1.3KB(+0.82%)
@mui/x-chat 0B(0.00%) 0B(0.00%)
@mui/x-license 0B(0.00%) 0B(0.00%)

Details of bundle changes


Check out the code infra dashboard for more information about this PR.

rita-codes and others added 4 commits August 31, 2026 12:23
The submit read the creation placeholder twice, and the data-timezone
lookup inlined the processed-event walk; a `dataTimezone` selector now
carries the lookup and the 'default' fallback.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDEgka4iDRFrenWeWFhunq
The form seeds its date fields from the display-timezone bounds, so resending
them untouched re-anchors the event to the display zone: viewed from another
timezone, an all-day event moved to a different day on a mere rename. Anchoring
the submit in the data timezone (previous approach) could not fix this — it
faithfully persisted the display day the form was seeded with.

Instead, leave start/end out of the update when none of the range fields is
dirty. This also keeps an untouched range out of the pattern-based recurring
update, where a display-zone start could shift a weekly series' BYDAY.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDEgka4iDRFrenWeWFhunq
@rita-codes rita-codes changed the title [scheduler] Anchor all-day dialog bounds to the event's own timezone [scheduler] Fix the event dialog moving untouched dates across timezones Aug 31, 2026
rita-codes and others added 2 commits August 31, 2026 13:29
…e2e pin

A time typed while all-day was toggled off stayed dirty after toggling it back
on, re-arming the range resend and reintroducing the cross-timezone day shift.
Only the keys the submitted range actually reads count now.

Also: RANGE_FORM_KEYS moves next to computeRange as the single copy of the list
(the placeholder keys derive from it), getDirtyValues drops its now-unused
excludeKeys parameter, the recurring rename test completes the scope flow on a
cross-timezone weekly series, the touch-resize test pins the seeded end time,
and a test pins the whole-displayed-range semantics of a partial edit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDEgka4iDRFrenWeWFhunq
The recurring scope paths (update, delete, drag) identified the occurrence by
its display-timezone start. For an all-day occurrence viewed from another
timezone those bounds are day-normalized to a different instant, so the
exception date and the detached event landed on the wrong data-zone day. The
occurrence's own data-timezone start is the identity the expansion keys on.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDEgka4iDRFrenWeWFhunq
rita-codes and others added 2 commits August 31, 2026 14:41
The data-timezone bounds are now the occurrence identity for recurring scope
operations, so every holder must maintain them:

- setEditingOccurrenceTimes and repointEditingOccurrence sync dataTimezone
  alongside the display bounds, so a follow-up edit or delete of the armed
  occurrence targets the post-resize/post-move occurrence.
- A rename-only scope change (no start/end in the changes) still re-points the
  armed occurrence onto the moved-to event, keeping its current bounds.
- The grid event primitives take dataStart/dataEnd so drag data carries the real
  occurrence identity instead of one fabricated from the display segment bounds.
- The 'dataTimezone' in occurrence checks share an isEventOccurrence guard, the
  RangeFormKey type derives from RANGE_FORM_KEYS, and the occurrenceStart
  parameters document the data-timezone contract.

New coverage: store-level identity-sync and rename-repoint tests, cross-timezone
delete pins for the dialog, context menu, and toolbar, a scope-'all' edited-day
pin, the all-day-to-timed conversion, and generateOccurrenceFromEvent units.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDEgka4iDRFrenWeWFhunq
The rename fallback fed the display bounds into the data-timezone sync, so a
rename-only scope change on a cross-timezone all-day armed occurrence relabeled
its identity onto the display day — the repoint keyed off the wrong day and a
follow-up delete excluded it. The fallback now threads the occurrence's own
data bounds through setEditingOccurrenceTimes and repointEditingOccurrence,
which accept explicit data bounds and only fall back to the instant-preserving
relabel for genuine time changes.

Also: an end-to-end cross-timezone drag test discriminates the dataStart
threading through the grid primitives, the scope-'all' pin asserts the end day
and the BYDAY, the exDate asserts parse through the adapter, the wrappers
compute the data bounds once, and the scope-sync comments say 'change' instead
of 'resize' now that renames flow through too.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDEgka4iDRFrenWeWFhunq
@github-actions github-actions Bot added the PR: out-of-date The pull request has merge conflicts and can't be merged. label Aug 31, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has conflicts, please resolve those before we can evaluate the pull request.

…-data-timezone

# Conflicts:
#	packages/x-scheduler/src/internals/components/event-dialog/EventDialog.test.tsx
@github-actions github-actions Bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged. label Aug 31, 2026
rita-codes and others added 6 commits August 31, 2026 18:10
…he pattern math

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CC6LfHbZXD549R8qtmQojJ
…-'all' update

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CC6LfHbZXD549R8qtmQojJ
…e drag, and the pending-validation untouched range

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CC6LfHbZXD549R8qtmQojJ

@flaviendelangle flaviendelangle left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

PR review

One merge-blocking bug confirmed. The existing targeted suite passed with 582 tests and 9 skipped; an added dialog reproduction fails.

Bugs (1)

1. 🔴 Preserve untouched data-timezone bounds after resizing

Location: SchedulerStore.ts:1120

start: processDate(
  adapter.setTimezone(start, occurrence.dataTimezone.timezone),
  adapter,
),

useDropTarget omits unchanged bounds from the update, but subsequently passes both display bounds to setEditingOccurrenceTimes. This new code overwrites the untouched data-timezone start with the normalized display-day start.

Failure scenario: Select a non-recurring all-day event on July 4 in UTC, displayed in New York, and resize only its end. The stored start remains July 4, but the selected occurrence’s start becomes July 3 at 04:00 UTC. Open the editor and add weekly recurrence: the confirmed dialog reproduction saves byDay: ['TH'] instead of ['FR'].

Fix: Preserve the original data-timezone value for each unchanged bound when refreshing the selected occurrence. Convert only committed changed bounds, including any scheduling adjustments. Add an end-only, cross-timezone all-day resize regression test.

Tests (0)

No findings.

Simplifications (0)

No findings.

Docs (0)

No findings.

Verdict

Request changes — an end-only resize can cause subsequent recurrence editing to save the wrong weekday.


🤖 Review generated with Codex

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@rita-codes

Copy link
Copy Markdown
Member Author

Fixed in df086e5. setEditingOccurrenceTimes now takes the changed bounds only, and the drop target passes what the committed update contains, so an untouched bound keeps its stored value in both timezones. Added the end-only cross-timezone regression at the store, drop-target and dialog levels.

@flaviendelangle flaviendelangle left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

PR review

Merge-blocking findings: two new regressions and two existing bugs left unresolved in the refactored paths. Targeted reproductions confirmed all four; 659 existing tests passed, with 9 skipped.

Bugs (4)

1. 🔴 All-day-to-timed drops can save an inverted range

Location: useDropTarget.ts:237

if (!adapter.isEqual(originalOccurrence.displayTimezone.start.value, start)) {
  changes.start = start;
}

This comparison ignores changes to allDay. An all-day event's normalized display start can equal the drop target while differing from its stored start.

Failure scenario: An all-day event starts July 4 at midnight UTC and displays from July 3 at midnight in New York. Dragging it into the July 3 timed grid at midnight omits start, sets allDay: false, and saves an end of 01:00. Its retained start is 20:00 that evening, after its end.

Fix: Submit both placeholder bounds whenever the drop changes allDay.

2. 🔴 Partial date submission can invert an event during DST fall-back

Location: FormContent.tsx:486

...(submitStart ? { start } : {}),
...(submitEnd ? { end } : {}),

Validation reconstructs both dates from the form, but submission now preserves untouched stored bounds. During a repeated hour, the reconstructed start can represent a different instant from the preserved start.

Failure scenario: In New York, an event starts at 2025-11-02T06:30Z, the second 01:30, and ends at 02:30. Change only the end to 01:45. Validation accepts the reconstructed first 01:30–01:45 interval, but saving retains 06:30Z and writes an end of 05:45Z.

Fix: Validate the actual merged range, including preserved bounds, before submitting it.

3. 🔴 External date updates are mistaken for pending resizes

Location: FormContent.tsx:407

occurrence.dataTimezone[bound].timestamp !== liveEvent.dataTimezone[bound].timestamp;

boundPending treats any difference between the editing snapshot and live event as an unpersisted resize. It does not establish that a local resize occurred.

Failure scenario: Open an event ending at 08:15. The host updates its end to 09:00 while the dialog remains open. Rename the event and save. The dialog resubmits 08:15 and overwrites the newer date.

This is an incomplete fix of the new untouched-bound contract; the previous unconditional submission also overwrote the date.

Fix: Track actual pending local date changes and only resend those. Otherwise retain the live event's untouched bounds.

4. 🔴 Deleting a pending split series crashes on scope confirmation

Location: SchedulerStore.ts:705

liveEvent != null
  ? liveEvent.dataTimezone.rrule != null
  : occurrence.dataTimezone.rrule != null

The new snapshot fallback opens the recurring scope dialog when the event is absent from the store. Confirmation still calls processedEventRequired at line 743 and throws.

Failure scenario: Resize with “This and following events,” then delete the selected new series before dataSource.persistEvents resolves. Confirming a deletion scope throws because the new series is not loaded yet.

This race existed before the refactor. The new fallback explicitly handles this state but leaves confirmation broken; its test only checks that the dialog opens.

Fix: Defer subsequent mutations until persistence completes, or stage the created event and serialize pending operations.

Tests (0)

No findings.

Simplifications (0)

No findings.

Docs (0)

No findings.

Verdict

Request changes — ordinary edits can persist invalid date ranges, and pending-series deletion can throw.


🤖 Review generated with Codex

rita-codes and others added 2 commits September 21, 2026 12:19
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@rita-codes

Copy link
Copy Markdown
Member Author

1 and 2 fixed in 1943ddb. A drop that toggles all-day now resends both bounds, since the stored ones belong to the other representation. The submit checks now run on the range the save writes, so an untouched bound is validated on its stored instant.

3 and 4 are not regressions of this PR. The dialog always resent both dates before, so an external update while the dialog is open was overwritten too, as the title or resource still are. Telling a pending local resize from an external update needs the lazy-loading plugin to track in-flight writes, which it does not do today. Scope confirmation already went through processedEventRequired on master, and the old dialog also opened the scope dialog from the snapshot. Serializing pending operations is a separate design change. Happy to open issues for both.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@rita-codes

Copy link
Copy Markdown
Member Author

Rethought 3 and 4, both in 0b8c40f after all.

3: the editing state now records the stored model's bounds when a committed change refreshes the snapshot. The dialog resends a bound only while the model still holds what it did at the resize; a bound the host moved since is kept.

4: an action on an event the store does not hold yet (a split still being persisted, or one that left the loaded range) no longer opens the scope dialog nor throws on confirmation. It surfaces a transient error, the same way a scheduling veto does, and the user retries once the write lands. Serializing pending operations stays out of scope.

@rita-codes

Copy link
Copy Markdown
Member Author

The not-loaded-event message is hardcoded in English like the scheduling veto; making both translatable needs a small mechanism in the store and ErrorContainer, tracked in #23665.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@flaviendelangle flaviendelangle left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

PR review

One merge-blocking validation regression confirmed with a targeted test. Existing targeted suites passed: 575 tests, 9 skipped. Browser tests were not run.

Bugs (1)

1. 🔴 Validate untouched bounds against the live event

Location: FormContent.tsx:416–418

const submittedStart = submitStart ? start : occurrence.displayTimezone.start.value;
const submittedEnd = submitEnd ? end : occurrence.displayTimezone.end.value;

Untouched bounds are now omitted from the update, preserving the live model’s values. Validation still uses the dialog’s occurrence snapshot, so it can approve a different range from the one saved.

Failure scenario: Open a 10:00–11:00 event. While the dialog remains open, the host changes its end to 10:15. Change the start to 10:30 and save. The reproduced result calls onEventsChange with start 10:30 and end 10:15.

Fix: Resolve omitted bounds from the live event for non-recurring updates, and validate the resulting range. Add a regression test combining a host update with a conflicting date edit.

Tests (0)

No findings.

Simplifications (0)

No findings.

Docs (0)

No findings.

Verdict

Request changes — saving can emit an event whose end precedes its start.


🤖 Review generated with Codex

@github-actions github-actions Bot added the PR: out-of-date The pull request has merge conflicts and can't be merged. label Sep 21, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has conflicts, please resolve those before we can evaluate the pull request.

…-data-timezone

# Conflicts:
#	packages/x-scheduler-internals/src/internals/utils/event-utils.test.ts
#	packages/x-scheduler-internals/src/internals/utils/event-utils.ts
@github-actions github-actions Bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged. label Sep 21, 2026
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@rita-codes

Copy link
Copy Markdown
Member Author

Fixed in 08a4293. The submit checks resolve an untouched bound from the live event on a non-recurring update, which is what the save keeps, so a bound the host moved while the dialog is open is validated against. Regression test with a host move plus a conflicting date edit.

@github-actions github-actions Bot added the PR: out-of-date The pull request has merge conflicts and can't be merged. label Sep 21, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has conflicts, please resolve those before we can evaluate the pull request.

…-data-timezone

# Conflicts:
#	packages/x-scheduler/src/internals/components/event-editing/ReadonlyEventDetails.tsx
@github-actions github-actions Bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged. label Sep 21, 2026
@rita-codes
rita-codes merged commit b5068fe into mui:master Sep 21, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope: scheduler Changes related to the scheduler. type: bug It doesn't behave as expected.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants