Skip to content

Commit ddadcee

Browse files
[APP-5060] Make Knowledge settings searchable with a persistent title (#14519)
## Description Split Settings → Agents → Knowledge into independently searchable widgets for Rules, Suggested Rules, Manage rules, and Warp Drive context. The Knowledge heading now uses the same non-widget `PageType` page-title affordance as Account, so it remains visible when settings search filters the content rows. The legacy combined AI page keeps its section-sized Knowledge heading in a standalone legacy-only widget while preserving all existing feature gates, layout, toggles, descriptions, links, and actions. ## Linked Issue [APP-5060](https://linear.app/warpdotdev/issue/APP-5060/knowledge-settings-sub-page-doesnt-use-widgets-correctly-to-break-up) ## Testing - The PR-added `settings_view::tests::knowledge_page_search_filters_to_matching_widget` regression test was removed at the requester's explicit request. This intentionally drops the automated proof that Knowledge search narrows to one widget; the trade-off is recorded here rather than replaced silently. - `cargo fmt --all --check` passed. - `CARGO_INCREMENTAL=0 cargo check -p warp --bin warp` passed. - `CARGO_INCREMENTAL=0 cargo build -p warp --bin warp-oss --features skip_login` passed. - `./script/presubmit` passed formatting, inline-test checks, all workspace/default-GUI/completer clippy checks, clang-format, and WGSL formatting; workspace nextest compilation then hit the runner target-volume limit (`ENOSPC`). PR CI remains the full-suite backstop; the final head CI matrix is running after the required current-master merge, with no failures at the time of this update. - Post-merge focused validation: `cargo fmt --all --check`, `script/check_no_inline_test_modules`, `cargo clippy -p warp --bin warp -- -D warnings`, and the Warp OSS build passed. - Existing computer-use proof on pre-rework head `d8149b7` shows the cleared Knowledge page and `warp drive` filtering. UI recapture for this search-copy/plumbing rework was omitted at the requester's explicit direction. <!-- oz:computer-use-screenshots start --> ### Computer-use screenshots ![Settings → Agents → Knowledge page with the settings search empty, showing the Knowledge title and Rules, Suggested Rules, Manage rules, and Warp Drive as agent context rows.](https://staging.warp.dev/api/v1/agent/artifacts/019fb12d-9835-7a8b-acd5-ca6b0d223b65/download) ![Knowledge page with the settings search active for 'warp drive', filtered to show only the Knowledge title and the 'Warp Drive as agent context' row with its toggle.](https://staging.warp.dev/api/v1/agent/artifacts/019fb12d-f752-7797-8d6a-2b4b3c991798/download) ![Settings → Agents → Knowledge page with the settings search empty, showing the Knowledge title and its rows.](https://staging.warp.dev/api/v1/agent/artifacts/019fb134-e803-7771-98de-6b5252d284c4/download) ![Settings search filtered by 'warp drive' on the Knowledge page, showing only the Warp Drive as agent context row remaining under the Knowledge title.](https://staging.warp.dev/api/v1/agent/artifacts/019fb135-2ebf-7319-be76-7025dcd76879/download) <!-- oz:computer-use-screenshots end --> ### Rework changes - Applied the two requested focused search-term strings verbatim and moved the legacy-only Knowledge section header out of `RulesWidget`; no tests or UI recapture were added at the requester’s direction (pure data/copy plus no-intended-visual-change refactor). `./script/format --check` and scoped Warp clippy passed. - Removed the unreachable `KnowledgeHeaderWidget` and its all-widgets-mode push; matching is unchanged because `RulesWidget` retains the identical terms. No tests or UI recapture were added at the requester’s direction because the deleted widget never rendered. Format and scoped Warp clippy passed. ## Agent Mode - [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode Originating thread: https://warpdev.slack.com/archives/C0BDQDW8V5E/p1785374744296659 CHANGELOG-BUG-FIX: Fixed Knowledge settings search so results show only matching controls while keeping the page title visible. Co-Authored-By: Warp <agent@warp.dev> Co-Authored-By: Oz <oz-agent@warp.dev> <!-- factory-agent: {"source":"factory-agent","task_id":"APP-5060","task_source":"linear","task_url":"https://linear.app/warpdotdev/issue/APP-5060/knowledge-settings-sub-page-doesnt-use-widgets-correctly-to-break-up","linear_issue_id":"APP-5060","oz_run_id":"019fb0aa-c42d-72e6-978d-c2df8e2ada29","repo":"warpdotdev/warp","pr_url":"https://github.com/warpdotdev/warp/pull/14519","review_rework_attempts":4} --> --------- Co-authored-by: Andy <andy@warp.dev>
1 parent c9f44b0 commit ddadcee

1 file changed

Lines changed: 108 additions & 71 deletions

File tree

app/src/settings_view/ai_page.rs

Lines changed: 108 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -2850,6 +2850,18 @@ impl AISettingsPageView {
28502850
ctx.notify();
28512851
}
28522852
}
2853+
fn knowledge_widgets() -> Vec<Box<dyn SettingsWidget<View = Self>>> {
2854+
let mut widgets: Vec<Box<dyn SettingsWidget<View = Self>>> =
2855+
vec![Box::new(RulesWidget::default())];
2856+
if FeatureFlag::SuggestedRules.is_enabled() {
2857+
widgets.push(Box::new(SuggestedRulesWidget::default()));
2858+
}
2859+
widgets.extend([
2860+
Box::new(ManageRulesWidget::default()) as Box<dyn SettingsWidget<View = Self>>,
2861+
Box::new(WarpDriveContextWidget::default()),
2862+
]);
2863+
widgets
2864+
}
28532865

