Don't block window creation on plugin runtime boot (#616)

This commit is contained in:
Gregory Schier
2026-09-01 09:14:50 -07:00
committed by GitHub
parent 8eebee460e
commit d461c982ec
15 changed files with 183 additions and 105 deletions
+6 -1
View File
@@ -121,7 +121,12 @@ pub trait PluginHost: Host {
/// a render — the variables come from the environment chain, which is an
/// ordinary database read — so handing back the callback keeps the rest of
/// rendering shared instead of pushing whole commands behind this trait.
fn template_callback(&self, purpose: RenderPurpose) -> impl TemplateCallback;
/// Async so hosts that finish booting their plugin runtime in the
/// background can wait for it here.
fn template_callback(
&self,
purpose: RenderPurpose,
) -> impl Future<Output = crate::Result<impl TemplateCallback>>;
/// Every template function the installed plugins expose, for the
/// autocomplete menu.
+1 -1
View File
@@ -66,7 +66,7 @@ pub(crate) async fn render_form_values<H: PluginHost>(
let environment_chain =
host.db().resolve_environments(&workspace_id, folder_id.as_deref(), environment_id)?;
let cb = host.template_callback(purpose);
let cb = host.template_callback(purpose).await?;
let rendered =
render_json_value(serde_json::to_value(&values)?, environment_chain, &cb, options).await?;
+2 -2
View File
@@ -21,7 +21,7 @@ pub async fn cmd_render_template<H: PluginHost>(
) -> Result<String> {
let environment_chain =
host.db().resolve_environments(&req.workspace_id, None, req.environment_id.as_deref())?;
let cb = host.template_callback(req.purpose.unwrap_or(RenderPurpose::Preview));
let cb = host.template_callback(req.purpose.unwrap_or(RenderPurpose::Preview)).await?;
let options = RenderOptions {
// A preview that throws would show the user an error where they expect
// to see the value so far, so callers rendering *into the UI* ask for
@@ -41,7 +41,7 @@ pub async fn cmd_template_tokens_to_string<H: PluginHost>(
host: H,
req: CmdTemplateTokensToStringReq,
) -> Result<String> {
let cb = host.template_callback(RenderPurpose::Preview);
let cb = host.template_callback(RenderPurpose::Preview).await?;
Ok(transform_args(req.tokens, &cb)?.to_string())
}
+5 -2
View File
@@ -250,8 +250,11 @@ impl PluginHost for SingleThreadedHost {
Err(yaak_commands::Error::Generic("no plugin runtime on this host".into()))
}
fn template_callback(&self, _purpose: RenderPurpose) -> impl TemplateCallback {
NoTemplateFunctions
async fn template_callback(
&self,
_purpose: RenderPurpose,
) -> yaak_commands::Result<impl TemplateCallback> {
Ok(NoTemplateFunctions)
}
async fn template_function_summaries(
+18 -17
View File
@@ -187,24 +187,25 @@ impl PluginManager {
}
let bundled_dirs = plugin_manager.list_bundled_plugin_dirs().await?;
let db = query_manager.connect();
for dir in &bundled_dirs {
if db.get_plugin_by_directory(dir).is_none() {
db.upsert_plugin(
&Plugin {
directory: dir.clone(),
enabled: true,
url: None,
source: PluginSource::Bundled,
..Default::default()
},
&UpdateSource::Background,
)?;
// Scope the db connection so the future stays Send across the await below
let plugins = {
let db = query_manager.connect();
for dir in &bundled_dirs {
if db.get_plugin_by_directory(dir).is_none() {
db.upsert_plugin(
&Plugin {
directory: dir.clone(),
enabled: true,
url: None,
source: PluginSource::Bundled,
..Default::default()
},
&UpdateSource::Background,
)?;
}
}
}
let plugins = db.list_plugins()?;
drop(db);
db.list_plugins()?
};
let init_errors = plugin_manager.initialize_all_plugins(plugins, plugin_context).await;
if !init_errors.is_empty() {