Skip to content

Commit fe8138b

Browse files
Fix Third party CLI agents Settings search results and keep the page title visible (#14524)
## Description Settings → Agents → **Third party CLI agents** was a single monolithic `CLIAgentWidget`, so a search that matched one control returned the entire page. Fixing that surfaced two follow-on issues with how settings pages render their title, both addressed here. - Split the page into seven focused `SettingsWidget`s so settings search filters at row/section granularity. - Preserve the existing empty-search layout, feature/setting gating, and the `cli_agents` deeplink target. - **Keep the page title visible while the rows are filtered**, on both Third party CLI agents and Editor and Code Review. The heading used to be drawn inside a widget, so any search term that filtered that widget out also removed the page title. Headings are now passed to `PageType` as page-level chrome, which the renderer draws once outside the filtered widget loop — the same affordance the Knowledge sub-page adopted in #14519 and the Account page has always used. `CodeSubpageHeaderWidget`, a header-only entry in the searchable widget list, is deleted outright. - **Make the title-to-content gap consistent across titled pages.** `PAGE_TITLE_MARGIN_BOTTOM` now reuses the existing `HEADER_PADDING` token, and the five pages that carried their own additional leading spacing no longer do, so every titled page derives that gap from the shared page chrome alone. ### Per-page spacing sources removed Each of these was an independent source that stacked on top of the shared title gap: - **Account** — `AccountWidget` wrapped its content in a 24px top margin (`VERTICAL_MARGIN`). - **Billing and Usage** — `BillingAndUsageWidget` wrapped its child view in a 15px top margin (`HEADER_PADDING`). - **Referrals** — the invite section wrapped its first label in 28px top padding (`PAGE_PADDING`). - **Shared blocks** — the header was wrapped in an extra hardcoded 24px bottom margin on top of `render_page_title`'s own gap. - **Privacy** — `SecretRedactionWidget` wrapped its column in 28px top padding (`PAGE_PADDING`). Scope note: `Warp Agent` and `Agent profiles` deliberately keep no page-level title. They are multi-section pages whose per-widget headings (`Active AI`, `Input`, `Voice`, `API Keys`, …) name individual sections, so those headings correctly disappear along with their own rows when filtered. Only single-topic pages, whose one heading names the whole page, belong in page chrome. ## Linked Issue [APP-5058](https://linear.app/warpdotdev/issue/APP-5058/third-party-cli-agents-settings-sub-page-doesnt-use-widgets-correctly) Originating thread: https://warpdev.slack.com/archives/C0BDQDW8V5E/p1785374792001539 ## Testing - [x] `./script/format` - [x] `CARGO_INCREMENTAL=0 cargo clippy -p warp --bin warp -- -D warnings` - [x] `CARGO_INCREMENTAL=0 cargo clippy -p warp --bin warp --tests -- -D warnings` - [x] `CARGO_INCREMENTAL=0 cargo build --bin warp` - [x] Earlier PR CI green on the pre-merge head: 20 passed, 9 skipped, 0 failing - [x] Computer-use verification of title persistence on **Third party CLI agents**: with `toolbar layout`, `coding agent toolbar` and `ctrl enter` active, the bold heading stays at the top; clearing restores the page with the heading intact. - [x] Computer-use verification of title persistence on **Editor and Code Review**: baseline 13 rows with the heading; `auto save` filters to 1 row (`Auto save`) with the heading still shown; `project explorer` filters to 2 rows (`Project explorer`, `Show hidden files in project explorer`) with the heading still shown; clearing restores all 13 rows with the heading present. - [x] Computer-use verification of spacing across eight titled pages. Six now render an identical gap of roughly half the heading's text height: Billing and Usage, Referrals, Privacy, Knowledge, Third party CLI agents, and Editor and Code Review. No overlapping text, duplicated headings, missing headings, or clipped content on any page. The two APP-5058 regression tests added earlier were removed at the requester's explicit request; computer-use proof is the behavior-level verification for this change. ### Two pages still show a larger gap, for a reason that is not title padding Verification was done in a logged-out session, and on two pages the remaining space is page content rather than the title gap. Both had their genuine duplicate padding source removed above. - **Account** — below the heading sits `AccountWidget`'s account-info block (avatar, name, email, plan badge), which renders empty when logged out, followed by the deliberate `DividerWidget` separator that carries its own 24px top margin. That divider separates the account block from the settings below and is doing real work, so it was left alone rather than absorbed into the title gap. In a logged-in session the band should be filled by the account block. **Worth a glance on a logged-in build.** - **Shared blocks** — the page was in its `Failed to load blocks. Please try again.` state, which is a centered message rendered through a helper that applies uniform `PAGE_PADDING`. That padding belongs to the empty/error state, not the title. ### Capture access note Artifact download links require Warp authentication. The GitHub App installation token available to this run cannot use GitHub's user-attachment uploader, so each state is also described in words above and the captures are preserved on the linked Oz run. <!-- oz:computer-use-screenshots start --> ### Computer-use screenshots ![Search 'ctrl enter' narrows the sidebar to only 'Third party CLI agents (1)', while the main content area remains the same 7 rows.](https://staging.warp.dev/api/v1/agent/artifacts/019fb5ca-2c7d-79ee-8144-ea3cf48d7fa2/download) ![After clearing the search, the sidebar is fully restored and the main content area shows the same 7 rows as baseline.](https://staging.warp.dev/api/v1/agent/artifacts/019fb5ca-7c4b-704a-95ae-26b44a1ec47f/download) ![Third party CLI agents settings page with search "ctrl enter" active — the sidebar is filtered to one entry but the main content area still shows all 7 setting rows.](https://staging.warp.dev/api/v1/agent/artifacts/019fb5d4-1141-7989-aec7-6986b4965d48/download) ![Third party CLI agents settings page with an empty sidebar search box, showing all setting rows.](https://staging.warp.dev/api/v1/agent/artifacts/019fb5d7-523c-7e65-bb61-afa0fcc4b674/download) ![With "toolbar layout" typed in the sidebar search, the sidebar filters (Third party CLI agents (1)) but the main content area still shows all 7 rows and the heading.](https://staging.warp.dev/api/v1/agent/artifacts/019fb5d8-1d7f-7704-b63b-bedf81c9e94c/download) ![Third party CLI agents settings page showing the heading and first row with a clear whitespace band between them.](https://staging.warp.dev/api/v1/agent/artifacts/019fb5e3-34d5-7aa5-9875-33f8d5843a1e/download) ![Knowledge settings page showing heading and first row 'Rules' with a whitespace band between them.](https://staging.warp.dev/api/v1/agent/artifacts/019fb5e3-a01c-782d-b1bf-2ea63f12c27f/download) ![Privacy settings page showing heading and 'Secret redaction' with a larger whitespace band between them.](https://staging.warp.dev/api/v1/agent/artifacts/019fb5e4-2bc1-7e98-800b-e1b08392dc12/download) ![Editor and Code Review settings page filtered by the search term "auto save", showing the heading and only the Auto save row.](https://staging.warp.dev/api/v1/agent/artifacts/019fb689-4b17-75c6-a4e7-fc19b6917165/download) ![Editor and Code Review page restored to its full 13-row list after clearing the search box, heading present.](https://staging.warp.dev/api/v1/agent/artifacts/019fb68a-22fa-7d03-ab77-c2d2936ac6ee/download) <!-- oz:computer-use-screenshots end --> <!-- oz:computer-use-videos start --> ### Computer-use video recordings [View video recording: Investigating whether the Third party CLI agents settings list narrows to matching rows when searching, and what action (typing, page switch, resize, scroll) triggers the repaint.](https://staging.warp.dev/api/v1/agent/artifacts/019fb5d4-385f-7b49-b261-352ca5896a13/download) <!-- oz:computer-use-videos end --> ### Follow-up candidates found while sweeping (deliberately NOT changed here) Two more pages have the same signature — a single-topic page whose one heading lives inside a searchable widget, so an active search term can filter the title away: - **Warpify** (`warpify_page.rs`) — categorized page with a `None` title; the "Warpify" heading lives in `TitleWidget` inside an unnamed category. - **Warp Drive** (`warp_drive_page.rs`) — uncategorized page with a `None` title and a header-only `WarpDriveHeaderWidget`, structurally identical to the `CodeSubpageHeaderWidget` deleted here. Monolith pages (Shared blocks, Keybindings, Teams, Oz cloud API keys, About, Environments) are **not** affected: their filter is all-or-nothing, so the title never vanishes while rows remain. Multi-section pages (Appearance, Features, Warp Agent, Agent profiles) are also not affected, because their headings legitimately belong to individual sections. ### Rework changes - **Page title disappeared under an active search term (requester report).** Moved the `Third party CLI agents` heading out of `CLIAgentWidget::render` into `PageType`'s page-title slot, mirroring the Knowledge sub-page (#14519) rather than inventing a new mechanism. - **Padding below the page title (requester follow-up).** Pointed `PAGE_TITLE_MARGIN_BOTTOM` at the existing `HEADER_PADDING` token so promoting a heading to chrome no longer tightens the gap. This also fixed the same regression Knowledge inherited from #14519. - **Too much padding on five pages (requester follow-up).** Diagnosed each page separately; all five genuinely had their own leading-spacing source stacking on the shared gap, and each was removed in favour of the shared page-title padding. Details in the "Per-page spacing sources removed" section above. - **`Editor and Code Review` title disappearing under search (requester follow-up).** Deleted the header-only `CodeSubpageHeaderWidget` and passed `subpage.title()` through `PageType` instead. This covers both Code subpages, since they shared that widget. No deeplink targets reference it. The legacy all-widgets Code view keeps its categorized section headers, matching the precedent set for Third party CLI agents. - **Removed the `PAGE_TITLE_MARGIN_BOTTOM` doc comment** at the requester's request; the surrounding constants carry none, and its rationale went stale once the per-page sources were consolidated. - **Brought current with `master`.** Merged rather than rebased, since the branch is shared and already carried merge commits. Conflict-free, including in `ai_page.rs`. - **Behaviour note:** deleting `CodeSubpageHeaderWidget` also removes the only widget whose `search_terms` were the literal page title, so searching the exact string `editor and code review` no longer matches this page. Previously it matched and rendered a bare heading with no controls, which was not useful; searching any real term (`editor`, `auto save`, `project explorer`) still works and now keeps the title visible. ## Agent Mode - [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode CHANGELOG-BUG-FIX: Fixed Settings search returning the entire Third party CLI agents page for a single matching control, kept page titles visible while results are filtered, and made the spacing below settings page titles consistent. <!-- factory-agent: {"source":"factory-agent","task_id":"APP-5058","task_source":"linear","task_url":"https://linear.app/warpdotdev/issue/APP-5058/third-party-cli-agents-settings-sub-page-doesnt-use-widgets-correctly","linear_issue_id":"APP-5058","oz_run_id":"019fb57a-8c8e-7165-8f6e-17b12361320b","repo":"warpdotdev/warp","pr_url":"https://github.com/warpdotdev/warp/pull/14524","review_rework_attempts":1} --> _Conversation: https://staging.warp.dev/conversation/4cf9720f-91f5-466c-a005-23a629a7e655_ _Run: https://oz.staging.warp.dev/runs/019fb57a-8c8e-7165-8f6e-17b12361320b_ Co-Authored-By: Warp <agent@warp.dev> Co-Authored-By: Oz <oz-agent@warp.dev> --------- Co-authored-by: Andy <andy@warp.dev>
1 parent 44f112c commit fe8138b

8 files changed

Lines changed: 369 additions & 262 deletions

File tree

app/src/settings_view/ai_page.rs

Lines changed: 355 additions & 205 deletions
Large diffs are not rendered by default.

app/src/settings_view/billing_and_usage_dispatch.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
44
use warp_core::features::FeatureFlag;
55
use warp_core::ui::appearance::Appearance;
6-
use warpui::elements::{ChildView, Container};
6+
use warpui::elements::ChildView;
77
use warpui::{AppContext, Element, Entity, SingletonEntity, View, ViewContext, ViewHandle};
88

99
use super::SettingsSection;
1010
use super::billing_and_usage_page::{BillingAndUsagePageEvent, BillingAndUsagePageView};
1111
use super::billing_and_usage_page_v2::BillingAndUsagePageV2View;
1212
use super::settings_page::{
13-
HEADER_PADDING, MatchData, PageType, SettingsPageMeta, SettingsPageViewHandle, SettingsWidget,
13+
MatchData, PageType, SettingsPageMeta, SettingsPageViewHandle, SettingsWidget,
1414
};
1515
use crate::auth::{AuthManager, AuthStateProvider};
1616
use crate::workspaces::user_workspaces::UserWorkspaces;
@@ -155,13 +155,10 @@ impl SettingsWidget for BillingAndUsageWidget {
155155
_appearance: &Appearance,
156156
app: &AppContext,
157157
) -> Box<dyn Element> {
158-
let inner = if view.use_v2(app) {
158+
if view.use_v2(app) {
159159
ChildView::new(&view.v2).finish()
160160
} else {
161161
ChildView::new(&view.v1).finish()
162-
};
163-
Container::new(inner)
164-
.with_margin_top(HEADER_PADDING)
165-
.finish()
162+
}
166163
}
167164
}

