mirror of
https://github.com/openai/codex.git
synced 2026-11-03 00:21:31 +00:00
/plugins: remove marketplace (#19843)
This PR adds marketplace removal to the /plugins menu, giving users a way to remove user-configured plugin marketplaces. It adds a `Ctrl+R` shortcut to remove selected marketplace tabs, a confirmation prompt, loading and error states, and the app-server request flow needed to perform marketplace/remove. After a successful removal, the TUI refreshes config, plugin mentions, user config, and plugin data so the removed marketplace disappears from the menu and other surfaces in the TUI. - Add `Ctrl+R` removal option for user-configured marketplace tabs - Show marketplace removal confirmation, loading, and error states - Route `marketplace/remove` through the TUI background request flow - Refresh config, plugin mentions, and plugin data after successful removal - Adds reusable per-tab footer hints so removal guidance only appears on applicable tabs - Add test coverage for `Ctrl+R` behavior while plugin search is active Steps to test: - Add a marketplace using the TUI /plugins menu - Use Ctrl+R to remove the marketplace - Accept the confirmation prompt - Confirm the marketplace is removed when the process completes.
This commit is contained in:
1 parent
c02814c106
commit
a85d265097
9 files changed
+593
-9
No files matched your search
@@ -7,6 +7,8 @@
|
||||
use super::*;
|
||||
use codex_app_server_protocol::MarketplaceAddParams;
|
||||
use codex_app_server_protocol::MarketplaceAddResponse;
|
||||
use codex_app_server_protocol::MarketplaceRemoveParams;
|
||||
use codex_app_server_protocol::MarketplaceRemoveResponse;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
|
||||
impl App {
|
||||
@@ -130,6 +132,30 @@ impl App {
|
||||
});
|
||||
}
|
||||
|
||||
pub(super) fn fetch_marketplace_remove(
|
||||
&mut self,
|
||||
app_server: &AppServerSession,
|
||||
cwd: PathBuf,
|
||||
marketplace_name: String,
|
||||
marketplace_display_name: String,
|
||||
) {
|
||||
let request_handle = app_server.request_handle();
|
||||
let app_event_tx = self.app_event_tx.clone();
|
||||
tokio::spawn(async move {
|
||||
let cwd_for_event = cwd.clone();
|
||||
let marketplace_name_for_event = marketplace_name.clone();
|
||||
let result = fetch_marketplace_remove(request_handle, marketplace_name)
|
||||
.await
|
||||
.map_err(|err| format!("Failed to remove marketplace: {err}"));
|
||||
app_event_tx.send(AppEvent::MarketplaceRemoveLoaded {
|
||||
cwd: cwd_for_event,
|
||||
marketplace_name: marketplace_name_for_event,
|
||||
marketplace_display_name,
|
||||
result,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub(super) fn fetch_plugin_install(
|
||||
&mut self,
|
||||
app_server: &AppServerSession,
|
||||
@@ -582,6 +608,19 @@ fn marketplace_add_source_for_request(cwd: &std::path::Path, source: String) ->
|
||||
source
|
||||
}
|
||||
|
||||
pub(super) async fn fetch_marketplace_remove(
|
||||
request_handle: AppServerRequestHandle,
|
||||
marketplace_name: String,
|
||||
) -> Result<MarketplaceRemoveResponse> {
|
||||
let request_id = RequestId::String(format!("marketplace-remove-{}", Uuid::new_v4()));
|
||||
request_handle
|
||||
.request_typed(ClientRequest::MarketplaceRemove {
|
||||
request_id,
|
||||
params: MarketplaceRemoveParams { marketplace_name },
|
||||
})
|
||||
.await
|
||||
.wrap_err("marketplace/remove failed in TUI")
|
||||
}
|
||||
pub(super) async fn fetch_plugin_install(
|
||||
request_handle: AppServerRequestHandle,
|
||||
marketplace_path: AbsolutePathBuf,
|
||||
|
||||
@@ -390,6 +390,21 @@ impl App {
|
||||
AppEvent::OpenMarketplaceAddLoading { source } => {
|
||||
self.chat_widget.open_marketplace_add_loading_popup(&source);
|
||||
}
|
||||
AppEvent::OpenMarketplaceRemoveConfirm {
|
||||
marketplace_name,
|
||||
marketplace_display_name,
|
||||
} => {
|
||||
self.chat_widget.open_marketplace_remove_confirmation(
|
||||
marketplace_name,
|
||||
marketplace_display_name,
|
||||
);
|
||||
}
|
||||
AppEvent::OpenMarketplaceRemoveLoading {
|
||||
marketplace_display_name,
|
||||
} => {
|
||||
self.chat_widget
|
||||
.open_marketplace_remove_loading_popup(&marketplace_display_name);
|
||||
}
|
||||
AppEvent::OpenPluginDetailLoading {
|
||||
plugin_display_name,
|
||||
} => {
|
||||
@@ -423,6 +438,44 @@ impl App {
|
||||
self.chat_widget
|
||||
.on_marketplace_add_loaded(cwd.clone(), source, result);
|
||||
if add_succeeded && self.chat_widget.config_ref().cwd.as_path() == cwd.as_path() {
|
||||
if let Err(err) = self.refresh_in_memory_config_from_disk().await {
|
||||
tracing::warn!(error = %err, "failed to refresh config after marketplace add");
|
||||
}
|
||||
self.fetch_plugins_list(app_server, cwd);
|
||||
}
|
||||
}
|
||||
AppEvent::FetchMarketplaceRemove {
|
||||
cwd,
|
||||
marketplace_name,
|
||||
marketplace_display_name,
|
||||
} => {
|
||||
self.fetch_marketplace_remove(
|
||||
app_server,
|
||||
cwd,
|
||||
marketplace_name,
|
||||
marketplace_display_name,
|
||||
);
|
||||
}
|
||||
AppEvent::MarketplaceRemoveLoaded {
|
||||
cwd,
|
||||
marketplace_name,
|
||||
marketplace_display_name,
|
||||
result,
|
||||
} => {
|
||||
let remove_succeeded = result.is_ok();
|
||||
self.chat_widget.on_marketplace_remove_loaded(
|
||||
cwd.clone(),
|
||||
marketplace_name,
|
||||
marketplace_display_name,
|
||||
result,
|
||||
);
|
||||
if remove_succeeded && self.chat_widget.config_ref().cwd.as_path() == cwd.as_path()
|
||||
{
|
||||
if let Err(err) = self.refresh_in_memory_config_from_disk().await {
|
||||
tracing::warn!(error = %err, "failed to refresh config after marketplace remove");
|
||||
}
|
||||
self.chat_widget.refresh_plugin_mentions();
|
||||
self.chat_widget.submit_op(AppCommand::reload_user_config());
|
||||
self.fetch_plugins_list(app_server, cwd);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user