diff --git a/frontend/src/app/providers/layout/sidebar/sidebar.tsx b/frontend/src/app/providers/layout/sidebar/sidebar.tsx index 780fb40..724b885 100644 --- a/frontend/src/app/providers/layout/sidebar/sidebar.tsx +++ b/frontend/src/app/providers/layout/sidebar/sidebar.tsx @@ -33,14 +33,14 @@ export const Sidebar: React.FC = ({ const [showTokenModal, setShowTokenModal] = useState(false); const [showGraphs, setShowGraphs] = useState(false); const [expandedAgents, setExpandedAgents] = useState>( - new Set(agents.map((a) => a.name)), + new Set(agents.map((a) => a.label)), ); - const toggleAgent = (name: string) => { + const toggleAgent = (label: string) => { setExpandedAgents((prev) => { const next = new Set(prev); - if (next.has(name)) next.delete(name); - else next.add(name); + if (next.has(label)) next.delete(label); + else next.add(label); return next; }); }; @@ -50,8 +50,8 @@ export const Sidebar: React.FC = ({ const query = searchQuery.toLowerCase(); return agents.filter( (agent) => - agent.name.toLowerCase().includes(query) || - agent.services.some((s) => s.name.toLowerCase().includes(query)), + agent.label.toLowerCase().includes(query) || + agent.services.some((s) => s.toLowerCase().includes(query)), ); }, [agents, searchQuery]); @@ -61,25 +61,25 @@ export const Sidebar: React.FC = ({ agents.forEach((agent) => { nodes.push({ - id: agent.name, - name: agent.name, + id: agent.label, + name: agent.label, type: "agent" as const, val: 8, - description: `Агент: ${agent.name}`, + description: `Агент: ${agent.label}`, }); agent.services.forEach((service) => { - const serviceId = `${agent.name}-${service.name}`; + const serviceId = `${agent.label}-${service}`; nodes.push({ id: serviceId, - name: service.name, + name: service, type: "service" as const, val: 12, - description: `Сервис: ${service.name} (${service.status})`, + description: `Сервис: ${service}`, }); links.push({ - source: agent.name, + source: agent.label, target: serviceId, type: "hosts", }); @@ -239,10 +239,10 @@ export const Sidebar: React.FC = ({ ) : (
{filteredAgents.map((agent) => { - const isExpanded = expandedAgents.has(agent.name); + const isExpanded = expandedAgents.has(agent.label); return (
= ({ {/* Agent header — кликабельный для сворачивания */}
toggleAgent(agent.name)} + onClick={() => toggleAgent(agent.label)} > {isExpanded ? ( @@ -269,13 +269,11 @@ export const Sidebar: React.FC = ({ className="text-sm font-medium flex-1 truncate" style={{ color: "var(--text-primary)" }} > - {agent.name} + {agent.label} - {/* Статус-индикатор агента (сколько сервисов запущено) */} + {/* Статус-индикатор агента (количество сервисов) */}
- {agent.services.filter( - (s) => s.status === "running", - ).length > 0 && ( + {agent.services.length > 0 && ( = ({ className="text-[10px]" style={{ color: "var(--text-muted)" }} > - { - agent.services.filter( - (s) => s.status === "running", - ).length - } - /{agent.services.length} + {agent.services.length}
{/* Кнопка удаления — появляется при наведении */} @@ -299,10 +292,10 @@ export const Sidebar: React.FC = ({ e.stopPropagation(); if ( window.confirm( - `Удалить агента "${agent.name}"?`, + `Удалить агента "${agent.label}"?`, ) ) { - removeAgent(agent.name); + removeAgent(agent.label); } }} className="opacity-0 group-hover:opacity-100 p-1 rounded transition-all flex-shrink-0" @@ -336,49 +329,32 @@ export const Sidebar: React.FC = ({ style={{ borderColor: "var(--border)" }} > {agent.services.map((service) => { - const isRunning = service.status === "running"; - const isError = service.status === "error"; - const isStopped = - service.status === "stopped" || !isRunning; - return (
- {service.name} + {service} {/* Status indicator */}
- {isRunning - ? "run" - : isError - ? "err" - : "stop"} + run
diff --git a/frontend/src/app/providers/layout/store/agent.store.ts b/frontend/src/app/providers/layout/store/agent.store.ts index fb00e96..e39f16e 100644 --- a/frontend/src/app/providers/layout/store/agent.store.ts +++ b/frontend/src/app/providers/layout/store/agent.store.ts @@ -12,30 +12,22 @@ interface AgentState { const mockAgents: AgentInfo[] = [ { - name: "agent-core-01", + label: "agent-core-01", token: "tok_a1b2c3d4e5f6g7h8", - services: [ - { name: "postgres", status: "running" }, - { name: "redis", status: "running" }, - { name: "log-collector", status: "running" }, - ], + services: ["postgres", "redis", "log-collector"], + connected_at: "2026-04-04 15:25:09", }, { - name: "agent-worker-02", + label: "agent-worker-02", token: "tok_x9y8z7w6v5u4t3s2", - services: [ - { name: "celery-worker", status: "running" }, - { name: "flower", status: "stopped" }, - ], + services: ["celery-worker", "flower"], + connected_at: "2026-04-04 15:25:09", }, { - name: "agent-monitor-03", + label: "agent-monitor-03", token: "tok_m1n2o3p4q5r6s7t8", - services: [ - { name: "prometheus", status: "running" }, - { name: "grafana", status: "running" }, - { name: "alertmanager", status: "stopped" }, - ], + services: ["prometheus", "grafana", "alertmanager"], + connected_at: "2026-04-04 15:25:09", }, ]; @@ -59,6 +51,6 @@ export const useAgentStore = create()((set, get) => ({ }, removeAgent: (name: string) => { - set({ agents: get().agents.filter((a) => a.name !== name) }); + set({ agents: get().agents.filter((a) => a.label !== name) }); }, })); diff --git a/frontend/src/modules/agent/api/agent.api.service.ts b/frontend/src/modules/agent/api/agent.api.service.ts index db258e8..14aacd2 100644 --- a/frontend/src/modules/agent/api/agent.api.service.ts +++ b/frontend/src/modules/agent/api/agent.api.service.ts @@ -45,17 +45,20 @@ class AgentApiService { } async searchLogs(filters?: LogFilters): Promise { - const response = await apiClient.get(this.logsBasePath, { - params: { - level: filters?.level, - service: filters?.service, - agent: filters?.agent, - date_from: filters?.date_from, - date_to: filters?.date_to, - limit: filters?.limit ?? 100, - offset: filters?.offset ?? 0, + const response = await apiClient.get( + `${this.logsBasePath}/mock`, + { + params: { + level: filters?.level, + service: filters?.service, + agent: filters?.agent, + date_from: filters?.date_from, + date_to: filters?.date_to, + limit: filters?.limit ?? 100, + offset: filters?.offset ?? 0, + }, }, - }); + ); return response.data; } diff --git a/frontend/src/modules/agent/types/agent.types.ts b/frontend/src/modules/agent/types/agent.types.ts index 6b7b168..adec31b 100644 --- a/frontend/src/modules/agent/types/agent.types.ts +++ b/frontend/src/modules/agent/types/agent.types.ts @@ -1,12 +1,8 @@ -export interface AgentService { - name: string; - status: string; -} - export interface AgentInfo { - name: string; - services: AgentService[]; token: string; + label: string; + services: string[]; + connected_at: string; } export interface LoginRequest { diff --git a/frontend/src/pages/graphs.page.tsx b/frontend/src/pages/graphs.page.tsx index 5879abd..eca7466 100644 --- a/frontend/src/pages/graphs.page.tsx +++ b/frontend/src/pages/graphs.page.tsx @@ -1,5 +1,10 @@ import { useMemo } from "react"; -import { Graph, type GraphData, type GraphNode, type GraphLink } from "@/modules/graph"; +import { + Graph, + type GraphData, + type GraphNode, + type GraphLink, +} from "@/modules/graph"; import { useAgentStore } from "@/app/providers/layout/store/agent.store"; const buildGraphFromAgents = (): GraphData => { @@ -10,26 +15,26 @@ const buildGraphFromAgents = (): GraphData => { agents.forEach((agent) => { // Агент как узел nodes.push({ - id: agent.name, - name: agent.name, + id: agent.label, + name: agent.label, type: "agent", val: 8, - description: `Агент: ${agent.name}`, + description: `Агент: ${agent.label}`, }); // Сервисы агента как узлы + связи agent.services.forEach((service) => { - const serviceId = `${agent.name}-${service.name}`; + const serviceId = `${agent.label}-${service}`; nodes.push({ id: serviceId, - name: service.name, + name: service, type: "service", val: 12, - description: `Сервис: ${service.name} (${service.status})`, + description: `Сервис: ${service}`, }); links.push({ - source: agent.name, + source: agent.label, target: serviceId, type: "hosts", }); diff --git a/frontend/src/pages/logs.page.tsx b/frontend/src/pages/logs.page.tsx index bedc742..6b2b824 100644 --- a/frontend/src/pages/logs.page.tsx +++ b/frontend/src/pages/logs.page.tsx @@ -21,11 +21,30 @@ const logLevelIcons: Record = { FATAL: , }; -const logLevelColors: Record = { - INFO: { bg: "var(--info-bg)", text: "var(--info-text)", border: "var(--info-border)" }, - WARNING: { bg: "var(--warning-bg)", text: "var(--warning-text)", border: "var(--warning-border)" }, - ERROR: { bg: "var(--error-bg)", text: "var(--error-text)", border: "var(--error-border)" }, - FATAL: { bg: "var(--fatal-bg)", text: "var(--fatal-text)", border: "var(--fatal-border)" }, +const logLevelColors: Record< + string, + { bg: string; text: string; border: string } +> = { + INFO: { + bg: "var(--info-bg)", + text: "var(--info-text)", + border: "var(--info-border)", + }, + WARNING: { + bg: "var(--warning-bg)", + text: "var(--warning-text)", + border: "var(--warning-border)", + }, + ERROR: { + bg: "var(--error-bg)", + text: "var(--error-text)", + border: "var(--error-border)", + }, + FATAL: { + bg: "var(--fatal-bg)", + text: "var(--fatal-text)", + border: "var(--fatal-border)", + }, }; export const LogsPage: React.FC = () => { @@ -47,7 +66,9 @@ export const LogsPage: React.FC = () => { setLogs(data); setTotalLogs(data.length); } catch (err) { - setError(err instanceof Error ? err.message : "Ошибка при загрузке логов"); + setError( + err instanceof Error ? err.message : "Ошибка при загрузке логов", + ); } finally { setIsLoading(false); } @@ -112,7 +133,10 @@ export const LogsPage: React.FC = () => { className="w-14 h-14 rounded-xl flex items-center justify-center" style={{ backgroundColor: "var(--bg-secondary)" }} > - +

{ }} > {/* Table Header */} -
- +
+ Найдено: {totalLogs} записей
{isLoading ? ( -
+
Загрузка логов...
) : logs.length === 0 ? ( -
+
Логи не найдены
) : ( @@ -193,36 +232,58 @@ export const LogsPage: React.FC = () => { - - - - - {logs.map((log, index) => { - const colors = logLevelColors[log.level] || logLevelColors.INFO; + const colors = + logLevelColors[log.level] || logLevelColors.INFO; return ( - - - - @@ -255,7 +325,10 @@ export const LogsPage: React.FC = () => { {/* Pagination */} -
+
- + Показано {logs.length} записей (смещение: {offset})
+ Время + Уровень + Сервис + Агент + Сообщение
+ {formatTimestamp(log.timestamp)} @@ -238,13 +299,22 @@ export const LogsPage: React.FC = () => { {log.level} + {log.service} + {log.agent} + {log.message}