app/src/settings_view/code_page.rs

Lines changed: 4 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,8 @@ use warpui::{
4040
#[cfg(feature = "local_fs")]
4141
use super::features::external_editor::ExternalEditorView;
4242
use super::settings_page::{
43-
Category, HEADER_PADDING, MatchData, PageType, SettingsPageMeta, SettingsPageViewHandle,
44-
SettingsWidget, TOGGLE_BUTTON_RIGHT_PADDING, build_sub_header, render_body_item,
45-
render_separator,
43+
Category, MatchData, PageType, SettingsPageMeta, SettingsPageViewHandle, SettingsWidget,
44+
TOGGLE_BUTTON_RIGHT_PADDING, render_body_item, render_separator,
4645
};
4746
use super::{
4847
LocalOnlyIconState, SettingsAction, SettingsSection, ToggleSettingActionPair, ToggleState,
@@ -433,10 +432,7 @@ impl CodeSettingsPageView {
433432
ctx.dispatch_typed_action(CodeSettingsPageAction::ManualAddDirectory);
434433
})
435434
});
436-
let mut widgets: Vec<Box<dyn SettingsWidget<View = Self>>> =
437-
vec![Box::new(CodeSubpageHeaderWidget {
438-
title: subpage.title(),
439-
})];
435+
let mut widgets: Vec<Box<dyn SettingsWidget<View = Self>>> = Vec::new();
440436
match subpage {
441437
CodeSubpage::Indexing => {
442438
widgets.push(Box::new(CodebaseIndexingCategorizedWidget {
@@ -463,9 +459,7 @@ impl CodeSettingsPageView {
463459
]);
464460
}
465461
}
466-
// Subpage widgets render their own subheader-sized titles,
467-
// so we don't pass a page-level title.
468-
self.page = PageType::new_uncategorized(widgets, None);
462+
self.page = PageType::new_uncategorized(widgets, Some(subpage.title()));
469463
} else {
470464
// None: rebuild the full categorized page (all widgets).
471465
self.page = Self::build_full_page(ctx);
@@ -2466,30 +2460,6 @@ impl CodePageWidget {
24662460
}
24672461
}
24682462

2469-
/// A simple widget that renders a subheader title for a Code subpage.
2470-
struct CodeSubpageHeaderWidget {
2471-
title: &'static str,
2472-
}
2473-
2474-
impl SettingsWidget for CodeSubpageHeaderWidget {
2475-
type View = CodeSettingsPageView;
2476-
2477-
fn search_terms(&self) -> &str {
2478-
self.title
2479-
}
2480-
2481-
fn render(
2482-
&self,
2483-
_view: &Self::View,
2484-
appearance: &Appearance,
2485-
_app: &AppContext,
2486-
) -> Box<dyn Element> {
2487-
build_sub_header(appearance, self.title, None)
2488-
.with_padding_bottom(HEADER_PADDING)
2489-
.finish()
2490-
}
2491-
}
2492-
24932463
struct CodebaseIndexingCategorizedWidget {
24942464
inner: CodePageWidget,
24952465
}

app/src/settings_view/main_page.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -659,11 +659,7 @@ impl SettingsWidget for AccountWidget {
659659
};
660660

661661
Flex::column()
662-
.with_child(
663-
Container::new(account_info)
664-
.with_margin_top(VERTICAL_MARGIN)
665-
.finish(),
666-
)
662+
.with_child(Container::new(account_info).finish())
667663
.finish()
668664
}
669665
}