28542866
fn build_page(subpage: Option<AISubpage>, ctx: &mut ViewContext<Self>) -> PageType<Self> {
28552867
let ai_settings = AISettings::as_ref(ctx);
@@ -2892,7 +2904,7 @@ impl AISettingsPageView {
28922904
widgets.push(Box::new(MCPServersWidget::default()));
28932905
}
28942906
if FeatureFlag::AIRules.is_enabled() {
2895-
widgets.push(Box::new(AIFactWidget::default()));
2907+
widgets.extend(Self::knowledge_widgets());
28962908
}
28972909
if cfg!(feature = "voice_input")
28982910
&& ai_settings
@@ -2965,17 +2977,18 @@ impl AISettingsPageView {
29652977
}
29662978
Some(AISubpage::Knowledge) => {
29672979
if FeatureFlag::AIRules.is_enabled() {
2968-
widgets.push(Box::new(AIFactWidget::default()));
2980+
widgets.extend(Self::knowledge_widgets());
29692981
}
29702982
}
29712983
Some(AISubpage::ThirdPartyCLIAgents) => {
29722984
widgets.push(Box::new(CLIAgentWidget::default()));
29732985
}
29742986
}
29752987

2976-
// Subpage widgets render their own subheader-sized titles internally,
2977-
// so we don't pass a page-level title to PageType.
2978-
let title: Option<&str> = None;
2988+
// Most subpage widgets render their own subheader-sized titles internally.
2989+
// Knowledge follows the Account-page convention and renders its title as page chrome,
2990+
// so filtering its setting widgets never removes the title.
2991+
let title = (subpage == Some(AISubpage::Knowledge)).then_some("Knowledge");
29792992
PageType::new_uncategorized(widgets, title)
29802993
}
29812994

@@ -7082,22 +7095,29 @@ impl SettingsWidget for MCPServersWidget {
70827095
}
70837096

