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:
69
apps/web/src/components/tasks/TaskItem.tsx
Normal file
69
apps/web/src/components/tasks/TaskItem.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import type { Task } from "@mosaic/shared";
|
||||
import { TaskStatus, TaskPriority } from "@mosaic/shared";
|
||||
import { formatDate, isPastTarget, isApproachingTarget } from "@/lib/utils/date-format";
|
||||
|
||||
interface TaskItemProps {
|
||||
task: Task;
|
||||
}
|
||||
|
||||
const statusIcons: Record<TaskStatus, string> = {
|
||||
[TaskStatus.NOT_STARTED]: "⚪",
|
||||
[TaskStatus.IN_PROGRESS]: "🟢",
|
||||
[TaskStatus.PAUSED]: "⏸️",
|
||||
[TaskStatus.COMPLETED]: "✅",
|
||||
[TaskStatus.ARCHIVED]: "💤",
|
||||
};
|
||||
|
||||
const priorityLabels: Record<TaskPriority, string> = {
|
||||
[TaskPriority.HIGH]: "High priority",
|
||||
[TaskPriority.MEDIUM]: "Medium priority",
|
||||
[TaskPriority.LOW]: "Low priority",
|
||||
};
|
||||
|
||||
export function TaskItem({ task }: TaskItemProps) {
|
||||
const statusIcon = statusIcons[task.status];
|
||||
const priorityLabel = priorityLabels[task.priority];
|
||||
|
||||
// PDA-friendly date status
|
||||
let dateStatus = "";
|
||||
if (task.dueDate) {
|
||||
if (isPastTarget(task.dueDate)) {
|
||||
dateStatus = "Target passed";
|
||||
} else if (isApproachingTarget(task.dueDate)) {
|
||||
dateStatus = "Approaching target";
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="bg-white p-4 rounded-lg shadow-sm border border-gray-200 hover:shadow-md transition-shadow">
|
||||
<div className="flex items-start gap-3">
|
||||
<span className="text-xl flex-shrink-0" aria-label={`Status: ${task.status}`}>
|
||||
{statusIcon}
|
||||
</span>
|
||||
<div className="flex-1 min-w-0">
|
||||
<h3 className="font-semibold text-gray-900 mb-1">{task.title}</h3>
|
||||
{task.description && (
|
||||
<p className="text-sm text-gray-600 mb-2">{task.description}</p>
|
||||
)}
|
||||
<div className="flex flex-wrap items-center gap-2 text-xs">
|
||||
{task.priority && (
|
||||
<span className="px-2 py-1 bg-blue-100 text-blue-700 rounded-full">
|
||||
{priorityLabel}
|
||||
</span>
|
||||
)}
|
||||
{task.dueDate && (
|
||||
<span className="text-gray-500">
|
||||
{formatDate(task.dueDate)}
|
||||
</span>
|
||||
)}
|
||||
{dateStatus && (
|
||||
<span className="px-2 py-1 bg-amber-100 text-amber-700 rounded-full">
|
||||
{dateStatus}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user