0.3.6 — plugin registry, Unreal extracted to a plugin, in-app update check + fixes
- Official plugin registry hosted on Gitea; client fetches registry.json over HTTPS and installs plugins via backend plugin_write_file. - Auto-install autoInstall plugins on first connect; per-machine enabled state. - Extract all Unreal tooling (Build Solution / Unreal Log) into a separate "unreal" plugin (defaultEnabled) driven through the new host.ue bridge; core UI no longer hard-wires Unreal. - Settings → Plugins: "Official plugins" section with Install buttons. - Status bar: "Updates" button (right of Log) triggers an update check without restarting the client. - Fixes: NEW badge hard-right/centered without shifting text; History commit size no longer flickers (cached per change); giant icons in empty plugin/ People lists; Get Latest hover contrast. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -2923,7 +2923,10 @@ async fn plugin_list() -> Result<Vec<Value>, String> {
|
||||
let Ok(m) = serde_json::from_str::<Value>(&txt) else { continue };
|
||||
let id = m.get("id").and_then(|v| v.as_str()).map(String::from)
|
||||
.unwrap_or_else(|| e.file_name().to_string_lossy().to_string());
|
||||
let enabled = *en.get(&id).unwrap_or(&true);
|
||||
// off by default unless the manifest opts in (defaultEnabled) — official
|
||||
// plugins like Unreal ship on; the user's choice persists in enabled.json
|
||||
let default_on = m.get("defaultEnabled").and_then(|v| v.as_bool()).unwrap_or(false);
|
||||
let enabled = *en.get(&id).unwrap_or(&default_on);
|
||||
out.push(serde_json::json!({
|
||||
"id": id,
|
||||
"name": m.get("name").and_then(|v| v.as_str()).unwrap_or(""),
|
||||
@ -2967,6 +2970,23 @@ async fn plugin_set_enabled(id: String, enabled: bool) -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Write one file of a plugin into <config>/plugins/<id>/<name>. The frontend
|
||||
/// fetches the file bytes from the registry over HTTPS and hands the content here;
|
||||
/// this only touches the confined plugins folder (id + name are path-validated).
|
||||
#[tauri::command]
|
||||
async fn plugin_write_file(id: String, name: String, content: String) -> Result<(), String> {
|
||||
if id.is_empty() || !id.chars().all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_' || c == '.') || id.contains("..") {
|
||||
return Err("Invalid plugin id".into());
|
||||
}
|
||||
if name.is_empty() || name.contains('/') || name.contains('\\') || name.contains("..") {
|
||||
return Err("Invalid file name".into());
|
||||
}
|
||||
let dir = plugins_dir().ok_or("No config dir")?.join(&id);
|
||||
std::fs::create_dir_all(&dir).map_err(|e| e.to_string())?;
|
||||
std::fs::write(dir.join(&name), content).map_err(|e| e.to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn copy_dir_recursive(from: &std::path::Path, to: &std::path::Path) -> std::io::Result<()> {
|
||||
std::fs::create_dir_all(to)?;
|
||||
for e in std::fs::read_dir(from)? {
|
||||
@ -3125,6 +3145,7 @@ pub fn run() {
|
||||
plugin_list,
|
||||
plugin_read_entry,
|
||||
plugin_set_enabled,
|
||||
plugin_write_file,
|
||||
plugin_install,
|
||||
plugin_remove,
|
||||
plugins_dir_path,
|
||||
|
||||
Reference in New Issue
Block a user