GPUI Box GitHub

Components / agent

ApprovalPrompt view

One request for permission, with the answer left to the caller.

A view survives a frame. Hold it in an Entity with cx.new(..) and reach it with .update(..).

use gpui_kit::agent::ApprovalPrompt;

Reviewed in approval.

Construct
new(ident: impl Into<Ident>, action: impl Into<SharedString>, _window: &mut Window, cx: &mut Context<Self>) -> Self
Options

Chain onto the value.

detail(detail: DescriptionItem) -> Self
details(details: impl IntoIterator<Item = DescriptionItem>) -> Self
always(scope: AlwaysScope) -> Self
status(status: ApprovalStatus) -> Self
Commands

Need a Context, so they need a view.

set_status(status: ApprovalStatus, cx: &mut Context<Self>)
approve(decision: ApprovalDecision, cx: &mut Context<Self>)
decline(cx: &mut Context<Self>)
Queries

Only answer; they change nothing.

current_status() -> &ApprovalStatus
Example · approval
fn approval(window: &mut Window, cx: &mut App) -> AnyElement {
    if !cx.has_global::<SceneApprovals>() {
        let pending = cx.new(|cx| {
            ApprovalPrompt::new(
                "scene.approval.pending",
                "Write to /work/report/summary.md",
                window,
                cx,
            )
            .details([
                DescriptionItem::new("tool", "Tool", "write-file"),
                DescriptionItem::new("path", "Path", "/work/report/summary.md"),
                DescriptionItem::new("bytes", "Size", "4 KB"),
            ])
            .always(AlwaysScope::Session)
            .always(AlwaysScope::path("/work/report"))
            .always(AlwaysScope::tool("write-file"))
        });
        let declined = cx.new(|cx| {
            ApprovalPrompt::new(
                "scene.approval.declined",
                "Delete /work/report/draft.md",
                window,
                cx,
            )
            .status(ApprovalStatus::Declined)
        });
        let expired = cx.new(|cx| {
            ApprovalPrompt::new(
                "scene.approval.expired",
                "Open a connection to build.internal:8443",
                window,
                cx,
            )
            .status(ApprovalStatus::Expired)
        });
        let superseded = cx.new(|cx| {
            ApprovalPrompt::new(
                "scene.approval.superseded",
                "Run the test suite in /work",
                window,
                cx,
            )
            .status(ApprovalStatus::Superseded {
                by: "a later request covering the whole workspace".into(),
            })
        });
        cx.set_global(SceneApprovals {
            pending,
            declined,
            expired,
            superseded,
        });
    }
    let prompts = cx.global::<SceneApprovals>();
    let pending = prompts.pending.clone();
    let declined = prompts.declined.clone();
    let expired = prompts.expired.clone();
    let superseded = prompts.superseded.clone();
    let theme = cx.theme().clone();

    stack(&theme)
        .w(px(560.0))
        .child(pending)
        .child(
            Divider::new()
                .id("scene.approval.rule.resolved")
                .label("Answered, expired, and replaced are three different things"),
        )
        .child(declined)
        .child(expired)
        .child(superseded)
        .into_any_element()
}

Source: crates/gpui-kit/src/agent/approval.rs