mirror of
https://github.com/hansjone/netx.git
synced 2026-10-09 02:00:46 +08:00
feat(ops): add managed NE management and batch CLI collection
Introduce workbench operations for multi-vendor NE CRUD/connect-test and Netmiko batch collection with job lifecycle controls, log downloads, and paginated run filters. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
282dbe75af
commit
042c015045
36 changed files with 3695 additions and 17 deletions
|
|
@ -1,5 +1,13 @@
|
|||
import type {
|
||||
CollectionJobDetail,
|
||||
CollectionJobItem,
|
||||
CollectionRunList,
|
||||
EligibleNeItem,
|
||||
IntegrationStatus,
|
||||
ManagedNeImportResult,
|
||||
ManagedNeItem,
|
||||
ManagedNeListResponse,
|
||||
ManagedNeMeta,
|
||||
UmeAlarmItem,
|
||||
UmeAlarmSubscriptionStatus,
|
||||
UmeNeItem,
|
||||
|
|
@ -25,6 +33,26 @@ export const apiPost = async <T,>(path: string, body: unknown): Promise<T> => {
|
|||
return data as T;
|
||||
};
|
||||
|
||||
export const apiPatch = async <T,>(path: string, body: unknown): Promise<T> => {
|
||||
const res = await fetch(path, {
|
||||
method: "PATCH",
|
||||
headers: { "content-type": "application/json", accept: "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
const text = await res.text();
|
||||
const data = text ? JSON.parse(text) : {};
|
||||
if (!res.ok) throw new Error(String((data as { detail?: string }).detail || `${res.status} ${path}`));
|
||||
return data as T;
|
||||
};
|
||||
|
||||
export const apiDelete = async <T,>(path: string): Promise<T> => {
|
||||
const res = await fetch(path, { method: "DELETE", headers: { accept: "application/json" } });
|
||||
const text = await res.text();
|
||||
const data = text ? JSON.parse(text) : {};
|
||||
if (!res.ok) throw new Error(String((data as { detail?: string }).detail || `${res.status} ${path}`));
|
||||
return data as T;
|
||||
};
|
||||
|
||||
export const fetchIntegrationStatus = () => apiGet<IntegrationStatus>("/v1/integrations/status");
|
||||
|
||||
export const fetchUmeAlarmSubscriptionStatus = () =>
|
||||
|
|
@ -64,6 +92,104 @@ export const fetchUmeNe = (params: { keyword: string; page: number; pageSize: nu
|
|||
);
|
||||
};
|
||||
|
||||
export const fetchManagedNeMeta = () =>
|
||||
Promise.all([
|
||||
apiGet<ManagedNeMeta>("/v1/managed-ne/meta/device-types"),
|
||||
apiGet<{ configured: boolean }>("/v1/managed-ne/meta/credentials-configured"),
|
||||
]).then(([types, creds]) => ({
|
||||
device_types: types.device_types,
|
||||
vendors: types.vendors,
|
||||
credentials_configured: creds.configured,
|
||||
}));
|
||||
|
||||
export const fetchManagedNe = (params: {
|
||||
keyword: string;
|
||||
vendor: string;
|
||||
connectStatus: string;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}) => {
|
||||
const p = new URLSearchParams();
|
||||
if (params.keyword) p.set("keyword", params.keyword);
|
||||
if (params.vendor) p.set("vendor", params.vendor);
|
||||
if (params.connectStatus) p.set("connect_status", params.connectStatus);
|
||||
p.set("page", String(Math.max(1, params.page)));
|
||||
p.set("page_size", String(Math.max(1, Math.min(500, params.pageSize))));
|
||||
return apiGet<ManagedNeListResponse>(`/v1/managed-ne?${p.toString()}`);
|
||||
};
|
||||
|
||||
export const createManagedNe = (body: Record<string, unknown>) =>
|
||||
apiPost<ManagedNeItem>("/v1/managed-ne", body);
|
||||
|
||||
export const updateManagedNe = (id: string, body: Record<string, unknown>) =>
|
||||
apiPatch<ManagedNeItem>(`/v1/managed-ne/${id}`, body);
|
||||
|
||||
export const deleteManagedNe = (id: string) => apiDelete<{ ok: boolean }>(`/v1/managed-ne/${id}`);
|
||||
|
||||
export const connectTestManagedNe = (ids: string[]) =>
|
||||
apiPost<{ ok: boolean; submitted: number }>("/v1/managed-ne/connect-test", { ids });
|
||||
|
||||
export const importManagedNe = async (file: File): Promise<ManagedNeImportResult> => {
|
||||
const form = new FormData();
|
||||
form.append("file", file);
|
||||
const res = await fetch("/v1/managed-ne/import", { method: "POST", body: form });
|
||||
const text = await res.text();
|
||||
const data = text ? JSON.parse(text) : {};
|
||||
if (!res.ok) throw new Error(String((data as { detail?: string }).detail || `${res.status} import`));
|
||||
return data as ManagedNeImportResult;
|
||||
};
|
||||
|
||||
export const fetchEligibleNe = (params: { page: number; pageSize: number }) => {
|
||||
const p = new URLSearchParams();
|
||||
p.set("page", String(Math.max(1, params.page)));
|
||||
p.set("page_size", String(Math.max(1, Math.min(500, params.pageSize))));
|
||||
return apiGet<{ total: number; page: number; page_size: number; items: EligibleNeItem[] }>(
|
||||
`/v1/ne-collections/eligible-ne?${p.toString()}`,
|
||||
);
|
||||
};
|
||||
|
||||
export const createNeCollection = (body: { title?: string; commands: string; ne_ids: string[] }) =>
|
||||
apiPost<CollectionJobItem>("/v1/ne-collections", body);
|
||||
|
||||
export const fetchNeCollections = (params: { page: number; pageSize: number }) => {
|
||||
const p = new URLSearchParams();
|
||||
p.set("page", String(Math.max(1, params.page)));
|
||||
p.set("page_size", String(Math.max(1, Math.min(100, params.pageSize))));
|
||||
return apiGet<{ total: number; page: number; page_size: number; items: CollectionJobItem[] }>(
|
||||
`/v1/ne-collections?${p.toString()}`,
|
||||
);
|
||||
};
|
||||
|
||||
export const fetchCollectionJob = (jobId: string) => apiGet<CollectionJobDetail>(`/v1/ne-collections/${jobId}`);
|
||||
|
||||
export const fetchCollectionRuns = (params: {
|
||||
jobId: string;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
status?: string;
|
||||
keyword?: string;
|
||||
}) => {
|
||||
const p = new URLSearchParams();
|
||||
p.set("page", String(Math.max(1, params.page)));
|
||||
p.set("page_size", String(Math.max(1, Math.min(200, params.pageSize))));
|
||||
if (params.status) p.set("status", params.status);
|
||||
if (params.keyword?.trim()) p.set("keyword", params.keyword.trim());
|
||||
return apiGet<CollectionRunList>(`/v1/ne-collections/${params.jobId}/runs?${p.toString()}`);
|
||||
};
|
||||
|
||||
export const pauseCollectionJob = (jobId: string) =>
|
||||
apiPost<CollectionJobItem>(`/v1/ne-collections/${jobId}/pause`, {});
|
||||
|
||||
export const restartCollectionJob = (jobId: string) =>
|
||||
apiPost<CollectionJobItem>(`/v1/ne-collections/${jobId}/restart`, {});
|
||||
|
||||
export const deleteCollectionJob = (jobId: string) =>
|
||||
apiDelete<{ ok: boolean }>(`/v1/ne-collections/${jobId}`);
|
||||
|
||||
export const collectionRunDownloadUrl = (runId: string) => `/v1/ne-collections/runs/${runId}/download`;
|
||||
|
||||
export const collectionJobDownloadUrl = (jobId: string) => `/v1/ne-collections/${jobId}/download`;
|
||||
|
||||
export const fetchUmeCurrentAlarms = (params: {
|
||||
severity: string;
|
||||
isCleared: string;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue