=== NEW === - studio/ — MCPEngine Studio scaffold (Next.js monorepo, build plan) - docs/FACTORY-V2.md — Factory v2 architecture doc - docs/CALENDLY_MCP_BUILD_SUMMARY.md — Calendly MCP build report === UPDATED SERVERS === - fieldedge: Added jobs-tools, UI build script, main entry update - lightspeed: Updated main + server entry points - squarespace: Added collection-browser + page-manager apps - toast: Added main + server entry points === INFRA === - infra/command-center/state.json — Updated pipeline state - infra/command-center/FACTORY-V2.md — Factory v2 operator playbook
76 lines
3.1 KiB
TypeScript
76 lines
3.1 KiB
TypeScript
"use client";
|
|
|
|
import { Card } from "@mcpengine/ui";
|
|
import Link from "next/link";
|
|
|
|
export type ProjectStatus = "draft" | "analyzed" | "generated" | "tested" | "deployed";
|
|
|
|
export interface Project {
|
|
id: string;
|
|
name: string;
|
|
status: ProjectStatus;
|
|
toolCount: number;
|
|
updatedAt: Date;
|
|
}
|
|
|
|
const statusConfig: Record<ProjectStatus, { label: string; color: string }> = {
|
|
draft: { label: "Draft", color: "bg-gray-600 text-gray-200" },
|
|
analyzed: { label: "Analyzed", color: "bg-yellow-600/20 text-yellow-400" },
|
|
generated: { label: "Generated", color: "bg-blue-600/20 text-blue-400" },
|
|
tested: { label: "Tested", color: "bg-emerald-600/20 text-emerald-400" },
|
|
deployed: { label: "Deployed", color: "bg-indigo-600/20 text-indigo-400" },
|
|
};
|
|
|
|
function relativeTime(date: Date): string {
|
|
const seconds = Math.floor((Date.now() - date.getTime()) / 1000);
|
|
if (seconds < 60) return "just now";
|
|
const minutes = Math.floor(seconds / 60);
|
|
if (minutes < 60) return `${minutes}m ago`;
|
|
const hours = Math.floor(minutes / 60);
|
|
if (hours < 24) return `${hours}h ago`;
|
|
const days = Math.floor(hours / 24);
|
|
if (days < 30) return `${days}d ago`;
|
|
return date.toLocaleDateString();
|
|
}
|
|
|
|
export function ProjectCard({ project }: { project: Project }) {
|
|
const status = statusConfig[project.status];
|
|
|
|
return (
|
|
<Link href={`/editor?project=${project.id}`}>
|
|
<Card className="bg-gray-900 border border-gray-800 hover:border-gray-600 rounded-xl p-5 transition-all cursor-pointer group h-full">
|
|
<div className="flex items-start justify-between mb-3">
|
|
<h3 className="font-semibold text-white group-hover:text-indigo-400 transition-colors truncate pr-2">
|
|
{project.name}
|
|
</h3>
|
|
<span
|
|
className={`text-xs font-medium px-2.5 py-0.5 rounded-full whitespace-nowrap ${status.color}`}
|
|
>
|
|
{status.label}
|
|
</span>
|
|
</div>
|
|
<div className="flex items-center justify-between text-sm text-gray-500">
|
|
<span className="flex items-center gap-1.5">
|
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth={2}
|
|
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
|
|
/>
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth={2}
|
|
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
|
/>
|
|
</svg>
|
|
{project.toolCount} tools
|
|
</span>
|
|
<span>{relativeTime(project.updatedAt)}</span>
|
|
</div>
|
|
</Card>
|
|
</Link>
|
|
);
|
|
}
|