9eba62c5b5
Root cause: handleAddNode/handleEdgeConfirm only updated Zustand store, never creating records in the DB. canvasApi.save() only updated positions of existing nodes, so nothing survived a page refresh. Fix: save now sends the full canvas state (all nodes + edges + data) and the backend does a full sync — upsert incoming, delete anything removed. This means Save is the single source of truth: no need to call individual create/update/delete APIs for every drag or edit.
58 lines
1.7 KiB
TypeScript
58 lines
1.7 KiB
TypeScript
import axios from 'axios'
|
|
import { useAuthStore } from '@/stores/authStore'
|
|
|
|
export const api = axios.create({
|
|
baseURL: '/api/v1',
|
|
})
|
|
|
|
api.interceptors.request.use((config) => {
|
|
const token = useAuthStore.getState().token
|
|
if (token) config.headers.Authorization = `Bearer ${token}`
|
|
return config
|
|
})
|
|
|
|
api.interceptors.response.use(
|
|
(r) => r,
|
|
(err) => {
|
|
if (err.response?.status === 401) useAuthStore.getState().logout()
|
|
return Promise.reject(err)
|
|
}
|
|
)
|
|
|
|
export const authApi = {
|
|
login: (username: string, password: string) =>
|
|
api.post<{ access_token: string }>('/auth/login', { username, password }),
|
|
}
|
|
|
|
export const canvasApi = {
|
|
load: () => api.get('/canvas'),
|
|
save: (payload: {
|
|
nodes: object[]
|
|
edges: object[]
|
|
viewport: object
|
|
}) => api.post('/canvas/save', payload),
|
|
}
|
|
|
|
export const nodesApi = {
|
|
create: (data: object) => api.post('/nodes', data),
|
|
update: (id: string, data: object) => api.patch(`/nodes/${id}`, data),
|
|
delete: (id: string) => api.delete(`/nodes/${id}`),
|
|
}
|
|
|
|
export const edgesApi = {
|
|
create: (data: object) => api.post('/edges', data),
|
|
delete: (id: string) => api.delete(`/edges/${id}`),
|
|
}
|
|
|
|
export const scanApi = {
|
|
trigger: () => api.post('/scan/trigger'),
|
|
pending: () => api.get('/scan/pending'),
|
|
hidden: () => api.get('/scan/hidden'),
|
|
runs: () => api.get('/scan/runs'),
|
|
approve: (id: string, nodeData: object) => api.post(`/scan/pending/${id}/approve`, nodeData),
|
|
hide: (id: string) => api.post(`/scan/pending/${id}/hide`),
|
|
ignore: (id: string) => api.post(`/scan/pending/${id}/ignore`),
|
|
getConfig: () => api.get<{ ranges: string[]; interval_seconds: number }>('/scan/config'),
|
|
saveConfig: (data: { ranges: string[]; interval_seconds: number }) => api.post('/scan/config', data),
|
|
}
|