fix: realign sqlite path and stabilize client data
This commit is contained in:
+40
-15
@@ -1,27 +1,50 @@
|
||||
import axios from 'axios';
|
||||
import type { Drawing, Collection } from '../types';
|
||||
import axios from "axios";
|
||||
import type { Drawing, Collection } from "../types";
|
||||
|
||||
export const API_URL = import.meta.env.VITE_API_URL || '/api';
|
||||
export const API_URL = import.meta.env.VITE_API_URL || "/api";
|
||||
|
||||
export const api = axios.create({
|
||||
baseURL: API_URL,
|
||||
});
|
||||
|
||||
export const getDrawings = async (search?: string, collectionId?: string | null) => {
|
||||
const coerceTimestamp = (value: string | number | Date): number => {
|
||||
if (typeof value === "number") return value;
|
||||
if (value instanceof Date) return value.getTime();
|
||||
const parsed = Date.parse(value);
|
||||
return Number.isNaN(parsed) ? Date.now() : parsed;
|
||||
};
|
||||
|
||||
const deserializeDrawing = (drawing: any): Drawing => ({
|
||||
...drawing,
|
||||
createdAt: coerceTimestamp(drawing.createdAt),
|
||||
updatedAt: coerceTimestamp(drawing.updatedAt),
|
||||
});
|
||||
|
||||
export const getDrawings = async (
|
||||
search?: string,
|
||||
collectionId?: string | null
|
||||
) => {
|
||||
const params: any = {};
|
||||
if (search) params.search = search;
|
||||
if (collectionId !== undefined) params.collectionId = collectionId === null ? 'null' : collectionId;
|
||||
const response = await api.get<Drawing[]>('/drawings', { params });
|
||||
return response.data;
|
||||
if (collectionId !== undefined)
|
||||
params.collectionId = collectionId === null ? "null" : collectionId;
|
||||
const response = await api.get<Drawing[]>("/drawings", { params });
|
||||
return response.data.map(deserializeDrawing);
|
||||
};
|
||||
|
||||
export const getDrawing = async (id: string) => {
|
||||
const response = await api.get<Drawing>(`/drawings/${id}`);
|
||||
return response.data;
|
||||
return deserializeDrawing(response.data);
|
||||
};
|
||||
|
||||
export const createDrawing = async (name?: string, collectionId?: string | null) => {
|
||||
const response = await api.post<{ id: string }>('/drawings', { name, collectionId });
|
||||
export const createDrawing = async (
|
||||
name?: string,
|
||||
collectionId?: string | null
|
||||
) => {
|
||||
const response = await api.post<{ id: string }>("/drawings", {
|
||||
name,
|
||||
collectionId,
|
||||
});
|
||||
return response.data;
|
||||
};
|
||||
|
||||
@@ -36,22 +59,24 @@ export const deleteDrawing = async (id: string) => {
|
||||
};
|
||||
|
||||
export const duplicateDrawing = async (id: string) => {
|
||||
const response = await api.post<{ id: string }>(`/drawings/${id}/duplicate`);
|
||||
return response.data;
|
||||
const response = await api.post<Drawing>(`/drawings/${id}/duplicate`);
|
||||
return deserializeDrawing(response.data);
|
||||
};
|
||||
|
||||
export const getCollections = async () => {
|
||||
const response = await api.get<Collection[]>('/collections');
|
||||
const response = await api.get<Collection[]>("/collections");
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const createCollection = async (name: string) => {
|
||||
const response = await api.post<Collection>('/collections', { name });
|
||||
const response = await api.post<Collection>("/collections", { name });
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const updateCollection = async (id: string, name: string) => {
|
||||
const response = await api.put<{ success: true }>(`/collections/${id}`, { name });
|
||||
const response = await api.put<{ success: true }>(`/collections/${id}`, {
|
||||
name,
|
||||
});
|
||||
return response.data;
|
||||
};
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ export const DrawingCard: React.FC<DrawingCardProps> = ({
|
||||
exportBackground: true,
|
||||
viewBackgroundColor: drawing.appState.viewBackgroundColor || "#ffffff"
|
||||
},
|
||||
files: null,
|
||||
files: drawing.files || {},
|
||||
exportPadding: 10
|
||||
});
|
||||
const previewHtml = svg.outerHTML;
|
||||
|
||||
@@ -9,7 +9,7 @@ import type { Drawing, Collection } from '../types';
|
||||
import { useDebounce } from '../hooks/useDebounce';
|
||||
import clsx from 'clsx';
|
||||
import { ConfirmModal } from '../components/ConfirmModal';
|
||||
import { importDrawings, importLibrary } from '../utils/importUtils';
|
||||
import { importDrawings } from '../utils/importUtils';
|
||||
|
||||
type Point = { x: number; y: number };
|
||||
|
||||
@@ -542,17 +542,14 @@ export const Dashboard: React.FC = () => {
|
||||
setIsLoading(true);
|
||||
|
||||
const libFiles = files.filter(f => f.name.endsWith('.excalidrawlib'));
|
||||
const drawingFiles = files.filter(f => !f.name.endsWith('.excalidrawlib'));
|
||||
|
||||
if (libFiles.length > 0) {
|
||||
for (const file of libFiles) {
|
||||
const res = await importLibrary(file);
|
||||
if (!res.success) {
|
||||
alert(`Failed to import library ${file.name}: ${res.error}`);
|
||||
}
|
||||
}
|
||||
setShowImportError({
|
||||
isOpen: true,
|
||||
message: 'Library (.excalidrawlib) imports are not supported in this build. Please import drawings (.excalidraw/.json) instead.'
|
||||
});
|
||||
}
|
||||
|
||||
const drawingFiles = files.filter(f => !f.name.endsWith('.excalidrawlib'));
|
||||
if (drawingFiles.length > 0) {
|
||||
const result = await importDrawings(drawingFiles, targetCollectionId, refreshData);
|
||||
if (result.failed > 0) {
|
||||
|
||||
@@ -76,43 +76,3 @@ export const importDrawings = async (
|
||||
|
||||
return { success: successCount, failed: failCount, errors };
|
||||
};
|
||||
|
||||
export const importLibrary = async (file: File) => {
|
||||
try {
|
||||
const text = await file.text();
|
||||
const data = JSON.parse(text);
|
||||
|
||||
let newItems = [];
|
||||
if (data.libraryItems) {
|
||||
newItems = data.libraryItems;
|
||||
} else if (Array.isArray(data)) {
|
||||
newItems = data;
|
||||
} else {
|
||||
throw new Error("Invalid library file format");
|
||||
}
|
||||
|
||||
// Fetch existing
|
||||
const existingRes = await fetch(`${API_URL}/library`);
|
||||
let existingItems = [];
|
||||
if (existingRes.ok) {
|
||||
const existingData = await existingRes.json();
|
||||
existingItems = existingData.libraryItems || [];
|
||||
}
|
||||
|
||||
// Merge (simple concat)
|
||||
const mergedItems = [...existingItems, ...newItems];
|
||||
|
||||
// Save
|
||||
const saveRes = await fetch(`${API_URL}/library`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ libraryItems: mergedItems }),
|
||||
});
|
||||
|
||||
if (!saveRes.ok) throw new Error("Failed to save library");
|
||||
return { success: true, count: newItems.length };
|
||||
} catch (err: any) {
|
||||
console.error("Library import failed:", err);
|
||||
return { success: false, error: err.message };
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user