From c110aafd2fdf354c0eacea7102560710788f8478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Gyebn=C3=A1r?= Date: Mon, 1 Dec 2025 13:52:52 +0100 Subject: [PATCH 01/10] Identifies logged-in users on Posthog --- Cargo.lock | 1 + crates/utils/re_analytics/src/event.rs | 24 +++++++++++++++++++ crates/utils/re_analytics/src/lib.rs | 5 ++++ .../utils/re_analytics/src/native/pipeline.rs | 8 +++---- crates/utils/re_analytics/src/posthog.rs | 16 +++++++++++++ crates/utils/re_auth/Cargo.toml | 1 + crates/utils/re_auth/src/oauth.rs | 8 +++++++ 7 files changed, 59 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 41fd394a6890..615bb510da8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8447,6 +8447,7 @@ dependencies = [ "js-sys", "jsonwebtoken", "rand 0.9.2", + "re_analytics", "re_log", "saturating_cast", "serde", diff --git a/crates/utils/re_analytics/src/event.rs b/crates/utils/re_analytics/src/event.rs index 2afe36f85891..9974b5d6439d 100644 --- a/crates/utils/re_analytics/src/event.rs +++ b/crates/utils/re_analytics/src/event.rs @@ -435,6 +435,30 @@ impl Properties for SettingsOpened { // ----------------------------------------------- +/// Links the current anonymous analytics ID to an authenticated user ID. +/// +/// This is sent when a user logs in, allowing us to connect their +/// pre-login anonymous activity with their authenticated identity. +pub struct SetPersonProperty { + /// The authenticated user ID to link to the current analytics ID. + pub email: String, +} + +impl Event for SetPersonProperty { + const NAME: &'static str = "$set"; + + const KIND: EventKind = EventKind::SetPersonProperty; +} + +impl Properties for SetPersonProperty { + fn serialize(self, event: &mut AnalyticsEvent) { + let Self { email } = self; + event.insert("email", email); + } +} + +// ----------------------------------------------- + #[cfg(test)] mod tests { use super::*; diff --git a/crates/utils/re_analytics/src/lib.rs b/crates/utils/re_analytics/src/lib.rs index 91ddbe62f16a..aba39f5f5239 100644 --- a/crates/utils/re_analytics/src/lib.rs +++ b/crates/utils/re_analytics/src/lib.rs @@ -61,6 +61,11 @@ pub enum EventKind { /// /// Used e.g. to associate an OS with a particular analytics ID upon its creation. Update, + + /// Set a property on the current analytics ID. + /// + /// Used e.g. to set the authenticated user's email address on the analytics ID. + SetPersonProperty, } // ---------------------------------------------------------------------------- diff --git a/crates/utils/re_analytics/src/native/pipeline.rs b/crates/utils/re_analytics/src/native/pipeline.rs index 62b09d53462f..a3b0126197cb 100644 --- a/crates/utils/re_analytics/src/native/pipeline.rs +++ b/crates/utils/re_analytics/src/native/pipeline.rs @@ -44,10 +44,10 @@ impl Pipeline { re_log::debug_once!("Analytics disabled in tests"); return Ok(None); } - if cfg!(debug_assertions) { - re_log::debug_once!("Analytics disabled in debug builds"); - return Ok(None); - } + // if cfg!(debug_assertions) { + // re_log::debug_once!("Analytics disabled in debug builds"); + // return Ok(None); + // } let sink = PostHogSink::default(); diff --git a/crates/utils/re_analytics/src/posthog.rs b/crates/utils/re_analytics/src/posthog.rs index 9b1beef0bcb8..60600bf97f01 100644 --- a/crates/utils/re_analytics/src/posthog.rs +++ b/crates/utils/re_analytics/src/posthog.rs @@ -13,6 +13,7 @@ pub const PUBLIC_POSTHOG_PROJECT_KEY: &str = "phc_sgKidIE4WYYFSJHd8LEYY1UZqASpnf pub enum PostHogEvent<'a> { Capture(PostHogCaptureEvent<'a>), Identify(PostHogIdentifyEvent<'a>), + Alias(PostHogSetPersonPropertiesEvent<'a>), } impl<'a> PostHogEvent<'a> { @@ -49,6 +50,12 @@ impl<'a> PostHogEvent<'a> { properties: [("session_id", session_id.into())].into(), set: properties.collect(), }), + crate::EventKind::SetPersonProperty => Self::Alias(PostHogSetPersonPropertiesEvent { + timestamp: event.time_utc, + event: "$set", + distinct_id: analytics_id, + properties: [("$set", properties.collect())].into(), + }), } } } @@ -73,6 +80,15 @@ pub struct PostHogIdentifyEvent<'a> { set: HashMap<&'a str, serde_json::Value>, } +// See https://posthog.com/docs/api/post-only-endpoints#alias. +#[derive(Debug, serde::Serialize)] +pub struct PostHogSetPersonPropertiesEvent<'a> { + timestamp: Timestamp, + event: &'a str, + distinct_id: &'a str, + properties: HashMap<&'a str, serde_json::Value>, +} + // See https://posthog.com/docs/api/post-only-endpoints#batch-events. #[derive(Debug, serde::Serialize)] pub struct PostHogBatch<'a> { diff --git a/crates/utils/re_auth/Cargo.toml b/crates/utils/re_auth/Cargo.toml index e43ecfcea45b..bdc81f0c659c 100644 --- a/crates/utils/re_auth/Cargo.toml +++ b/crates/utils/re_auth/Cargo.toml @@ -37,6 +37,7 @@ oauth = [ ] [dependencies] +re_analytics.workspace = true re_log.workspace = true async-trait.workspace = true diff --git a/crates/utils/re_auth/src/oauth.rs b/crates/utils/re_auth/src/oauth.rs index 51363b46643d..d91dd72471ab 100644 --- a/crates/utils/re_auth/src/oauth.rs +++ b/crates/utils/re_auth/src/oauth.rs @@ -195,6 +195,14 @@ impl InMemoryCredentials { /// Ensure credentials are persisted to disk before using them. pub fn ensure_stored(self) -> Result { storage::store(&self.0)?; + + // Send an alias event to link the analytics ID to the authenticated user + if let Some(analytics) = re_analytics::Analytics::global_get() { + analytics.record(re_analytics::event::SetPersonProperty { + email: self.0.user.email.clone(), + }); + } + Ok(self.0) } } From e6d454d82169cd43ae71871b5f420c5e1e08fe2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Gyebn=C3=A1r?= Date: Mon, 1 Dec 2025 14:50:44 +0100 Subject: [PATCH 02/10] Update --- crates/utils/re_analytics/src/event.rs | 5 ++--- crates/utils/re_analytics/src/lib.rs | 7 ++++--- crates/utils/re_analytics/src/native/pipeline.rs | 8 ++++---- crates/utils/re_analytics/src/posthog.rs | 4 ++-- crates/utils/re_auth/src/oauth.rs | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/crates/utils/re_analytics/src/event.rs b/crates/utils/re_analytics/src/event.rs index 9974b5d6439d..1db0f1ce5ef7 100644 --- a/crates/utils/re_analytics/src/event.rs +++ b/crates/utils/re_analytics/src/event.rs @@ -435,19 +435,18 @@ impl Properties for SettingsOpened { // ----------------------------------------------- -/// Links the current anonymous analytics ID to an authenticated user ID. +/// Links the current anonymous analytics ID to an authenticated user. /// /// This is sent when a user logs in, allowing us to connect their /// pre-login anonymous activity with their authenticated identity. pub struct SetPersonProperty { - /// The authenticated user ID to link to the current analytics ID. pub email: String, } impl Event for SetPersonProperty { const NAME: &'static str = "$set"; - const KIND: EventKind = EventKind::SetPersonProperty; + const KIND: EventKind = EventKind::SetPersonProperties; } impl Properties for SetPersonProperty { diff --git a/crates/utils/re_analytics/src/lib.rs b/crates/utils/re_analytics/src/lib.rs index aba39f5f5239..7e99f686eb89 100644 --- a/crates/utils/re_analytics/src/lib.rs +++ b/crates/utils/re_analytics/src/lib.rs @@ -62,10 +62,11 @@ pub enum EventKind { /// Used e.g. to associate an OS with a particular analytics ID upon its creation. Update, - /// Set a property on the current analytics ID. + /// Set properties of an authenticated user. /// - /// Used e.g. to set the authenticated user's email address on the analytics ID. - SetPersonProperty, + /// Used to set the user's email address after they log in so that we can link + /// anonymous analytics IDs to the authenticated users. + SetPersonProperties, } // ---------------------------------------------------------------------------- diff --git a/crates/utils/re_analytics/src/native/pipeline.rs b/crates/utils/re_analytics/src/native/pipeline.rs index a3b0126197cb..62b09d53462f 100644 --- a/crates/utils/re_analytics/src/native/pipeline.rs +++ b/crates/utils/re_analytics/src/native/pipeline.rs @@ -44,10 +44,10 @@ impl Pipeline { re_log::debug_once!("Analytics disabled in tests"); return Ok(None); } - // if cfg!(debug_assertions) { - // re_log::debug_once!("Analytics disabled in debug builds"); - // return Ok(None); - // } + if cfg!(debug_assertions) { + re_log::debug_once!("Analytics disabled in debug builds"); + return Ok(None); + } let sink = PostHogSink::default(); diff --git a/crates/utils/re_analytics/src/posthog.rs b/crates/utils/re_analytics/src/posthog.rs index 60600bf97f01..d6ddfde91341 100644 --- a/crates/utils/re_analytics/src/posthog.rs +++ b/crates/utils/re_analytics/src/posthog.rs @@ -50,7 +50,7 @@ impl<'a> PostHogEvent<'a> { properties: [("session_id", session_id.into())].into(), set: properties.collect(), }), - crate::EventKind::SetPersonProperty => Self::Alias(PostHogSetPersonPropertiesEvent { + crate::EventKind::SetPersonProperties => Self::Alias(PostHogSetPersonPropertiesEvent { timestamp: event.time_utc, event: "$set", distinct_id: analytics_id, @@ -80,7 +80,7 @@ pub struct PostHogIdentifyEvent<'a> { set: HashMap<&'a str, serde_json::Value>, } -// See https://posthog.com/docs/api/post-only-endpoints#alias. +// See https://posthog.com/docs/product-analytics/person-properties. #[derive(Debug, serde::Serialize)] pub struct PostHogSetPersonPropertiesEvent<'a> { timestamp: Timestamp, diff --git a/crates/utils/re_auth/src/oauth.rs b/crates/utils/re_auth/src/oauth.rs index d91dd72471ab..4595a3d48eb9 100644 --- a/crates/utils/re_auth/src/oauth.rs +++ b/crates/utils/re_auth/src/oauth.rs @@ -196,7 +196,7 @@ impl InMemoryCredentials { pub fn ensure_stored(self) -> Result { storage::store(&self.0)?; - // Send an alias event to link the analytics ID to the authenticated user + // Link the analytics ID to the authenticated user if let Some(analytics) = re_analytics::Analytics::global_get() { analytics.record(re_analytics::event::SetPersonProperty { email: self.0.user.email.clone(), From 08198dfd1cfbd36c4235e72f54bbeb1c07ae3f4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Gyebn=C3=A1r?= Date: Tue, 2 Dec 2025 14:32:50 +0100 Subject: [PATCH 03/10] Adds `LoadDataSource` analytics events --- .../store/re_data_source/src/data_source.rs | 86 +++++++++++++++++++ crates/store/re_data_source/src/lib.rs | 2 +- crates/utils/re_analytics/src/event.rs | 41 +++++++++ .../utils/re_analytics/src/native/pipeline.rs | 8 +- crates/viewer/re_viewer/src/app.rs | 19 +++- 5 files changed, 149 insertions(+), 7 deletions(-) diff --git a/crates/store/re_data_source/src/data_source.rs b/crates/store/re_data_source/src/data_source.rs index 80ccb6fd5415..61ef53115409 100644 --- a/crates/store/re_data_source/src/data_source.rs +++ b/crates/store/re_data_source/src/data_source.rs @@ -272,6 +272,92 @@ impl LogDataSource { Self::RedapProxy(uri) => Ok(re_grpc_client::stream(uri, on_msg)), } } + + /// Returns analytics data for this data source. + pub fn analytics(&self) -> LogDataSourceAnalytics { + match self { + Self::RrdHttpUrl { url, .. } => { + let file_extension = std::path::Path::new(url.path()) + .extension() + .and_then(|e| e.to_str()) + .map(|s| s.to_lowercase()); + LogDataSourceAnalytics { + source_type: "http", + file_extension, + file_source: None, + } + } + + #[cfg(not(target_arch = "wasm32"))] + Self::FilePath(file_src, path) => { + let file_extension = path + .extension() + .and_then(|e| e.to_str()) + .map(|s| s.to_lowercase()); + LogDataSourceAnalytics { + source_type: "file", + file_extension, + file_source: Some(Self::file_source_to_analytics_str(file_src)), + } + } + + Self::FileContents(file_src, file_contents) => { + let file_extension = std::path::Path::new(&file_contents.name) + .extension() + .and_then(|e| e.to_str()) + .map(|s| s.to_lowercase()); + LogDataSourceAnalytics { + source_type: "file_contents", + file_extension, + file_source: Some(Self::file_source_to_analytics_str(file_src)), + } + } + + #[cfg(not(target_arch = "wasm32"))] + Self::Stdin => LogDataSourceAnalytics { + source_type: "stdin", + file_extension: None, + file_source: None, + }, + + Self::RedapDatasetPartition { .. } => LogDataSourceAnalytics { + source_type: "redap_grpc", + file_extension: None, + file_source: None, + }, + + Self::RedapProxy(_) => LogDataSourceAnalytics { + source_type: "redap_proxy", + file_extension: None, + file_source: None, + }, + } + } + + fn file_source_to_analytics_str(file_source: &re_log_types::FileSource) -> &'static str { + use re_log_types::FileSource; + match file_source { + FileSource::Cli => "cli", + FileSource::Uri => "uri", + FileSource::DragAndDrop { .. } => "drag_and_drop", + FileSource::FileDialog { .. } => "file_dialog", + FileSource::Sdk => "sdk", + } + } +} + +/// Analytics data extracted from a [`LogDataSource`]. +#[derive(Clone, Debug)] +pub struct LogDataSourceAnalytics { + /// The type of data source (e.g., "file", "http", ``redap_grpc``, "stdin"). + pub source_type: &'static str, + + /// The file extension if applicable (e.g., "rrd", "png", "glb"). + pub file_extension: Option, + + /// How the file was opened (e.g., "cli", ``file_dialog``, ``drag_and_drop``). + /// Only applicable for file-based sources. + pub file_source: Option<&'static str>, } // TODO(ab, andreas): This should be replaced by the use of `AsyncRuntimeHandle`. However, this diff --git a/crates/store/re_data_source/src/lib.rs b/crates/store/re_data_source/src/lib.rs index 69477fa407e6..8bfa2b979495 100644 --- a/crates/store/re_data_source/src/lib.rs +++ b/crates/store/re_data_source/src/lib.rs @@ -11,7 +11,7 @@ mod data_source; #[cfg(not(target_arch = "wasm32"))] mod load_stdin; -pub use self::data_source::LogDataSource; +pub use self::data_source::{LogDataSource, LogDataSourceAnalytics}; // ---------------------------------------------------------------------------- diff --git a/crates/utils/re_analytics/src/event.rs b/crates/utils/re_analytics/src/event.rs index 1db0f1ce5ef7..4a4a0e0111f3 100644 --- a/crates/utils/re_analytics/src/event.rs +++ b/crates/utils/re_analytics/src/event.rs @@ -458,6 +458,47 @@ impl Properties for SetPersonProperty { // ----------------------------------------------- +/// Tracks when a data source is loaded from the viewer. +/// +/// This is sent when a user opens a file, URL, or other data source. +pub struct LoadDataSource { + /// The type of data source being loaded (e.g., "file", "http", "redap_grpc", "stdin"). + pub source_type: &'static str, + + /// The file extension if applicable (e.g., "rrd", "png", "glb"). + /// None for non-file sources like stdin or gRPC streams. + pub file_extension: Option, + + /// How the file was opened (e.g., "cli", "file_dialog", "drag_and_drop"). + /// Only applicable for file-based sources. + pub file_source: Option<&'static str>, + + /// Whether the data source stream was started successfully. + pub started_successfully: bool, +} + +impl Event for LoadDataSource { + const NAME: &'static str = "load_data_source"; +} + +impl Properties for LoadDataSource { + fn serialize(self, event: &mut AnalyticsEvent) { + let Self { + source_type, + file_extension, + file_source, + started_successfully, + } = self; + + event.insert("source_type", source_type); + event.insert_opt("file_extension", file_extension); + event.insert_opt("file_source", file_source.map(|s| s.to_owned())); + event.insert("started_successfully", started_successfully); + } +} + +// ----------------------------------------------- + #[cfg(test)] mod tests { use super::*; diff --git a/crates/utils/re_analytics/src/native/pipeline.rs b/crates/utils/re_analytics/src/native/pipeline.rs index 62b09d53462f..a3b0126197cb 100644 --- a/crates/utils/re_analytics/src/native/pipeline.rs +++ b/crates/utils/re_analytics/src/native/pipeline.rs @@ -44,10 +44,10 @@ impl Pipeline { re_log::debug_once!("Analytics disabled in tests"); return Ok(None); } - if cfg!(debug_assertions) { - re_log::debug_once!("Analytics disabled in debug builds"); - return Ok(None); - } + // if cfg!(debug_assertions) { + // re_log::debug_once!("Analytics disabled in debug builds"); + // return Ok(None); + // } let sink = PostHogSink::default(); diff --git a/crates/viewer/re_viewer/src/app.rs b/crates/viewer/re_viewer/src/app.rs index 1a69808c04a5..07f3230d1988 100644 --- a/crates/viewer/re_viewer/src/app.rs +++ b/crates/viewer/re_viewer/src/app.rs @@ -1348,14 +1348,29 @@ impl App { }) }; - match data_source + let started_successfully = match data_source .clone() .stream(&self.connection_registry, Some(waker)) { - Ok(rx) => self.add_log_receiver(rx), + Ok(rx) => { + self.add_log_receiver(rx); + true + } Err(err) => { re_log::error!("Failed to open data source: {}", re_error::format(err)); + false } + }; + + #[cfg(feature = "analytics")] + if let Some(analytics) = re_analytics::Analytics::global_or_init() { + let data_source_analytics = data_source.analytics(); + analytics.record(re_analytics::event::LoadDataSource { + source_type: data_source_analytics.source_type, + file_extension: data_source_analytics.file_extension, + file_source: data_source_analytics.file_source, + started_successfully, + }); } } From 2316969f059472b9a57346a9c9c04abe596999e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Gyebn=C3=A1r?= Date: Tue, 2 Dec 2025 15:44:48 +0100 Subject: [PATCH 04/10] Resets debug gate --- crates/utils/re_analytics/src/native/pipeline.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/utils/re_analytics/src/native/pipeline.rs b/crates/utils/re_analytics/src/native/pipeline.rs index a3b0126197cb..62b09d53462f 100644 --- a/crates/utils/re_analytics/src/native/pipeline.rs +++ b/crates/utils/re_analytics/src/native/pipeline.rs @@ -44,10 +44,10 @@ impl Pipeline { re_log::debug_once!("Analytics disabled in tests"); return Ok(None); } - // if cfg!(debug_assertions) { - // re_log::debug_once!("Analytics disabled in debug builds"); - // return Ok(None); - // } + if cfg!(debug_assertions) { + re_log::debug_once!("Analytics disabled in debug builds"); + return Ok(None); + } let sink = PostHogSink::default(); From 3ace267013f8c1f069366b46ba2c59e65a6297b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Gyebn=C3=A1r?= Date: Wed, 3 Dec 2025 12:05:34 +0100 Subject: [PATCH 05/10] Lint --- crates/viewer/re_viewer/src/app.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/viewer/re_viewer/src/app.rs b/crates/viewer/re_viewer/src/app.rs index 07727d777e04..8c578e45a42d 100644 --- a/crates/viewer/re_viewer/src/app.rs +++ b/crates/viewer/re_viewer/src/app.rs @@ -1365,7 +1365,7 @@ impl App { }) }; - let started_successfully = match data_source + let _started_successfully = match data_source .clone() .stream(&self.connection_registry, Some(waker)) { @@ -1386,7 +1386,7 @@ impl App { source_type: data_source_analytics.source_type, file_extension: data_source_analytics.file_extension, file_source: data_source_analytics.file_source, - started_successfully, + started_successfully: _started_successfully, }); } } From 09f17f24de2e45b30588477c91cb6c1a24fd941d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Gyebn=C3=A1r?= Date: Wed, 3 Dec 2025 12:58:48 +0100 Subject: [PATCH 06/10] Update --- crates/store/re_data_source/src/data_source.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/store/re_data_source/src/data_source.rs b/crates/store/re_data_source/src/data_source.rs index 96cb8e39ad4d..afa83781a19e 100644 --- a/crates/store/re_data_source/src/data_source.rs +++ b/crates/store/re_data_source/src/data_source.rs @@ -288,7 +288,7 @@ impl LogDataSource { file_source: None, }, - Self::RedapDatasetPartition { .. } => LogDataSourceAnalytics { + Self::RedapDatasetSegment { .. } => LogDataSourceAnalytics { source_type: "redap_grpc", file_extension: None, file_source: None, From 14d565e5fcd248e0ccad8127347b04ab343390f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Gyebn=C3=A1r?= Date: Wed, 3 Dec 2025 13:47:20 +0100 Subject: [PATCH 07/10] Fix --- crates/store/re_data_source/src/data_source.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/store/re_data_source/src/data_source.rs b/crates/store/re_data_source/src/data_source.rs index afa83781a19e..353e97dac289 100644 --- a/crates/store/re_data_source/src/data_source.rs +++ b/crates/store/re_data_source/src/data_source.rs @@ -250,7 +250,7 @@ impl LogDataSource { .and_then(|e| e.to_str()) .map(|s| s.to_lowercase()); LogDataSourceAnalytics { - source_type: "http", + source_type: "rrd_http_url", file_extension, file_source: None, } @@ -263,7 +263,7 @@ impl LogDataSource { .and_then(|e| e.to_str()) .map(|s| s.to_lowercase()); LogDataSourceAnalytics { - source_type: "file", + source_type: "file_path", file_extension, file_source: Some(Self::file_source_to_analytics_str(file_src)), } @@ -289,7 +289,7 @@ impl LogDataSource { }, Self::RedapDatasetSegment { .. } => LogDataSourceAnalytics { - source_type: "redap_grpc", + source_type: "redap_dataset_segment", file_extension: None, file_source: None, }, From 237a250db3f985ce5d6d3f6a2d4f35494efe59ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Gyebn=C3=A1r?= Date: Wed, 3 Dec 2025 14:24:38 +0100 Subject: [PATCH 08/10] Lint --- crates/utils/re_analytics/src/event.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/utils/re_analytics/src/event.rs b/crates/utils/re_analytics/src/event.rs index 4a4a0e0111f3..5d25eb22195c 100644 --- a/crates/utils/re_analytics/src/event.rs +++ b/crates/utils/re_analytics/src/event.rs @@ -462,14 +462,14 @@ impl Properties for SetPersonProperty { /// /// This is sent when a user opens a file, URL, or other data source. pub struct LoadDataSource { - /// The type of data source being loaded (e.g., "file", "http", "redap_grpc", "stdin"). + /// The type of data source being loaded (e.g., "file", "http" etc.). pub source_type: &'static str, /// The file extension if applicable (e.g., "rrd", "png", "glb"). /// None for non-file sources like stdin or gRPC streams. pub file_extension: Option, - /// How the file was opened (e.g., "cli", "file_dialog", "drag_and_drop"). + /// How the file was opened (e.g., "cli", "`file_dialog`" etc.). /// Only applicable for file-based sources. pub file_source: Option<&'static str>, From 2c5c75ac39f7e19e8d43fc9b7a8a010b668a3382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Gyebn=C3=A1r?= Date: Wed, 3 Dec 2025 15:03:56 +0100 Subject: [PATCH 09/10] Lint --- crates/viewer/re_viewer/src/app.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/viewer/re_viewer/src/app.rs b/crates/viewer/re_viewer/src/app.rs index 72a802c2e534..3c3ffd7d8d30 100644 --- a/crates/viewer/re_viewer/src/app.rs +++ b/crates/viewer/re_viewer/src/app.rs @@ -1375,7 +1375,7 @@ impl App { match stream { Ok(rx) => self.add_log_receiver(rx), Err(err) => { - re_log::error!("Failed to open data source: {}", re_error::format(err)); + re_log::error!("Failed to open data source: {}", re_error::format(err)) } }; } From c0a2c381f29bbdc14b3913af5e7e1af3bef5939a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Gyebn=C3=A1r?= Date: Wed, 3 Dec 2025 15:17:31 +0100 Subject: [PATCH 10/10] lint --- crates/viewer/re_viewer/src/app.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/viewer/re_viewer/src/app.rs b/crates/viewer/re_viewer/src/app.rs index 3c3ffd7d8d30..05caa040149f 100644 --- a/crates/viewer/re_viewer/src/app.rs +++ b/crates/viewer/re_viewer/src/app.rs @@ -1375,9 +1375,9 @@ impl App { match stream { Ok(rx) => self.add_log_receiver(rx), Err(err) => { - re_log::error!("Failed to open data source: {}", re_error::format(err)) + re_log::error!("Failed to open data source: {}", re_error::format(err)); } - }; + } } /// Applies a fragment.