From 7f4d21f8427b9c183829e5a11fe382093f2fb54d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20G=C3=B6rtler?= Date: Mon, 2 Dec 2024 17:09:07 +0100 Subject: [PATCH 1/8] Create an example of a larger time-varying graph --- .../check_graph_time_layout.py | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 tests/python/release_checklist/check_graph_time_layout.py diff --git a/tests/python/release_checklist/check_graph_time_layout.py b/tests/python/release_checklist/check_graph_time_layout.py new file mode 100644 index 000000000000..75bb443417df --- /dev/null +++ b/tests/python/release_checklist/check_graph_time_layout.py @@ -0,0 +1,59 @@ +from __future__ import annotations + +import os +import random +from argparse import Namespace + +from uuid import uuid4 +import rerun as rr +import rerun.blueprint as rrb + +README = """\ +# Graph view + +Please check the following: +* Run the graph view in an endless loop and see if how it looks (TM). +""" + + +def log_readme() -> None: + rr.log("readme", rr.TextDocument(README, media_type=rr.MediaType.MARKDOWN), static=True) + + +def log_graphs() -> None: + nodes = ["root"] + edges = [] + + for i in range(50): + existing = random.choice(nodes) + new_node = str(i) + nodes.append(new_node) + edges.append((existing, new_node)) + + rr.set_time_sequence("frame", i) + rr.log("graph", rr.GraphNodes(nodes, labels=nodes), rr.GraphEdges(edges, graph_type=rr.GraphType.Directed)) + + rr.send_blueprint( + rrb.Blueprint( + rrb.Grid( + rrb.GraphView(origin="graph", name="Graph"), + rrb.TextDocumentView(origin="readme", name="Instructions"), + ) + ) + ) + + +def run(args: Namespace) -> None: + rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4()) + + log_readme() + log_graphs() + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser(description="Interactive release checklist") + rr.script_add_args(parser) + args = parser.parse_args() + run(args) From 72103ae7ab0c13fae4673488ce61549abfee06f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20G=C3=B6rtler?= Date: Wed, 4 Dec 2024 10:21:16 +0100 Subject: [PATCH 2/8] Implement incremental layouts (closes #8282) --- .../src/layout/provider.rs | 23 +++++++++++++++---- .../re_space_view_graph/src/ui/state.rs | 18 +++++++++++---- .../check_graph_time_layout.py | 6 +++-- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/crates/viewer/re_space_view_graph/src/layout/provider.rs b/crates/viewer/re_space_view_graph/src/layout/provider.rs index e6482ea1be1d..1036a2b20797 100644 --- a/crates/viewer/re_space_view_graph/src/layout/provider.rs +++ b/crates/viewer/re_space_view_graph/src/layout/provider.rs @@ -33,11 +33,26 @@ pub struct ForceLayoutProvider { impl ForceLayoutProvider { pub fn new(request: LayoutRequest) -> Self { + Self::new_impl(request, None) + } + + pub fn new_with_previous(request: LayoutRequest, layout: &Layout) -> Self { + Self::new_impl(request, Some(layout)) + } + + // TODO(grtlr): Consider consuming the old layout to avoid re-allocating the extents. + // That logic has to be revised when adding the blueprints anyways. + fn new_impl(request: LayoutRequest, layout: Option<&Layout>) -> Self { let nodes = request.graphs.iter().flat_map(|(_, graph_template)| { - graph_template - .nodes - .iter() - .map(|n| (n.0, fj::Node::from(n.1))) + graph_template.nodes.iter().map(|n| { + let mut fj_node = fj::Node::from(n.1); + if let Some(rect) = layout.and_then(|l| l.get_node(n.0)) { + let pos = rect.center(); + fj_node = fj_node.position(pos.x as f64, pos.y as f64); + } + + (n.0, fj_node) + }) }); let mut node_index = ahash::HashMap::default(); diff --git a/crates/viewer/re_space_view_graph/src/ui/state.rs b/crates/viewer/re_space_view_graph/src/ui/state.rs index dad235b3586a..749e3720f937 100644 --- a/crates/viewer/re_space_view_graph/src/ui/state.rs +++ b/crates/viewer/re_space_view_graph/src/ui/state.rs @@ -104,15 +104,25 @@ impl LayoutState { self // no op } // We need to recompute the layout. - Self::None | Self::Finished { .. } => { + Self::None => { let provider = ForceLayoutProvider::new(new_request); let layout = provider.init(); Self::InProgress { layout, provider } } - Self::InProgress { provider, .. } if provider.request != new_request => { - let provider = ForceLayoutProvider::new(new_request); - let layout = provider.init(); + Self::Finished { layout, .. } => { + let mut provider = ForceLayoutProvider::new_with_previous(new_request, &layout); + let mut layout = provider.init(); + provider.tick(&mut layout); + + Self::InProgress { layout, provider } + } + Self::InProgress { + layout, provider, .. + } if provider.request != new_request => { + let mut provider = ForceLayoutProvider::new_with_previous(new_request, &layout); + let mut layout = provider.init(); + provider.tick(&mut layout); Self::InProgress { layout, provider } } diff --git a/tests/python/release_checklist/check_graph_time_layout.py b/tests/python/release_checklist/check_graph_time_layout.py index 75bb443417df..9bb71436b4aa 100644 --- a/tests/python/release_checklist/check_graph_time_layout.py +++ b/tests/python/release_checklist/check_graph_time_layout.py @@ -3,8 +3,8 @@ import os import random from argparse import Namespace - from uuid import uuid4 + import rerun as rr import rerun.blueprint as rrb @@ -12,7 +12,8 @@ # Graph view Please check the following: -* Run the graph view in an endless loop and see if how it looks (TM). +* Run the graph view in an endless loop and see if how it looks good (TM). +* Try scrubbing the timeline to see how the graph layout changes over time. """ @@ -24,6 +25,7 @@ def log_graphs() -> None: nodes = ["root"] edges = [] + # Randomly add nodes and edges to the graph for i in range(50): existing = random.choice(nodes) new_node = str(i) From 6ee3b4e5c2969bc699b57293fda0db3bc8e2be94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20G=C3=B6rtler?= Date: Wed, 4 Dec 2024 17:31:21 +0100 Subject: [PATCH 3/8] Update tests/python/release_checklist/check_graph_time_layout.py Co-authored-by: Antoine Beyeler <49431240+abey79@users.noreply.github.com> --- tests/python/release_checklist/check_graph_time_layout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/python/release_checklist/check_graph_time_layout.py b/tests/python/release_checklist/check_graph_time_layout.py index 9bb71436b4aa..eb763fa7b495 100644 --- a/tests/python/release_checklist/check_graph_time_layout.py +++ b/tests/python/release_checklist/check_graph_time_layout.py @@ -12,7 +12,7 @@ # Graph view Please check the following: -* Run the graph view in an endless loop and see if how it looks good (TM). +* Run the graph view in an endless loop and see if it looks good (TM). * Try scrubbing the timeline to see how the graph layout changes over time. """ From ac26588559539a67e17c591471585d3a74ce5cdc Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Wed, 4 Dec 2024 08:57:04 +0100 Subject: [PATCH 4/8] improve view property ui methods (#8305) ### Related * split out of #8234 ### What * use `ViewProperty` util construct some more * route individual property ui via `view_property_component_ui_custom` making it easier to draw custom ui for specific view properties while still having all tooltip & extra menus be the same --- crates/viewer/re_space_view/src/lib.rs | 4 +- .../re_space_view/src/view_property_ui.rs | 220 ++++++++---------- .../src/view_properties.rs | 15 +- 3 files changed, 114 insertions(+), 125 deletions(-) diff --git a/crates/viewer/re_space_view/src/lib.rs b/crates/viewer/re_space_view/src/lib.rs index e6620167efc8..c7e20d3ba711 100644 --- a/crates/viewer/re_space_view/src/lib.rs +++ b/crates/viewer/re_space_view/src/lib.rs @@ -30,7 +30,9 @@ pub use query::{ pub use results_ext::{ HybridLatestAtResults, HybridResults, HybridResultsChunkIter, RangeResultsExt, }; -pub use view_property_ui::view_property_ui; +pub use view_property_ui::{ + view_property_component_ui, view_property_component_ui_custom, view_property_ui, +}; pub mod external { pub use re_entity_db::external::*; diff --git a/crates/viewer/re_space_view/src/view_property_ui.rs b/crates/viewer/re_space_view/src/view_property_ui.rs index 5136494bc590..f9e174f7487d 100644 --- a/crates/viewer/re_space_view/src/view_property_ui.rs +++ b/crates/viewer/re_space_view/src/view_property_ui.rs @@ -1,14 +1,12 @@ -use re_chunk_store::{external::re_chunk::Arrow2Array, RowId}; use re_types_core::{ - reflection::{ArchetypeFieldReflection, ArchetypeReflection}, - Archetype, ArchetypeName, ArchetypeReflectionMarker, ComponentName, + reflection::ArchetypeFieldReflection, Archetype, ArchetypeReflectionMarker, ComponentName, }; use re_ui::{list_item, UiExt as _}; use re_viewer_context::{ ComponentFallbackProvider, ComponentUiTypes, QueryContext, SpaceViewId, SpaceViewState, ViewerContext, }; -use re_viewport_blueprint::entity_path_for_view_property; +use re_viewport_blueprint::ViewProperty; /// Display the UI for editing all components of a blueprint archetype. /// @@ -20,79 +18,49 @@ pub fn view_property_ui( fallback_provider: &dyn ComponentFallbackProvider, view_state: &dyn SpaceViewState, ) { - let name = A::name(); - if let Some(reflection) = ctx.reflection.archetypes.get(&name) { - view_property_ui_impl( - ctx, - ui, - view_id, - name, - reflection, - view_state, - fallback_provider, - ); - } else { - // The `ArchetypeReflectionMarker` bound should make this impossible. - re_log::warn_once!("Missing reflection data for archetype {name:?}."); - } + let view_property = + ViewProperty::from_archetype::(ctx.blueprint_db(), ctx.blueprint_query, view_id); + view_property_ui_impl(ctx, ui, &view_property, fallback_provider, view_state); } fn view_property_ui_impl( ctx: &ViewerContext<'_>, ui: &mut egui::Ui, - view_id: SpaceViewId, - name: ArchetypeName, - reflection: &ArchetypeReflection, - view_state: &dyn SpaceViewState, + property: &ViewProperty, fallback_provider: &dyn ComponentFallbackProvider, + view_state: &dyn SpaceViewState, ) { - let blueprint_path = entity_path_for_view_property(view_id, ctx.blueprint_db().tree(), name); - let query_ctx = QueryContext { - viewer_ctx: ctx, - target_entity_path: &blueprint_path, - archetype_name: Some(name), - query: ctx.blueprint_query, - view_state, - view_ctx: None, + let Some(reflection) = ctx.reflection.archetypes.get(&property.archetype_name) else { + // The `ArchetypeReflectionMarker` bound should make this impossible. + re_log::warn_once!( + "Missing reflection data for archetype {:?}.", + property.archetype_name + ); + return; }; - let component_results = ctx.blueprint_db().latest_at( - ctx.blueprint_query, - &blueprint_path, - reflection.fields.iter().map(|field| field.component_name), - ); - + let query_ctx = property.query_context(ctx, view_state); // If the property archetype only has a single component, don't show an additional hierarchy level! if reflection.fields.len() == 1 { let field = &reflection.fields[0]; - let component_array = component_results.component_batch_raw(&field.component_name); view_property_component_ui( &query_ctx, ui, - field.component_name, + property, reflection.display_name, field, - &blueprint_path, - component_results.component_row_id(&field.component_name), - component_array.as_deref(), fallback_provider, ); } else { let sub_prop_ui = |ui: &mut egui::Ui| { for field in &reflection.fields { - let display_name = &field.display_name; - - let component_array = component_results.component_batch_raw(&field.component_name); view_property_component_ui( &query_ctx, ui, - field.component_name, - display_name, + property, + field.display_name, field, - &blueprint_path, - component_results.component_row_id(&field.component_name), - component_array.as_deref(), fallback_provider, ); } @@ -102,7 +70,7 @@ fn view_property_ui_impl( .interactive(false) .show_hierarchical_with_children( ui, - ui.make_persistent_id(name.full_name()), + ui.make_persistent_id(property.archetype_name.full_name()), true, list_item::LabelContent::new(reflection.display_name), sub_prop_ui, @@ -111,36 +79,91 @@ fn view_property_ui_impl( } /// Draw view property ui for a single component of a view property archetype. -#[allow(clippy::too_many_arguments)] -fn view_property_component_ui( +/// +/// Use [`view_property_ui`] whenever possible to show the ui for all components of a view property archetype. +/// This function is only useful if you want to show custom ui for some of the components. +pub fn view_property_component_ui( ctx: &QueryContext<'_>, ui: &mut egui::Ui, - component_name: ComponentName, - root_item_display_name: &str, + property: &ViewProperty, + display_name: &str, field: &ArchetypeFieldReflection, - blueprint_path: &re_log_types::EntityPath, - row_id: Option, - component_array: Option<&dyn Arrow2Array>, fallback_provider: &dyn ComponentFallbackProvider, ) { - let singleline_list_item_content = singleline_list_item_content( - ctx, - root_item_display_name, - blueprint_path, - component_name, - row_id, - component_array, - fallback_provider, - ); + let component_array = property.component_raw(field.component_name); + let row_id = property.component_row_id(field.component_name); let ui_types = ctx .viewer_ctx .component_ui_registry - .registered_ui_types(component_name); + .registered_ui_types(field.component_name); + + let singleline_ui: &dyn Fn(&mut egui::Ui) = &|ui| { + ctx.viewer_ctx.component_ui_registry.singleline_edit_ui( + ctx, + ui, + ctx.viewer_ctx.blueprint_db(), + ctx.target_entity_path, + field.component_name, + row_id, + component_array.as_deref(), + fallback_provider, + ); + }; + + let multiline_ui: &dyn Fn(&mut egui::Ui) = &|ui| { + ctx.viewer_ctx.component_ui_registry.multiline_edit_ui( + ctx, + ui, + ctx.viewer_ctx.blueprint_db(), + ctx.target_entity_path, + field.component_name, + row_id, + component_array.as_deref(), + fallback_provider, + ); + }; + // Do this as a separate step to avoid borrowing issues. + let multiline_ui_ref: Option<&dyn Fn(&mut egui::Ui)> = + if ui_types.contains(ComponentUiTypes::MultiLineEditor) { + Some(multiline_ui) + } else { + None + }; - let list_item_response = if ui_types.contains(ComponentUiTypes::MultiLineEditor) { + view_property_component_ui_custom( + ctx, + ui, + property, + display_name, + field, + singleline_ui, + multiline_ui_ref, + ); +} + +/// Draw view property ui for a single component of a view property archetype with custom ui for singleline & multiline. +/// +/// Use [`view_property_ui`] whenever possible to show the ui for all components of a view property archetype. +/// This function is only useful if you want to show custom ui for some of the components. +pub fn view_property_component_ui_custom( + ctx: &QueryContext<'_>, + ui: &mut egui::Ui, + property: &ViewProperty, + display_name: &str, + field: &ArchetypeFieldReflection, + singleline_ui: &dyn Fn(&mut egui::Ui), + multiline_ui: Option<&dyn Fn(&mut egui::Ui)>, +) { + let singleline_list_item_content = list_item::PropertyContent::new(display_name) + .menu_button(&re_ui::icons::MORE, |ui| { + menu_more(ctx.viewer_ctx, ui, property, field.component_name); + }) + .value_fn(move |ui, _| singleline_ui(ui)); + + let list_item_response = if let Some(multiline_ui) = multiline_ui { let default_open = false; - let id = egui::Id::new((blueprint_path.hash(), component_name)); + let id = egui::Id::new((ctx.target_entity_path.hash(), field.component_name)); ui.list_item() .interactive(false) .show_hierarchical_with_children( @@ -149,16 +172,7 @@ fn view_property_component_ui( default_open, singleline_list_item_content, |ui| { - ctx.viewer_ctx.component_ui_registry.multiline_edit_ui( - ctx, - ui, - ctx.viewer_ctx.blueprint_db(), - blueprint_path, - component_name, - row_id, - component_array, - fallback_provider, - ); + multiline_ui(ui); }, ) .item_response @@ -177,14 +191,13 @@ fn view_property_component_ui( fn menu_more( ctx: &ViewerContext<'_>, ui: &mut egui::Ui, - blueprint_path: &re_log_types::EntityPath, + property: &ViewProperty, component_name: ComponentName, - component_array: Option<&dyn Arrow2Array>, ) { + let component_array = property.component_raw(component_name); + let property_differs_from_default = component_array - != ctx - .raw_latest_at_in_default_blueprint(blueprint_path, component_name) - .as_deref(); + != ctx.raw_latest_at_in_default_blueprint(&property.blueprint_store_path, component_name); let response = ui .add_enabled( @@ -199,7 +212,7 @@ If no default blueprint was set or it didn't set any value for this field, this "The property is already set to the same value it has in the default blueprint", ); if response.clicked() { - ctx.reset_blueprint_component_by_name(blueprint_path, component_name); + ctx.reset_blueprint_component_by_name(&property.blueprint_store_path, component_name); ui.close_menu(); } @@ -214,43 +227,10 @@ This has the same effect as not setting the value in the blueprint at all." ) .on_disabled_hover_text("The property is already unset."); if response.clicked() { - ctx.clear_blueprint_component_by_name(blueprint_path, component_name); + ctx.clear_blueprint_component_by_name(&property.blueprint_store_path, component_name); ui.close_menu(); } // TODO(andreas): The next logical thing here is now to save it to the default blueprint! // This should be fairly straight forward except that we need to make sure that a default blueprint exists in the first place. } - -fn singleline_list_item_content<'a>( - ctx: &'a QueryContext<'_>, - display_name: &str, - blueprint_path: &'a re_log_types::EntityPath, - component_name: ComponentName, - row_id: Option, - component_array: Option<&'a dyn Arrow2Array>, - fallback_provider: &'a dyn ComponentFallbackProvider, -) -> list_item::PropertyContent<'a> { - list_item::PropertyContent::new(display_name) - .menu_button(&re_ui::icons::MORE, move |ui| { - menu_more( - ctx.viewer_ctx, - ui, - blueprint_path, - component_name, - component_array, - ); - }) - .value_fn(move |ui, _| { - ctx.viewer_ctx.component_ui_registry.singleline_edit_ui( - ctx, - ui, - ctx.viewer_ctx.blueprint_db(), - blueprint_path, - component_name, - row_id, - component_array, - fallback_provider, - ); - }) -} diff --git a/crates/viewer/re_viewport_blueprint/src/view_properties.rs b/crates/viewer/re_viewport_blueprint/src/view_properties.rs index 2216e84555a1..1accc8427470 100644 --- a/crates/viewer/re_viewport_blueprint/src/view_properties.rs +++ b/crates/viewer/re_viewport_blueprint/src/view_properties.rs @@ -33,10 +33,17 @@ pub struct ViewProperty { /// stored. pub blueprint_store_path: EntityPath, - archetype_name: ArchetypeName, - component_names: Vec, - query_results: LatestAtResults, - blueprint_query: LatestAtQuery, + /// Name of the property archetype. + pub archetype_name: ArchetypeName, + + /// List of all components in this property. + pub component_names: Vec, + + /// Query results for all queries of this property. + pub query_results: LatestAtResults, + + /// Blueprint query used for querying. + pub blueprint_query: LatestAtQuery, } impl ViewProperty { From 35af461370b844c02539c5d8650bdaac9d67a426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= Date: Wed, 4 Dec 2024 11:58:12 +0100 Subject: [PATCH 5/8] Update changelog for 0.20.3 (#8310) --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2771bf0f4a32..a94fc73a0c0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ ## [Unreleased](https://github.com/rerun-io/rerun/compare/latest...HEAD) +## [0.20.3](https://github.com/rerun-io/rerun/compare/0.20.2...0.20.3) - Web viewer fix + +### 🔎 Details + +#### 🪳 Bug fixes +- Fix web viewer feature flags [#8295](https://github.com/rerun-io/rerun/pull/8295) + ## [0.20.2](https://github.com/rerun-io/rerun/compare/0.20.1...0.20.2) - Build fix ### 🔎 Details From bbc845c315bba3e9da290ba9c109d22e080b2293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20G=C3=B6rtler?= Date: Wed, 4 Dec 2024 14:54:06 +0100 Subject: [PATCH 6/8] Bump `hashbrown@0.15.0` to `0.15.1` to fix vuln (#8315) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What Fixes CI problems (https://github.com/rerun-io/rerun/actions/runs/12160549310/job/33913118372?pr=8313): ``` error[vulnerability]: Borsh serialization of HashMap is non-canonical ┌─ /home/runner/work/rerun/rerun/Cargo.lock:225:1 │ 225 │ hashbrown 0.15.0 registry+https://github.com/rust-lang/crates.io-index │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected │ ├ ID: RUSTSEC-2024-0402 ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2024-0402 ├ The borsh serialization of the HashMap did not follow the borsh specification. It potentially produced non-canonical encodings dependent on insertion order. It also did not perform canonicty checks on decoding. This can result in consensus splits and cause equivalent objects to be considered distinct. This was patched in 0.15.1. ``` --- Cargo.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a5d7e947a821..7d4e35d51472 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -59,7 +59,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f47983a1084940ba9a39c077a8c63e55c619388be5476ac04c804cfbd1e63459" dependencies = [ "accesskit", - "hashbrown 0.15.0", + "hashbrown 0.15.1", "immutable-chunkmap", ] @@ -71,7 +71,7 @@ checksum = "7329821f3bd1101e03a7d2e03bd339e3ac0dc64c70b4c9f9ae1949e3ba8dece1" dependencies = [ "accesskit", "accesskit_consumer 0.26.0", - "hashbrown 0.15.0", + "hashbrown 0.15.1", "objc2", "objc2-app-kit", "objc2-foundation", @@ -103,7 +103,7 @@ checksum = "24fcd5d23d70670992b823e735e859374d694a3d12bfd8dd32bd3bd8bedb5d81" dependencies = [ "accesskit", "accesskit_consumer 0.26.0", - "hashbrown 0.15.0", + "hashbrown 0.15.1", "paste", "static_assertions", "windows 0.58.0", @@ -2998,9 +2998,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" dependencies = [ "allocator-api2", "equivalent", @@ -3409,7 +3409,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.15.0", + "hashbrown 0.15.1", "serde", ] @@ -3826,7 +3826,7 @@ version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.15.0", + "hashbrown 0.15.1", ] [[package]] From 6dc510eb1732d69f1bbc91c3eaea5653ba31d042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20G=C3=B6rtler?= Date: Wed, 4 Dec 2024 17:16:51 +0100 Subject: [PATCH 7/8] Visually differentiate implicit nodes in graph view (#8313) ### What After refactoring, _implicit_ nodes were visualized using regular `text_color` and where therefore no possible to differentiate from regular nodes. This PR fixes that. image The node on the bottom (darker gray) is implicit. --- crates/viewer/re_space_view_graph/src/graph/mod.rs | 4 ++-- crates/viewer/re_space_view_graph/src/ui/draw.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/viewer/re_space_view_graph/src/graph/mod.rs b/crates/viewer/re_space_view_graph/src/graph/mod.rs index 8e6b29b7d47f..4ddb4c969087 100644 --- a/crates/viewer/re_space_view_graph/src/graph/mod.rs +++ b/crates/viewer/re_space_view_graph/src/graph/mod.rs @@ -114,7 +114,7 @@ impl Graph { nodes.push(Node::Implicit { id: edge.source_index, graph_node: edge.source.clone(), - label: DrawableLabel::implicit_circle(), + label: DrawableLabel::implicit_circle(ui), }); seen.insert(edge.source_index); } @@ -122,7 +122,7 @@ impl Graph { nodes.push(Node::Implicit { id: edge.target_index, graph_node: edge.target.clone(), - label: DrawableLabel::implicit_circle(), + label: DrawableLabel::implicit_circle(ui), }); seen.insert(edge.target_index); } diff --git a/crates/viewer/re_space_view_graph/src/ui/draw.rs b/crates/viewer/re_space_view_graph/src/ui/draw.rs index e8db060fda71..39440e4bc069 100644 --- a/crates/viewer/re_space_view_graph/src/ui/draw.rs +++ b/crates/viewer/re_space_view_graph/src/ui/draw.rs @@ -56,10 +56,10 @@ impl DrawableLabel { Self::Circle(CircleLabel { radius, color }) } - pub fn implicit_circle() -> Self { + pub fn implicit_circle(ui: &Ui) -> Self { Self::Circle(CircleLabel { radius: 4.0, - color: None, + color: Some(ui.style().visuals.weak_text_color()), }) } From d4ba371a2ce66bc39be7185a830042bd3c3b002f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20G=C3=B6rtler?= Date: Wed, 4 Dec 2024 17:40:27 +0100 Subject: [PATCH 8/8] Improve check instructions --- tests/python/release_checklist/check_graph_time_layout.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/python/release_checklist/check_graph_time_layout.py b/tests/python/release_checklist/check_graph_time_layout.py index eb763fa7b495..3d469e1b72c5 100644 --- a/tests/python/release_checklist/check_graph_time_layout.py +++ b/tests/python/release_checklist/check_graph_time_layout.py @@ -9,11 +9,13 @@ import rerun.blueprint as rrb README = """\ -# Graph view +# Time-varying graph view + +Please watch out for any twitching, jumping, or other wise unexpected changes to +the layout when navigating the timeline. Please check the following: -* Run the graph view in an endless loop and see if it looks good (TM). -* Try scrubbing the timeline to see how the graph layout changes over time. +* Scrub the timeline to see how the graph layout changes over time. """