Push the rest
This commit is contained in:
107
frontend/src/api/wwi.ts
Normal file
107
frontend/src/api/wwi.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
||||
import { currentAccessToken } from "../auth/oidc";
|
||||
import type {
|
||||
WWIKpi,
|
||||
WWIReorderRecommendation,
|
||||
WWISupplierScore,
|
||||
WWIBusinessEvent,
|
||||
WWIWhatIfResult,
|
||||
WWIScenario,
|
||||
} from "./types";
|
||||
|
||||
const API_BASE = import.meta.env.VITE_API_BASE_URL ?? "http://localhost:8000";
|
||||
const tracer = trace.getTracer("wwi-frontend-api");
|
||||
|
||||
function authHeaders(): Record<string, string> {
|
||||
const token = currentAccessToken();
|
||||
return token ? { Authorization: `Bearer ${token}` } : {};
|
||||
}
|
||||
|
||||
async function get<T>(path: string, spanName: string): Promise<T> {
|
||||
return tracer.startActiveSpan(spanName, async (span) => {
|
||||
try {
|
||||
const resp = await fetch(`${API_BASE}${path}`, {
|
||||
headers: { Accept: "application/json", ...authHeaders() },
|
||||
});
|
||||
if (!resp.ok) {
|
||||
const body = await resp.text();
|
||||
throw new Error(`HTTP ${resp.status}: ${body}`);
|
||||
}
|
||||
span.setAttribute("http.status_code", resp.status);
|
||||
span.setStatus({ code: SpanStatusCode.OK });
|
||||
return (await resp.json()) as T;
|
||||
} catch (err) {
|
||||
span.recordException(err as Error);
|
||||
span.setStatus({ code: SpanStatusCode.ERROR, message: String(err) });
|
||||
throw err;
|
||||
} finally {
|
||||
span.end();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function post<T>(path: string, body: unknown, spanName: string): Promise<T> {
|
||||
return tracer.startActiveSpan(spanName, async (span) => {
|
||||
try {
|
||||
const resp = await fetch(`${API_BASE}${path}`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
...authHeaders(),
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
if (!resp.ok) {
|
||||
const text = await resp.text();
|
||||
throw new Error(`HTTP ${resp.status}: ${text}`);
|
||||
}
|
||||
span.setAttribute("http.status_code", resp.status);
|
||||
span.setStatus({ code: SpanStatusCode.OK });
|
||||
return (await resp.json()) as T;
|
||||
} catch (err) {
|
||||
span.recordException(err as Error);
|
||||
span.setStatus({ code: SpanStatusCode.ERROR, message: String(err) });
|
||||
throw err;
|
||||
} finally {
|
||||
span.end();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export const getWWIKpis = () =>
|
||||
get<WWIKpi>("/api/wwi/sales/kpis", "frontend.wwi.sales_kpis");
|
||||
|
||||
export const getWWIReorderRecommendations = () =>
|
||||
get<WWIReorderRecommendation[]>(
|
||||
"/api/wwi/stock/recommendations",
|
||||
"frontend.wwi.reorder_recommendations",
|
||||
);
|
||||
|
||||
export const getWWISupplierScores = (topN = 10) =>
|
||||
get<WWISupplierScore[]>(
|
||||
`/api/wwi/suppliers/scores?top_n=${topN}`,
|
||||
"frontend.wwi.supplier_scores",
|
||||
);
|
||||
|
||||
export const getWWIBusinessEvents = (limit = 100) =>
|
||||
get<WWIBusinessEvent[]>(
|
||||
`/api/wwi/events?limit=${limit}`,
|
||||
"frontend.wwi.business_events",
|
||||
);
|
||||
|
||||
export const createWWIScenario = (
|
||||
stockItemKey: number,
|
||||
demandMultiplier: number,
|
||||
) =>
|
||||
post<WWIWhatIfResult>(
|
||||
"/api/wwi/scenarios",
|
||||
{ stock_item_key: stockItemKey, demand_multiplier: demandMultiplier },
|
||||
"frontend.wwi.create_scenario",
|
||||
);
|
||||
|
||||
export const getWWIScenarios = (limit = 20) =>
|
||||
get<WWIScenario[]>(
|
||||
`/api/wwi/scenarios?limit=${limit}`,
|
||||
"frontend.wwi.list_scenarios",
|
||||
);
|
||||
Reference in New Issue
Block a user