app/src/settings_view/privacy_page.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use warpui::{
3232

3333
use super::privacy::{AddRegexModal, AddRegexModalEvent};
3434
use super::settings_page::{
35-
HEADER_PADDING, LocalOnlyIconState, MatchData, PAGE_PADDING, PageType, SettingsPageMeta,
35+
HEADER_PADDING, LocalOnlyIconState, MatchData, PageType, SettingsPageMeta,
3636
SettingsPageViewHandle, SettingsWidget, TOGGLE_BUTTON_RIGHT_PADDING, ToggleState,
3737
render_body_item, render_sub_header,
3838
};
@@ -1366,9 +1366,7 @@ impl SettingsWidget for SecretRedactionWidget {
13661366
column.add_child(self.horizontal_divider(appearance));
13671367
}
13681368

1369-
Container::new(column.finish())
1370-
.with_padding_top(PAGE_PADDING)
1371-
.finish()
1369+
Container::new(column.finish()).finish()
13721370
}
13731371
}
13741372

app/src/settings_view/referrals_page.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -619,11 +619,7 @@ impl ReferralsWidget {
619619
appearance: &Appearance,
620620
) -> Box<dyn Element> {
621621
Flex::column()
622-
.with_child(
623-
Container::new(self.render_label("Link", appearance))
624-
.with_padding_top(PAGE_PADDING)
625-
.finish(),
626-
)
622+
.with_child(self.render_label("Link", appearance))
627623
.with_child(self.render_link_row(view, appearance))
628624
.with_child(self.render_label("Email", appearance))
629625
.with_child(self.render_email_row(view, appearance))

app/src/settings_view/settings_page.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ pub const TOGGLE_BUTTON_RIGHT_PADDING: f32 = 5.;
5757
pub const HEADER_PADDING: f32 = 15.;
5858
pub const CONTENT_FONT_SIZE: f32 = 12.;
5959
pub const SUBHEADER_MARGIN_BOTTOM: f32 = 4.;
60-
pub const PAGE_TITLE_MARGIN_BOTTOM: f32 = 4.;
60+
pub const PAGE_TITLE_MARGIN_BOTTOM: f32 = HEADER_PADDING;
6161
pub(super) const PAGE_PADDING: f32 = 28.;
6262
pub(super) const HEADER_FONT_SIZE: f32 = 23.;
6363
pub const SUBHEADER_FONT_SIZE: f32 = 16.;

app/src/settings_view/show_blocks_view.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -799,7 +799,7 @@ impl SettingsWidget for ShowBlocksWidget {
799799

800800
let header = render_page_title("Shared blocks", HEADER_FONT_SIZE, appearance);
801801
let col = Flex::column()
802-
.with_child(Container::new(header).with_margin_bottom(24.).finish())
802+
.with_child(header)
803803
.with_child(Expanded::new(1., stack.finish()).finish());
804804

805805
col.finish()

0 commit comments

Comments
 (0)