feat(developer): replace agents iframe with informational landing and live agent table
LangGraph is API-only with no web UI, so the ToolEmbed iframe pattern doesn't work. Replace it with an informational landing page featuring a hero section, connection status indicator, quick-start card grid linking to docs/GitHub/examples, and a live table of registered agents fetched from the LangGraph POST /assistants/search endpoint. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -98,7 +98,27 @@
|
||||
"tokens_used": "Verbrauchte Token",
|
||||
"error_rate": "Fehlerrate",
|
||||
"not_configured": "Nicht konfiguriert",
|
||||
"open_new_tab": "In neuem Tab oeffnen"
|
||||
"open_new_tab": "In neuem Tab oeffnen",
|
||||
"agents_status_connected": "Verbunden",
|
||||
"agents_status_not_connected": "Nicht verbunden",
|
||||
"agents_config_hint": "Setzen Sie LANGGRAPH_URL in .env, um eine Verbindung herzustellen",
|
||||
"agents_quick_start": "Schnellstart",
|
||||
"agents_docs": "Dokumentation",
|
||||
"agents_docs_desc": "Offizielle LangGraph-Dokumentation und API-Anleitungen.",
|
||||
"agents_getting_started": "Erste Schritte",
|
||||
"agents_getting_started_desc": "Schritt-fuer-Schritt-Anleitung zum Erstellen Ihres ersten Agenten.",
|
||||
"agents_github": "GitHub",
|
||||
"agents_github_desc": "Quellcode, Issues und Community-Beitraege.",
|
||||
"agents_examples": "Beispiele",
|
||||
"agents_examples_desc": "Einsatzbereite Vorlagen und Beispielprojekte fuer Agenten.",
|
||||
"agents_api_ref": "API-Referenz",
|
||||
"agents_api_ref_desc": "Lokale Swagger-Dokumentation fuer Ihre LangGraph-Instanz.",
|
||||
"agents_running_title": "Laufende Agenten",
|
||||
"agents_none": "Keine Agenten registriert. Stellen Sie einen Assistenten in LangGraph bereit, um ihn hier zu sehen.",
|
||||
"agents_col_name": "Name",
|
||||
"agents_col_id": "ID",
|
||||
"agents_col_description": "Beschreibung",
|
||||
"agents_col_status": "Status"
|
||||
},
|
||||
"org": {
|
||||
"title": "Organisation",
|
||||
|
||||
@@ -98,7 +98,27 @@
|
||||
"tokens_used": "Tokens Used",
|
||||
"error_rate": "Error Rate",
|
||||
"not_configured": "Not Configured",
|
||||
"open_new_tab": "Open in New Tab"
|
||||
"open_new_tab": "Open in New Tab",
|
||||
"agents_status_connected": "Connected",
|
||||
"agents_status_not_connected": "Not Connected",
|
||||
"agents_config_hint": "Set LANGGRAPH_URL in .env to connect",
|
||||
"agents_quick_start": "Quick Start",
|
||||
"agents_docs": "Documentation",
|
||||
"agents_docs_desc": "Official LangGraph documentation and API guides.",
|
||||
"agents_getting_started": "Getting Started",
|
||||
"agents_getting_started_desc": "Step-by-step tutorial to build your first agent.",
|
||||
"agents_github": "GitHub",
|
||||
"agents_github_desc": "Source code, issues, and community contributions.",
|
||||
"agents_examples": "Examples",
|
||||
"agents_examples_desc": "Ready-to-use templates and example agent projects.",
|
||||
"agents_api_ref": "API Reference",
|
||||
"agents_api_ref_desc": "Local Swagger docs for your LangGraph instance.",
|
||||
"agents_running_title": "Running Agents",
|
||||
"agents_none": "No agents registered. Deploy an assistant to LangGraph to see it here.",
|
||||
"agents_col_name": "Name",
|
||||
"agents_col_id": "ID",
|
||||
"agents_col_description": "Description",
|
||||
"agents_col_status": "Status"
|
||||
},
|
||||
"org": {
|
||||
"title": "Organization",
|
||||
|
||||
@@ -98,7 +98,27 @@
|
||||
"tokens_used": "Tokens utilizados",
|
||||
"error_rate": "Tasa de errores",
|
||||
"not_configured": "No configurado",
|
||||
"open_new_tab": "Abrir en nueva pestana"
|
||||
"open_new_tab": "Abrir en nueva pestana",
|
||||
"agents_status_connected": "Conectado",
|
||||
"agents_status_not_connected": "No conectado",
|
||||
"agents_config_hint": "Configure LANGGRAPH_URL en .env para conectar",
|
||||
"agents_quick_start": "Inicio rapido",
|
||||
"agents_docs": "Documentacion",
|
||||
"agents_docs_desc": "Documentacion oficial de LangGraph y guias de API.",
|
||||
"agents_getting_started": "Primeros pasos",
|
||||
"agents_getting_started_desc": "Tutorial paso a paso para crear su primer agente.",
|
||||
"agents_github": "GitHub",
|
||||
"agents_github_desc": "Codigo fuente, issues y contribuciones de la comunidad.",
|
||||
"agents_examples": "Ejemplos",
|
||||
"agents_examples_desc": "Plantillas y proyectos de agentes listos para usar.",
|
||||
"agents_api_ref": "Referencia API",
|
||||
"agents_api_ref_desc": "Documentacion Swagger local para su instancia de LangGraph.",
|
||||
"agents_running_title": "Agentes en ejecucion",
|
||||
"agents_none": "No hay agentes registrados. Despliegue un asistente en LangGraph para verlo aqui.",
|
||||
"agents_col_name": "Nombre",
|
||||
"agents_col_id": "ID",
|
||||
"agents_col_description": "Descripcion",
|
||||
"agents_col_status": "Estado"
|
||||
},
|
||||
"org": {
|
||||
"title": "Organizacion",
|
||||
|
||||
@@ -98,7 +98,27 @@
|
||||
"tokens_used": "Tokens utilises",
|
||||
"error_rate": "Taux d'erreur",
|
||||
"not_configured": "Non configure",
|
||||
"open_new_tab": "Ouvrir dans un nouvel onglet"
|
||||
"open_new_tab": "Ouvrir dans un nouvel onglet",
|
||||
"agents_status_connected": "Connecte",
|
||||
"agents_status_not_connected": "Non connecte",
|
||||
"agents_config_hint": "Definissez LANGGRAPH_URL dans .env pour vous connecter",
|
||||
"agents_quick_start": "Demarrage rapide",
|
||||
"agents_docs": "Documentation",
|
||||
"agents_docs_desc": "Documentation officielle de LangGraph et guides API.",
|
||||
"agents_getting_started": "Premiers pas",
|
||||
"agents_getting_started_desc": "Tutoriel etape par etape pour creer votre premier agent.",
|
||||
"agents_github": "GitHub",
|
||||
"agents_github_desc": "Code source, issues et contributions de la communaute.",
|
||||
"agents_examples": "Exemples",
|
||||
"agents_examples_desc": "Modeles et projets d'agents prets a l'emploi.",
|
||||
"agents_api_ref": "Reference API",
|
||||
"agents_api_ref_desc": "Documentation Swagger locale pour votre instance LangGraph.",
|
||||
"agents_running_title": "Agents en cours",
|
||||
"agents_none": "Aucun agent enregistre. Deployez un assistant dans LangGraph pour le voir ici.",
|
||||
"agents_col_name": "Nom",
|
||||
"agents_col_id": "ID",
|
||||
"agents_col_description": "Description",
|
||||
"agents_col_status": "Statut"
|
||||
},
|
||||
"org": {
|
||||
"title": "Organisation",
|
||||
|
||||
@@ -98,7 +98,27 @@
|
||||
"tokens_used": "Tokens Utilizados",
|
||||
"error_rate": "Taxa de Erros",
|
||||
"not_configured": "Nao configurado",
|
||||
"open_new_tab": "Abrir em novo separador"
|
||||
"open_new_tab": "Abrir em novo separador",
|
||||
"agents_status_connected": "Conectado",
|
||||
"agents_status_not_connected": "Nao conectado",
|
||||
"agents_config_hint": "Defina LANGGRAPH_URL no .env para conectar",
|
||||
"agents_quick_start": "Inicio rapido",
|
||||
"agents_docs": "Documentacao",
|
||||
"agents_docs_desc": "Documentacao oficial do LangGraph e guias de API.",
|
||||
"agents_getting_started": "Primeiros passos",
|
||||
"agents_getting_started_desc": "Tutorial passo a passo para criar o seu primeiro agente.",
|
||||
"agents_github": "GitHub",
|
||||
"agents_github_desc": "Codigo fonte, issues e contribuicoes da comunidade.",
|
||||
"agents_examples": "Exemplos",
|
||||
"agents_examples_desc": "Modelos e projetos de agentes prontos a usar.",
|
||||
"agents_api_ref": "Referencia API",
|
||||
"agents_api_ref_desc": "Documentacao Swagger local para a sua instancia LangGraph.",
|
||||
"agents_running_title": "Agentes em execucao",
|
||||
"agents_none": "Nenhum agente registado. Implemente um assistente no LangGraph para o ver aqui.",
|
||||
"agents_col_name": "Nome",
|
||||
"agents_col_id": "ID",
|
||||
"agents_col_description": "Descricao",
|
||||
"agents_col_status": "Estado"
|
||||
},
|
||||
"org": {
|
||||
"title": "Organizacao",
|
||||
|
||||
247
assets/main.css
247
assets/main.css
@@ -3374,4 +3374,251 @@ h6 {
|
||||
.feature-card {
|
||||
padding: 20px 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== Agents Page ===== */
|
||||
.agents-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 32px;
|
||||
gap: 32px;
|
||||
}
|
||||
|
||||
.agents-hero {
|
||||
max-width: 720px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.agents-hero-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.agents-hero-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
min-width: 48px;
|
||||
background: linear-gradient(135deg, var(--accent), var(--accent-secondary));
|
||||
color: var(--avatar-text);
|
||||
border-radius: 12px;
|
||||
font-size: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.agents-hero-title {
|
||||
font-family: 'Space Grotesk', sans-serif;
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
color: var(--text-heading);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.agents-hero-desc {
|
||||
font-size: 15px;
|
||||
color: var(--text-muted);
|
||||
line-height: 1.6;
|
||||
max-width: 600px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.agents-status {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.agents-status-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.agents-status-dot--on {
|
||||
background-color: #22c55e;
|
||||
}
|
||||
|
||||
.agents-status-dot--off {
|
||||
background-color: var(--text-faint);
|
||||
}
|
||||
|
||||
.agents-status-url {
|
||||
font-family: 'JetBrains Mono', 'Fira Code', monospace;
|
||||
color: var(--accent);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.agents-status-hint {
|
||||
font-size: 13px;
|
||||
color: var(--text-faint);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.agents-section-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: var(--text-heading);
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
|
||||
.agents-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.agents-card {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
background-color: var(--bg-card);
|
||||
border: 1px solid var(--border-primary);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
transition: border-color 0.2s, transform 0.2s;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.agents-card:hover {
|
||||
border-color: var(--accent);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.agents-card-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
min-width: 36px;
|
||||
background: linear-gradient(135deg, var(--accent), var(--accent-secondary));
|
||||
color: var(--avatar-text);
|
||||
border-radius: 8px;
|
||||
font-size: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.agents-card-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--text-heading);
|
||||
margin: 12px 0 4px;
|
||||
}
|
||||
|
||||
.agents-card-desc {
|
||||
font-size: 13px;
|
||||
color: var(--text-muted);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.agents-card--disabled {
|
||||
opacity: 0.4;
|
||||
pointer-events: none;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/* -- Agents table -- */
|
||||
.agents-table-section {
|
||||
max-width: 960px;
|
||||
}
|
||||
|
||||
.agents-table-wrap {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.agents-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.agents-table thead th {
|
||||
text-align: left;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--text-faint);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
padding: 8px 12px;
|
||||
border-bottom: 1px solid var(--border-secondary);
|
||||
}
|
||||
|
||||
.agents-table tbody td {
|
||||
padding: 10px 12px;
|
||||
border-bottom: 1px solid var(--border-primary);
|
||||
color: var(--text-primary);
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.agents-table tbody tr:hover {
|
||||
background-color: var(--bg-surface);
|
||||
}
|
||||
|
||||
.agents-cell-name {
|
||||
font-weight: 600;
|
||||
color: var(--text-heading);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.agents-cell-id {
|
||||
font-family: 'JetBrains Mono', 'Fira Code', monospace;
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.agents-cell-desc {
|
||||
max-width: 300px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.agents-cell-none {
|
||||
color: var(--text-faint);
|
||||
}
|
||||
|
||||
.agents-badge {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
padding: 2px 10px;
|
||||
border-radius: 9999px;
|
||||
}
|
||||
|
||||
.agents-badge--active {
|
||||
background-color: rgba(34, 197, 94, 0.15);
|
||||
color: #22c55e;
|
||||
}
|
||||
|
||||
.agents-table-loading,
|
||||
.agents-table-empty {
|
||||
font-size: 14px;
|
||||
color: var(--text-faint);
|
||||
font-style: italic;
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.agents-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.agents-page {
|
||||
padding: 20px 16px;
|
||||
}
|
||||
|
||||
.agents-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
107
src/infrastructure/langgraph.rs
Normal file
107
src/infrastructure/langgraph.rs
Normal file
@@ -0,0 +1,107 @@
|
||||
use dioxus::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::models::AgentEntry;
|
||||
|
||||
/// Raw assistant object returned by the LangGraph `POST /assistants/search`
|
||||
/// endpoint. Only the fields we display are deserialized; unknown keys are
|
||||
/// silently ignored thanks to serde defaults.
|
||||
#[cfg(feature = "server")]
|
||||
#[derive(Deserialize)]
|
||||
struct LangGraphAssistant {
|
||||
assistant_id: String,
|
||||
#[serde(default)]
|
||||
name: String,
|
||||
#[serde(default)]
|
||||
graph_id: String,
|
||||
#[serde(default)]
|
||||
metadata: serde_json::Value,
|
||||
}
|
||||
|
||||
/// Fetch the list of assistants (agents) from a LangGraph instance.
|
||||
///
|
||||
/// Calls `POST <langgraph_url>/assistants/search` with an empty body to
|
||||
/// retrieve every registered assistant. Each result is mapped to the
|
||||
/// frontend-friendly `AgentEntry` model.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A vector of `AgentEntry` structs. Returns an empty vector when the
|
||||
/// LangGraph URL is not configured or the service is unreachable.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `ServerFnError` on network or deserialization failures that
|
||||
/// indicate a misconfigured (but present) LangGraph instance.
|
||||
#[server(endpoint = "list-langgraph-agents")]
|
||||
pub async fn list_langgraph_agents() -> Result<Vec<AgentEntry>, ServerFnError> {
|
||||
let state: crate::infrastructure::ServerState =
|
||||
dioxus_fullstack::FullstackContext::extract().await?;
|
||||
|
||||
let base_url = state.services.langgraph_url.clone();
|
||||
if base_url.is_empty() {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
|
||||
let url = format!("{}/assistants/search", base_url.trim_end_matches('/'));
|
||||
|
||||
let client = reqwest::Client::builder()
|
||||
.timeout(std::time::Duration::from_secs(5))
|
||||
.build()
|
||||
.map_err(|e| ServerFnError::new(format!("HTTP client error: {e}")))?;
|
||||
|
||||
// LangGraph expects a POST with a JSON body (empty object = no filters).
|
||||
let resp = match client
|
||||
.post(&url)
|
||||
.header("content-type", "application/json")
|
||||
.body("{}")
|
||||
.send()
|
||||
.await
|
||||
{
|
||||
Ok(r) if r.status().is_success() => r,
|
||||
Ok(r) => {
|
||||
let status = r.status();
|
||||
let body = r.text().await.unwrap_or_default();
|
||||
tracing::error!("LangGraph returned {status}: {body}");
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("LangGraph request failed: {e}");
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
};
|
||||
|
||||
let assistants: Vec<LangGraphAssistant> = resp
|
||||
.json()
|
||||
.await
|
||||
.map_err(|e| ServerFnError::new(format!("Failed to parse LangGraph response: {e}")))?;
|
||||
|
||||
let entries = assistants
|
||||
.into_iter()
|
||||
.map(|a| {
|
||||
// Use the assistant name if present, otherwise fall back to graph_id.
|
||||
let name = if a.name.is_empty() {
|
||||
a.graph_id.clone()
|
||||
} else {
|
||||
a.name
|
||||
};
|
||||
|
||||
// Extract a description from metadata if available.
|
||||
let description = a
|
||||
.metadata
|
||||
.get("description")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("")
|
||||
.to_string();
|
||||
|
||||
AgentEntry {
|
||||
id: a.assistant_id,
|
||||
name,
|
||||
description,
|
||||
status: "active".to_string(),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(entries)
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
// the #[server] macro generates client stubs for the web target)
|
||||
pub mod auth_check;
|
||||
pub mod chat;
|
||||
pub mod langgraph;
|
||||
pub mod llm;
|
||||
pub mod ollama;
|
||||
pub mod searxng;
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
use dioxus::prelude::*;
|
||||
|
||||
use crate::components::ToolEmbed;
|
||||
use crate::i18n::{t, Locale};
|
||||
use crate::models::ServiceUrlsContext;
|
||||
|
||||
/// Agents page embedding the LangGraph agent builder.
|
||||
/// Agents informational landing page for LangGraph.
|
||||
///
|
||||
/// When `langgraph_url` is configured, embeds the service in an iframe
|
||||
/// with a pop-out button. Otherwise shows a "Not Configured" placeholder.
|
||||
/// Since LangGraph is API-only (no web UI), this page displays a hero section
|
||||
/// explaining its role, a connection status indicator, a card grid linking
|
||||
/// to documentation, and a live table of registered agents fetched from the
|
||||
/// LangGraph assistants API.
|
||||
#[component]
|
||||
pub fn AgentsPage() -> Element {
|
||||
let locale = use_context::<Signal<Locale>>();
|
||||
@@ -15,13 +16,209 @@ pub fn AgentsPage() -> Element {
|
||||
let l = *locale.read();
|
||||
let url = svc.read().langgraph_url.clone();
|
||||
|
||||
// Derive whether a LangGraph URL is configured
|
||||
let connected = !url.is_empty();
|
||||
// Build the API reference URL from the configured base, falling back to "#"
|
||||
let api_ref_href = if connected {
|
||||
format!("{}/docs", url)
|
||||
} else {
|
||||
"#".to_string()
|
||||
};
|
||||
|
||||
// Fetch agents from LangGraph when connected
|
||||
let agents_resource = use_resource(move || async move {
|
||||
match crate::infrastructure::langgraph::list_langgraph_agents().await {
|
||||
Ok(agents) => agents,
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to fetch agents: {e}");
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
rsx! {
|
||||
ToolEmbed {
|
||||
url,
|
||||
title: t(l, "developer.agents_title"),
|
||||
description: t(l, "developer.agents_desc"),
|
||||
icon: "A",
|
||||
launch_label: t(l, "developer.launch_agents"),
|
||||
div { class: "agents-page",
|
||||
// -- Hero section --
|
||||
div { class: "agents-hero",
|
||||
div { class: "agents-hero-row",
|
||||
div { class: "agents-hero-icon placeholder-icon", "A" }
|
||||
h2 { class: "agents-hero-title",
|
||||
{t(l, "developer.agents_title")}
|
||||
}
|
||||
}
|
||||
p { class: "agents-hero-desc",
|
||||
{t(l, "developer.agents_desc")}
|
||||
}
|
||||
|
||||
// -- Connection status --
|
||||
if connected {
|
||||
div { class: "agents-status",
|
||||
span {
|
||||
class: "agents-status-dot agents-status-dot--on",
|
||||
}
|
||||
span { {t(l, "developer.agents_status_connected")} }
|
||||
code { class: "agents-status-url", {url.clone()} }
|
||||
}
|
||||
} else {
|
||||
div { class: "agents-status",
|
||||
span {
|
||||
class: "agents-status-dot agents-status-dot--off",
|
||||
}
|
||||
span { {t(l, "developer.agents_status_not_connected")} }
|
||||
span { class: "agents-status-hint",
|
||||
{t(l, "developer.agents_config_hint")}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- Running Agents table --
|
||||
div { class: "agents-table-section",
|
||||
h3 { class: "agents-section-title",
|
||||
{t(l, "developer.agents_running_title")}
|
||||
}
|
||||
|
||||
match agents_resource.read().as_ref() {
|
||||
None => {
|
||||
rsx! {
|
||||
p { class: "agents-table-loading",
|
||||
{t(l, "common.loading")}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(agents) if agents.is_empty() => {
|
||||
rsx! {
|
||||
p { class: "agents-table-empty",
|
||||
{t(l, "developer.agents_none")}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(agents) => {
|
||||
rsx! {
|
||||
div { class: "agents-table-wrap",
|
||||
table { class: "agents-table",
|
||||
thead {
|
||||
tr {
|
||||
th { {t(l, "developer.agents_col_name")} }
|
||||
th { {t(l, "developer.agents_col_id")} }
|
||||
th { {t(l, "developer.agents_col_description")} }
|
||||
th { {t(l, "developer.agents_col_status")} }
|
||||
}
|
||||
}
|
||||
tbody {
|
||||
for agent in agents.iter() {
|
||||
tr { key: "{agent.id}",
|
||||
td { class: "agents-cell-name",
|
||||
{agent.name.clone()}
|
||||
}
|
||||
td {
|
||||
code { class: "agents-cell-id",
|
||||
{agent.id.clone()}
|
||||
}
|
||||
}
|
||||
td { class: "agents-cell-desc",
|
||||
if agent.description.is_empty() {
|
||||
span { class: "agents-cell-none", "--" }
|
||||
} else {
|
||||
{agent.description.clone()}
|
||||
}
|
||||
}
|
||||
td {
|
||||
span { class: "agents-badge agents-badge--active",
|
||||
{agent.status.clone()}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- Quick Start card grid --
|
||||
h3 { class: "agents-section-title",
|
||||
{t(l, "developer.agents_quick_start")}
|
||||
}
|
||||
|
||||
div { class: "agents-grid",
|
||||
// Documentation
|
||||
a {
|
||||
class: "agents-card",
|
||||
href: "https://langchain-ai.github.io/langgraph/",
|
||||
target: "_blank",
|
||||
rel: "noopener noreferrer",
|
||||
div { class: "agents-card-icon placeholder-icon", "D" }
|
||||
div { class: "agents-card-title",
|
||||
{t(l, "developer.agents_docs")}
|
||||
}
|
||||
div { class: "agents-card-desc",
|
||||
{t(l, "developer.agents_docs_desc")}
|
||||
}
|
||||
}
|
||||
|
||||
// Getting Started
|
||||
a {
|
||||
class: "agents-card",
|
||||
href: "https://langchain-ai.github.io/langgraph/tutorials/introduction/",
|
||||
target: "_blank",
|
||||
rel: "noopener noreferrer",
|
||||
div { class: "agents-card-icon placeholder-icon", "G" }
|
||||
div { class: "agents-card-title",
|
||||
{t(l, "developer.agents_getting_started")}
|
||||
}
|
||||
div { class: "agents-card-desc",
|
||||
{t(l, "developer.agents_getting_started_desc")}
|
||||
}
|
||||
}
|
||||
|
||||
// GitHub
|
||||
a {
|
||||
class: "agents-card",
|
||||
href: "https://github.com/langchain-ai/langgraph",
|
||||
target: "_blank",
|
||||
rel: "noopener noreferrer",
|
||||
div { class: "agents-card-icon placeholder-icon", "H" }
|
||||
div { class: "agents-card-title",
|
||||
{t(l, "developer.agents_github")}
|
||||
}
|
||||
div { class: "agents-card-desc",
|
||||
{t(l, "developer.agents_github_desc")}
|
||||
}
|
||||
}
|
||||
|
||||
// Examples
|
||||
a {
|
||||
class: "agents-card",
|
||||
href: "https://github.com/langchain-ai/langgraph/tree/main/examples",
|
||||
target: "_blank",
|
||||
rel: "noopener noreferrer",
|
||||
div { class: "agents-card-icon placeholder-icon", "E" }
|
||||
div { class: "agents-card-title",
|
||||
{t(l, "developer.agents_examples")}
|
||||
}
|
||||
div { class: "agents-card-desc",
|
||||
{t(l, "developer.agents_examples_desc")}
|
||||
}
|
||||
}
|
||||
|
||||
// API Reference (disabled when URL is empty)
|
||||
a {
|
||||
class: if connected { "agents-card" } else { "agents-card agents-card--disabled" },
|
||||
href: "{api_ref_href}",
|
||||
target: "_blank",
|
||||
rel: "noopener noreferrer",
|
||||
div { class: "agents-card-icon placeholder-icon", "R" }
|
||||
div { class: "agents-card-title",
|
||||
{t(l, "developer.agents_api_ref")}
|
||||
}
|
||||
div { class: "agents-card-desc",
|
||||
{t(l, "developer.agents_api_ref_desc")}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user