Fix singleton to series conversion with complete RRULE parameter support
All checks were successful
Build and Push Docker Image / docker (push) Successful in 2m16s
All checks were successful
Build and Push Docker Image / docker (push) Successful in 2m16s
- Add new context menu callback for singleton events to avoid series pipeline - Implement complete RRULE construction with INTERVAL, COUNT, and UNTIL parameters - Update frontend service methods to pass recurrence parameters correctly - Add missing recurrence fields to backend UpdateEventRequest model - Fix parameter ordering in frontend method calls - Ensure singleton→series conversion uses single event pipeline initially This resolves issues where converting singleton events to recurring series would not respect recurrence interval (every N days), count (N occurrences), or until date parameters. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -723,8 +723,12 @@ pub fn App() -> Html {
|
||||
crate::components::event_form::RecurrenceType::Monthly |
|
||||
crate::components::event_form::RecurrenceType::Yearly);
|
||||
|
||||
web_sys::console::log_1(&format!("🐛 FRONTEND DEBUG: is_recurring={}, edit_scope={:?}, original_uid={:?}",
|
||||
is_recurring, event_data_for_update.edit_scope, event_data_for_update.original_uid).into());
|
||||
|
||||
let update_result = if is_recurring && event_data_for_update.edit_scope.is_some() {
|
||||
// Use series update endpoint for recurring events
|
||||
// Only use series endpoint for existing recurring events being edited
|
||||
// Singleton→series conversion should use regular update_event endpoint
|
||||
let edit_action = event_data_for_update.edit_scope.unwrap();
|
||||
let scope = match edit_action {
|
||||
crate::components::EditAction::EditAll => "all_in_series".to_string(),
|
||||
@@ -754,12 +758,13 @@ pub fn App() -> Html {
|
||||
params.14, // reminder
|
||||
params.15, // recurrence
|
||||
params.16, // recurrence_days
|
||||
params.17, // recurrence_interval
|
||||
params.18, // recurrence_count
|
||||
params.19, // recurrence_until
|
||||
params.17, // calendar_path
|
||||
params.20, // calendar_path
|
||||
scope,
|
||||
event_data_for_update.occurrence_date.map(|d| d.format("%Y-%m-%d").to_string()), // occurrence_date
|
||||
params.20, // timezone
|
||||
params.21, // timezone
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
@@ -786,11 +791,11 @@ pub fn App() -> Html {
|
||||
params.14, // reminder
|
||||
params.15, // recurrence
|
||||
params.16, // recurrence_days
|
||||
params.17, // calendar_path
|
||||
vec![], // exception_dates - empty for simple updates
|
||||
None, // update_action - None for regular updates
|
||||
None, // until_date - None for regular updates
|
||||
params.20, // timezone
|
||||
params.17, // recurrence_interval
|
||||
params.18, // recurrence_count
|
||||
params.19, // recurrence_until
|
||||
params.20, // calendar_path
|
||||
params.21, // timezone
|
||||
)
|
||||
.await
|
||||
};
|
||||
@@ -874,10 +879,11 @@ pub fn App() -> Html {
|
||||
params.14, // reminder
|
||||
params.15, // recurrence
|
||||
params.16, // recurrence_days
|
||||
params.17, // recurrence_interval
|
||||
params.18, // recurrence_count
|
||||
params.19, // recurrence_until
|
||||
params.17, // calendar_path
|
||||
params.20, // timezone
|
||||
params.20, // calendar_path
|
||||
params.21, // timezone
|
||||
)
|
||||
.await;
|
||||
match create_result {
|
||||
@@ -1042,12 +1048,13 @@ pub fn App() -> Html {
|
||||
original_event.categories.join(","),
|
||||
reminder_str.clone(),
|
||||
recurrence_str.clone(),
|
||||
vec![false; 7],
|
||||
None,
|
||||
None,
|
||||
original_event.calendar_path.clone(),
|
||||
scope.clone(),
|
||||
occurrence_date,
|
||||
vec![false; 7], // recurrence_days
|
||||
1, // recurrence_interval - default for drag-and-drop
|
||||
None, // recurrence_count
|
||||
None, // recurrence_until
|
||||
original_event.calendar_path.clone(), // calendar_path
|
||||
scope.clone(), // update_scope
|
||||
occurrence_date, // occurrence_date
|
||||
{
|
||||
// Get timezone offset
|
||||
let date = js_sys::Date::new_0();
|
||||
@@ -1055,7 +1062,7 @@ pub fn App() -> Html {
|
||||
let hours = -(timezone_offset as i32) / 60; // Convert to hours, negate for proper sign
|
||||
let minutes = (timezone_offset as i32).abs() % 60;
|
||||
format!("{:+03}:{:02}", hours, minutes) // Format as +05:00 or -04:00
|
||||
},
|
||||
}, // timezone
|
||||
)
|
||||
.await,
|
||||
)
|
||||
@@ -1099,14 +1106,10 @@ pub fn App() -> Html {
|
||||
reminder_str,
|
||||
recurrence_str,
|
||||
recurrence_days,
|
||||
1, // recurrence_interval - default to 1 for drag-and-drop
|
||||
None, // recurrence_count - preserve existing
|
||||
None, // recurrence_until - preserve existing
|
||||
original_event.calendar_path,
|
||||
original_event.exdate.clone(),
|
||||
if preserve_rrule {
|
||||
Some("update_series".to_string())
|
||||
} else {
|
||||
Some("this_and_future".to_string())
|
||||
},
|
||||
until_date,
|
||||
{
|
||||
// Get timezone offset
|
||||
let date = js_sys::Date::new_0();
|
||||
@@ -1639,6 +1642,19 @@ pub fn App() -> Html {
|
||||
}
|
||||
}
|
||||
})}
|
||||
on_edit_singleton={Callback::from({
|
||||
let event_context_menu_event = event_context_menu_event.clone();
|
||||
let event_context_menu_open = event_context_menu_open.clone();
|
||||
let create_event_modal_open = create_event_modal_open.clone();
|
||||
let event_edit_scope = event_edit_scope.clone();
|
||||
move |event: VEvent| {
|
||||
// For singleton events, open edit modal WITHOUT setting edit_scope
|
||||
event_context_menu_event.set(Some(event));
|
||||
event_edit_scope.set(None); // Explicitly set to None for singleton edits
|
||||
event_context_menu_open.set(false);
|
||||
create_event_modal_open.set(true);
|
||||
}
|
||||
})}
|
||||
on_view_details={Callback::from({
|
||||
let event_context_menu_open = event_context_menu_open.clone();
|
||||
let view_event_modal_open = view_event_modal_open.clone();
|
||||
|
||||
Reference in New Issue
Block a user