Add intelligent caching and auto-refresh for external calendars
Implements server-side database caching with 5-minute refresh intervals to dramatically improve external calendar performance while keeping data fresh. Backend changes: - New external_calendar_cache table with ICS data storage - Smart cache logic: serves from cache if < 5min old, fetches fresh otherwise - Cache repository methods for get/update/clear operations - Migration script for cache table creation Frontend changes: - 5-minute auto-refresh interval for background updates - Manual refresh button (🔄) for each external calendar - Last updated timestamps showing when each calendar was refreshed - Centralized refresh function with proper cleanup on logout Performance improvements: - Initial load: instant from cache vs slow external HTTP requests - Background updates: fresh data without user waiting - Reduced external API calls: only when cache is stale - Scalable: handles multiple external calendars efficiently 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
use crate::components::CalendarListItem;
|
||||
use crate::services::calendar_service::{UserInfo, ExternalCalendar};
|
||||
use chrono::{DateTime, Local, TimeZone, Utc};
|
||||
use web_sys::HtmlSelectElement;
|
||||
use yew::prelude::*;
|
||||
use yew_router::prelude::*;
|
||||
@@ -105,6 +106,7 @@ pub struct SidebarProps {
|
||||
pub external_calendars: Vec<ExternalCalendar>,
|
||||
pub on_external_calendar_toggle: Callback<i32>,
|
||||
pub on_external_calendar_delete: Callback<i32>,
|
||||
pub on_external_calendar_refresh: Callback<i32>,
|
||||
pub color_picker_open: Option<String>,
|
||||
pub on_color_change: Callback<(String, String)>,
|
||||
pub on_color_picker_toggle: Callback<String>,
|
||||
@@ -277,7 +279,36 @@ pub fn sidebar(props: &SidebarProps) -> Html {
|
||||
style={format!("background-color: {}", cal.color)}
|
||||
/>
|
||||
<span class="external-calendar-name">{&cal.name}</span>
|
||||
<span class="external-calendar-indicator"></span>
|
||||
<div class="external-calendar-actions">
|
||||
{
|
||||
if let Some(last_fetched) = cal.last_fetched {
|
||||
let local_time = last_fetched.with_timezone(&chrono::Local);
|
||||
html! {
|
||||
<span class="last-updated" title={format!("Last updated: {}", local_time.format("%Y-%m-%d %H:%M"))}>
|
||||
{format!("{}", local_time.format("%H:%M"))}
|
||||
</span>
|
||||
}
|
||||
} else {
|
||||
html! {
|
||||
<span class="last-updated">{"Never"}</span>
|
||||
}
|
||||
}
|
||||
}
|
||||
<button
|
||||
class="external-calendar-refresh-btn"
|
||||
title="Refresh calendar"
|
||||
onclick={{
|
||||
let on_refresh = props.on_external_calendar_refresh.clone();
|
||||
let cal_id = cal.id;
|
||||
Callback::from(move |e: MouseEvent| {
|
||||
e.stop_propagation();
|
||||
on_refresh.emit(cal_id);
|
||||
})
|
||||
}}
|
||||
>
|
||||
{"🔄"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
if *external_context_menu_open == Some(cal.id) {
|
||||
|
||||
Reference in New Issue
Block a user