fix(desktop): invalidate filtered catalog on changed hosted head
This commit is contained in:
@@ -396,6 +396,19 @@ impl App {
|
|||||||
let catalog_changed = match &result {
|
let catalog_changed = match &result {
|
||||||
Ok(Outcome::Remote(remote)) => {
|
Ok(Outcome::Remote(remote)) => {
|
||||||
matches!(request.operation, Operation::Publish | Operation::Save)
|
matches!(request.operation, Operation::Publish | Operation::Save)
|
||||||
|
// A changed bound head can enter/leave the active
|
||||||
|
// filter or page even when no row was displayed.
|
||||||
|
|| self.hosted.session.as_ref().is_some_and(|session| {
|
||||||
|
session.connection.base() == request.connection.base()
|
||||||
|
&& session.resource_id == remote.resource_id
|
||||||
|
&& session.etag != remote.etag
|
||||||
|
})
|
||||||
|
|| self.hosted.uncertain.as_ref().is_some_and(|failed| {
|
||||||
|
failed.operation == Operation::Save
|
||||||
|
&& failed.connection.base() == request.connection.base()
|
||||||
|
&& failed.resource_id == Some(remote.resource_id)
|
||||||
|
&& failed.etag.as_ref().is_some_and(|etag| etag != &remote.etag)
|
||||||
|
})
|
||||||
|| self.hosted.catalog.iter().any(|item| {
|
|| self.hosted.catalog.iter().any(|item| {
|
||||||
item.resource_id == remote.resource_id
|
item.resource_id == remote.resource_id
|
||||||
&& item.revision != remote.revision
|
&& item.revision != remote.revision
|
||||||
|
|||||||
@@ -729,3 +729,89 @@ fn hosted_catalog_invalidation_follows_service_writes_and_observed_revision_chan
|
|||||||
"Leaving the hosted destination cannot make old results fresh"
|
"Leaving the hosted destination cannot make old results fresh"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hosted_new_revision_invalidates_filtered_catalog_even_without_a_displayed_row() {
|
||||||
|
let mut app = App::with_project(Project::empty());
|
||||||
|
rename(&mut app, "Original");
|
||||||
|
let resource = bind(&mut app);
|
||||||
|
send(&mut app, Event::Query("Renamed".into()));
|
||||||
|
send(&mut app, Event::Connect);
|
||||||
|
complete(
|
||||||
|
&mut app,
|
||||||
|
Ok(Outcome::Catalog(crate::hosted::client::Catalog {
|
||||||
|
items: vec![],
|
||||||
|
next_after: None,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
assert!(!app.hosted.catalog_stale);
|
||||||
|
assert!(
|
||||||
|
app.hosted
|
||||||
|
.catalog_message()
|
||||||
|
.unwrap()
|
||||||
|
.starts_with("No models found")
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut unchanged = remote(app.document.snapshot(), resource, 1);
|
||||||
|
unchanged.etag = app.hosted.session.as_ref().unwrap().etag.clone();
|
||||||
|
send(&mut app, Event::Check);
|
||||||
|
complete(&mut app, Ok(Outcome::Remote(unchanged)));
|
||||||
|
assert!(
|
||||||
|
!app.hosted.catalog_stale,
|
||||||
|
"An unchanged bound head keeps the filtered snapshot fresh"
|
||||||
|
);
|
||||||
|
|
||||||
|
// A different engineer changes the hosted model so it now matches the filter.
|
||||||
|
let mut changed = Document::from_bundle(app.document.bundle().clone(), LIMITS).unwrap();
|
||||||
|
changed
|
||||||
|
.execute(Command::Rename(changed.project().id, "Renamed".into()))
|
||||||
|
.unwrap();
|
||||||
|
send(&mut app, Event::Check);
|
||||||
|
complete(
|
||||||
|
&mut app,
|
||||||
|
Ok(Outcome::Remote(remote(changed.snapshot(), resource, 2))),
|
||||||
|
);
|
||||||
|
assert_eq!(app.hosted.review.as_ref().unwrap().remote.revision, 2);
|
||||||
|
assert!(
|
||||||
|
app.hosted.request.is_none(),
|
||||||
|
"No polling or automatic catalog request"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
app.hosted.catalog_stale,
|
||||||
|
"Known newer revision can change membership in an empty filtered catalog"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!app.hosted
|
||||||
|
.catalog_message()
|
||||||
|
.unwrap()
|
||||||
|
.starts_with("No models found")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hosted_changed_bound_head_does_not_invalidate_another_services_empty_filter() {
|
||||||
|
let mut app = App::with_project(Project::empty());
|
||||||
|
let resource = bind(&mut app);
|
||||||
|
send(&mut app, Event::Base("http://127.0.0.1:9876".into()));
|
||||||
|
send(&mut app, Event::Query("Renamed".into()));
|
||||||
|
send(&mut app, Event::Connect);
|
||||||
|
complete(
|
||||||
|
&mut app,
|
||||||
|
Ok(Outcome::Catalog(crate::hosted::client::Catalog {
|
||||||
|
items: vec![],
|
||||||
|
next_after: None,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
send(&mut app, Event::Check);
|
||||||
|
let changed = remote(app.document.snapshot(), resource, 2);
|
||||||
|
complete(&mut app, Ok(Outcome::Remote(changed)));
|
||||||
|
assert!(app.hosted.review.is_some());
|
||||||
|
assert!(!app.hosted.catalog_stale);
|
||||||
|
assert!(
|
||||||
|
app.hosted
|
||||||
|
.catalog_message()
|
||||||
|
.unwrap()
|
||||||
|
.starts_with("No models found")
|
||||||
|
);
|
||||||
|
assert!(app.hosted.request.is_none());
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user