feat: expand graph lifecycle and data platform

This commit is contained in:
xuelong committed 2026-08-24 01:07:29 -07:00
1 parent 00af885b1a
commit 15368f2779
50 files changed
+17461 -1040

No files matched your search

+215 -6
View File
@@ -16,6 +16,12 @@ export const DEFAULT_PROJECT_CONTEXT: KgProjectContext = {
graphName: "guiyang_new2",
};
export const EMPTY_PROJECT_CONTEXT: KgProjectContext = {
tenantId: "",
projectId: "",
graphName: "",
};
const PROJECT_DISPLAY_NAMES: Record<string, string> = {
"CityGraph-new2": "城市图谱",
guiyang_new2: "贵阳城市图谱",
@@ -64,7 +70,12 @@ export function displayStatusName(value?: string | null): string {
export function getProjectContext(): KgProjectContext {
try {
const parsed = JSON.parse(localStorage.getItem(PROJECT_CONTEXT_KEY) || "{}");
const stored = localStorage.getItem(PROJECT_CONTEXT_KEY);
if (stored === null) return DEFAULT_PROJECT_CONTEXT;
const parsed = JSON.parse(stored);
if (parsed?.projectId === "") {
return EMPTY_PROJECT_CONTEXT;
}
return {
tenantId: parsed.tenantId || DEFAULT_PROJECT_CONTEXT.tenantId,
projectId: parsed.projectId || DEFAULT_PROJECT_CONTEXT.projectId,
@@ -80,13 +91,20 @@ export function setProjectContext(context: KgProjectContext) {
window.dispatchEvent(new CustomEvent("znkg-project-context", { detail: context }));
}
export function clearProjectContext() {
setProjectContext(EMPTY_PROJECT_CONTEXT);
}
api.interceptors.request.use((config) => {
const token = localStorage.getItem("token");
if (token) config.headers.Authorization = `Bearer ${token}`;
const context = getProjectContext();
config.headers["X-KG-Tenant-Id"] = context.tenantId;
config.headers["X-KG-Project-Id"] = context.projectId;
config.headers["X-KG-Graph-Name"] = context.graphName;
if (context.tenantId) config.headers["X-KG-Tenant-Id"] = context.tenantId;
else delete config.headers["X-KG-Tenant-Id"];
if (context.projectId) config.headers["X-KG-Project-Id"] = context.projectId;
else delete config.headers["X-KG-Project-Id"];
if (context.graphName) config.headers["X-KG-Graph-Name"] = context.graphName;
else delete config.headers["X-KG-Graph-Name"];
return config;
});
@@ -109,18 +127,174 @@ export const login = (username: string, password: string) =>
export const whoami = () => api.get("/auth/me");
// ── Projects / Graph releases ──
export const listProjects = () => api.get("/projects");
export type ProjectSummary = {
project_id: string;
tenant_id?: string;
display_name?: string;
name?: string;
description?: string | null;
status?: string;
created_at?: string;
updated_at?: string;
};
export type GraphReleaseSummary = {
graph_release_id: string | number;
project_id: string;
tenant_id?: string;
graph_name: string;
alias?: string;
status?: string;
schema_id?: string | number | null;
created_at?: string;
updated_at?: string;
};
export type GraphProjectProvisionRequest = {
project_id: string;
display_name: string;
tenant_id?: string;
graph_name?: string;
schema: Record<string, unknown>;
graph_data: {
nodes: Array<Record<string, unknown>>;
relations: Array<Record<string, unknown>>;
};
};
export type GraphProjectProvisionResponse = {
project?: ProjectSummary;
graph_release?: GraphReleaseSummary;
schema?: Record<string, unknown>;
graph?: { graph_name: string; nodes: number; relations: number };
counts?: Record<string, number>;
};
export type ProjectDeletionGraphImpact = {
graph_name: string;
exists_in_falkordb: boolean | null;
shared: boolean;
other_project_ids: string[];
will_delete: boolean;
};
export type ProjectDeletionImpact = {
project_id: string;
display_name: string;
counts: Record<string, number>;
graphs: ProjectDeletionGraphImpact[];
protected_resources: string[];
falkordb_error?: string;
};
export type GraphProjectDeleteResponse = {
status: "deleted" | "deleted_with_cleanup_pending";
project_id: string;
deleted_counts: Record<string, number>;
deleted_graphs: string[];
already_absent_graphs: string[];
shared_graphs_preserved: string[];
cleanup_pending: Array<{
graph_name: string;
error: string;
task_id?: string | number;
}>;
protected_resources: string[];
};
export const listProjects = () => api.get<ProjectSummary[]>("/projects");
export const createProject = (data: unknown) => api.post("/projects", data);
export const listGraphReleases = (projectId: string) =>
api.get(`/projects/${encodeURIComponent(projectId)}/graph-releases`);
api.get<GraphReleaseSummary[]>(`/projects/${encodeURIComponent(projectId)}/graph-releases`);
export const createGraphRelease = (projectId: string, data: unknown) =>
api.post(`/projects/${encodeURIComponent(projectId)}/graph-releases`, data);
export const provisionGraphProject = (data: GraphProjectProvisionRequest) =>
api.post<GraphProjectProvisionResponse>("/projects/provision", data);
export const updateGraphProject = (projectId: string, data: { display_name: string }) =>
api.patch<ProjectSummary>(`/projects/${encodeURIComponent(projectId)}`, data);
export const getGraphProjectDeletionImpact = (projectId: string) =>
api.get<ProjectDeletionImpact>(
`/projects/${encodeURIComponent(projectId)}/deletion-impact`,
);
export const deleteGraphProject = (projectId: string, confirmProjectId: string) =>
api.delete<GraphProjectDeleteResponse>(`/projects/${encodeURIComponent(projectId)}`, {
params: { confirm_project_id: confirmProjectId },
});
// ── Project relational data platform ──
export const listProjectDatabases = () =>
api.get("/data-platform/databases");
export const createRelationalDatabase = (data: unknown) =>
api.post("/data-platform/databases", data);
export const updateRelationalDatabase = (projectId: string, data: unknown) =>
api.patch(`/data-platform/databases/${encodeURIComponent(projectId)}`, data);
export const deleteRelationalDatabase = (projectId: string, data: unknown) =>
api.delete(`/data-platform/databases/${encodeURIComponent(projectId)}`, { data });
export const listProjectDataTables = (projectId: string) =>
api.get(`/data-platform/databases/${encodeURIComponent(projectId)}/tables`);
export const executeProjectDatabaseSql = (projectId: string, sql: string) =>
api.post(
`/data-platform/databases/${encodeURIComponent(projectId)}/console/execute`,
{ sql },
);
export const getProjectDataTableInspection = (projectId: string, tableCode: string) =>
api.get(
`/data-platform/databases/${encodeURIComponent(projectId)}/tables/${encodeURIComponent(tableCode)}/inspection`,
);
export const createProjectDataTableColumn = (
projectId: string,
tableCode: string,
data: unknown,
) =>
api.post(
`/data-platform/databases/${encodeURIComponent(projectId)}/tables/${encodeURIComponent(tableCode)}/columns`,
data,
);
export const updateProjectDataTableColumn = (
projectId: string,
tableCode: string,
columnCode: string,
data: unknown,
) =>
api.patch(
`/data-platform/databases/${encodeURIComponent(projectId)}/tables/${encodeURIComponent(tableCode)}/columns/${encodeURIComponent(columnCode)}`,
data,
);
export const deleteProjectDataTableColumn = (
projectId: string,
tableCode: string,
columnCode: string,
data: unknown,
) =>
api.delete(
`/data-platform/databases/${encodeURIComponent(projectId)}/tables/${encodeURIComponent(tableCode)}/columns/${encodeURIComponent(columnCode)}`,
{ data },
);
export const createProjectDataTable = (projectId: string, data: unknown) =>
api.post(`/data-platform/databases/${encodeURIComponent(projectId)}/tables`, data);
export const createProjectDataTableFromSql = (projectId: string, data: unknown) =>
api.post(
`/data-platform/databases/${encodeURIComponent(projectId)}/tables/from-sql`,
data,
);
export const updateProjectDataTable = (
projectId: string,
tableCode: string,
data: unknown,
) =>
api.patch(
`/data-platform/databases/${encodeURIComponent(projectId)}/tables/${encodeURIComponent(tableCode)}`,
data,
);
export const deleteProjectDataTable = (
projectId: string,
tableCode: string,
data: unknown,
) =>
api.delete(
`/data-platform/databases/${encodeURIComponent(projectId)}/tables/${encodeURIComponent(tableCode)}`,
{ data },
);
export const listProjectTableRecords = (
projectId: string,
tableCode: string,
@@ -157,6 +331,39 @@ export const deleteProjectTableRecord = (
api.delete(
`/data-platform/databases/${encodeURIComponent(projectId)}/tables/${encodeURIComponent(tableCode)}/records/${encodeURIComponent(recordId)}`,
);
export const previewProjectTableCsvImport = (
projectId: string,
tableCode: string,
file: File,
) => {
const form = new FormData();
form.append("file", file);
return api.post(
`/data-platform/databases/${encodeURIComponent(projectId)}/tables/${encodeURIComponent(tableCode)}/records/import/preview`,
form,
);
};
export const importProjectTableCsv = (
projectId: string,
tableCode: string,
file: File,
) => {
const form = new FormData();
form.append("file", file);
return api.post(
`/data-platform/databases/${encodeURIComponent(projectId)}/tables/${encodeURIComponent(tableCode)}/records/import`,
form,
);
};
export const exportProjectTableCsv = (
projectId: string,
tableCode: string,
params?: Record<string, unknown>,
) =>
api.get(
`/data-platform/databases/${encodeURIComponent(projectId)}/tables/${encodeURIComponent(tableCode)}/records/export`,
{ params, responseType: "blob" },
);
export const listOntologySchemas = () => api.get("/ontology-schemas");
export const getCurrentOntologySchema = () => api.get("/ontology-schemas/current");
export const getOntologySchema = (schemaId: string | number) =>
@@ -217,8 +424,10 @@ export const plazaOverview = () => api.get("/plaza/overview");
export const plazaUsage = () => api.get("/plaza/usage");
export const plazaAlerts = () => api.get("/plaza/alerts");
export const plazaAmapConfig = () => api.get("/plaza/amap-config");
export const plazaWeatherHourly = () => api.get("/plaza/weather/hourly");
export const plazaMapPois = () => api.get("/plaza/map-pois");
export const plazaBusRoutes = () => api.get("/plaza/bus-routes");
export const plazaMapZones = () => api.get("/plaza/map-zones");
export const plazaMapPoiDetail = (placeId: string) =>
api.get(`/plaza/map-pois/${encodeURIComponent(placeId)}`);
export const plazaUserQuery = (data: unknown) => api.post("/plaza/user-query", data);