Add site compatibility diagnostics page
This commit is contained in:
@@ -22,6 +22,7 @@ mod search;
|
|||||||
mod settings;
|
mod settings;
|
||||||
mod shortcuts;
|
mod shortcuts;
|
||||||
mod sidebar_tabs;
|
mod sidebar_tabs;
|
||||||
|
mod site_compatibility;
|
||||||
mod site_permissions_settings;
|
mod site_permissions_settings;
|
||||||
mod site_settings;
|
mod site_settings;
|
||||||
mod sleep;
|
mod sleep;
|
||||||
@@ -67,6 +68,7 @@ impl ElyShell {
|
|||||||
"ely://history" => self.render_history_page(snapshot, cx),
|
"ely://history" => self.render_history_page(snapshot, cx),
|
||||||
"ely://archive" => self.render_archive_page(snapshot, cx),
|
"ely://archive" => self.render_archive_page(snapshot, cx),
|
||||||
"ely://task-manager" => self.render_task_manager_page(snapshot),
|
"ely://task-manager" => self.render_task_manager_page(snapshot),
|
||||||
|
"ely://site-compatibility" => self.render_site_compatibility_page(snapshot),
|
||||||
"ely://plugins" => self.render_plugin_catalog_page(snapshot, cx),
|
"ely://plugins" => self.render_plugin_catalog_page(snapshot, cx),
|
||||||
url if url.starts_with("ely://crash/") => self.render_crash_route(snapshot, url, cx),
|
url if url.starts_with("ely://crash/") => self.render_crash_route(snapshot, url, cx),
|
||||||
url if url.starts_with("ely://plugin/") => {
|
url if url.starts_with("ely://plugin/") => {
|
||||||
|
|||||||
@@ -0,0 +1,429 @@
|
|||||||
|
use ely_browser_core::BrowserSnapshot;
|
||||||
|
use ely_design_system::colors;
|
||||||
|
use ely_domain::{BrowserTab, ProfileKind, SiteOrigin, TabState};
|
||||||
|
use gpui::{AnyElement, IntoElement, ParentElement, Styled, div, px, rgb};
|
||||||
|
use gpui_component::{IconName, StyledExt, clipboard::Clipboard, scroll::ScrollableElement};
|
||||||
|
|
||||||
|
use super::{ElyShell, render_canvas_surface};
|
||||||
|
|
||||||
|
const BUILD_REVISION: &str = env!("ELY_BUILD_REVISION");
|
||||||
|
const GPUI_VERSION: &str = env!("ELY_GPUI_VERSION");
|
||||||
|
const SERVO_VERSION: &str = env!("ELY_SERVO_VERSION");
|
||||||
|
|
||||||
|
impl ElyShell {
|
||||||
|
pub(super) fn render_site_compatibility_page(
|
||||||
|
&mut self,
|
||||||
|
snapshot: &BrowserSnapshot,
|
||||||
|
) -> AnyElement {
|
||||||
|
let Some(active_tab) = active_tab(snapshot) else {
|
||||||
|
return render_canvas_surface(
|
||||||
|
div().size_full().p_8().flex().flex_col().gap_5().child(render_missing_tab()),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
let origin = origin_for_tab(active_tab);
|
||||||
|
let report = diagnostic_report(snapshot, active_tab, origin.as_ref());
|
||||||
|
|
||||||
|
render_canvas_surface(
|
||||||
|
div()
|
||||||
|
.size_full()
|
||||||
|
.p_8()
|
||||||
|
.flex()
|
||||||
|
.flex_col()
|
||||||
|
.gap_5()
|
||||||
|
.child(render_compatibility_header(snapshot, active_tab, report.clone()))
|
||||||
|
.child(render_compatibility_summary(snapshot, active_tab, origin.as_ref()))
|
||||||
|
.child(render_compatibility_rows(snapshot, active_tab, origin.as_ref())),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_missing_tab() -> AnyElement {
|
||||||
|
div()
|
||||||
|
.rounded_md()
|
||||||
|
.border_1()
|
||||||
|
.border_color(rgb(colors::HAIRLINE))
|
||||||
|
.bg(rgb(colors::CANVAS_SOFT))
|
||||||
|
.px_4()
|
||||||
|
.py_3()
|
||||||
|
.flex()
|
||||||
|
.items_center()
|
||||||
|
.gap_3()
|
||||||
|
.child(div().text_color(rgb(colors::ERROR)).child(IconName::TriangleAlert))
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.text_sm()
|
||||||
|
.font_semibold()
|
||||||
|
.text_color(rgb(colors::INK))
|
||||||
|
.child("Active tab is unavailable."),
|
||||||
|
)
|
||||||
|
.into_any_element()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_compatibility_header(
|
||||||
|
snapshot: &BrowserSnapshot,
|
||||||
|
active_tab: &BrowserTab,
|
||||||
|
report: String,
|
||||||
|
) -> AnyElement {
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.items_end()
|
||||||
|
.justify_between()
|
||||||
|
.gap_4()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.min_w_0()
|
||||||
|
.flex()
|
||||||
|
.flex_col()
|
||||||
|
.gap_2()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.text_size(px(26.0))
|
||||||
|
.text_color(rgb(colors::INK))
|
||||||
|
.child("Site Compatibility"),
|
||||||
|
)
|
||||||
|
.child(div().text_sm().truncate().text_color(rgb(colors::MUTED)).child(format!(
|
||||||
|
"{} / {}",
|
||||||
|
snapshot.active_profile_name,
|
||||||
|
diagnostic_url_scope(active_tab)
|
||||||
|
))),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.items_center()
|
||||||
|
.gap_2()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.items_center()
|
||||||
|
.gap_2()
|
||||||
|
.text_xs()
|
||||||
|
.font_semibold()
|
||||||
|
.text_color(rgb(colors::MUTED))
|
||||||
|
.child(IconName::Inspector)
|
||||||
|
.child("Diagnostics"),
|
||||||
|
)
|
||||||
|
.child(Clipboard::new("copy-site-compatibility-diagnostics").value(report)),
|
||||||
|
)
|
||||||
|
.into_any_element()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_compatibility_summary(
|
||||||
|
snapshot: &BrowserSnapshot,
|
||||||
|
active_tab: &BrowserTab,
|
||||||
|
origin: Option<&SiteOrigin>,
|
||||||
|
) -> AnyElement {
|
||||||
|
let (title, detail, icon, color) = match active_tab.state() {
|
||||||
|
TabState::Ready => (
|
||||||
|
"Current page is ready",
|
||||||
|
"Diagnostics omit URL path and query before copying.",
|
||||||
|
IconName::CircleCheck,
|
||||||
|
colors::SUCCESS,
|
||||||
|
),
|
||||||
|
TabState::Loading => (
|
||||||
|
"Current page is loading",
|
||||||
|
"Capture diagnostics after the page reaches a stable state.",
|
||||||
|
IconName::LoaderCircle,
|
||||||
|
colors::PRIMARY,
|
||||||
|
),
|
||||||
|
TabState::Crashed => (
|
||||||
|
"Current page crashed",
|
||||||
|
"The copied report includes tab state and profile-scoped permissions.",
|
||||||
|
IconName::TriangleAlert,
|
||||||
|
colors::ERROR,
|
||||||
|
),
|
||||||
|
TabState::Discarded => (
|
||||||
|
"Current page is sleeping",
|
||||||
|
"Wake the tab to refresh Servo rendering details.",
|
||||||
|
IconName::EyeOff,
|
||||||
|
colors::MUTED,
|
||||||
|
),
|
||||||
|
TabState::Archived => (
|
||||||
|
"Current page is archived",
|
||||||
|
"Restore the tab to refresh Servo rendering details.",
|
||||||
|
IconName::Folder,
|
||||||
|
colors::MUTED,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
div()
|
||||||
|
.rounded_md()
|
||||||
|
.border_1()
|
||||||
|
.border_color(rgb(colors::HAIRLINE))
|
||||||
|
.bg(rgb(colors::CANVAS_SOFT))
|
||||||
|
.px_4()
|
||||||
|
.py_3()
|
||||||
|
.flex()
|
||||||
|
.items_center()
|
||||||
|
.justify_between()
|
||||||
|
.gap_4()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.min_w_0()
|
||||||
|
.flex()
|
||||||
|
.items_center()
|
||||||
|
.gap_3()
|
||||||
|
.child(div().text_color(rgb(color)).child(icon))
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.min_w_0()
|
||||||
|
.flex()
|
||||||
|
.flex_col()
|
||||||
|
.gap_1()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.text_sm()
|
||||||
|
.font_semibold()
|
||||||
|
.text_color(rgb(colors::INK))
|
||||||
|
.child(title),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div().text_xs().truncate().text_color(rgb(colors::MUTED)).child(detail),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.items_center()
|
||||||
|
.gap_3()
|
||||||
|
.text_xs()
|
||||||
|
.font_semibold()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.text_color(rgb(colors::MUTED))
|
||||||
|
.child(format!("{} permissions", site_permission_count(snapshot, origin))),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.text_color(rgb(colors::MUTED))
|
||||||
|
.child(format!("{} audits", site_permission_audit_count(snapshot, origin))),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.into_any_element()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_compatibility_rows(
|
||||||
|
snapshot: &BrowserSnapshot,
|
||||||
|
active_tab: &BrowserTab,
|
||||||
|
origin: Option<&SiteOrigin>,
|
||||||
|
) -> AnyElement {
|
||||||
|
div()
|
||||||
|
.flex_1()
|
||||||
|
.min_h_0()
|
||||||
|
.flex()
|
||||||
|
.flex_col()
|
||||||
|
.overflow_y_scrollbar()
|
||||||
|
.border_t_1()
|
||||||
|
.border_color(rgb(colors::HAIRLINE))
|
||||||
|
.child(compatibility_row(
|
||||||
|
IconName::Globe,
|
||||||
|
"URL Scope",
|
||||||
|
diagnostic_url_scope(active_tab),
|
||||||
|
"Scheme, host, and port only",
|
||||||
|
))
|
||||||
|
.child(compatibility_row(
|
||||||
|
IconName::CircleUser,
|
||||||
|
"Profile",
|
||||||
|
&snapshot.active_profile_name,
|
||||||
|
profile_kind_label(&snapshot.active_profile_kind),
|
||||||
|
))
|
||||||
|
.child(compatibility_row(
|
||||||
|
IconName::GalleryVerticalEnd,
|
||||||
|
"Space",
|
||||||
|
&snapshot.active_space_name,
|
||||||
|
"Active workspace context",
|
||||||
|
))
|
||||||
|
.child(compatibility_row(
|
||||||
|
IconName::CircleCheck,
|
||||||
|
"Tab State",
|
||||||
|
tab_state_label(active_tab.state()),
|
||||||
|
active_tab.title(),
|
||||||
|
))
|
||||||
|
.child(compatibility_row(
|
||||||
|
IconName::Globe,
|
||||||
|
"Servo",
|
||||||
|
format!("servo {SERVO_VERSION}"),
|
||||||
|
"Web rendering engine",
|
||||||
|
))
|
||||||
|
.child(compatibility_row(
|
||||||
|
IconName::Frame,
|
||||||
|
"GPUI",
|
||||||
|
format!("gpui {GPUI_VERSION}"),
|
||||||
|
"Native shell renderer",
|
||||||
|
))
|
||||||
|
.child(compatibility_row(IconName::GitHub, "Build", BUILD_REVISION, "Git revision"))
|
||||||
|
.child(compatibility_row(
|
||||||
|
IconName::CircleCheck,
|
||||||
|
"Site Permissions",
|
||||||
|
site_permission_count(snapshot, origin).to_string(),
|
||||||
|
"Profile-scoped configured decisions",
|
||||||
|
))
|
||||||
|
.child(compatibility_row(
|
||||||
|
IconName::Inspector,
|
||||||
|
"Console Summary",
|
||||||
|
"No console events captured",
|
||||||
|
"Current Servo host bridge does not expose console events",
|
||||||
|
))
|
||||||
|
.into_any_element()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compatibility_row(
|
||||||
|
icon: IconName,
|
||||||
|
label: &'static str,
|
||||||
|
value: impl Into<String>,
|
||||||
|
detail: impl Into<String>,
|
||||||
|
) -> AnyElement {
|
||||||
|
let value = value.into();
|
||||||
|
let detail = detail.into();
|
||||||
|
|
||||||
|
div()
|
||||||
|
.py_3()
|
||||||
|
.border_b_1()
|
||||||
|
.border_color(rgb(colors::HAIRLINE))
|
||||||
|
.flex()
|
||||||
|
.items_center()
|
||||||
|
.justify_between()
|
||||||
|
.gap_4()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.min_w_0()
|
||||||
|
.flex()
|
||||||
|
.items_center()
|
||||||
|
.gap_3()
|
||||||
|
.child(div().text_color(rgb(colors::MUTED_SOFT)).child(icon))
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.min_w_0()
|
||||||
|
.flex()
|
||||||
|
.flex_col()
|
||||||
|
.gap_1()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.text_sm()
|
||||||
|
.font_semibold()
|
||||||
|
.truncate()
|
||||||
|
.text_color(rgb(colors::INK))
|
||||||
|
.child(label),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div().text_xs().truncate().text_color(rgb(colors::MUTED)).child(detail),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.max_w(px(360.0))
|
||||||
|
.truncate()
|
||||||
|
.text_sm()
|
||||||
|
.font_semibold()
|
||||||
|
.text_color(rgb(colors::INK))
|
||||||
|
.child(value),
|
||||||
|
)
|
||||||
|
.into_any_element()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn diagnostic_report(
|
||||||
|
snapshot: &BrowserSnapshot,
|
||||||
|
active_tab: &BrowserTab,
|
||||||
|
origin: Option<&SiteOrigin>,
|
||||||
|
) -> String {
|
||||||
|
[
|
||||||
|
"ELY Browser Site Compatibility Diagnostics".to_string(),
|
||||||
|
format!("Build: {BUILD_REVISION}"),
|
||||||
|
format!("Servo: servo {SERVO_VERSION}"),
|
||||||
|
format!("GPUI: gpui {GPUI_VERSION}"),
|
||||||
|
format!("Space: {}", snapshot.active_space_name),
|
||||||
|
format!("Profile: {}", snapshot.active_profile_name),
|
||||||
|
format!("Profile kind: {}", profile_kind_label(&snapshot.active_profile_kind)),
|
||||||
|
format!("URL scope: {}", diagnostic_url_scope(active_tab)),
|
||||||
|
format!("Tab title: {}", active_tab.title()),
|
||||||
|
format!("Tab state: {}", tab_state_label(active_tab.state())),
|
||||||
|
format!("Site permissions: {}", site_permission_count(snapshot, origin)),
|
||||||
|
format!("Permission audit events: {}", site_permission_audit_count(snapshot, origin)),
|
||||||
|
"Console summary: No console events captured by the current Servo host bridge.".to_string(),
|
||||||
|
]
|
||||||
|
.join("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn active_tab(snapshot: &BrowserSnapshot) -> Option<&BrowserTab> {
|
||||||
|
snapshot.tabs.iter().find(|tab| tab.id() == &snapshot.active_tab_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn origin_for_tab(tab: &BrowserTab) -> Option<SiteOrigin> {
|
||||||
|
SiteOrigin::from_url(tab.url()).ok().flatten()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn diagnostic_url_scope(tab: &BrowserTab) -> String {
|
||||||
|
origin_for_tab(tab)
|
||||||
|
.map_or_else(|| tab.url().as_str().to_string(), |origin| origin.as_str().to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn site_permission_count(snapshot: &BrowserSnapshot, origin: Option<&SiteOrigin>) -> usize {
|
||||||
|
let Some(origin) = origin else {
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
snapshot.site_permissions.iter().filter(|entry| entry.origin() == origin).count()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn site_permission_audit_count(snapshot: &BrowserSnapshot, origin: Option<&SiteOrigin>) -> usize {
|
||||||
|
let Some(origin) = origin else {
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
snapshot.site_permission_audit_events.iter().filter(|event| event.origin() == origin).count()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn profile_kind_label(profile_kind: &ProfileKind) -> &'static str {
|
||||||
|
match profile_kind {
|
||||||
|
ProfileKind::Standard => "Standard",
|
||||||
|
ProfileKind::Private => "Private",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tab_state_label(state: &TabState) -> &'static str {
|
||||||
|
match state {
|
||||||
|
TabState::Loading => "Loading",
|
||||||
|
TabState::Ready => "Ready",
|
||||||
|
TabState::Crashed => "Crashed",
|
||||||
|
TabState::Discarded => "Sleeping",
|
||||||
|
TabState::Archived => "Archived",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use ely_domain::{ProfileId, SpaceId, TabId, UrlText};
|
||||||
|
|
||||||
|
use super::{BrowserTab, diagnostic_url_scope};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn diagnostic_url_scope_omits_path_and_query() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let tab = BrowserTab::new(
|
||||||
|
TabId::new(),
|
||||||
|
SpaceId::new(),
|
||||||
|
ProfileId::new(),
|
||||||
|
"Example",
|
||||||
|
UrlText::parse("https://example.com/private/path?token=secret#hash")?,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(diagnostic_url_scope(&tab), "https://example.com");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn diagnostic_url_scope_keeps_internal_route() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let tab = BrowserTab::new(
|
||||||
|
TabId::new(),
|
||||||
|
SpaceId::new(),
|
||||||
|
ProfileId::new(),
|
||||||
|
"Settings",
|
||||||
|
UrlText::parse("ely://settings/advanced")?,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(diagnostic_url_scope(&tab), "ely://settings/advanced");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@ fn internal_page_title(url: &str) -> Option<&'static str> {
|
|||||||
"ely://history" => Some("History"),
|
"ely://history" => Some("History"),
|
||||||
"ely://archive" => Some("Archived Tabs"),
|
"ely://archive" => Some("Archived Tabs"),
|
||||||
"ely://task-manager" => Some("Task Manager"),
|
"ely://task-manager" => Some("Task Manager"),
|
||||||
|
"ely://site-compatibility" => Some("Site Compatibility"),
|
||||||
"ely://plugins" => Some("Plugin Marketplace"),
|
"ely://plugins" => Some("Plugin Marketplace"),
|
||||||
url if crash_route_tab_id(url).is_some() => Some("Tab Recovery"),
|
url if crash_route_tab_id(url).is_some() => Some("Tab Recovery"),
|
||||||
url if plugin_detail_route_id(url).is_some() => Some("Plugin Details"),
|
url if plugin_detail_route_id(url).is_some() => Some("Plugin Details"),
|
||||||
@@ -198,6 +199,10 @@ pub(crate) fn task_manager_url() -> Result<UrlText, CoreError> {
|
|||||||
internal_page_url("ely://task-manager")
|
internal_page_url("ely://task-manager")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn site_compatibility_url() -> Result<UrlText, CoreError> {
|
||||||
|
internal_page_url("ely://site-compatibility")
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn plugins_url() -> Result<UrlText, CoreError> {
|
pub(crate) fn plugins_url() -> Result<UrlText, CoreError> {
|
||||||
internal_page_url("ely://plugins")
|
internal_page_url("ely://plugins")
|
||||||
}
|
}
|
||||||
@@ -263,13 +268,22 @@ const SETTINGS_ROUTE_MATCHES: &[SettingsRouteMatch] = &[
|
|||||||
},
|
},
|
||||||
SettingsRouteMatch {
|
SettingsRouteMatch {
|
||||||
route: "ely://settings/advanced",
|
route: "ely://settings/advanced",
|
||||||
exact_terms: &["advanced", "advanced settings", "runtime", "diagnostics", "diagnostic"],
|
exact_terms: &[
|
||||||
|
"advanced",
|
||||||
|
"advanced settings",
|
||||||
|
"runtime",
|
||||||
|
"diagnostics",
|
||||||
|
"diagnostic",
|
||||||
|
"compatibility",
|
||||||
|
"site compatibility",
|
||||||
|
],
|
||||||
search_terms: &[
|
search_terms: &[
|
||||||
"Advanced",
|
"Advanced",
|
||||||
"Local runtime policies and audit counters.",
|
"Local runtime policies and audit counters.",
|
||||||
"runtime policy",
|
"runtime policy",
|
||||||
"audit counters",
|
"audit counters",
|
||||||
"diagnostics",
|
"diagnostics",
|
||||||
|
"site compatibility",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
SettingsRouteMatch {
|
SettingsRouteMatch {
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ use crate::{
|
|||||||
move_tab_space_name, new_private_profile_name, new_profile_name, new_space_name, note_body,
|
move_tab_space_name, new_private_profile_name, new_profile_name, new_space_name, note_body,
|
||||||
notes_url, plugin_detail_url, plugin_settings_url, plugins_url, reading_list_url,
|
notes_url, plugin_detail_url, plugin_settings_url, plugins_url, reading_list_url,
|
||||||
reading_progress_percent, rename_tab_group_name, search_url, settings_page_url,
|
reading_progress_percent, rename_tab_group_name, search_url, settings_page_url,
|
||||||
settings_url, shortcut_settings_url, space_icon, space_settings_url, split_group_name,
|
settings_url, shortcut_settings_url, site_compatibility_url, space_icon,
|
||||||
switch_profile_name, sync_status_url, tab_group_color_hex, tab_group_name, tab_note_body,
|
space_settings_url, split_group_name, switch_profile_name, sync_status_url,
|
||||||
task_manager_url,
|
tab_group_color_hex, tab_group_name, tab_note_body, task_manager_url,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -267,6 +267,17 @@ impl BrowserCore {
|
|||||||
self.open_tab(task_manager_url()?);
|
self.open_tab(task_manager_url()?);
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
"site-compatibility"
|
||||||
|
| "site compatibility"
|
||||||
|
| "open-site-compatibility"
|
||||||
|
| "open site compatibility"
|
||||||
|
| "compatibility"
|
||||||
|
| "diagnostics"
|
||||||
|
| "site-diagnostics"
|
||||||
|
| "site diagnostics" => {
|
||||||
|
self.open_tab(site_compatibility_url()?);
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
"plugins"
|
"plugins"
|
||||||
| "open-plugins"
|
| "open-plugins"
|
||||||
| "open plugins"
|
| "open plugins"
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
use ely_browser_core::{BrowserCore, InitialBrowserConfig};
|
||||||
|
use ely_domain::CommandIntent;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn open_site_compatibility_command_opens_diagnostics_page() -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
|
||||||
|
|
||||||
|
core.set_command_query(">open-site-compatibility");
|
||||||
|
let intent = core.submit_command()?;
|
||||||
|
let active_tab = core.active_tab()?;
|
||||||
|
|
||||||
|
assert_eq!(intent, Some(CommandIntent::Command("open-site-compatibility".to_string())));
|
||||||
|
assert_eq!(active_tab.title(), "Site Compatibility");
|
||||||
|
assert_eq!(active_tab.url().as_str(), "ely://site-compatibility");
|
||||||
|
assert_eq!(core.snapshot()?.command_query, "");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user