Skip to content

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

89 linesCodeBlameRaw
1import type { Route } from "./+types/tree";
2import { page } from "../../lib/meta";
3import { TreeView } from "../../components/repo-view";
4import { redirectIfBranchRenamed } from "../../lib/branch-redirect.server";
5import { commitChecksFor } from "../../lib/commit-checks.server";
6import { aboutFor } from "../../lib/about.server";
7import { environmentsFor } from "../../lib/deployments.server";
8import { lastCommitsFor } from "../../lib/last-commits.server";
9import { showOneCommit } from "../../lib/commit-people.server";
10import { repos } from "../../lib/services.server";
11import { getViewer, unwrap } from "../../lib/session.server";
12import { useProject } from "./layout";
13import { ForkBar } from "../../components/fork-bar";
14import { forkSourceFor } from "../../lib/forks.server";
15import { repoPages } from "../../lib/repo-live";
16import { useRepoLive } from "../../lib/use-repo-live";
17import { isFailed, part } from "../../lib/partial";
18import { Unavailable } from "../../components/boundary";
19
20export function meta({ params, ...args }: Route.MetaArgs) {
21 const path = params["*"] ? `${params["*"]} · ` : "";
22 return page(args, { title: `${path}${params.owner}/${params.repo} · g1t` });
23}
24
25export async function loader({ params, context, request }: Route.LoaderArgs) {
26 const path = { namespace: params.owner, name: params.repo };
27 const viewer = getViewer(context);
28 const [tree, branches, environments, fork] = await Promise.all([
29 repos.tree(path, viewer, params.ref, params["*"] ?? ""),
30 // For the branch menu; the page still shows without it, and the menu
31 // says when it could not be loaded.
32 part(repos.branches(path, viewer), "Branches"),
33 // For the About sidebar's Deployments panel, shown at the root only.
34 params["*"] ? null : part(environmentsFor(path, viewer), "Deployments"),
35 // A fork's parent, for the bar above its files, at the root only.
36 params["*"] ? null : part(forkSourceFor(context, params, viewer), "Where this fork came from"),
37 ]);
38 // A branch that was renamed: the same folder on its new name.
39 if (!tree.ok && tree.error.code === "not_found") await redirectIfBranchRenamed(request, path, viewer, params.ref);
40 // Each entry's last commit walks history: streamed in after the list.
41 const lastCommits = lastCommitsFor(path, viewer, params.ref, params["*"] ?? "");
42 const found = unwrap(tree);
43 // The latest commit's author, as their account where there is one.
44 const value = { ...found, head: await showOneCommit(found.head) };
45 // The About beside the files, streamed in after them.
46 const about = value.head && !value.path ? aboutFor(path, viewer, value.repo.id) : null;
47 // The latest commit's checks: streamed in beside it.
48 const checks = commitChecksFor(path, viewer, [value.head?.hash]);
49 return {
50 tree: value,
51 branches: isFailed(branches) ? branches : branches.ok ? branches.value : null,
52 lastCommits,
53 about,
54 deployments: environments,
55 checks,
56 fork,
57 };
58}
59
60export default function Tree({ loaderData }: Route.ComponentProps) {
61 const project = useProject();
62 // The files and latest commit follow pushes to the branch (none for a
63 // tag or a commit); the latest commit's checks update as they report.
64 const { tree, fork } = loaderData;
65 // Without the branch list, the page follows its branch as if it were one.
66 const branches = isFailed(loaderData.branches) ? null : loaderData.branches;
67 const names = branches?.map((branch) => branch.name);
68 useRepoLive({ match: repoPages.files({ branch: !names || names.includes(tree.ref) ? tree.ref : null, branches: names, sha: tree.head?.hash }) });
69 return (
70 <TreeView
71 tree={loaderData.tree}
72 branches={loaderData.branches}
73 lastCommits={loaderData.lastCommits}
74 checks={loaderData.checks}
75 about={loaderData.about}
76 canPush={Boolean(project?.access.can.push)}
77 deployments={loaderData.deployments}
78 fork={
79 isFailed(fork) ? (
80 <div className="mb-4">
81 <Unavailable compact what={fork.what} />
82 </div>
83 ) : fork && project && branches?.some((branch) => branch.name === tree.ref) ? (
84 <ForkBar base={`/${tree.repo.namespace}/${tree.repo.name}`} branch={tree.ref} parent={fork} canPush={Boolean(project.access.can.push)} />
85 ) : null
86 }
87 />
88 );
89}