feat(#37-41): Add domains, ideas, relationships, agents, widgets schema
Schema additions for issues #37-41: New models: - Domain (#37): Life domains (work, marriage, homelab, etc.) - Idea (#38): Brain dumps with pgvector embeddings - Relationship (#39): Generic entity linking (blocks, depends_on) - Agent (#40): ClawdBot agent tracking with metrics - AgentSession (#40): Conversation session tracking - WidgetDefinition (#41): HUD widget registry - UserLayout (#41): Per-user dashboard configuration Updated models: - Task, Event, Project: Added domainId foreign key - User, Workspace: Added new relations New enums: - IdeaStatus: CAPTURED, PROCESSING, ACTIONABLE, ARCHIVED, DISCARDED - RelationshipType: BLOCKS, BLOCKED_BY, DEPENDS_ON, etc. - AgentStatus: IDLE, WORKING, WAITING, ERROR, TERMINATED - EntityType: Added IDEA, DOMAIN Migration: 20260129182803_add_domains_ideas_agents_widgets
This commit is contained in:
70
apps/web/src/components/tasks/TaskList.tsx
Normal file
70
apps/web/src/components/tasks/TaskList.tsx
Normal file
@@ -0,0 +1,70 @@
|
||||
import type { Task } from "@mosaic/shared";
|
||||
import { TaskItem } from "./TaskItem";
|
||||
import { getDateGroupLabel } from "@/lib/utils/date-format";
|
||||
|
||||
interface TaskListProps {
|
||||
tasks: Task[];
|
||||
isLoading: boolean;
|
||||
}
|
||||
|
||||
export function TaskList({ tasks, isLoading }: TaskListProps) {
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex justify-center items-center p-8">
|
||||
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"></div>
|
||||
<span className="ml-3 text-gray-600">Loading tasks...</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Handle null/undefined tasks gracefully
|
||||
if (!tasks || tasks.length === 0) {
|
||||
return (
|
||||
<div className="text-center p-8 text-gray-500">
|
||||
<p className="text-lg">No tasks scheduled</p>
|
||||
<p className="text-sm mt-2">Your task list is clear</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Group tasks by date
|
||||
const groupedTasks = tasks.reduce((groups, task) => {
|
||||
if (!task.dueDate) {
|
||||
return groups;
|
||||
}
|
||||
const label = getDateGroupLabel(task.dueDate);
|
||||
if (!groups[label]) {
|
||||
groups[label] = [];
|
||||
}
|
||||
groups[label].push(task);
|
||||
return groups;
|
||||
}, {} as Record<string, Task[]>);
|
||||
|
||||
const groupOrder = ["Today", "Tomorrow", "This Week", "Next Week", "Later"];
|
||||
|
||||
return (
|
||||
<main className="space-y-6">
|
||||
{groupOrder.map((groupLabel) => {
|
||||
const groupTasks = groupedTasks[groupLabel];
|
||||
if (!groupTasks || groupTasks.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<section key={groupLabel}>
|
||||
<h2 className="text-lg font-semibold text-gray-700 mb-3">
|
||||
{groupLabel}
|
||||
</h2>
|
||||
<ul className="space-y-2">
|
||||
{groupTasks.map((task) => (
|
||||
<li key={task.id}>
|
||||
<TaskItem task={task} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
);
|
||||
})}
|
||||
</main>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user