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