v1.4.0: Auto-compact streaming, Bedrock summarization support, subagent orchestration, and Galaxy rebrand continuation
Major features: - Auto-compact: triggers conversation summarization when context window >= 85%, compacts Bedrock message history to a summary pair, and tracks live context tokens - Bedrock summarization: plumbs `is_summarization` flag through translator/client/response pipeline, handles SummarizeConversation input type, and marks `summarized` in metadata - Session restore: rebuilds bedrock_message_history from persisted task messages via newly-public `convert_proto_message`, preventing empty history on reconnect - Subagent orchestration: adds SubagentQuestion/Answer/CompletionSummary event types, parent-child question routing with depth limits, retry counting, and drain methods - Summarization UI: inline SummarizationView in AI blocks with progress/finished states Refactors: - Rename WarpTheme → GalaxyTheme across ~100 files (rebrand continuation) - Rename warp_home_config_dir → galaxy_home_config_dir and related path functions - Predefined rules: replace "System Defined Rule #N" with descriptive names (e.g. "Correctness Over Speed", "Never Guess") and add lookup helpers - Usage view: replace cumulative input/output token display with live context tokens, cache hit rate calculation, and separate cache read/write stats - Telemetry: remove verbose doc comments, simplify trait definitions - Facts view: simplify delete permission check (always allow local deletion) - Remove warp_managed_paths_watcher.rs (dead code) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
eaa2ddc75e
commit
6f54e2cb30
@@ -13,7 +13,7 @@ cfg_if::cfg_if! {
|
||||
use ignore::gitignore::Gitignore;
|
||||
use async_channel::Sender;
|
||||
|
||||
const RULES_FILE_PATTERN: [&str; 2] = ["WARP.md", "AGENTS.md"];
|
||||
const RULES_FILE_PATTERN: [&str; 4] = ["GALAXY.md", "WARP.md", "CLAUDE.md", "AGENTS.md"];
|
||||
const MAX_SCAN_DEPTH: usize = 3;
|
||||
const MAX_FILES_TO_SCAN: usize = 5000;
|
||||
}
|
||||
@@ -28,13 +28,23 @@ pub struct ProjectRule {
|
||||
#[derive(Debug, Default)]
|
||||
struct RuleAtPath {
|
||||
parent_path: PathBuf,
|
||||
galaxy_md: Option<ProjectRule>,
|
||||
warp_md: Option<ProjectRule>,
|
||||
claude_md: Option<ProjectRule>,
|
||||
agents_md: Option<ProjectRule>,
|
||||
}
|
||||
|
||||
impl RuleAtPath {
|
||||
fn respected_rule(&self) -> Option<&ProjectRule> {
|
||||
self.warp_md.as_ref().or(self.agents_md.as_ref())
|
||||
fn all_rules(&self) -> Vec<&ProjectRule> {
|
||||
[
|
||||
self.galaxy_md.as_ref(),
|
||||
self.warp_md.as_ref(),
|
||||
self.claude_md.as_ref(),
|
||||
self.agents_md.as_ref(),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,12 +92,14 @@ impl ProjectRules {
|
||||
|
||||
// Collect all applicable rules (rules in directories that are ancestors of the target path)
|
||||
for rule in &self.rules {
|
||||
if let Some(respected_rule) = rule.respected_rule() {
|
||||
// Check if the rule's directory is an ancestor of or equal to the target path
|
||||
if path.starts_with(&rule.parent_path) {
|
||||
active_rules.push(respected_rule.clone());
|
||||
} else {
|
||||
available_rule_paths.push(respected_rule.path.to_string_lossy().to_string());
|
||||
if path.starts_with(&rule.parent_path) {
|
||||
for project_rule in rule.all_rules() {
|
||||
active_rules.push(project_rule.clone());
|
||||
}
|
||||
} else {
|
||||
for project_rule in rule.all_rules() {
|
||||
available_rule_paths
|
||||
.push(project_rule.path.to_string_lossy().to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,16 +121,16 @@ impl ProjectRules {
|
||||
.iter_mut()
|
||||
.find(|rule| rule.parent_path == parent)?;
|
||||
|
||||
if file_name.to_lowercase() == "warp.md" {
|
||||
rule.warp_md.take()
|
||||
} else if file_name.to_lowercase() == "agents.md" {
|
||||
rule.agents_md.take()
|
||||
} else {
|
||||
None
|
||||
match file_name.to_lowercase().as_str() {
|
||||
"galaxy.md" => rule.galaxy_md.take(),
|
||||
"warp.md" => rule.warp_md.take(),
|
||||
"claude.md" => rule.claude_md.take(),
|
||||
"agents.md" => rule.agents_md.take(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Upsert a rule to the set of project rules. This will create a new RuleAtPath entry if none exists and update the existin one
|
||||
/// Upsert a rule to the set of project rules. This will create a new RuleAtPath entry if none exists and update the existing one
|
||||
/// otherwise.
|
||||
#[cfg_attr(not(feature = "local_fs"), allow(dead_code))]
|
||||
fn upsert_rule(&mut self, path: &Path, content: String) {
|
||||
@@ -139,32 +151,29 @@ impl ProjectRules {
|
||||
content,
|
||||
});
|
||||
|
||||
match existing_rule {
|
||||
Some(rule) => {
|
||||
if file_name.to_lowercase() == "warp.md" {
|
||||
rule.warp_md = rule_file;
|
||||
} else if file_name.to_lowercase() == "agents.md" {
|
||||
rule.agents_md = rule_file;
|
||||
}
|
||||
}
|
||||
let rule_ref = match existing_rule {
|
||||
Some(rule) => rule,
|
||||
None => {
|
||||
let mut rule = RuleAtPath {
|
||||
self.rules.push(RuleAtPath {
|
||||
parent_path: parent.to_path_buf(),
|
||||
..Default::default()
|
||||
};
|
||||
if file_name.to_lowercase() == "warp.md" {
|
||||
rule.warp_md = rule_file;
|
||||
} else if file_name.to_lowercase() == "agents.md" {
|
||||
rule.agents_md = rule_file;
|
||||
}
|
||||
self.rules.push(rule);
|
||||
});
|
||||
self.rules.last_mut().unwrap()
|
||||
}
|
||||
};
|
||||
|
||||
match file_name.to_lowercase().as_str() {
|
||||
"galaxy.md" => rule_ref.galaxy_md = rule_file,
|
||||
"warp.md" => rule_ref.warp_md = rule_file,
|
||||
"claude.md" => rule_ref.claude_md = rule_file,
|
||||
"agents.md" => rule_ref.agents_md = rule_file,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Singleton model that keeps track of mapping between paths and rule files
|
||||
/// Currently supports WARP.md files, but designed to be extensible
|
||||
/// Supports GALAXY.md, WARP.md, CLAUDE.md, and AGENTS.md project rule files
|
||||
#[cfg_attr(not(feature = "local_fs"), allow(dead_code))]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ProjectContextModel {
|
||||
@@ -237,18 +246,12 @@ impl ProjectContextModel {
|
||||
discovered_rules: rule_files
|
||||
.rules
|
||||
.iter()
|
||||
.filter_map(|rule| {
|
||||
rule.warp_md.as_ref().map(|rule| ProjectRulePath {
|
||||
.flat_map(|rule| {
|
||||
rule.all_rules().into_iter().map(|r| ProjectRulePath {
|
||||
project_root: root_clone.clone(),
|
||||
path: rule.path.clone(),
|
||||
path: r.path.clone(),
|
||||
})
|
||||
})
|
||||
.chain(rule_files.rules.iter().filter_map(|rule| {
|
||||
rule.agents_md.as_ref().map(|rule| ProjectRulePath {
|
||||
project_root: root_clone.clone(),
|
||||
path: rule.path.clone(),
|
||||
})
|
||||
}))
|
||||
.collect(),
|
||||
deleted_rules: Default::default(),
|
||||
};
|
||||
@@ -489,7 +492,7 @@ impl ProjectContextModel {
|
||||
(existing_rules, rules_delta)
|
||||
}
|
||||
|
||||
/// Scan a directory for rule files (currently WARP.md, extensible for future file types)
|
||||
/// Scan a directory for rule files (GALAXY.md, WARP.md, CLAUDE.md, AGENTS.md)
|
||||
/// Uses repo_metadata::entry::build_tree for efficient directory traversal
|
||||
#[cfg(feature = "local_fs")]
|
||||
async fn scan_directory_for_rules(dir_path: &Path) -> Result<ProjectRules> {
|
||||
@@ -576,11 +579,10 @@ impl ProjectContextModel {
|
||||
|
||||
pub fn indexed_rules(&self) -> impl Iterator<Item = PathBuf> + '_ {
|
||||
self.path_to_rules.values().flat_map(|rules| {
|
||||
rules.rules.iter().filter_map(|rules| {
|
||||
rules
|
||||
.respected_rule()
|
||||
.map(|project_rule| project_rule.path.clone())
|
||||
})
|
||||
rules
|
||||
.rules
|
||||
.iter()
|
||||
.flat_map(|rule| rule.all_rules().into_iter().map(|r| r.path.clone()))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -590,8 +592,9 @@ impl ProjectContextModel {
|
||||
.get(workspace_path)
|
||||
.into_iter()
|
||||
.flat_map(|rules| {
|
||||
rules.rules.iter().filter_map(|rule| {
|
||||
rule.respected_rule()
|
||||
rules.rules.iter().flat_map(|rule| {
|
||||
rule.all_rules()
|
||||
.into_iter()
|
||||
.map(|project_rule| project_rule.path.clone())
|
||||
})
|
||||
})
|
||||
|
||||
@@ -121,12 +121,12 @@ fn test_find_applicable_rules_handles_root_path() {
|
||||
|
||||
#[test]
|
||||
fn test_find_applicable_rules_complex_scenario() {
|
||||
// This test covers the example from the original request:
|
||||
// For path /a/b/c/file.rs with rules:
|
||||
// - /a/WARP.md
|
||||
// - /a/AGENTS.md
|
||||
// - /a/b/WARP.md
|
||||
// - /a/b/AGENTS.md
|
||||
// All ancestor rule files should be included.
|
||||
let mut rules = ProjectRules::default();
|
||||
|
||||
rules.upsert_rule(Path::new("/a/WARP.md"), "a_warp".to_string());
|
||||
@@ -138,13 +138,13 @@ fn test_find_applicable_rules_complex_scenario() {
|
||||
let path = PathBuf::from("/a/b/c/file.rs");
|
||||
|
||||
let result = rules.find_active_or_applicable_rules(&path).active_rules;
|
||||
assert_eq!(result.len(), 2);
|
||||
assert_eq!(result.len(), 4);
|
||||
|
||||
// Expect only WARP.md files to be included as they have higher priority.
|
||||
assert_eq!(result[0].path, PathBuf::from("/a/WARP.md"));
|
||||
assert_eq!(result[0].content, "a_warp");
|
||||
assert_eq!(result[1].path, PathBuf::from("/a/b/WARP.md"));
|
||||
assert_eq!(result[1].content, "ab_warp");
|
||||
let paths: Vec<PathBuf> = result.iter().map(|r| r.path.clone()).collect();
|
||||
assert!(paths.contains(&PathBuf::from("/a/WARP.md")));
|
||||
assert!(paths.contains(&PathBuf::from("/a/AGENTS.md")));
|
||||
assert!(paths.contains(&PathBuf::from("/a/b/WARP.md")));
|
||||
assert!(paths.contains(&PathBuf::from("/a/b/AGENTS.md")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -159,7 +159,7 @@ pub fn provider_rank(provider: SkillProvider) -> usize {
|
||||
|
||||
pub fn home_skills_path(provider: SkillProvider) -> Option<PathBuf> {
|
||||
if provider == SkillProvider::Warp {
|
||||
return galaxy_core::paths::warp_home_skills_dir();
|
||||
return galaxy_core::paths::galaxy_home_skills_dir();
|
||||
}
|
||||
let definition = SKILL_PROVIDER_DEFINITIONS
|
||||
.iter()
|
||||
@@ -220,17 +220,17 @@ mod tests {
|
||||
fn warp_home_skills_path_uses_warp_home_path() {
|
||||
assert_eq!(
|
||||
home_skills_path(SkillProvider::Warp),
|
||||
galaxy_core::paths::warp_home_skills_dir()
|
||||
galaxy_core::paths::galaxy_home_skills_dir()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn warp_home_skill_path_is_home_warp_skill() {
|
||||
let Some(warp_home_skills_dir) = galaxy_core::paths::warp_home_skills_dir() else {
|
||||
let Some(galaxy_home_skills_dir) = galaxy_core::paths::galaxy_home_skills_dir() else {
|
||||
eprintln!("Skipping test: home directory not available");
|
||||
return;
|
||||
};
|
||||
let path = warp_home_skills_dir.join("my-skill").join("SKILL.md");
|
||||
let path = galaxy_home_skills_dir.join("my-skill").join("SKILL.md");
|
||||
|
||||
assert_eq!(get_provider_for_path(&path), Some(SkillProvider::Warp));
|
||||
assert_eq!(get_scope_for_path(&path), SkillScope::Home);
|
||||
|
||||
@@ -216,7 +216,7 @@ impl Args {
|
||||
}
|
||||
}
|
||||
|
||||
if !FeatureFlag::WarpManagedSecrets.is_enabled() {
|
||||
if !FeatureFlag::GalaxyManagedSecrets.is_enabled() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() > 1 && args[1] == "secret" {
|
||||
eprintln!("error: unrecognized subcommand 'secret'\n");
|
||||
@@ -313,7 +313,7 @@ impl Args {
|
||||
}
|
||||
|
||||
// Hide the secret subcommand from help text.
|
||||
if !FeatureFlag::WarpManagedSecrets.is_enabled() {
|
||||
if !FeatureFlag::GalaxyManagedSecrets.is_enabled() {
|
||||
command = command.mut_subcommand("secret", |c| c.hide(true));
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ fn base_warp_config_dir_name() -> String {
|
||||
///
|
||||
/// This preserves the historical `.warp*` directory shape while still isolating dev, local,
|
||||
/// integration, oss, and optional development profiles.
|
||||
pub fn warp_home_config_dir_name() -> String {
|
||||
pub fn galaxy_home_config_dir_name() -> String {
|
||||
let base_dir_name = base_warp_config_dir_name();
|
||||
|
||||
if let Some(data_profile) = ChannelState::data_profile() {
|
||||
@@ -67,13 +67,13 @@ pub fn warp_home_config_dir_name() -> String {
|
||||
/// Unlike [`data_dir`] and [`config_local_dir`] on non-macOS platforms, this intentionally keeps
|
||||
/// user-facing config under a `.warp-core*` directory in the home directory instead of
|
||||
/// using the platform XDG/AppData project directories.
|
||||
pub fn warp_home_config_dir() -> Option<PathBuf> {
|
||||
dirs::home_dir().map(|home_dir| home_dir.join(warp_home_config_dir_name()))
|
||||
pub fn galaxy_home_config_dir() -> Option<PathBuf> {
|
||||
dirs::home_dir().map(|home_dir| home_dir.join(galaxy_home_config_dir_name()))
|
||||
}
|
||||
|
||||
/// Returns the legacy `~/.warp*` config directory path for the current channel,
|
||||
/// used to detect and migrate data from a previous Warp installation.
|
||||
pub fn legacy_warp_home_config_dir() -> Option<PathBuf> {
|
||||
pub fn legacy_galaxy_home_config_dir() -> Option<PathBuf> {
|
||||
let base = LEGACY_WARP_CONFIG_DIR;
|
||||
let dir_name = match ChannelState::channel() {
|
||||
Channel::Stable | Channel::Preview => base.to_owned(),
|
||||
@@ -100,10 +100,10 @@ pub fn legacy_warp_home_config_dir() -> Option<PathBuf> {
|
||||
/// - The new directory already exists.
|
||||
/// - The old directory does not exist.
|
||||
pub fn migrate_legacy_config_dir_if_needed() {
|
||||
let Some(old_dir) = legacy_warp_home_config_dir() else {
|
||||
let Some(old_dir) = legacy_galaxy_home_config_dir() else {
|
||||
return;
|
||||
};
|
||||
let Some(new_dir) = warp_home_config_dir() else {
|
||||
let Some(new_dir) = galaxy_home_config_dir() else {
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -198,12 +198,12 @@ pub fn migrate_legacy_config_dir_if_needed() {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn warp_home_skills_dir() -> Option<PathBuf> {
|
||||
warp_home_config_dir().map(|warp_config_dir| warp_config_dir.join("skills"))
|
||||
pub fn galaxy_home_skills_dir() -> Option<PathBuf> {
|
||||
galaxy_home_config_dir().map(|warp_config_dir| warp_config_dir.join("skills"))
|
||||
}
|
||||
|
||||
pub fn warp_home_mcp_config_file_path() -> Option<PathBuf> {
|
||||
warp_home_config_dir().map(|warp_config_dir| warp_config_dir.join(".mcp.json"))
|
||||
pub fn galaxy_home_mcp_config_file_path() -> Option<PathBuf> {
|
||||
galaxy_home_config_dir().map(|warp_config_dir| warp_config_dir.join(".mcp.json"))
|
||||
}
|
||||
|
||||
/// Returns the macOS config directory name for the current channel.
|
||||
|
||||
@@ -37,7 +37,7 @@ fn test_config_local_dir_path() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_warp_home_config_dir_path() {
|
||||
fn test_galaxy_home_config_dir_path() {
|
||||
let home_dir = home_dir().expect("Should be able to compute home directory");
|
||||
let expected_dir_name = match ChannelState::data_profile() {
|
||||
Some(data_profile) => format!(".warp-core-oss-{data_profile}"),
|
||||
@@ -45,20 +45,20 @@ fn test_warp_home_config_dir_path() {
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
warp_home_config_dir(),
|
||||
galaxy_home_config_dir(),
|
||||
Some(home_dir.join(expected_dir_name))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_warp_home_skills_and_mcp_paths() {
|
||||
let Some(config_dir) = warp_home_config_dir() else {
|
||||
let Some(config_dir) = galaxy_home_config_dir() else {
|
||||
panic!("Should be able to compute Warp home config directory");
|
||||
};
|
||||
|
||||
assert_eq!(warp_home_skills_dir(), Some(config_dir.join("skills")));
|
||||
assert_eq!(galaxy_home_skills_dir(), Some(config_dir.join("skills")));
|
||||
assert_eq!(
|
||||
warp_home_mcp_config_file_path(),
|
||||
galaxy_home_mcp_config_file_path(),
|
||||
Some(config_dir.join(".mcp.json"))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,62 +1,19 @@
|
||||
use std::{fmt, marker::PhantomData};
|
||||
|
||||
use galaxyui::{AppContext, Entity, SingletonEntity};
|
||||
use serde_json::Value;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
// Re-export for macro use.
|
||||
#[doc(hidden)]
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
pub use inventory::submit;
|
||||
|
||||
use crate::{
|
||||
channel::{Channel, ChannelState},
|
||||
features::FeatureFlag,
|
||||
};
|
||||
use crate::features::FeatureFlag;
|
||||
|
||||
/// Core trait defining telemetry event behavior.
|
||||
///
|
||||
/// This trait encapsulates the basic functionality required for any telemetry event
|
||||
/// in the Warp ecosystem. It enables events to be defined in any crate while maintaining
|
||||
/// consistent telemetry reporting behavior.
|
||||
pub trait TelemetryEvent: RegisteredTelemetryEvent {
|
||||
/// Returns the name of the telemetry event.
|
||||
///
|
||||
/// The name should be a stable identifier that uniquely identifies this type of event.
|
||||
/// It is used for analytics tracking and should remain consistent over time.
|
||||
///
|
||||
/// Returns a borrowed string to avoid allocations for static event names.
|
||||
fn name(&self) -> &'static str;
|
||||
|
||||
/// Returns optional structured data associated with this event.
|
||||
///
|
||||
/// The payload allows events to include additional context or metadata beyond
|
||||
/// just the event name. This is useful for including dynamic data about the
|
||||
/// event occurrence.
|
||||
///
|
||||
/// Returns None if the event has no additional data to report.
|
||||
fn payload(&self) -> Option<Value>;
|
||||
|
||||
/// Returns a human-readable description of what this event represents.
|
||||
///
|
||||
/// The description should clearly explain the significance of the event to help
|
||||
/// with analytics and monitoring. This is used both for documentation and
|
||||
/// telemetry dashboards.
|
||||
fn description(&self) -> &'static str;
|
||||
|
||||
/// Determines if an event is enabled in the current build. This only works when all
|
||||
/// feature flags are set appropriately, so this should be used when running
|
||||
/// the bundled app.
|
||||
fn enablement_state(&self) -> EnablementState;
|
||||
|
||||
/// Returns whether this event contains user-generated content (UGC).
|
||||
///
|
||||
/// Events containing UGC may need special handling for privacy and data
|
||||
/// retention reasons. This flag helps route the event to the appropriate
|
||||
/// analytics destination.
|
||||
fn contains_ugc(&self) -> bool;
|
||||
|
||||
/// Returns an iterator over the descriptors for all telemetry events of this type.
|
||||
fn event_descs() -> impl Iterator<Item = Box<dyn TelemetryEventDesc>>;
|
||||
}
|
||||
|
||||
@@ -72,40 +29,28 @@ macro_rules! register_telemetry_event {
|
||||
};
|
||||
}
|
||||
|
||||
/// Marker trait for known telemetry events. We rely on this to print an exhaustive telemetry
|
||||
/// table in Warp's documentation.
|
||||
///
|
||||
/// DO NOT implement this trait directly - use the [`register_telemetry_event!`] macro instead.
|
||||
pub trait RegisteredTelemetryEvent {}
|
||||
|
||||
/// An abstract description of a telemetry event we may emit. Every [`TelemetryEvent`] has a
|
||||
/// corresponding [`TelemetryEventDesc`].
|
||||
pub trait TelemetryEventDesc: fmt::Debug {
|
||||
pub trait TelemetryEventDesc: std::fmt::Debug {
|
||||
fn name(&self) -> &'static str;
|
||||
fn description(&self) -> &'static str;
|
||||
fn enablement_state(&self) -> EnablementState;
|
||||
}
|
||||
|
||||
/// A type-erased version of [`TelemetryEventRegistration`]. This is only used by the
|
||||
/// [`register_telemetry_event!`] macro implementation.
|
||||
#[doc(hidden)]
|
||||
pub trait AnyTelemetryEventRegistration: Sync {
|
||||
/// Returns an iterator over the descriptors for all telemetry events in this [`TelemetryEvent`] implementation.
|
||||
fn events(&self) -> Box<dyn Iterator<Item = Box<dyn TelemetryEventDesc>>>;
|
||||
}
|
||||
|
||||
/// Adapter for statically registering all [`TelemetryEvent`] implementations.
|
||||
#[doc(hidden)]
|
||||
pub struct TelemetryEventRegistration<T: TelemetryEvent + 'static> {
|
||||
/// Marker that `TelemetryEventRegistration` references `T`, but doesn't own a `T` value.
|
||||
/// See https://doc.rust-lang.org/nomicon/phantom-data.html
|
||||
_marker: PhantomData<fn(T) -> T>,
|
||||
_marker: std::marker::PhantomData<fn(T) -> T>,
|
||||
}
|
||||
|
||||
impl<T: TelemetryEvent + 'static> TelemetryEventRegistration<T> {
|
||||
pub const fn adapt() -> &'static dyn AnyTelemetryEventRegistration {
|
||||
&Self {
|
||||
_marker: PhantomData,
|
||||
_marker: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,9 +61,6 @@ impl<T: TelemetryEvent + 'static> AnyTelemetryEventRegistration for TelemetryEve
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over all discriminants of `T` as [`TelemetryEventDesc`]s.
|
||||
///
|
||||
/// Telemetry events that use [`strum`] may use this to implement [`TelemetryEvent::event_descs`].
|
||||
pub fn enum_events<T>() -> impl Iterator<Item = Box<dyn TelemetryEventDesc>>
|
||||
where
|
||||
T: strum::IntoDiscriminant,
|
||||
@@ -128,107 +70,47 @@ where
|
||||
.map(|discriminant| Box::new(discriminant) as Box<dyn TelemetryEventDesc>)
|
||||
}
|
||||
|
||||
// Collect adapters for all registered telemetry events. Because `inventory::collect!` requires a
|
||||
// concrete type, we use `&static dyn Trait` to erase the generics.
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
inventory::collect!(&'static dyn AnyTelemetryEventRegistration);
|
||||
|
||||
/// Returns all registered telemetry events. This is not available in WASM builds, as it relies on
|
||||
/// the [`inventory`] crate, which does not fully work in our WASM configuration.
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
pub fn all_events() -> impl Iterator<Item = Box<dyn TelemetryEventDesc>> {
|
||||
inventory::iter::<&'static dyn AnyTelemetryEventRegistration>().flat_map(|meta| meta.events())
|
||||
}
|
||||
|
||||
// Sends a telemetry `track` event to Rudderstack asynchronously. It adds events to the static
|
||||
// telemetry queue that is periodically flushed to the Rudderstack API.
|
||||
// This is the recommended way of recording telemetry events.
|
||||
// You should almost always use this, unless the recording is time-sensitive and cannot be lost.
|
||||
// To send a telemetry event synchronously, use [`send_telemetry_sync_from_ctx`].
|
||||
/// No-op: telemetry has been removed from Galaxy.
|
||||
#[macro_export]
|
||||
macro_rules! send_telemetry_from_ctx {
|
||||
($event:expr, $ctx:expr) => {
|
||||
#[allow(unused_imports)]
|
||||
use galaxy_core::telemetry::TelemetryEvent as _;
|
||||
let event = $event;
|
||||
if event.enablement_state().is_enabled() {
|
||||
let auth_state =
|
||||
<$crate::telemetry::TelemetryContextModel as galaxyui::SingletonEntity>::handle(
|
||||
$ctx,
|
||||
)
|
||||
.as_ref($ctx);
|
||||
let user_id = auth_state.user_id($ctx);
|
||||
let anonymous_id = auth_state.anonymous_id($ctx);
|
||||
galaxyui::record_telemetry_from_ctx!(
|
||||
user_id,
|
||||
anonymous_id,
|
||||
event.name().into(),
|
||||
event.payload(),
|
||||
event.contains_ugc(),
|
||||
$ctx
|
||||
);
|
||||
}
|
||||
let _ = &$event;
|
||||
let _ = &$ctx;
|
||||
};
|
||||
}
|
||||
|
||||
/// Sends telemetry `track` event to Rudderstack API asynchronously. This is the same as the
|
||||
/// [`send_telemetry_from_ctx`], except it can be called in instances where you only have
|
||||
/// a `AppContext` rather than a `ViewContext`/`ModelContext`.
|
||||
///
|
||||
/// If possible, use [`send_telemetry_from_ctx`].
|
||||
/// No-op: telemetry has been removed from Galaxy.
|
||||
#[macro_export]
|
||||
macro_rules! send_telemetry_from_app_ctx {
|
||||
($event:expr, $app_ctx:expr) => {
|
||||
let event = $event;
|
||||
if event.enablement_state().is_enabled() {
|
||||
let auth_state =
|
||||
<$crate::telemetry::TelemetryContextModel as galaxyui::SingletonEntity>::handle(
|
||||
$app_ctx,
|
||||
)
|
||||
.as_ref($app_ctx);
|
||||
let user_id = auth_state.user_id($app_ctx.as_ref());
|
||||
let anonymous_id = auth_state.anonymous_id($app_ctx.as_ref());
|
||||
galaxyui::record_telemetry_on_executor!(
|
||||
user_id,
|
||||
anonymous_id,
|
||||
event.name().into(),
|
||||
event.payload(),
|
||||
event.contains_ugc(),
|
||||
$app_ctx.background_executor()
|
||||
);
|
||||
}
|
||||
let _ = &$event;
|
||||
let _ = &$app_ctx;
|
||||
};
|
||||
}
|
||||
|
||||
/// Gives information about when a telemetry event is enabled.
|
||||
#[derive(Debug)]
|
||||
pub enum EnablementState {
|
||||
Always,
|
||||
/// The telemetry event is enabled when a particular feature flag is enabled.
|
||||
Flag(FeatureFlag),
|
||||
/// The event is enabled if the app is running in one of the contained channels.
|
||||
ChannelSpecific {
|
||||
channels: Vec<Channel>,
|
||||
},
|
||||
ChannelSpecific { channels: Vec<crate::channel::Channel> },
|
||||
}
|
||||
|
||||
impl EnablementState {
|
||||
pub fn is_enabled(&self) -> bool {
|
||||
match self {
|
||||
EnablementState::Always => true,
|
||||
EnablementState::Flag(flag) => flag.is_enabled(),
|
||||
EnablementState::ChannelSpecific { channels } => {
|
||||
let app_channel = ChannelState::channel();
|
||||
channels.contains(&app_channel)
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for the context provider that allows us to send telemetry payloads.
|
||||
pub trait TelemetryContextProvider {
|
||||
fn user_id(&self, ctx: &AppContext) -> Option<String>;
|
||||
|
||||
fn anonymous_id(&self, ctx: &AppContext) -> String;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ use galaxyui::{
|
||||
Entity, ModelContext, SingletonEntity,
|
||||
};
|
||||
|
||||
use super::{builder::UiBuilder, theme::WarpTheme};
|
||||
use super::{builder::UiBuilder, theme::GalaxyTheme};
|
||||
|
||||
/// The standard font size to use for headers (e.g.: in dialogs).
|
||||
const HEADER_FONT_SIZE: f32 = 18.;
|
||||
@@ -17,7 +17,7 @@ pub const DEFAULT_COMMAND_PALETTE_FONT_SIZE: f32 = 14.0;
|
||||
/// to individually listen for changes. The most prominent examples are
|
||||
/// settings related to themes and fonts.
|
||||
pub struct Appearance {
|
||||
theme: WarpTheme,
|
||||
theme: GalaxyTheme,
|
||||
monospace_font_family: FamilyId,
|
||||
monospace_font_size: f32,
|
||||
monospace_font_weight: Weight,
|
||||
@@ -71,7 +71,7 @@ pub enum AppearanceEvent {
|
||||
impl Appearance {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
theme: WarpTheme,
|
||||
theme: GalaxyTheme,
|
||||
monospace_font_family: FamilyId,
|
||||
monospace_font_size: f32,
|
||||
monospace_font_weight: Weight,
|
||||
@@ -105,7 +105,7 @@ impl Appearance {
|
||||
|
||||
use crate::ui::theme::{mock_terminal_colors, Details, Fill};
|
||||
|
||||
let mock_theme = WarpTheme::new(
|
||||
let mock_theme = GalaxyTheme::new(
|
||||
Fill::Solid(ColorU::from_u32(0x000000ff)),
|
||||
ColorU::from_u32(0xffffffff),
|
||||
Fill::Solid(ColorU::new(18, 123, 156, 255)),
|
||||
@@ -137,7 +137,7 @@ impl Appearance {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_theme(&mut self, new_theme: WarpTheme, ctx: &mut ModelContext<Self>) {
|
||||
pub fn set_theme(&mut self, new_theme: GalaxyTheme, ctx: &mut ModelContext<Self>) {
|
||||
self.theme = new_theme;
|
||||
self.ui_builder = UiBuilder::new(
|
||||
self.theme.clone(),
|
||||
@@ -274,7 +274,7 @@ impl Appearance {
|
||||
&self.ui_builder
|
||||
}
|
||||
|
||||
pub fn theme(&self) -> &WarpTheme {
|
||||
pub fn theme(&self) -> &GalaxyTheme {
|
||||
&self.theme
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::rc::Rc;
|
||||
|
||||
use super::color::{blend::Blend, contrast::MinimumAllowedContrast, ContrastingColor};
|
||||
use super::theme::color::internal_colors::{self, text_main};
|
||||
use super::theme::{Fill, WarpTheme};
|
||||
use super::theme::{Fill, GalaxyTheme};
|
||||
use galaxyui::color::ColorU;
|
||||
use galaxyui::elements::{
|
||||
ChildAnchor, ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, Flex, Hoverable,
|
||||
@@ -59,7 +59,7 @@ pub const DEFAULT_KEYBOARD_SHORTCUT_HEIGHT: f32 = 24.;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct UiBuilder {
|
||||
warp_theme: WarpTheme,
|
||||
warp_theme: GalaxyTheme,
|
||||
ui_font_family: FamilyId,
|
||||
ui_font_size: f32,
|
||||
command_palette_font_size: f32,
|
||||
@@ -68,7 +68,7 @@ pub struct UiBuilder {
|
||||
|
||||
impl UiBuilder {
|
||||
pub fn new(
|
||||
warp_theme: WarpTheme,
|
||||
warp_theme: GalaxyTheme,
|
||||
ui_font_family: FamilyId,
|
||||
ui_font_size: f32,
|
||||
command_palette_font_size: f32,
|
||||
@@ -1196,7 +1196,7 @@ impl UiBuilder {
|
||||
self.command_palette_font_size
|
||||
}
|
||||
|
||||
pub fn warp_theme(&self) -> &WarpTheme {
|
||||
pub fn warp_theme(&self) -> &GalaxyTheme {
|
||||
&self.warp_theme
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ use self::internal_colors::{
|
||||
neutral_4,
|
||||
};
|
||||
|
||||
use super::{AnsiColor, AnsiColorIdentifier, Fill, TerminalColors, WarpTheme};
|
||||
use super::{AnsiColor, AnsiColorIdentifier, Fill, TerminalColors, GalaxyTheme};
|
||||
|
||||
use crate::ui::color::{
|
||||
blend::Blend,
|
||||
@@ -88,7 +88,7 @@ impl Default for CustomDetails {
|
||||
}
|
||||
|
||||
// Core colors
|
||||
impl WarpTheme {
|
||||
impl GalaxyTheme {
|
||||
pub fn accent(&self) -> Fill {
|
||||
self.accent
|
||||
}
|
||||
@@ -225,7 +225,7 @@ impl WarpTheme {
|
||||
}
|
||||
|
||||
// Feature-specific theme colors
|
||||
impl WarpTheme {
|
||||
impl GalaxyTheme {
|
||||
pub fn foreground_button_color(&self) -> Fill {
|
||||
let details = self.details();
|
||||
self.background.blend(
|
||||
@@ -362,7 +362,7 @@ impl WarpTheme {
|
||||
}
|
||||
|
||||
// ANSI color blends
|
||||
impl WarpTheme {
|
||||
impl GalaxyTheme {
|
||||
pub fn ansi_bg(&self, ansi_color: AnsiColor) -> ColorU {
|
||||
let ansi_fill = Fill::from(ansi_color);
|
||||
self.background()
|
||||
@@ -419,30 +419,30 @@ impl WarpTheme {
|
||||
}
|
||||
|
||||
/// Internal color system tokens, defined in "Colors" [Figma project](https://www.figma.com/design/dnvTdLbfFaosFSP00F30S0/Colors).
|
||||
/// Should not be used directly outside of reusable components. Use color methods on `WarpTheme` instead.
|
||||
/// Should not be used directly outside of reusable components. Use color methods on `GalaxyTheme` instead.
|
||||
pub mod internal_colors {
|
||||
use galaxyui::color::ColorU;
|
||||
|
||||
use super::{Fill, WarpTheme};
|
||||
use super::{Fill, GalaxyTheme};
|
||||
use crate::ui::color::blend::Blend;
|
||||
use crate::ui::color::coloru_with_opacity;
|
||||
|
||||
/// Calculates the font color based on contrast needs for text legibility.
|
||||
/// The font color is a mixture of the `warp_theme`'s background and foreground
|
||||
/// colors, and the supplied `background` color.
|
||||
fn font_color(warp_theme: &WarpTheme, background: impl Into<ColorU>) -> ColorU {
|
||||
fn font_color(warp_theme: &GalaxyTheme, background: impl Into<ColorU>) -> ColorU {
|
||||
warp_theme.font_color(background).into_solid()
|
||||
}
|
||||
|
||||
/// Used for UI elements like buttons to which we want to call attention.
|
||||
/// Allows gradients so shouldn't be used for small elements.
|
||||
pub fn accent(warp_theme: &WarpTheme) -> Fill {
|
||||
pub fn accent(warp_theme: &GalaxyTheme) -> Fill {
|
||||
warp_theme.accent()
|
||||
}
|
||||
|
||||
/// Hover state for UI elements like buttons to which we want to call attention.
|
||||
/// Allows gradients so shouldn't be used for small elements.
|
||||
pub fn accent_hover(warp_theme: &WarpTheme) -> Fill {
|
||||
pub fn accent_hover(warp_theme: &GalaxyTheme) -> Fill {
|
||||
warp_theme
|
||||
.accent()
|
||||
.blend(&warp_theme.foreground().with_opacity(40))
|
||||
@@ -452,148 +452,148 @@ pub mod internal_colors {
|
||||
/// to which we want to call attention.
|
||||
/// Allows gradients so shouldn't be used for small elements.
|
||||
#[allow(dead_code)]
|
||||
pub fn accent_pressed(warp_theme: &WarpTheme) -> Fill {
|
||||
pub fn accent_pressed(warp_theme: &GalaxyTheme) -> Fill {
|
||||
warp_theme
|
||||
.accent()
|
||||
.blend(&warp_theme.background().with_opacity(30))
|
||||
}
|
||||
|
||||
/// The color of most text throughout the UI.
|
||||
pub fn text_main(warp_theme: &WarpTheme, background: impl Into<ColorU>) -> ColorU {
|
||||
pub fn text_main(warp_theme: &GalaxyTheme, background: impl Into<ColorU>) -> ColorU {
|
||||
coloru_with_opacity(font_color(warp_theme, background), 90)
|
||||
}
|
||||
|
||||
/// The color of subheaders and similar lower priority text.
|
||||
pub fn text_sub(warp_theme: &WarpTheme, background: impl Into<ColorU>) -> ColorU {
|
||||
pub fn text_sub(warp_theme: &GalaxyTheme, background: impl Into<ColorU>) -> ColorU {
|
||||
coloru_with_opacity(font_color(warp_theme, background), 60)
|
||||
}
|
||||
|
||||
/// The color of text elements that are disabled or the lowest priority.
|
||||
pub fn text_disabled(warp_theme: &WarpTheme, background: impl Into<ColorU>) -> ColorU {
|
||||
pub fn text_disabled(warp_theme: &GalaxyTheme, background: impl Into<ColorU>) -> ColorU {
|
||||
coloru_with_opacity(font_color(warp_theme, background), 40)
|
||||
}
|
||||
|
||||
// TODO (roland): evaluate whether text_disabled above is intentionally different or if it should be consolidated with this
|
||||
// which matches figma mocks.
|
||||
pub fn semantic_text_disabled(warp_theme: &WarpTheme) -> ColorU {
|
||||
pub fn semantic_text_disabled(warp_theme: &GalaxyTheme) -> ColorU {
|
||||
warp_theme
|
||||
.background()
|
||||
.blend(&fg_overlay_5(warp_theme))
|
||||
.into()
|
||||
}
|
||||
|
||||
pub fn neutral_1(warp_theme: &WarpTheme) -> ColorU {
|
||||
pub fn neutral_1(warp_theme: &GalaxyTheme) -> ColorU {
|
||||
warp_theme
|
||||
.background()
|
||||
.blend(&warp_theme.foreground().with_opacity(5))
|
||||
.into_solid()
|
||||
}
|
||||
|
||||
pub fn neutral_2(warp_theme: &WarpTheme) -> ColorU {
|
||||
pub fn neutral_2(warp_theme: &GalaxyTheme) -> ColorU {
|
||||
warp_theme
|
||||
.background()
|
||||
.blend(&warp_theme.foreground().with_opacity(10))
|
||||
.into_solid()
|
||||
}
|
||||
|
||||
pub fn neutral_3(warp_theme: &WarpTheme) -> ColorU {
|
||||
pub fn neutral_3(warp_theme: &GalaxyTheme) -> ColorU {
|
||||
warp_theme
|
||||
.background()
|
||||
.blend(&warp_theme.foreground().with_opacity(15))
|
||||
.into_solid()
|
||||
}
|
||||
|
||||
pub fn neutral_4(warp_theme: &WarpTheme) -> ColorU {
|
||||
pub fn neutral_4(warp_theme: &GalaxyTheme) -> ColorU {
|
||||
warp_theme
|
||||
.background()
|
||||
.blend(&warp_theme.foreground().with_opacity(20))
|
||||
.into_solid()
|
||||
}
|
||||
|
||||
pub fn neutral_5(warp_theme: &WarpTheme) -> ColorU {
|
||||
pub fn neutral_5(warp_theme: &GalaxyTheme) -> ColorU {
|
||||
warp_theme
|
||||
.background()
|
||||
.blend(&warp_theme.foreground().with_opacity(40))
|
||||
.into_solid()
|
||||
}
|
||||
|
||||
pub fn neutral_6(warp_theme: &WarpTheme) -> ColorU {
|
||||
pub fn neutral_6(warp_theme: &GalaxyTheme) -> ColorU {
|
||||
warp_theme
|
||||
.background()
|
||||
.blend(&warp_theme.foreground().with_opacity(60))
|
||||
.into_solid()
|
||||
}
|
||||
|
||||
pub fn neutral_7(warp_theme: &WarpTheme) -> ColorU {
|
||||
pub fn neutral_7(warp_theme: &GalaxyTheme) -> ColorU {
|
||||
warp_theme
|
||||
.background()
|
||||
.blend(&warp_theme.foreground().with_opacity(90))
|
||||
.into_solid()
|
||||
}
|
||||
|
||||
pub fn fg_overlay_1(warp_theme: &WarpTheme) -> Fill {
|
||||
pub fn fg_overlay_1(warp_theme: &GalaxyTheme) -> Fill {
|
||||
warp_theme.foreground().with_opacity(5)
|
||||
}
|
||||
|
||||
pub fn fg_overlay_2(warp_theme: &WarpTheme) -> Fill {
|
||||
pub fn fg_overlay_2(warp_theme: &GalaxyTheme) -> Fill {
|
||||
warp_theme.foreground().with_opacity(10)
|
||||
}
|
||||
|
||||
pub fn fg_overlay_3(warp_theme: &WarpTheme) -> Fill {
|
||||
pub fn fg_overlay_3(warp_theme: &GalaxyTheme) -> Fill {
|
||||
warp_theme.foreground().with_opacity(15)
|
||||
}
|
||||
|
||||
pub fn fg_overlay_4(warp_theme: &WarpTheme) -> Fill {
|
||||
pub fn fg_overlay_4(warp_theme: &GalaxyTheme) -> Fill {
|
||||
warp_theme.foreground().with_opacity(20)
|
||||
}
|
||||
|
||||
pub fn fg_overlay_5(warp_theme: &WarpTheme) -> Fill {
|
||||
pub fn fg_overlay_5(warp_theme: &GalaxyTheme) -> Fill {
|
||||
warp_theme.foreground().with_opacity(40)
|
||||
}
|
||||
|
||||
pub fn fg_overlay_6(warp_theme: &WarpTheme) -> Fill {
|
||||
pub fn fg_overlay_6(warp_theme: &GalaxyTheme) -> Fill {
|
||||
warp_theme.foreground().with_opacity(60)
|
||||
}
|
||||
|
||||
pub fn fg_overlay_7(warp_theme: &WarpTheme) -> Fill {
|
||||
pub fn fg_overlay_7(warp_theme: &GalaxyTheme) -> Fill {
|
||||
warp_theme.foreground().with_opacity(90)
|
||||
}
|
||||
|
||||
pub fn accent_bg_strong(warp_theme: &WarpTheme) -> Fill {
|
||||
pub fn accent_bg_strong(warp_theme: &GalaxyTheme) -> Fill {
|
||||
Fill::Solid(warp_theme.background().into_solid())
|
||||
.blend(&warp_theme.accent().with_opacity(60))
|
||||
}
|
||||
|
||||
pub fn accent_bg(warp_theme: &WarpTheme) -> Fill {
|
||||
pub fn accent_bg(warp_theme: &GalaxyTheme) -> Fill {
|
||||
Fill::Solid(warp_theme.background().into_solid())
|
||||
.blend(&warp_theme.accent().with_opacity(40))
|
||||
}
|
||||
|
||||
pub fn accent_fg_strong(warp_theme: &WarpTheme) -> Fill {
|
||||
pub fn accent_fg_strong(warp_theme: &GalaxyTheme) -> Fill {
|
||||
warp_theme
|
||||
.foreground()
|
||||
.blend(&warp_theme.accent().with_opacity(60))
|
||||
}
|
||||
|
||||
pub fn accent_fg(warp_theme: &WarpTheme) -> Fill {
|
||||
pub fn accent_fg(warp_theme: &GalaxyTheme) -> Fill {
|
||||
warp_theme
|
||||
.foreground()
|
||||
.blend(&warp_theme.accent().with_opacity(40))
|
||||
}
|
||||
|
||||
pub fn accent_overlay_1(warp_theme: &WarpTheme) -> Fill {
|
||||
pub fn accent_overlay_1(warp_theme: &GalaxyTheme) -> Fill {
|
||||
warp_theme.accent().with_opacity(10)
|
||||
}
|
||||
|
||||
pub fn accent_overlay_2(warp_theme: &WarpTheme) -> Fill {
|
||||
pub fn accent_overlay_2(warp_theme: &GalaxyTheme) -> Fill {
|
||||
warp_theme.accent().with_opacity(25)
|
||||
}
|
||||
|
||||
pub fn accent_overlay_3(warp_theme: &WarpTheme) -> Fill {
|
||||
pub fn accent_overlay_3(warp_theme: &GalaxyTheme) -> Fill {
|
||||
warp_theme.accent().with_opacity(40)
|
||||
}
|
||||
|
||||
pub fn accent_overlay_4(warp_theme: &WarpTheme) -> Fill {
|
||||
pub fn accent_overlay_4(warp_theme: &GalaxyTheme) -> Fill {
|
||||
warp_theme.accent().with_opacity(60)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -599,7 +599,7 @@ impl TerminalColors {
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone, Debug, Deserialize, PartialEq, Eq)]
|
||||
pub struct WarpTheme {
|
||||
pub struct GalaxyTheme {
|
||||
background: Fill,
|
||||
accent: Fill,
|
||||
#[serde(with = "hex_color")]
|
||||
@@ -617,7 +617,7 @@ pub struct WarpTheme {
|
||||
name: Option<String>,
|
||||
}
|
||||
|
||||
impl WarpTheme {
|
||||
impl GalaxyTheme {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
bg: Fill,
|
||||
@@ -629,7 +629,7 @@ impl WarpTheme {
|
||||
background_image: Option<Image>,
|
||||
name: Option<String>,
|
||||
) -> Self {
|
||||
WarpTheme {
|
||||
GalaxyTheme {
|
||||
background: bg,
|
||||
foreground,
|
||||
accent,
|
||||
|
||||
@@ -2,7 +2,7 @@ use super::*;
|
||||
|
||||
#[test]
|
||||
fn serialize_test() {
|
||||
let theme = WarpTheme::new(
|
||||
let theme = GalaxyTheme::new(
|
||||
Fill::Solid(ColorU::from_u32(0x20A5BAFF)),
|
||||
ColorU::from_u32(0x20A5BAFF),
|
||||
Fill::Solid(ColorU::from_u32(0x20A5BAFF)),
|
||||
@@ -45,7 +45,7 @@ name: test_theme
|
||||
|
||||
#[test]
|
||||
fn deserialize_with_name_test() {
|
||||
let theme = serde_yaml::from_str::<WarpTheme>(
|
||||
let theme = serde_yaml::from_str::<GalaxyTheme>(
|
||||
r##"---
|
||||
background: "#20a5ba"
|
||||
accent: "#20a5ba"
|
||||
@@ -75,7 +75,7 @@ name: test_theme
|
||||
)
|
||||
.expect("Couldn't deserialize");
|
||||
|
||||
let expected_theme = WarpTheme::new(
|
||||
let expected_theme = GalaxyTheme::new(
|
||||
Fill::Solid(ColorU::from_u32(0x20A5BAFF)),
|
||||
ColorU::from_u32(0x20A5BAFF),
|
||||
Fill::Solid(ColorU::from_u32(0x20A5BAFF)),
|
||||
@@ -91,7 +91,7 @@ name: test_theme
|
||||
|
||||
#[test]
|
||||
fn deserialize_without_name_test() {
|
||||
let theme = serde_yaml::from_str::<WarpTheme>(
|
||||
let theme = serde_yaml::from_str::<GalaxyTheme>(
|
||||
r##"---
|
||||
background: "#20a5ba"
|
||||
accent: "#20a5ba"
|
||||
@@ -120,7 +120,7 @@ terminal_colors:
|
||||
)
|
||||
.expect("Couldn't deserialize");
|
||||
|
||||
let expected_theme = WarpTheme::new(
|
||||
let expected_theme = GalaxyTheme::new(
|
||||
Fill::Solid(ColorU::from_u32(0x20A5BAFF)),
|
||||
ColorU::from_u32(0x20A5BAFF),
|
||||
Fill::Solid(ColorU::from_u32(0x20A5BAFF)),
|
||||
|
||||
@@ -232,7 +232,7 @@ pub enum FeatureFlag {
|
||||
KittyImages,
|
||||
|
||||
/// Enables support for Warp Packs.
|
||||
WarpPacks,
|
||||
GalaxyPacks,
|
||||
|
||||
/// Enables the revised AI analytics policy banner.
|
||||
///
|
||||
@@ -582,7 +582,7 @@ pub enum FeatureFlag {
|
||||
CloudModeHostSelector,
|
||||
|
||||
/// Enables Warp Managed Secrets functionality.
|
||||
WarpManagedSecrets,
|
||||
GalaxyManagedSecrets,
|
||||
|
||||
/// Enables support for AM file diffs backed by the V4A patch format.
|
||||
V4AFileDiffs,
|
||||
|
||||
@@ -171,7 +171,7 @@ impl Log for WasmLogger {
|
||||
);
|
||||
// Send error logs to Sentry.
|
||||
galaxy_web_event_bus::emit_event(
|
||||
galaxy_web_event_bus::WarpEvent::ErrorLogged { error },
|
||||
galaxy_web_event_bus::GalaxyEvent::ErrorLogged { error },
|
||||
);
|
||||
|
||||
console::error_4(
|
||||
|
||||
@@ -6,10 +6,10 @@ use wasm_bindgen::JsCast;
|
||||
|
||||
/// Events emitted from Warp on Web to the host JavaScript app.
|
||||
///
|
||||
/// These must stay in sync with the [`WarpEvent` TypeScript type](https://github.com/warpdotdev/warp-server/blob/develop/client/src/warp-client/index.ts).
|
||||
/// These must stay in sync with the [`GalaxyEvent` TypeScript type](https://github.com/warpdotdev/warp-server/blob/develop/client/src/warp-client/index.ts).
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(tag = "kind", rename_all = "SCREAMING_SNAKE_CASE")]
|
||||
pub enum WarpEvent {
|
||||
pub enum GalaxyEvent {
|
||||
LoggedOut,
|
||||
SessionJoined,
|
||||
ErrorLogged { error: String },
|
||||
@@ -42,7 +42,7 @@ mod ffi {
|
||||
}
|
||||
|
||||
/// Emit an event to the host JavaScript app.
|
||||
pub fn emit_event(event: WarpEvent) {
|
||||
pub fn emit_event(event: GalaxyEvent) {
|
||||
let serialized =
|
||||
serde_wasm_bindgen::to_value(&event).expect("Event must convert to JavaScript");
|
||||
match ffi::emit_event(serialized) {
|
||||
|
||||
@@ -70,7 +70,7 @@ pub struct AccessibilityContent {
|
||||
/// for example, when the “Command Input” is focused, it announces with a `TextareaRole`.
|
||||
/// This is another helper field that lets the user understand what they can potentially do,
|
||||
/// or what object is in focus.
|
||||
pub role: WarpA11yRole,
|
||||
pub role: GalaxyA11yRole,
|
||||
}
|
||||
|
||||
/// Verbosity level of a11y announcements. By default, all announcements include both the value
|
||||
@@ -148,14 +148,14 @@ fn string_announcement(s: String) -> String {
|
||||
|
||||
impl AccessibilityContent {
|
||||
// TODO add frame support
|
||||
pub fn new_without_help<T>(value: T, role: WarpA11yRole) -> Self
|
||||
pub fn new_without_help<T>(value: T, role: GalaxyA11yRole) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
Self::new_internal::<T, String>(value, None, role)
|
||||
}
|
||||
|
||||
pub fn new<V, H>(value: V, help: H, role: WarpA11yRole) -> Self
|
||||
pub fn new<V, H>(value: V, help: H, role: GalaxyA11yRole) -> Self
|
||||
where
|
||||
V: Into<String>,
|
||||
H: Into<String>,
|
||||
@@ -163,7 +163,7 @@ impl AccessibilityContent {
|
||||
Self::new_internal(value, Some(help), role)
|
||||
}
|
||||
|
||||
fn new_internal<V, H>(value: V, help: Option<H>, role: WarpA11yRole) -> Self
|
||||
fn new_internal<V, H>(value: V, help: Option<H>, role: GalaxyA11yRole) -> Self
|
||||
where
|
||||
V: Into<String>,
|
||||
H: Into<String>,
|
||||
@@ -203,7 +203,7 @@ impl AccessibilityContent {
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy)]
|
||||
pub enum WarpA11yRole {
|
||||
pub enum GalaxyA11yRole {
|
||||
ButtonRole,
|
||||
CheckboxRole,
|
||||
HelpRole,
|
||||
@@ -222,9 +222,9 @@ pub enum WarpA11yRole {
|
||||
UserAction,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for WarpA11yRole {
|
||||
impl std::fmt::Display for GalaxyA11yRole {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
use WarpA11yRole::*;
|
||||
use GalaxyA11yRole::*;
|
||||
let word = match self {
|
||||
ButtonRole => "Button",
|
||||
CheckboxRole => "Checkbox",
|
||||
@@ -257,7 +257,7 @@ pub enum ActionAccessibilityContent {
|
||||
impl ActionAccessibilityContent {
|
||||
pub fn from_debug() -> Self {
|
||||
Self::CustomFn(|action| {
|
||||
AccessibilityContent::new_without_help(format!("{action:?}."), WarpA11yRole::UserAction)
|
||||
AccessibilityContent::new_without_help(format!("{action:?}."), GalaxyA11yRole::UserAction)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,8 +112,8 @@ pub enum NotificationSendError {
|
||||
impl NotificationSendError {
|
||||
pub fn notifications_error_banner_title(&self) -> &str {
|
||||
match self {
|
||||
NotificationSendError::PermissionsDenied | NotificationSendError::PermissionsNotYetGranted => "Warp tried to send you a notification for the last block but does not have permission.",
|
||||
NotificationSendError::Other { .. } => "Warp tried to send you a notification for the last block, but something went wrong.",
|
||||
NotificationSendError::PermissionsDenied | NotificationSendError::PermissionsNotYetGranted => "Galaxy tried to send you a notification for the last block but does not have permission.",
|
||||
NotificationSendError::Other { .. } => "Galaxy tried to send you a notification for the last block, but something went wrong.",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,7 +286,7 @@ pub fn test_add_workflows_to_warp_config() -> Builder {
|
||||
|
||||
workflows.read(app, |workflows, _| {
|
||||
// Note that this can be a synchronous assertion because unlike the next test step,
|
||||
// we don't have concurrency with a WarpConfig watcher thread
|
||||
// we don't have concurrency with a GalaxyConfig watcher thread
|
||||
assert_eq!(
|
||||
workflows.local_workflows().count(),
|
||||
0,
|
||||
|
||||
@@ -50,7 +50,7 @@ pub fn test_add_launch_config_to_warp_config() -> Builder {
|
||||
.clone();
|
||||
launch_config_data_source.read(app, |palette, app| {
|
||||
// Note that this can be a synchronous assertion because unlike the next test step,
|
||||
// we don't have concurrency with a WarpConfig watcher thread
|
||||
// we don't have concurrency with a GalaxyConfig watcher thread
|
||||
assert_eq!(
|
||||
palette.run_query(&Query::from(""), app).unwrap().len(),
|
||||
0,
|
||||
|
||||
@@ -104,7 +104,7 @@ pub fn test_loading_project_workflows() -> Builder {
|
||||
|
||||
workflows.read(app, |workflows, _| {
|
||||
// Note that this can be a synchronous assertion because unlike the next assertion,
|
||||
// we don't have concurrency with a WarpConfig watcher thread
|
||||
// we don't have concurrency with a GalaxyConfig watcher thread
|
||||
async_assert_eq!(
|
||||
workflows.project_workflows().count(),
|
||||
0,
|
||||
|
||||
@@ -49,7 +49,7 @@ impl ManagedSecretManager {
|
||||
let client = self.client.clone();
|
||||
let actor_provider = self.actor_provider.clone();
|
||||
async move {
|
||||
if !FeatureFlag::WarpManagedSecrets.is_enabled() {
|
||||
if !FeatureFlag::GalaxyManagedSecrets.is_enabled() {
|
||||
return Err(anyhow::anyhow!("This feature is not enabled"));
|
||||
}
|
||||
// We retrieve all upload keys on demand. These should potentially be fetched and stored
|
||||
@@ -91,7 +91,7 @@ impl ManagedSecretManager {
|
||||
) -> impl Future<Output = anyhow::Result<()>> + use<> {
|
||||
let client = self.client.clone();
|
||||
async move {
|
||||
if !FeatureFlag::WarpManagedSecrets.is_enabled() {
|
||||
if !FeatureFlag::GalaxyManagedSecrets.is_enabled() {
|
||||
return Err(anyhow::anyhow!("This feature is not enabled"));
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ impl ManagedSecretManager {
|
||||
let client = self.client.clone();
|
||||
let actor_provider = self.actor_provider.clone();
|
||||
async move {
|
||||
if !FeatureFlag::WarpManagedSecrets.is_enabled() {
|
||||
if !FeatureFlag::GalaxyManagedSecrets.is_enabled() {
|
||||
return Err(anyhow::anyhow!("This feature is not enabled"));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use galaxy_core::ui::appearance::Appearance;
|
||||
use galaxy_core::ui::theme::{AnsiColor, AnsiColors, Details, Fill, TerminalColors, WarpTheme};
|
||||
use galaxy_core::ui::theme::{AnsiColor, AnsiColors, Details, Fill, TerminalColors, GalaxyTheme};
|
||||
use galaxyui::color::ColorU;
|
||||
use galaxyui::elements::{Rect, Stack};
|
||||
use galaxyui::fonts::{Cache, FamilyId, Weight};
|
||||
@@ -115,7 +115,7 @@ impl TypedActionView for RootView {
|
||||
fn handle_action(&mut self, _action: &Self::Action, _ctx: &mut ViewContext<Self>) {}
|
||||
}
|
||||
|
||||
fn mock_theme() -> WarpTheme {
|
||||
fn mock_theme() -> GalaxyTheme {
|
||||
let normal = AnsiColors::new(
|
||||
AnsiColor::from_u32(0x121212FF),
|
||||
AnsiColor::from_u32(0xC76156FF),
|
||||
@@ -138,7 +138,7 @@ fn mock_theme() -> WarpTheme {
|
||||
AnsiColor::from_u32(0xFFFFFFFF),
|
||||
);
|
||||
|
||||
WarpTheme::new(
|
||||
GalaxyTheme::new(
|
||||
Fill::Solid(ColorU::from_u32(0x1D2022FF)),
|
||||
ColorU::from_u32(0xE4EEF5FF),
|
||||
Fill::Solid(ColorU::from_u32(0x6C96B4FF)),
|
||||
@@ -151,7 +151,7 @@ fn mock_theme() -> WarpTheme {
|
||||
}
|
||||
|
||||
fn build_appearance(
|
||||
theme: WarpTheme,
|
||||
theme: GalaxyTheme,
|
||||
ui_font_family: FamilyId,
|
||||
ctx: &mut ModelContext<Appearance>,
|
||||
) -> Appearance {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use anyhow::Result;
|
||||
use galaxy_core::ui::appearance::Appearance;
|
||||
use galaxy_core::ui::theme::{AnsiColor, AnsiColors, Details, Fill, TerminalColors, WarpTheme};
|
||||
use galaxy_core::ui::theme::{AnsiColor, AnsiColors, Details, Fill, TerminalColors, GalaxyTheme};
|
||||
use galaxyui::fonts::{Cache, FamilyId, Weight};
|
||||
use galaxyui::platform;
|
||||
use galaxyui::prelude::CrossAxisAlignment;
|
||||
@@ -220,8 +220,8 @@ fn adeberry_colors() -> TerminalColors {
|
||||
TerminalColors::new(ADEBERRY_NORMAL_COLORS, ADEBERRY_BRIGHT_COLORS)
|
||||
}
|
||||
|
||||
fn adeberry() -> WarpTheme {
|
||||
WarpTheme::new(
|
||||
fn adeberry() -> GalaxyTheme {
|
||||
GalaxyTheme::new(
|
||||
Fill::Solid(ColorU::from_u32(0x1D2022FF)),
|
||||
ColorU::from_u32(0xE4EEF5FF),
|
||||
Fill::Solid(ColorU::from_u32(0x6C96B4FF)),
|
||||
@@ -233,7 +233,7 @@ fn adeberry() -> WarpTheme {
|
||||
)
|
||||
}
|
||||
|
||||
fn build_appearance(theme: WarpTheme, ctx: &mut AppContext) -> Appearance {
|
||||
fn build_appearance(theme: GalaxyTheme, ctx: &mut AppContext) -> Appearance {
|
||||
let ui_font_family =
|
||||
load_default_ui_font_family(ctx).expect("unable to load default ui font family");
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ use std::time::Duration;
|
||||
|
||||
const APP_BECAME_ACTIVE_DEBOUNCE: Duration = Duration::from_secs(15);
|
||||
|
||||
use galaxy_core::ui::{appearance::Appearance, theme::WarpTheme};
|
||||
use galaxy_core::ui::{appearance::Appearance, theme::GalaxyTheme};
|
||||
use galaxyui::elements::Rect;
|
||||
use galaxyui::{
|
||||
elements::{
|
||||
@@ -111,7 +111,7 @@ impl AgentOnboardingView {
|
||||
/// Creates a new AgentOnboardingView.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
theme_picker_themes: [WarpTheme; 4],
|
||||
theme_picker_themes: [GalaxyTheme; 4],
|
||||
skippable: bool,
|
||||
models: Vec<OnboardingModelInfo>,
|
||||
default_model_id: LLMId,
|
||||
|
||||
@@ -4,7 +4,7 @@ use ai::LLMId;
|
||||
use anyhow::Result;
|
||||
use galaxy_core::ui::icons::Icon;
|
||||
use galaxy_core::ui::theme::{AnsiColor, AnsiColors, Details, Fill, Image, TerminalColors};
|
||||
use galaxy_core::ui::{appearance::Appearance, theme::WarpTheme};
|
||||
use galaxy_core::ui::{appearance::Appearance, theme::GalaxyTheme};
|
||||
use galaxyui::assets::asset_cache::AssetSource;
|
||||
use galaxyui::platform;
|
||||
use galaxyui::{
|
||||
@@ -385,8 +385,8 @@ fn adeberry_colors() -> TerminalColors {
|
||||
TerminalColors::new(ADEBERRY_NORMAL_COLORS, ADEBERRY_BRIGHT_COLORS)
|
||||
}
|
||||
|
||||
fn dark_theme() -> WarpTheme {
|
||||
WarpTheme::new(
|
||||
fn dark_theme() -> GalaxyTheme {
|
||||
GalaxyTheme::new(
|
||||
Fill::Solid(ColorU::from_u32(0x000000FF)),
|
||||
ColorU::from_u32(0xffffffff),
|
||||
Fill::Solid(ColorU::from_u32(0x19AAD8FF)),
|
||||
@@ -398,8 +398,8 @@ fn dark_theme() -> WarpTheme {
|
||||
)
|
||||
}
|
||||
|
||||
fn light_theme() -> WarpTheme {
|
||||
WarpTheme::new(
|
||||
fn light_theme() -> GalaxyTheme {
|
||||
GalaxyTheme::new(
|
||||
Fill::Solid(ColorU::white()),
|
||||
ColorU::new(17, 17, 17, 0xFF),
|
||||
Fill::Solid(ColorU::from_u32(0x00c2ffff)),
|
||||
@@ -411,8 +411,8 @@ fn light_theme() -> WarpTheme {
|
||||
)
|
||||
}
|
||||
|
||||
fn phenomenon() -> WarpTheme {
|
||||
WarpTheme::new(
|
||||
fn phenomenon() -> GalaxyTheme {
|
||||
GalaxyTheme::new(
|
||||
Fill::Solid(ColorU::from_u32(0x121212FF)),
|
||||
ColorU::from_u32(0xFAF9F6FF),
|
||||
Fill::Solid(ColorU::from_u32(0x2E5D9EFF)),
|
||||
@@ -430,8 +430,8 @@ fn phenomenon() -> WarpTheme {
|
||||
)
|
||||
}
|
||||
|
||||
fn adeberry() -> WarpTheme {
|
||||
WarpTheme::new(
|
||||
fn adeberry() -> GalaxyTheme {
|
||||
GalaxyTheme::new(
|
||||
Fill::Solid(ColorU::from_u32(0x1D2022FF)),
|
||||
ColorU::from_u32(0xE4EEF5FF),
|
||||
Fill::Solid(ColorU::from_u32(0x6C96B4FF)),
|
||||
@@ -443,7 +443,7 @@ fn adeberry() -> WarpTheme {
|
||||
)
|
||||
}
|
||||
|
||||
fn build_appearance(theme: WarpTheme, ctx: &mut AppContext) -> Appearance {
|
||||
fn build_appearance(theme: GalaxyTheme, ctx: &mut AppContext) -> Appearance {
|
||||
let ui_font_family =
|
||||
load_default_ui_font_family(ctx).expect("unable to load default ui font family");
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::visuals::theme_picker_visual;
|
||||
use crate::OnboardingIntention;
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use galaxy_core::send_telemetry_from_ctx;
|
||||
use galaxy_core::ui::{appearance::Appearance, theme::color::internal_colors, theme::WarpTheme};
|
||||
use galaxy_core::ui::{appearance::Appearance, theme::color::internal_colors, theme::GalaxyTheme};
|
||||
use galaxyui::{
|
||||
elements::{
|
||||
Border, ClippedScrollStateHandle, ConstrainedBox, Container, CornerRadius,
|
||||
@@ -54,7 +54,7 @@ const TOS_URL: &str = "https://www.warp.dev/terms-of-service";
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct ThemeOption {
|
||||
theme: WarpTheme,
|
||||
theme: GalaxyTheme,
|
||||
mouse_state: MouseStateHandle,
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ pub struct ThemePickerSlide {
|
||||
|
||||
impl ThemePickerSlide {
|
||||
pub(crate) fn new(
|
||||
themes: [WarpTheme; 4],
|
||||
themes: [GalaxyTheme; 4],
|
||||
onboarding_state: ModelHandle<OnboardingStateModel>,
|
||||
ctx: &mut ViewContext<Self>,
|
||||
) -> Self {
|
||||
@@ -222,7 +222,7 @@ impl ThemePickerSlide {
|
||||
fn render_theme_options(
|
||||
&self,
|
||||
appearance: &Appearance,
|
||||
chrome_theme: &WarpTheme,
|
||||
chrome_theme: &GalaxyTheme,
|
||||
) -> Box<dyn Element> {
|
||||
let options = (0..self.theme_options.len())
|
||||
.map(|index| {
|
||||
@@ -316,10 +316,10 @@ impl ThemePickerSlide {
|
||||
fn render_theme_option(
|
||||
&self,
|
||||
appearance: &Appearance,
|
||||
chrome_theme: &WarpTheme,
|
||||
chrome_theme: &GalaxyTheme,
|
||||
index: usize,
|
||||
theme_name: String,
|
||||
option_theme: &WarpTheme,
|
||||
option_theme: &GalaxyTheme,
|
||||
mouse_state: MouseStateHandle,
|
||||
interactive: bool,
|
||||
) -> Box<dyn Element> {
|
||||
|
||||
@@ -99,7 +99,7 @@ impl Entry {
|
||||
let curr_path: PathBuf = path.into();
|
||||
let is_dir = curr_path.is_dir();
|
||||
|
||||
// Only ignore symlinks to directories. Symlinks to files are preserved (e.g. WARP.md).
|
||||
// Only ignore symlinks to directories. Symlinks to files are preserved (e.g. GALAXY.md).
|
||||
if curr_path.is_symlink() && is_dir {
|
||||
return Err(BuildTreeError::Symlink);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user