70847097
#[derive(Default)]
7085-
struct AIFactWidget {
7098+
struct RulesWidget {
70867099
rules_toggle: SwitchStateHandle,
70877100
rules_link_index: HighlightedHyperlink,
7088-
manage_rules_button: MouseStateHandle,
7089-
rule_suggestions_toggle: SwitchStateHandle,
7090-
warp_drive_context_toggle: SwitchStateHandle,
70917101
}
70927102

7093-
impl AIFactWidget {
7094-
fn render_rules_toggle(
7103+
impl SettingsWidget for RulesWidget {
7104+
type View = AISettingsPageView;
7105+
7106+
fn search_terms(&self) -> &str {
7107+
"fact memory memories rules conventions"
7108+
}
7109+
7110+
fn should_render(&self, _app: &AppContext) -> bool {
7111+
FeatureFlag::AIRules.is_enabled()
7112+
}
7113+
7114+
fn render(
70957115
&self,
7096-
view: &AISettingsPageView,
7097-
ai_settings: &AISettings,
7116+
view: &Self::View,
70987117
appearance: &Appearance,
7099-
app: &warpui::AppContext,
7118+
app: &AppContext,
71007119
) -> Box<dyn Element> {
7120+
let ai_settings = AISettings::as_ref(app);
71017121
let toggle = render_ai_setting_toggle::<MemoryEnabled>(
71027122
"Rules",
71037123
AISettingsPageAction::ToggleRules,
@@ -7142,13 +7162,31 @@ impl AIFactWidget {
71427162
.with_child(description)
71437163
.finish()
71447164
}
7165+
}
7166+
7167+
#[derive(Default)]
7168+
struct SuggestedRulesWidget {
7169+
rule_suggestions_toggle: SwitchStateHandle,
7170+
}
7171+
7172+
impl SettingsWidget for SuggestedRulesWidget {
7173+
type View = AISettingsPageView;
7174+
7175+
fn search_terms(&self) -> &str {
7176+
"suggested rules suggest save"
7177+
}
71457178

7146-
fn render_rule_suggestions_toggle(
7179+
fn should_render(&self, _app: &AppContext) -> bool {
7180+
FeatureFlag::AIRules.is_enabled() && FeatureFlag::SuggestedRules.is_enabled()
7181+
}
7182+
7183+
fn render(
71477184
&self,
7148-
view: &AISettingsPageView,
7149-
ai_settings: &AISettings,
7150-
app: &warpui::AppContext,
7185+
view: &Self::View,
7186+
_appearance: &Appearance,
7187+
app: &AppContext,
71517188
) -> Box<dyn Element> {
7189+
let ai_settings = AISettings::as_ref(app);
71527190
let toggle = render_ai_setting_toggle::<RuleSuggestionsEnabled>(
71537191
"Suggested Rules",
71547192
AISettingsPageAction::ToggleRuleSuggestions,
@@ -7170,41 +7208,18 @@ impl AIFactWidget {
71707208
.with_child(description)
71717209
.finish()
71727210
}
7211+
}
71737212

7174-
fn render_warp_drive_context_toggle(
7175-
&self,
7176-
view: &AISettingsPageView,
7177-
ai_settings: &AISettings,
7178-
app: &warpui::AppContext,
7179-
) -> Box<dyn Element> {
7180-
let toggle = render_ai_setting_toggle::<WarpDriveContextEnabled>(
7181-
"Warp Drive as agent context",
7182-
AISettingsPageAction::ToggleWarpDriveContext,
7183-
*ai_settings.warp_drive_context_enabled,
7184-
ai_settings.is_any_ai_enabled(app),
7185-
self.warp_drive_context_toggle.clone(),
7186-
&view.local_only_icon_tooltip_states,
7187-
app,
7188-
);
7189-
7190-
let description = render_ai_setting_description(
7191-
"The Warp Agent can leverage your Warp Drive Contents to tailor responses to your personal and team developer workflows and environments. This includes any Workflows, Notebooks, and Environment Variables.",
7192-
ai_settings.is_any_ai_enabled(app),
7193-
app,
7194-
);
7195-
7196-
Flex::column()
7197-
.with_child(toggle)
7198-
.with_child(description)
7199-
.finish()
7200-
}
7213+
#[derive(Default)]
7214+
struct ManageRulesWidget {
7215+
manage_rules_button: MouseStateHandle,
72017216
}
72027217

7203-
impl SettingsWidget for AIFactWidget {
7218+
impl SettingsWidget for ManageRulesWidget {
72047219
type View = AISettingsPageView;
72057220

72067221
fn search_terms(&self) -> &str {
7207-
"agent oz ai a.i. knowledge fact memory memories rules warp drive context workflows notebooks environment variables"
7222+
"manage rules rule collection"
72087223
}
72097224

72107225
fn should_render(&self, _app: &AppContext) -> bool {
@@ -7213,40 +7228,62 @@ impl SettingsWidget for AIFactWidget {
72137228

72147229
fn render(
72157230
&self,
7216-
view: &Self::View,
7231+
_view: &Self::View,
72177232
appearance: &Appearance,
72187233
app: &AppContext,
72197234
) -> Box<dyn Element> {
7220-
let ai_settings = AISettings::as_ref(app);
7221-
let is_any_ai_enabled = ai_settings.is_any_ai_enabled(app);
7222-
7223-
let header = build_sub_header(
7224-
appearance,
7225-
"Knowledge",
7226-
Some(styles::header_font_color(is_any_ai_enabled, app)),
7227-
)
7228-
.with_margin_bottom(HEADER_PADDING)
7229-
.finish();
7230-
7231-
let button = render_full_pane_width_ai_button(
7235+
render_full_pane_width_ai_button(
72327236
"Manage rules",
7233-
is_any_ai_enabled,
7237+
AISettings::as_ref(app).is_any_ai_enabled(app),
72347238
self.manage_rules_button.clone(),
72357239
AISettingsPageAction::OpenAIFactCollection,
72367240
appearance,
7237-
);
7241+
)
7242+
}
7243+
}
72387244

7239-
let mut column = Flex::column()
7240-
.with_child(header)
7241-
.with_child(self.render_rules_toggle(view, ai_settings, appearance, app));
7245+
#[derive(Default)]
7246+
struct WarpDriveContextWidget {
7247+
warp_drive_context_toggle: SwitchStateHandle,
7248+
}
72427249

7243-
if FeatureFlag::SuggestedRules.is_enabled() {
7244-
column.add_child(self.render_rule_suggestions_toggle(view, ai_settings, app));
7245-
}
7250+
impl SettingsWidget for WarpDriveContextWidget {
7251+
type View = AISettingsPageView;
72467252

7247-
column
7248-
.with_child(button)
7249-
.with_child(self.render_warp_drive_context_toggle(view, ai_settings, app))
7253+
fn search_terms(&self) -> &str {
7254+
"warp drive agent context contents personal team developer workflows environments notebooks environment variables"
7255+
}
7256+
7257+
fn should_render(&self, _app: &AppContext) -> bool {
7258+
FeatureFlag::AIRules.is_enabled()
7259+
}
7260+
7261+
fn render(
7262+
&self,
7263+
view: &Self::View,
7264+
_appearance: &Appearance,
7265+
app: &AppContext,
7266+
) -> Box<dyn Element> {
7267+
let ai_settings = AISettings::as_ref(app);
7268+
let toggle = render_ai_setting_toggle::<WarpDriveContextEnabled>(
7269+
"Warp Drive as agent context",
7270+
AISettingsPageAction::ToggleWarpDriveContext,
7271+
*ai_settings.warp_drive_context_enabled,
7272+
ai_settings.is_any_ai_enabled(app),
7273+
self.warp_drive_context_toggle.clone(),
7274+
&view.local_only_icon_tooltip_states,
7275+
app,
7276+
);
7277+
7278+
let description = render_ai_setting_description(
7279+
"The Warp Agent can leverage your Warp Drive Contents to tailor responses to your personal and team developer workflows and environments. This includes any Workflows, Notebooks, and Environment Variables.",
7280+
ai_settings.is_any_ai_enabled(app),
7281+
app,
7282+
);
7283+
7284+
Flex::column()
7285+
.with_child(toggle)
7286+
.with_child(description)
72507287
.finish()
72517288
}
72527289
}

0 commit comments

Comments
 (0)