Merge branch 'frontend' of gitea.d3m0k1d.ru:d3m0k1d/HellreigN into HEAD
ci-front / build (push) Successful in 1m54s
ci-front / build (push) Successful in 1m54s
This commit is contained in:
@@ -22,14 +22,14 @@ class AgentApiService {
|
||||
|
||||
async getAgents(): Promise<AgentInfo[]> {
|
||||
const response = await apiClient.get<AgentInfo[]>(this.basePath);
|
||||
return response.data;
|
||||
return Array.isArray(response.data) ? response.data : [];
|
||||
}
|
||||
|
||||
async getUsers(): Promise<TokenUser[]> {
|
||||
const response = await apiClient.get<TokenUser[]>(
|
||||
`${this.authBasePath}/tokens`,
|
||||
);
|
||||
return response.data;
|
||||
return Array.isArray(response.data) ? response.data : [];
|
||||
}
|
||||
|
||||
async createUser(data: TokenCreate): Promise<void> {
|
||||
@@ -45,20 +45,27 @@ class AgentApiService {
|
||||
}
|
||||
|
||||
async searchLogs(filters?: LogFilters): Promise<LogEntry[]> {
|
||||
const response = await apiClient.get<LogEntry[]>(
|
||||
`${this.logsBasePath}/mock`,
|
||||
{
|
||||
const response = await apiClient.get<LogEntry[]>(this.logsBasePath, {
|
||||
params: {
|
||||
level: filters?.level,
|
||||
service: filters?.service,
|
||||
agent: filters?.agent,
|
||||
date_from: filters?.date_from,
|
||||
date_to: filters?.date_to,
|
||||
level: filters?.level || undefined,
|
||||
service: filters?.service || undefined,
|
||||
agent: filters?.agent || undefined,
|
||||
date_from: filters?.date_from || undefined,
|
||||
date_to: filters?.date_to || undefined,
|
||||
limit: filters?.limit ?? 100,
|
||||
offset: filters?.offset ?? 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!Array.isArray(response.data)) {
|
||||
console.error(
|
||||
"[Logs] Unexpected response format:",
|
||||
typeof response.data,
|
||||
response.data,
|
||||
);
|
||||
return [];
|
||||
}
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
@@ -74,21 +81,21 @@ class AgentApiService {
|
||||
const response = await apiClient.get<string[]>(
|
||||
`${this.logsBasePath}/agents`,
|
||||
);
|
||||
return response.data;
|
||||
return Array.isArray(response.data) ? response.data : [];
|
||||
}
|
||||
|
||||
async getDistinctLevels(): Promise<string[]> {
|
||||
const response = await apiClient.get<string[]>(
|
||||
`${this.logsBasePath}/levels`,
|
||||
);
|
||||
return response.data;
|
||||
return Array.isArray(response.data) ? response.data : [];
|
||||
}
|
||||
|
||||
async getDistinctServices(): Promise<string[]> {
|
||||
const response = await apiClient.get<string[]>(
|
||||
`${this.logsBasePath}/services`,
|
||||
);
|
||||
return response.data;
|
||||
return Array.isArray(response.data) ? response.data : [];
|
||||
}
|
||||
|
||||
// User management methods
|
||||
@@ -96,6 +103,9 @@ class AgentApiService {
|
||||
const response = await apiClient.get<TokenUser>(
|
||||
`${this.authBasePath}/users/${login}`,
|
||||
);
|
||||
if (!response.data || typeof response.data !== "object") {
|
||||
throw new Error(`User not found: ${login}`);
|
||||
}
|
||||
return response.data;
|
||||
}
|
||||
|
||||
@@ -103,7 +113,7 @@ class AgentApiService {
|
||||
const response = await apiClient.get<TokenUser[]>(
|
||||
`${this.authBasePath}/users/inactive`,
|
||||
);
|
||||
return response.data;
|
||||
return Array.isArray(response.data) ? response.data : [];
|
||||
}
|
||||
|
||||
async updateUser(login: string, data: TokenUpdate): Promise<void> {
|
||||
|
||||
@@ -63,12 +63,20 @@ export const LogsPage: React.FC = () => {
|
||||
try {
|
||||
const filters = getFilters();
|
||||
const data = await agentApiService.searchLogs(filters);
|
||||
if (!Array.isArray(data)) {
|
||||
console.error("[Logs] Expected array, got:", typeof data);
|
||||
setLogs([]);
|
||||
setTotalLogs(0);
|
||||
return;
|
||||
}
|
||||
setLogs(data);
|
||||
setTotalLogs(data.length);
|
||||
} catch (err) {
|
||||
setError(
|
||||
err instanceof Error ? err.message : "Ошибка при загрузке логов",
|
||||
);
|
||||
setLogs([]);
|
||||
setTotalLogs(0);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
@@ -76,14 +84,44 @@ export const LogsPage: React.FC = () => {
|
||||
|
||||
const fetchDistinctData = useCallback(async () => {
|
||||
try {
|
||||
const [services, agents] = await Promise.all([
|
||||
const [servicesResult, agentsResult] = await Promise.allSettled([
|
||||
agentApiService.getDistinctServices(),
|
||||
agentApiService.getDistinctAgents(),
|
||||
]);
|
||||
setAvailableServices(services);
|
||||
setAvailableAgents(agents);
|
||||
|
||||
if (
|
||||
servicesResult.status === "fulfilled" &&
|
||||
Array.isArray(servicesResult.value)
|
||||
) {
|
||||
setAvailableServices(servicesResult.value);
|
||||
} else {
|
||||
console.error(
|
||||
"[Logs] Failed to fetch services:",
|
||||
servicesResult.status === "rejected"
|
||||
? servicesResult.reason
|
||||
: "non-array response",
|
||||
);
|
||||
setAvailableServices([]);
|
||||
}
|
||||
|
||||
if (
|
||||
agentsResult.status === "fulfilled" &&
|
||||
Array.isArray(agentsResult.value)
|
||||
) {
|
||||
setAvailableAgents(agentsResult.value);
|
||||
} else {
|
||||
console.error(
|
||||
"[Logs] Failed to fetch agents:",
|
||||
agentsResult.status === "rejected"
|
||||
? agentsResult.reason
|
||||
: "non-array response",
|
||||
);
|
||||
setAvailableAgents([]);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Failed to fetch distinct data:", err);
|
||||
console.error("[Logs] Failed to fetch distinct data:", err);
|
||||
setAvailableServices([]);
|
||||
setAvailableAgents([]);
|
||||
}
|
||||
}, []);
|
||||
|
||||
@@ -108,8 +146,10 @@ export const LogsPage: React.FC = () => {
|
||||
setOffset(Math.max(0, offset - limit));
|
||||
};
|
||||
|
||||
const formatTimestamp = (timestamp: string) => {
|
||||
const formatTimestamp = (timestamp: string | undefined | null) => {
|
||||
if (!timestamp) return "—";
|
||||
const date = new Date(timestamp);
|
||||
if (isNaN(date.getTime())) return "—";
|
||||
return date.toLocaleString("ru-RU", {
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
@@ -266,8 +306,9 @@ export const LogsPage: React.FC = () => {
|
||||
</thead>
|
||||
<tbody>
|
||||
{logs.map((log, index) => {
|
||||
const level = log.level || "INFO";
|
||||
const colors =
|
||||
logLevelColors[log.level] || logLevelColors.INFO;
|
||||
logLevelColors[level] || logLevelColors.INFO;
|
||||
return (
|
||||
<tr
|
||||
key={index}
|
||||
@@ -295,27 +336,27 @@ export const LogsPage: React.FC = () => {
|
||||
borderColor: colors.border,
|
||||
}}
|
||||
>
|
||||
{logLevelIcons[log.level]}
|
||||
{log.level}
|
||||
{logLevelIcons[level]}
|
||||
{level}
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
className="px-4 py-3 text-sm"
|
||||
style={{ color: "var(--text-primary)" }}
|
||||
>
|
||||
{log.service}
|
||||
{log.service || "—"}
|
||||
</td>
|
||||
<td
|
||||
className="px-4 py-3 text-sm font-mono"
|
||||
style={{ color: "var(--text-primary)" }}
|
||||
>
|
||||
{log.agent}
|
||||
{log.agent || "—"}
|
||||
</td>
|
||||
<td
|
||||
className="px-4 py-3 text-sm"
|
||||
style={{ color: "var(--text-primary)" }}
|
||||
>
|
||||
{log.message}
|
||||
{log.message || "—"}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
|
||||
@@ -22,7 +22,7 @@ class ApiClient {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
validateStatus: (status) => {
|
||||
return status >= 200 && status < 500;
|
||||
return status >= 200 && status < 400;
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user