feat(tabs): run the idle archive policy on a periodic sweep

This commit is contained in:
2026-07-10 12:15:20 -04:00
parent 175702e55a
commit fd7f8c3ef0
4 changed files with 82 additions and 24 deletions
@@ -23,6 +23,11 @@ const NAV_GROUPS: &[NavGroup] = &[
NavGroup {
label: "GENERAL",
items: &[
NavItem {
icon: IconName::Settings2,
label: "General",
route: "ely://settings/general",
},
NavItem {
icon: IconName::Palette,
label: "Appearance",
@@ -24,7 +24,7 @@ const ARCHIVE_POLICY_OPTIONS: &[ArchivePolicyOption] = &[
},
ArchivePolicyOption {
label: "Today",
detail: "Archive idle unpinned tabs during daily cleanup.",
detail: "Archive unpinned tabs left idle since yesterday.",
policy: ArchivePolicy::IdleDays(0),
},
ArchivePolicyOption {
+3 -23
View File
@@ -31,6 +31,7 @@ mod sync_inbox;
mod sync_state;
mod tab_groups;
mod tab_lifecycle;
mod timers;
mod web_surface;
mod web_surface_cadence;
mod web_surface_controller;
@@ -52,7 +53,7 @@ mod gpui_harness_tests;
use ely_browser_core::{BrowserCore, InitialBrowserConfig};
use ely_domain::{DEFAULT_TRANSLUCENCY_PCT, ProfileId, SpaceId, TabId};
use gpui::{AppContext, Context, Entity, FocusHandle, Subscription, Timer, Window};
use gpui::{AppContext, Context, Entity, FocusHandle, Subscription, Window};
use gpui_component::input::{InputEvent, InputState};
use gpui_component::slider::{SliderEvent, SliderState, SliderValue};
@@ -313,7 +314,7 @@ impl ElyShell {
if should_run_initial_sync {
shell.trigger_cloud_sync_upload();
}
start_external_web_surface_timer(cx);
timers::start(cx);
shell
}
@@ -477,24 +478,3 @@ impl ElyShell {
}
}
}
fn start_external_web_surface_timer(cx: &mut Context<ElyShell>) {
cx.spawn(async move |shell, cx| {
loop {
let delay = match shell.update(cx, |shell, _| shell.external_web_surface_tick_delay()) {
Ok(delay) => delay,
Err(_) => break,
};
Timer::after(delay).await;
let result = shell.update(cx, |shell, cx| {
if shell.tick_external_web_surfaces(cx) {
cx.notify();
}
});
if result.is_err() {
break;
}
}
})
.detach();
}
+73
View File
@@ -0,0 +1,73 @@
//! Long-lived shell timers, started once per window at construction.
use std::time::Duration;
use gpui::{Context, Timer};
use super::{ElyShell, ShellState};
/// Idle tabs archive on this cadence when the active Space opts into an
/// idle policy; the sweep is a no-op for `ArchivePolicy::Manual`.
const IDLE_ARCHIVE_SWEEP_INTERVAL: Duration = Duration::from_secs(30 * 60);
pub(super) fn start(cx: &mut Context<ElyShell>) {
start_external_web_surface_timer(cx);
start_idle_archive_timer(cx);
}
fn start_external_web_surface_timer(cx: &mut Context<ElyShell>) {
cx.spawn(async move |shell, cx| {
loop {
let delay = match shell.update(cx, |shell, _| shell.external_web_surface_tick_delay()) {
Ok(delay) => delay,
Err(_) => break,
};
Timer::after(delay).await;
let result = shell.update(cx, |shell, cx| {
if shell.tick_external_web_surfaces(cx) {
cx.notify();
}
});
if result.is_err() {
break;
}
}
})
.detach();
}
fn start_idle_archive_timer(cx: &mut Context<ElyShell>) {
cx.spawn(async move |shell, cx| {
loop {
Timer::after(IDLE_ARCHIVE_SWEEP_INTERVAL).await;
let result = shell.update(cx, |shell, cx| {
let ShellState::Ready(core) = &mut shell.state else {
return;
};
match core.archive_idle_tabs(std::time::SystemTime::now()) {
Ok(0) => {}
Ok(archived) => {
tracing::info!(
target: "ely::archive",
archived,
"idle archive sweep archived tabs",
);
shell.schedule_cloud_sync_upload(cx);
cx.notify();
}
Err(error) => {
tracing::warn!(
target: "ely::archive",
error = %error,
"idle archive sweep failed",
);
}
}
});
if result.is_err() {
break;
}
}
})
.detach();
}