mission-control/lib/data/projects.ts
OpenClaw Bot 762c59500e Mission Control Phase 2: Transform Tasks page to overview
- Replaced kanban with task overview/summary view
- Added task stats cards (total, in progress, high priority, overdue)
- Added recent activity sections (updated, completed, high priority)
- Added quick action links to gantt-board
- Created lib/data/tasks.ts with data fetching functions
- Removed file-based storage (taskDb.ts, api/tasks/route.ts)
- Connected to gantt-board Supabase for real data
2026-02-21 22:48:15 -06:00

59 lines
1.5 KiB
TypeScript

import { getServiceSupabase } from "@/lib/supabase/client";
export interface Project {
id: string;
name: string;
description?: string;
color: string;
createdAt: string;
}
function toNonEmptyString(value: unknown): string | undefined {
return typeof value === "string" && value.trim().length > 0 ? value : undefined;
}
function mapProjectRow(row: Record<string, unknown>): Project {
return {
id: String(row.id ?? ""),
name: toNonEmptyString(row.name) ?? "Untitled Project",
description: toNonEmptyString(row.description),
color: toNonEmptyString(row.color) ?? "#3b82f6",
createdAt: toNonEmptyString(row.created_at) ?? new Date().toISOString(),
};
}
/**
* Fetch all projects from Supabase
*/
export async function fetchAllProjects(): Promise<Project[]> {
const supabase = getServiceSupabase();
const { data, error } = await supabase
.from("projects")
.select("*")
.order("created_at", { ascending: true });
if (error) {
console.error("Error fetching projects:", error);
throw new Error(`Failed to fetch projects: ${error.message}`);
}
return (data || []).map((row) => mapProjectRow(row as Record<string, unknown>));
}
/**
* Count total projects
*/
export async function countProjects(): Promise<number> {
const supabase = getServiceSupabase();
const { count, error } = await supabase
.from("projects")
.select("*", { count: "exact", head: true });
if (error) {
console.error("Error counting projects:", error);
return 0;
}
return count || 0;
}