Compare commits
2 Commits
5feef51e7e
...
feature/up
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54d56eae40 | ||
|
|
b7cf724e05 |
@@ -57,11 +57,12 @@ if os.path.exists(static_dir):
|
|||||||
# Catch-all for SPA routing (must be last)
|
# Catch-all for SPA routing (must be last)
|
||||||
@app.get("/{full_path:path}")
|
@app.get("/{full_path:path}")
|
||||||
async def serve_spa_routes(full_path: str):
|
async def serve_spa_routes(full_path: str):
|
||||||
# Don't catch API routes
|
# Don't catch API routes or health endpoint
|
||||||
if full_path.startswith("api/") or full_path.startswith("health") or full_path.startswith("project/"):
|
if full_path.startswith("api/") or full_path.startswith("health"):
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
raise HTTPException(status_code=404, detail="Not found")
|
raise HTTPException(status_code=404, detail="Not found")
|
||||||
|
|
||||||
|
# Serve SPA for all other routes (including /project/*)
|
||||||
index_path = os.path.join(static_dir, "index.html")
|
index_path = os.path.join(static_dir, "index.html")
|
||||||
if os.path.exists(index_path):
|
if os.path.exists(index_path):
|
||||||
return FileResponse(index_path)
|
return FileResponse(index_path)
|
||||||
|
|||||||
@@ -10,10 +10,22 @@ async function handleResponse<T>(response: Response): Promise<T> {
|
|||||||
return response.json();
|
return response.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Paginated response type
|
||||||
|
interface PaginatedResponse<T> {
|
||||||
|
items: T[];
|
||||||
|
pagination: {
|
||||||
|
page: number;
|
||||||
|
limit: number;
|
||||||
|
total: number;
|
||||||
|
total_pages: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Project API
|
// Project API
|
||||||
export async function listProjects(): Promise<Project[]> {
|
export async function listProjects(): Promise<Project[]> {
|
||||||
const response = await fetch(`${API_BASE}/projects`);
|
const response = await fetch(`${API_BASE}/projects`);
|
||||||
return handleResponse<Project[]>(response);
|
const data = await handleResponse<PaginatedResponse<Project>>(response);
|
||||||
|
return data.items;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createProject(data: { name: string; description?: string; is_public?: boolean }): Promise<Project> {
|
export async function createProject(data: { name: string; description?: string; is_public?: boolean }): Promise<Project> {
|
||||||
|
|||||||
@@ -16,18 +16,18 @@ function Layout({ children }: LayoutProps) {
|
|||||||
<Link to="/" className="logo">
|
<Link to="/" className="logo">
|
||||||
<div className="logo-icon">
|
<div className="logo-icon">
|
||||||
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
{/* Three trees representing an orchard */}
|
{/* Three fruit trees representing an orchard */}
|
||||||
{/* Left tree */}
|
{/* Left tree - rounded canopy */}
|
||||||
<ellipse cx="6" cy="9" rx="4" ry="5" fill="currentColor" opacity="0.7"/>
|
<path d="M6 14 Q6 8 3 8 Q6 4 6 4 Q6 4 9 8 Q6 8 6 14" fill="currentColor" opacity="0.6"/>
|
||||||
<rect x="5" y="13" width="2" height="5" fill="currentColor"/>
|
<rect x="5.25" y="13" width="1.5" height="4" fill="currentColor" opacity="0.6"/>
|
||||||
{/* Center tree (larger) */}
|
{/* Center tree - larger rounded canopy */}
|
||||||
<ellipse cx="12" cy="7" rx="5" ry="6" fill="currentColor"/>
|
<path d="M12 12 Q12 5 8 5 Q12 1 12 1 Q12 1 16 5 Q12 5 12 12" fill="currentColor"/>
|
||||||
<rect x="11" y="12" width="2" height="6" fill="currentColor"/>
|
<rect x="11.25" y="11" width="1.5" height="5" fill="currentColor"/>
|
||||||
{/* Right tree */}
|
{/* Right tree - rounded canopy */}
|
||||||
<ellipse cx="18" cy="9" rx="4" ry="5" fill="currentColor" opacity="0.7"/>
|
<path d="M18 14 Q18 8 15 8 Q18 4 18 4 Q18 4 21 8 Q18 8 18 14" fill="currentColor" opacity="0.6"/>
|
||||||
<rect x="17" y="13" width="2" height="5" fill="currentColor"/>
|
<rect x="17.25" y="13" width="1.5" height="4" fill="currentColor" opacity="0.6"/>
|
||||||
{/* Ground line */}
|
{/* Ground */}
|
||||||
<line x1="2" y1="18" x2="22" y2="18" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" opacity="0.5"/>
|
<ellipse cx="12" cy="19" rx="9" ry="1.5" fill="currentColor" opacity="0.3"/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<span className="logo-text">Orchard</span>
|
<span className="logo-text">Orchard</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user