feat: add CopyButton component and copy-to-clipboard across dashboard
Some checks failed
CI / Detect Changes (pull_request) Has been cancelled
CI / Deploy Agent (pull_request) Has been cancelled
CI / Deploy Dashboard (pull_request) Has been cancelled
CI / Deploy Docs (pull_request) Has been cancelled
CI / Deploy MCP (pull_request) Has been cancelled
CI / Check (pull_request) Has been cancelled
Some checks failed
CI / Detect Changes (pull_request) Has been cancelled
CI / Deploy Agent (pull_request) Has been cancelled
CI / Deploy Dashboard (pull_request) Has been cancelled
CI / Deploy Docs (pull_request) Has been cancelled
CI / Deploy MCP (pull_request) Has been cancelled
CI / Check (pull_request) Has been cancelled
New reusable CopyButton component with checkmark feedback after copy. Added copy buttons to: - SSH public key display (add repo modal) - Webhook URL field (edit repo modal) - Webhook secret field (edit repo modal) - Code snippets in finding detail (via enhanced CodeSnippet component) - Suggested fix code blocks - MCP server endpoint URLs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
45
compliance-dashboard/src/components/copy_button.rs
Normal file
45
compliance-dashboard/src/components/copy_button.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_free_icons::icons::bs_icons::*;
|
||||
use dioxus_free_icons::Icon;
|
||||
|
||||
/// A small copy-to-clipboard button that shows a checkmark after copying.
|
||||
///
|
||||
/// Usage: `CopyButton { value: "text to copy" }`
|
||||
#[component]
|
||||
pub fn CopyButton(value: String, #[props(default = false)] small: bool) -> Element {
|
||||
let mut copied = use_signal(|| false);
|
||||
|
||||
let size = if small { 12 } else { 14 };
|
||||
let class = if small {
|
||||
"copy-btn copy-btn-sm"
|
||||
} else {
|
||||
"copy-btn"
|
||||
};
|
||||
|
||||
rsx! {
|
||||
button {
|
||||
class: class,
|
||||
title: if copied() { "Copied!" } else { "Copy to clipboard" },
|
||||
onclick: move |_| {
|
||||
let val = value.clone();
|
||||
// Escape single quotes for JS
|
||||
let escaped = val.replace('\\', "\\\\").replace('\'', "\\'");
|
||||
let js = format!("navigator.clipboard.writeText('{escaped}')");
|
||||
document::eval(&js);
|
||||
copied.set(true);
|
||||
spawn(async move {
|
||||
#[cfg(feature = "web")]
|
||||
gloo_timers::future::TimeoutFuture::new(2000).await;
|
||||
#[cfg(not(feature = "web"))]
|
||||
tokio::time::sleep(std::time::Duration::from_secs(2)).await;
|
||||
copied.set(false);
|
||||
});
|
||||
},
|
||||
if copied() {
|
||||
Icon { icon: BsCheckLg, width: size, height: size }
|
||||
} else {
|
||||
Icon { icon: BsClipboard, width: size, height: size }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user