diff --git a/frontend/src/modules/agent/api/agent.api.service.ts b/frontend/src/modules/agent/api/agent.api.service.ts new file mode 100644 index 0000000..e5f629f --- /dev/null +++ b/frontend/src/modules/agent/api/agent.api.service.ts @@ -0,0 +1,78 @@ +import { apiClient } from "@/shared/api/axios.instance"; +import type { + AgentInfo, + TokenCreate, + TokenUser, + LogEntry, + LogFilters, + InsertLogRequest, + InsertLogsRequest, +} from "../types/agent.types"; + +class AgentApiService { + private readonly basePath = "/agents"; + private readonly authBasePath = "/auth"; + private readonly logsBasePath = "/logs"; + + async getAgents(): Promise { + const response = await apiClient.get(this.basePath); + return response.data; + } + + async getUsers(): Promise { + const response = await apiClient.get(`${this.authBasePath}/tokens`); + return response.data; + } + + async createUser(data: TokenCreate): Promise { + await apiClient.post(`${this.authBasePath}/token`, data); + } + + async deleteUser(login: string): Promise { + await apiClient.delete(`${this.authBasePath}/tokens/${login}`); + } + + async deleteMyAccount(): Promise { + await apiClient.delete(`${this.authBasePath}/token`); + } + + 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, + }, + }); + return response.data; + } + + async insertLog(entry: InsertLogRequest): Promise { + await apiClient.post(this.logsBasePath, entry); + } + + async insertLogsBatch(data: InsertLogsRequest): Promise { + await apiClient.post(`${this.logsBasePath}/batch`, data); + } + + async getDistinctAgents(): Promise { + const response = await apiClient.get(`${this.logsBasePath}/agents`); + return response.data; + } + + async getDistinctLevels(): Promise { + const response = await apiClient.get(`${this.logsBasePath}/levels`); + return response.data; + } + + async getDistinctServices(): Promise { + const response = await apiClient.get(`${this.logsBasePath}/services`); + return response.data; + } +} + +export const agentApiService = new AgentApiService(); diff --git a/frontend/src/modules/agent/hooks/useAgents.hook.ts b/frontend/src/modules/agent/hooks/useAgents.hook.ts new file mode 100644 index 0000000..7aef8ae --- /dev/null +++ b/frontend/src/modules/agent/hooks/useAgents.hook.ts @@ -0,0 +1,36 @@ +import { useState, useEffect, useCallback } from "react"; +import { agentApiService } from "../api/agent.api.service"; +import type { AgentInfo } from "../types/agent.types"; + +interface UseAgentsResult { + agents: AgentInfo[]; + isLoading: boolean; + error: string | null; + refetch: () => Promise; +} + +export function useAgents(): UseAgentsResult { + const [agents, setAgents] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(null); + + const fetchAgents = useCallback(async () => { + setIsLoading(true); + setError(null); + try { + const data = await agentApiService.getAgents(); + setAgents(data); + } catch (err) { + const message = err instanceof Error ? err.message : "Failed to fetch agents"; + setError(message); + } finally { + setIsLoading(false); + } + }, []); + + useEffect(() => { + fetchAgents(); + }, [fetchAgents]); + + return { agents, isLoading, error, refetch: fetchAgents }; +} diff --git a/frontend/src/modules/agent/index.ts b/frontend/src/modules/agent/index.ts new file mode 100644 index 0000000..0dab406 --- /dev/null +++ b/frontend/src/modules/agent/index.ts @@ -0,0 +1,18 @@ +export { SSHAgentForm } from "./ui/SSHAgentForm"; +export type { SSHAgentConfig, ExtraField } from "./ui/SSHAgentForm"; + +export { useAgents } from "./hooks/useAgents.hook"; + +export { agentApiService } from "./api/agent.api.service"; + +export type { + AgentInfo, + LoginRequest, + LoginResponse, + TokenCreate, + TokenUser, + LogEntry, + InsertLogRequest, + InsertLogsRequest, + LogFilters, +} from "./types/agent.types"; diff --git a/frontend/src/modules/agent/types/agent.types.ts b/frontend/src/modules/agent/types/agent.types.ts new file mode 100644 index 0000000..ce0aa51 --- /dev/null +++ b/frontend/src/modules/agent/types/agent.types.ts @@ -0,0 +1,71 @@ +export interface AgentInfo { + label: string; + services: string[]; + token: string; +} + +export interface LoginRequest { + login: string; + password: string; +} + +export interface LoginResponse { + last_name: string; + login: string; + name: string; + permission_admin: boolean; + permission_manage_agent: boolean; + permission_view: boolean; + token: string; +} + +export interface TokenCreate { + login: string; + name: string; + last_name: string; + password: string; + permission_admin?: boolean; + permission_manage_agent?: boolean; + permission_view?: boolean; +} + +export interface TokenUser { + id: number; + login: string; + name: string; + last_name: string; + permission_admin: boolean; + permission_manage_agent: boolean; + permission_view: boolean; + token: string; +} + +export interface LogEntry { + agent: string; + level: string; + message: string; + service: string; + timestamp: string; +} + +export interface InsertLogRequest { + agent: string; + level: string; + message: string; + service: string; + timestamp?: string; +} + +export interface InsertLogsRequest { + logs: InsertLogRequest[]; +} + +export interface LogFilters { + level?: string; + service?: string; + agent?: string; + date_from?: string; + date_to?: string; + limit?: number; + offset?: number; +} diff --git a/frontend/src/pages/add-agents.page.tsx b/frontend/src/pages/add-agents.page.tsx index a56fffa..eb01f41 100644 --- a/frontend/src/pages/add-agents.page.tsx +++ b/frontend/src/pages/add-agents.page.tsx @@ -1,5 +1,6 @@ import React, { useState } from "react"; import { SSHAgentForm } from "../modules/agent/ui/SSHAgentForm"; +import { agentApiService } from "../modules/agent/api/agent.api.service"; import { FiPlusCircle, FiSend } from "react-icons/fi"; interface SSHAgentConfig { @@ -66,18 +67,22 @@ export const AddAgentsPage: React.FC = () => { setSubmitError(null); try { + // Получаем текущих агентов для проверки подключения + const currentAgents = await agentApiService.getAgents(); + console.log("Current agents:", currentAgents); + // TODO: Реальный API вызов для развертывания агентов - console.log("Deploying agents:", agents); - - // Имитация задержки API - await new Promise((resolve) => setTimeout(resolve, 1500)); - + // Пока выводим список подключенных агентов setSubmitMessage( - `Успешно отправлено ${agents.length} сервер(ов) на развертывание`, + `Успешно подключено ${currentAgents.length} агент(ов). Серверы: ${agents.length}`, ); setAgents([createEmptyAgentConfig()]); } catch (error) { - setSubmitError("Ошибка при развертывании на серверах"); + setSubmitError( + error instanceof Error + ? error.message + : "Ошибка при подключении к серверам", + ); } finally { setIsSubmitting(false); }