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.

59 linesCodeBlameRaw
1import { hasCodeAccess } from "@g1t/contracts";
2import { Stack, router } from "expo-router";
3import { BookLock, BookMarked, Code2 } from "lucide-react-native";
4import { useState } from "react";
5import { FlatList, RefreshControl, View } from "react-native";
6
7import { Badge, Empty, ErrorView, Field, Loading, Row, Screen } from "@/components/ui";
8import { useDescriptions, useRepos } from "@/lib/code";
9import { useSignedIn } from "@/lib/session";
10import { ago } from "@/lib/time";
11import { space, useColors } from "@/theme";
12
13/** Code: the workspace's repositories you can see, newest first. */
14export default function Repos() {
15 const { workspace } = useSignedIn();
16 const [search, setSearch] = useState("");
17 const repos = useRepos(search.trim());
18 const descriptions = useDescriptions(workspace?.slug);
19 const colors = useColors();
20
21 if (workspace && !hasCodeAccess(workspace)) {
22 return (
23 <Screen>
24 <Stack.Screen options={{ title: "Code" }} />
25 <Empty icon={Code2} title="Code is not on for you here" body={`${workspace.name ?? workspace.slug} gives you Chat and Docs. Ask an owner for Code.`} />
26 </Screen>
27 );
28 }
29
30 return (
31 <Screen>
32 <Stack.Screen options={{ title: "Code" }} />
33 <View style={{ padding: space.lg, paddingBottom: space.sm }}>
34 <Field label="Find a repository" placeholder="Name" value={search} onChangeText={setSearch} returnKeyType="search" />
35 </View>
36 {repos.isPending ? (
37 <Loading />
38 ) : repos.error ? (
39 <ErrorView error={repos.error} retry={() => repos.refetch()} />
40 ) : (
41 <FlatList
42 data={repos.data}
43 keyExtractor={(repo) => repo.id}
44 refreshControl={<RefreshControl refreshing={repos.isRefetching} onRefresh={() => repos.refetch()} tintColor={colors.accent} />}
45 ListEmptyComponent={<Empty icon={BookMarked} title={search ? "Nothing matches" : "No repositories yet"} />}
46 renderItem={({ item }) => (
47 <Row
48 leading={item.is_private ? <BookLock size={20} color={colors.muted} /> : <BookMarked size={20} color={colors.muted} />}
49 title={`${item.namespace}/${item.name}`}
50 subtitle={descriptions.data?.[`${item.namespace}/${item.name}`.toLowerCase()] ?? `Created ${ago(item.created_at)}`}
51 trailing={item.archived_at ? <Badge label="Archived" tone="warn" /> : null}
52 onPress={() => router.push({ pathname: "/code/[owner]/[repo]", params: { owner: item.namespace, repo: item.name } })}
53 />
54 )}
55 />
56 )}
57 </Screen>
58 );
59}