flagon-io/g1t

public

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t/apps/web/app/routes/repo/layout.tsx

132 lines4,455 bytesCodeBlame

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Agents as a team: lifecycle, merge queue, billing and a new shell1import {
2 BookMarked,
3 CircleDot,
4 Code2,
5 GitPullRequest,
6 History,
7 ListTree,
8 Lock,
9 Settings,
10} from "lucide-react";
11import { Link, Outlet, useRouteLoaderData } from "react-router";
Initial g1t: services, event bus, intents and attempts12
13import type { Route } from "./+types/layout";
Agents as a team: lifecycle, merge queue, billing and a new shell14import { Pill, TabLink as Tab } from "../../components/ui";
Work service in Rust, with RFC 3339 timestamps15import { repos, work } from "../../lib/services.server";
Agents as a team: lifecycle, merge queue, billing and a new shell16import { getViewer, roleIn, unwrap } from "../../lib/session.server";
Initial g1t: services, event bus, intents and attempts17
18export function meta({ params }: Route.MetaArgs) {
19 return [{ title: `${params.owner}/${params.repo} · g1t` }];
20}
21
22export async function loader({ params, context }: Route.LoaderArgs) {
23 const viewer = getViewer(context);
24 const path = { namespace: params.owner, name: params.repo };
Issues and pull requests replace intents and attempts25 const [repo, counts] = await Promise.all([
Rust repos service with shipping; pull requests kept in the model26 repos.get(path, viewer),
Issues and pull requests replace intents and attempts27 work.counts(path, viewer),
Initial g1t: services, event bus, intents and attempts28 ]);
29 return {
30 repo: unwrap(repo),
Issues and pull requests replace intents and attempts31 open: counts.ok ? counts.value : { issues: 0, pulls: 0 },
Agents as a team: lifecycle, merge queue, billing and a new shell32 member: roleIn(viewer, params.owner) != null,
Initial g1t: services, event bus, intents and attempts33 };
34}
35
36export default function RepoLayout({ loaderData }: Route.ComponentProps) {
Agents as a team: lifecycle, merge queue, billing and a new shell37 const { repo, open, member } = loaderData;
Initial g1t: services, event bus, intents and attempts38 const base = `/${repo.namespace}/${repo.name}`;
Agents as a team: lifecycle, merge queue, billing and a new shell39 const signedIn = useRouteLoaderData("root")?.user != null;
40 if (signedIn) {
41 return (
42 <>
43 <div className="border-b border-line">
44 <div className="mx-auto flex max-w-6xl flex-wrap items-center gap-x-3 gap-y-1 px-4 py-3 sm:px-6">
45 {repo.isPrivate ? (
46 <Lock size={15} className="text-faint" />
47 ) : (
48 <BookMarked size={15} className="text-faint" />
49 )}
50 <h1 className="font-mono text-[0.9375rem]">
51 <Link to={`/${repo.namespace}`} className="text-muted hover:text-fg">
52 {repo.namespace}
53 </Link>
54 <span className="mx-1 text-faint">/</span>
55 <Link to={base} className="font-semibold hover:underline">
56 {repo.name}
57 </Link>
58 </h1>
59 <Pill>{repo.isPrivate ? "private" : "public"}</Pill>
60 {repo.description && (
61 <p className="min-w-0 truncate text-sm text-muted">{repo.description}</p>
62 )}
63 </div>
64 </div>
65 <div className="mx-auto max-w-6xl px-4 py-6 sm:px-6">
66 <Outlet />
67 </div>
68 </>
69 );
70 }
Initial g1t: services, event bus, intents and attempts71 return (
API and MCP server, Rust identity service, registration, site redesign72 <>
73 {/* The repository's own header band, under the site header. */}
74 <div className="border-b border-line bg-surface/60">
75 <div className="mx-auto max-w-6xl px-4 pt-6">
76 <div className="flex flex-wrap items-center gap-2.5">
77 {repo.isPrivate ? (
78 <Lock size={17} className="text-faint" />
79 ) : (
80 <BookMarked size={17} className="text-faint" />
81 )}
82 <h1 className="font-mono text-lg">
83 <Link to={`/${repo.namespace}`} className="text-muted hover:text-fg">
84 {repo.namespace}
85 </Link>
86 <span className="mx-1 text-faint">/</span>
87 <Link to={base} className="font-semibold hover:underline">
88 {repo.name}
89 </Link>
90 </h1>
91 <Pill>{repo.isPrivate ? "private" : "public"}</Pill>
92 </div>
93 {repo.description && (
94 <p className="mt-2 max-w-2xl text-sm text-muted">{repo.description}</p>
Initial g1t: services, event bus, intents and attempts95 )}
API and MCP server, Rust identity service, registration, site redesign96 <nav className="mt-5 flex gap-6">
97 <Tab to={base} end icon={<Code2 size={15} />}>
98 Code
99 </Tab>
Issues and pull requests replace intents and attempts100 <Tab to={`${base}/issues`} icon={<CircleDot size={15} />} count={open.issues}>
101 Issues
102 </Tab>
103 <Tab
104 to={`${base}/pulls`}
105 also={`${base}/pull`}
106 icon={<GitPullRequest size={15} />}
107 count={open.pulls}
108 >
109 Pull requests
API and MCP server, Rust identity service, registration, site redesign110 </Tab>
111 <Tab to={`${base}/commits`} icon={<History size={15} />}>
112 Commits
113 </Tab>
Agents as a team: lifecycle, merge queue, billing and a new shell114 {member && (
115 <Tab to={`${base}/plans`} icon={<ListTree size={15} />}>
116 Plan
117 </Tab>
118 )}
119 {member && (
120 <Tab to={`${base}/settings`} icon={<Settings size={15} />}>
121 Settings
122 </Tab>
123 )}
API and MCP server, Rust identity service, registration, site redesign124 </nav>
125 </div>
126 </div>
127 <div className="mx-auto max-w-6xl px-4 py-6">
128 <Outlet />
129 </div>
130 </>
Initial g1t: services, event bus, intents and attempts131 );
132}