- Widen code inspector panel from 450px to 550px for better readability - Redesign graph index landing page with polished repo cards showing name, git URL, branch, findings count, and relative update time - Add search suggestions dropdown in graph explorer that appears on typing >= 2 chars, showing node name, kind badge, and file path - Add full graph explorer styles matching Obsidian Control dark theme Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
91 lines
4.5 KiB
Rust
91 lines
4.5 KiB
Rust
use dioxus::prelude::*;
|
|
|
|
use crate::app::Route;
|
|
use crate::components::page_header::PageHeader;
|
|
use crate::infrastructure::repositories::fetch_repositories;
|
|
|
|
#[component]
|
|
pub fn GraphIndexPage() -> Element {
|
|
let repos = use_resource(|| async { fetch_repositories(1).await.ok() });
|
|
|
|
rsx! {
|
|
PageHeader {
|
|
title: "Code Knowledge Graph",
|
|
description: "Select a repository to explore its code graph",
|
|
}
|
|
|
|
match &*repos.read() {
|
|
Some(Some(data)) => {
|
|
let repo_list = &data.data;
|
|
if repo_list.is_empty() {
|
|
rsx! {
|
|
div { class: "card",
|
|
p { "No repositories found. Add a repository first." }
|
|
}
|
|
}
|
|
} else {
|
|
rsx! {
|
|
div { class: "graph-index-grid",
|
|
for repo in repo_list {
|
|
{
|
|
let repo_id = repo.id.map(|id| id.to_hex()).unwrap_or_default();
|
|
let name = repo.name.clone();
|
|
let url = repo.git_url.clone();
|
|
let branch = repo.default_branch.clone();
|
|
let findings = repo.findings_count;
|
|
let findings_label = if findings != 1 { format!("{findings} findings") } else { "1 finding".to_string() };
|
|
let updated = {
|
|
let now = chrono::Utc::now();
|
|
let diff = now.signed_duration_since(repo.updated_at);
|
|
if diff.num_minutes() < 1 {
|
|
"just now".to_string()
|
|
} else if diff.num_hours() < 1 {
|
|
format!("{}m ago", diff.num_minutes())
|
|
} else if diff.num_days() < 1 {
|
|
format!("{}h ago", diff.num_hours())
|
|
} else if diff.num_days() < 30 {
|
|
format!("{}d ago", diff.num_days())
|
|
} else {
|
|
repo.updated_at.format("%Y-%m-%d").to_string()
|
|
}
|
|
};
|
|
rsx! {
|
|
Link {
|
|
to: Route::GraphExplorerPage { repo_id },
|
|
class: "graph-repo-card",
|
|
div { class: "graph-repo-card-header",
|
|
div { class: "graph-repo-card-icon", "\u{29BB}" }
|
|
h3 { class: "graph-repo-card-name", "{name}" }
|
|
}
|
|
if !url.is_empty() {
|
|
p { class: "graph-repo-card-url", "{url}" }
|
|
}
|
|
div { class: "graph-repo-card-meta",
|
|
span { class: "graph-repo-card-tag",
|
|
"\u{E0A0} {branch}"
|
|
}
|
|
span { class: "graph-repo-card-tag graph-repo-card-tag-findings",
|
|
"{findings_label}"
|
|
}
|
|
span { class: "graph-repo-card-tag",
|
|
"Updated {updated}"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
Some(None) => rsx! {
|
|
div { class: "card", p { "Failed to load repositories." } }
|
|
},
|
|
None => rsx! {
|
|
div { class: "loading", "Loading repositories..." }
|
|
},
|
|
}
|
|
}
|
|
}
|