mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2025-04-28 17:39:47 +00:00
Migrated the clipboard function from Tauri JS to the runtime API using encryption
This commit is contained in:
parent
79afd42195
commit
1d12facd58
@ -165,7 +165,7 @@ public abstract partial class AssistantBase : ComponentBase
|
||||
|
||||
protected async Task CopyToClipboard()
|
||||
{
|
||||
await this.Rust.CopyText2Clipboard(this.JsRuntime, this.Snackbar, this.Result2Copy());
|
||||
await this.Rust.CopyText2Clipboard(this.Snackbar, this.Result2Copy());
|
||||
}
|
||||
|
||||
private static string? GetButtonIcon(string icon)
|
||||
|
@ -100,7 +100,7 @@ public partial class ContentBlockComponent : ComponentBase
|
||||
{
|
||||
case ContentType.TEXT:
|
||||
var textContent = (ContentText) this.Content;
|
||||
await this.Rust.CopyText2Clipboard(this.JsRuntime, this.Snackbar, textContent.Text);
|
||||
await this.Rust.CopyText2Clipboard(this.Snackbar, textContent.Text);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -78,36 +78,44 @@ public sealed class Rust(string apiPort) : IDisposable
|
||||
/// <summary>
|
||||
/// Tries to copy the given text to the clipboard.
|
||||
/// </summary>
|
||||
/// <param name="jsRuntime">The JS runtime to access the Rust code.</param>
|
||||
/// <param name="snackbar">The snackbar to show the result.</param>
|
||||
/// <param name="text">The text to copy to the clipboard.</param>
|
||||
public async Task CopyText2Clipboard(IJSRuntime jsRuntime, ISnackbar snackbar, string text)
|
||||
public async Task CopyText2Clipboard(ISnackbar snackbar, string text)
|
||||
{
|
||||
var response = await jsRuntime.InvokeAsync<SetClipboardResponse>("window.__TAURI__.invoke", "set_clipboard", new SetClipboardText(text));
|
||||
var msg = response.Success switch
|
||||
var message = "Successfully copied the text to your clipboard";
|
||||
var iconColor = Color.Error;
|
||||
var severity = Severity.Error;
|
||||
try
|
||||
{
|
||||
true => "Successfully copied text to clipboard!",
|
||||
false => $"Failed to copy text to clipboard: {response.Issue}",
|
||||
};
|
||||
|
||||
var severity = response.Success switch
|
||||
{
|
||||
true => Severity.Success,
|
||||
false => Severity.Error,
|
||||
};
|
||||
|
||||
snackbar.Add(msg, severity, config =>
|
||||
{
|
||||
config.Icon = Icons.Material.Filled.ContentCopy;
|
||||
config.IconSize = Size.Large;
|
||||
config.IconColor = severity switch
|
||||
var response = await this.http.PostAsync("/clipboard/set", new StringContent(await text.Encrypt(this.encryptor!)));
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
Severity.Success => Color.Success,
|
||||
Severity.Error => Color.Error,
|
||||
|
||||
_ => Color.Default,
|
||||
};
|
||||
});
|
||||
this.logger!.LogError($"Failed to copy the text to the clipboard due to an network error: '{response.StatusCode}'");
|
||||
message = "Failed to copy the text to your clipboard.";
|
||||
return;
|
||||
}
|
||||
|
||||
var state = await response.Content.ReadFromJsonAsync<SetClipboardResponse>();
|
||||
if (!state.Success)
|
||||
{
|
||||
this.logger!.LogError("Failed to copy the text to the clipboard.");
|
||||
message = "Failed to copy the text to your clipboard.";
|
||||
return;
|
||||
}
|
||||
|
||||
iconColor = Color.Success;
|
||||
severity = Severity.Success;
|
||||
this.logger!.LogDebug("Successfully copied the text to the clipboard.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
snackbar.Add(message, severity, config =>
|
||||
{
|
||||
config.Icon = Icons.Material.Filled.ContentCopy;
|
||||
config.IconSize = Size.Large;
|
||||
config.IconColor = iconColor;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<UpdateResponse> CheckForUpdate(IJSRuntime jsRuntime)
|
||||
|
@ -6,10 +6,8 @@ namespace AIStudio.Tools.Services;
|
||||
/// Wire up the clipboard service to copy Markdown to the clipboard.
|
||||
/// We use our own Rust-based clipboard service for this.
|
||||
/// </summary>
|
||||
public sealed class MarkdownClipboardService(Rust rust, IJSRuntime jsRuntime, ISnackbar snackbar) : IMudMarkdownClipboardService
|
||||
public sealed class MarkdownClipboardService(Rust rust, ISnackbar snackbar) : IMudMarkdownClipboardService
|
||||
{
|
||||
private IJSRuntime JsRuntime { get; } = jsRuntime;
|
||||
|
||||
private ISnackbar Snackbar { get; } = snackbar;
|
||||
|
||||
private Rust Rust { get; } = rust;
|
||||
@ -18,5 +16,5 @@ public sealed class MarkdownClipboardService(Rust rust, IJSRuntime jsRuntime, IS
|
||||
/// Gets called when the user wants to copy the Markdown to the clipboard.
|
||||
/// </summary>
|
||||
/// <param name="text">The Markdown text to copy.</param>
|
||||
public async ValueTask CopyToClipboardAsync(string text) => await this.Rust.CopyText2Clipboard(this.JsRuntime, this.Snackbar, text);
|
||||
public async ValueTask CopyToClipboardAsync(string text) => await this.Rust.CopyText2Clipboard(this.Snackbar, text);
|
||||
}
|
@ -194,7 +194,7 @@ async fn main() {
|
||||
//
|
||||
tauri::async_runtime::spawn(async move {
|
||||
_ = rocket::custom(figment)
|
||||
.mount("/", routes![dotnet_port, dotnet_ready])
|
||||
.mount("/", routes![dotnet_port, dotnet_ready, set_clipboard])
|
||||
.ignite().await.unwrap()
|
||||
.launch().await.unwrap();
|
||||
});
|
||||
@ -312,7 +312,7 @@ async fn main() {
|
||||
})
|
||||
.plugin(tauri_plugin_window_state::Builder::default().build())
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
store_secret, get_secret, delete_secret, set_clipboard,
|
||||
store_secret, get_secret, delete_secret,
|
||||
check_for_update, install_update
|
||||
])
|
||||
.build(tauri::generate_context!())
|
||||
@ -848,36 +848,49 @@ struct DeleteSecretResponse {
|
||||
issue: String,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn set_clipboard(text: String) -> SetClipboardResponse {
|
||||
#[post("/clipboard/set", data = "<encrypted_text>")]
|
||||
fn set_clipboard(encrypted_text: EncryptedText) -> Json<SetClipboardResponse> {
|
||||
|
||||
// Decrypt this text first:
|
||||
let decrypted_text = match ENCRYPTION.decrypt(&encrypted_text) {
|
||||
Ok(text) => text,
|
||||
Err(e) => {
|
||||
error!(Source = "Clipboard"; "Failed to decrypt the text: {e}.");
|
||||
return Json(SetClipboardResponse {
|
||||
success: false,
|
||||
issue: e,
|
||||
})
|
||||
},
|
||||
};
|
||||
|
||||
let clipboard_result = Clipboard::new();
|
||||
let mut clipboard = match clipboard_result {
|
||||
Ok(clipboard) => clipboard,
|
||||
Err(e) => {
|
||||
error!(Source = "Clipboard"; "Failed to get the clipboard instance: {e}.");
|
||||
return SetClipboardResponse {
|
||||
return Json(SetClipboardResponse {
|
||||
success: false,
|
||||
issue: e.to_string(),
|
||||
}
|
||||
})
|
||||
},
|
||||
};
|
||||
|
||||
let set_text_result = clipboard.set_text(text);
|
||||
let set_text_result = clipboard.set_text(decrypted_text);
|
||||
match set_text_result {
|
||||
Ok(_) => {
|
||||
debug!(Source = "Clipboard"; "Text was set to the clipboard successfully.");
|
||||
SetClipboardResponse {
|
||||
Json(SetClipboardResponse {
|
||||
success: true,
|
||||
issue: String::from(""),
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
Err(e) => {
|
||||
error!(Source = "Clipboard"; "Failed to set text to the clipboard: {e}.");
|
||||
SetClipboardResponse {
|
||||
Json(SetClipboardResponse {
|
||||
success: false,
|
||||
issue: e.to_string(),
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user