Add DAST, graph modules, toast notifications, and dashboard enhancements

Add DAST scanning and code knowledge graph features across the stack:
- compliance-dast and compliance-graph workspace crates
- Agent API handlers and routes for DAST targets/scans and graph builds
- Core models and traits for DAST and graph domains
- Dashboard pages for DAST targets/findings/overview and graph explorer/impact
- Toast notification system with auto-dismiss for async action feedback
- Button click animations and disabled states for better UX

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sharang Parnerkar
2026-03-04 13:53:50 +01:00
parent 03ee69834d
commit cea8f59e10
69 changed files with 8745 additions and 54 deletions

View File

@@ -0,0 +1,86 @@
use dioxus::prelude::*;
#[derive(Clone, PartialEq)]
pub enum ToastType {
Success,
Error,
Info,
}
#[derive(Clone, PartialEq)]
pub struct ToastMessage {
pub id: usize,
pub message: String,
pub toast_type: ToastType,
}
#[derive(Clone, Copy)]
pub struct Toasts {
items: Signal<Vec<ToastMessage>>,
next_id: Signal<usize>,
}
impl Toasts {
pub fn new() -> Self {
Self {
items: Signal::new(vec![]),
next_id: Signal::new(0),
}
}
pub fn push(&mut self, toast_type: ToastType, message: impl Into<String>) {
let id = *self.next_id.read();
*self.next_id.write() = id + 1;
self.items.write().push(ToastMessage {
id,
message: message.into(),
toast_type,
});
#[cfg(feature = "web")]
{
let mut items = self.items;
spawn(async move {
gloo_timers::future::TimeoutFuture::new(4_000).await;
items.write().retain(|t| t.id != id);
});
}
}
pub fn remove(&mut self, id: usize) {
self.items.write().retain(|t| t.id != id);
}
}
#[component]
pub fn ToastContainer() -> Element {
let mut toasts = use_context::<Toasts>();
let items = toasts.items.read();
rsx! {
div { class: "toast-container",
for toast in items.iter() {
{
let toast_id = toast.id;
let type_class = match toast.toast_type {
ToastType::Success => "toast-success",
ToastType::Error => "toast-error",
ToastType::Info => "toast-info",
};
rsx! {
div {
key: "{toast_id}",
class: "toast {type_class}",
span { "{toast.message}" }
button {
class: "toast-dismiss",
onclick: move |_| toasts.remove(toast_id),
"\u{00d7}"
}
}
}
}
}
}
}
}