mirror of
https://github.com/openai/codex.git
synced 2026-11-05 08:28:29 +00:00
## Summary The desktop app now presents the on-request permissions mode as `Ask for approval` and the manual-review-backed mode as `Approve for me`. The TUI still exposed older/internal labels like `Default` and `Auto-review`, which made the same underlying settings look different across clients. This updates the TUI UX copy to match the app without changing the underlying default behavior. Fresh threads continue to use the existing on-request approval mode, now displayed as `Ask for approval`. The label changes cover `/permissions`, explicit profile permissions menus, status surfaces, config persistence history/error text, and the corresponding TUI snapshots. ### Before <img width="1181" height="119" alt="Screenshot 2026-05-28 at 10 19 47 PM" src="https://github.com/user-attachments/assets/0664846b-b6dd-4931-b4dd-d0af0d42058e" /> <img width="523" height="19" alt="Screenshot 2026-05-28 at 10 21 29 PM" src="https://github.com/user-attachments/assets/7899c33e-b35d-4684-8389-97e357803423" /> ### After <img width="1216" height="117" alt="Screenshot 2026-05-28 at 10 19 32 PM" src="https://github.com/user-attachments/assets/015aab43-ac97-411f-8031-75cdd887251b" /> <img width="567" height="18" alt="Screenshot 2026-05-28 at 10 20 24 PM" src="https://github.com/user-attachments/assets/28b6422c-b823-4298-b221-c83d46d09d66" />
172 lines
6.1 KiB
Rust
172 lines
6.1 KiB
Rust
use super::*;
|
|
|
|
impl ChatWidget {
|
|
pub(super) fn open_permission_profiles_popup(&mut self) {
|
|
let active_profile_id = self
|
|
.config
|
|
.permissions
|
|
.active_permission_profile()
|
|
.map(|profile| profile.id);
|
|
let presets = builtin_approval_presets();
|
|
let Some(read_only) = presets.iter().find(|preset| preset.id == "read-only") else {
|
|
self.add_error_message(
|
|
"Internal error: missing the 'read-only' approval preset.".to_string(),
|
|
);
|
|
return;
|
|
};
|
|
let Some(default) = presets.iter().find(|preset| preset.id == "auto") else {
|
|
self.add_error_message(
|
|
"Internal error: missing the 'auto' approval preset.".to_string(),
|
|
);
|
|
return;
|
|
};
|
|
let Some(full_access) = presets.iter().find(|preset| preset.id == "full-access") else {
|
|
self.add_error_message(
|
|
"Internal error: missing the 'full-access' approval preset.".to_string(),
|
|
);
|
|
return;
|
|
};
|
|
let mut items = vec![
|
|
self.builtin_permission_mode_selection_item(
|
|
default,
|
|
":workspace",
|
|
default
|
|
.description
|
|
.replace(" (Identical to Agent mode)", ""),
|
|
AskForApproval::from(default.approval),
|
|
ApprovalsReviewer::User,
|
|
),
|
|
];
|
|
if self.config.features.enabled(Feature::GuardianApproval) {
|
|
items.push(self.builtin_permission_mode_selection_item(
|
|
default,
|
|
":workspace",
|
|
AUTO_REVIEW_DESCRIPTION.to_string(),
|
|
AskForApproval::OnRequest,
|
|
ApprovalsReviewer::AutoReview,
|
|
));
|
|
}
|
|
items.push(self.builtin_permission_mode_selection_item(
|
|
full_access,
|
|
":danger-no-sandbox",
|
|
full_access.description.to_string(),
|
|
AskForApproval::from(full_access.approval),
|
|
ApprovalsReviewer::User,
|
|
));
|
|
items.push(self.builtin_permission_mode_selection_item(
|
|
read_only,
|
|
":read-only",
|
|
read_only.description.to_string(),
|
|
AskForApproval::from(read_only.approval),
|
|
ApprovalsReviewer::User,
|
|
));
|
|
items.extend(
|
|
self.config
|
|
.custom_permission_profiles
|
|
.iter()
|
|
.map(|profile| {
|
|
Self::permission_profile_selection_item(
|
|
&profile.id,
|
|
&profile.id,
|
|
profile
|
|
.description
|
|
.as_deref()
|
|
.unwrap_or("Configured permission profile."),
|
|
active_profile_id.as_deref(),
|
|
)
|
|
}),
|
|
);
|
|
|
|
self.bottom_pane.show_selection_view(SelectionViewParams {
|
|
title: Some("Update Model Permissions".to_string()),
|
|
footer_hint: Some(standard_popup_hint_line()),
|
|
items,
|
|
header: Box::new(()),
|
|
..Default::default()
|
|
});
|
|
}
|
|
|
|
fn builtin_permission_mode_selection_item(
|
|
&self,
|
|
preset: &ApprovalPreset,
|
|
id: &str,
|
|
description: String,
|
|
approval_policy: AskForApproval,
|
|
approvals_reviewer: ApprovalsReviewer,
|
|
) -> SelectionItem {
|
|
let label = match (preset.id, approvals_reviewer) {
|
|
("auto", ApprovalsReviewer::AutoReview) => APPROVE_FOR_ME_LABEL,
|
|
("auto", ApprovalsReviewer::User) => ASK_FOR_APPROVAL_LABEL,
|
|
_ => preset.label,
|
|
};
|
|
let active_profile_id = self
|
|
.config
|
|
.permissions
|
|
.active_permission_profile()
|
|
.map(|profile| profile.id);
|
|
let current_approval =
|
|
AskForApproval::from(self.config.permissions.approval_policy.value());
|
|
let current_reviewer = self.config.approvals_reviewer;
|
|
let profile_id = id.to_string();
|
|
let selection = PermissionProfileSelection {
|
|
profile_id,
|
|
approval_policy: Some(approval_policy),
|
|
approvals_reviewer: Some(approvals_reviewer),
|
|
display_label: label.to_string(),
|
|
};
|
|
SelectionItem {
|
|
name: label.to_string(),
|
|
description: Some(description),
|
|
is_current: active_profile_id.as_deref() == Some(id)
|
|
&& current_approval == approval_policy
|
|
&& current_reviewer == approvals_reviewer,
|
|
actions: self.permission_mode_actions(
|
|
preset,
|
|
label.to_string(),
|
|
approvals_reviewer,
|
|
Some(selection),
|
|
/*return_to_permissions*/ true,
|
|
),
|
|
dismiss_on_select: true,
|
|
disabled_reason: self
|
|
.config
|
|
.permissions
|
|
.approval_policy
|
|
.can_set(&approval_policy.to_core())
|
|
.err()
|
|
.map(|err| err.to_string())
|
|
.or_else(|| {
|
|
self.config
|
|
.permissions
|
|
.can_set_permission_profile(&preset.permission_profile)
|
|
.err()
|
|
.map(|err| err.to_string())
|
|
}),
|
|
..Default::default()
|
|
}
|
|
}
|
|
|
|
fn permission_profile_selection_item(
|
|
label: &str,
|
|
id: &str,
|
|
description: &str,
|
|
active_profile_id: Option<&str>,
|
|
) -> SelectionItem {
|
|
let id_for_action = id.to_string();
|
|
let selection = PermissionProfileSelection {
|
|
profile_id: id_for_action.clone(),
|
|
approval_policy: None,
|
|
approvals_reviewer: None,
|
|
display_label: id_for_action,
|
|
};
|
|
SelectionItem {
|
|
name: label.to_string(),
|
|
description: Some(description.to_string()),
|
|
is_current: active_profile_id == Some(id),
|
|
actions: Self::permission_profile_selection_actions(selection),
|
|
dismiss_on_select: true,
|
|
..Default::default()
|
|
}
|
|
}
|
|
}
|