Skip to content
Source
Sign inSign up

PullRequestRoutingSettings.tsx

112 lines4.6 KB

1import { ListChoiceRow } from "../../components/ui/ListChoiceRow";
2import * as Dialog from "../../components/ui/Dialog";
3import { useAtomValue } from "@effect/atom-react";
4import {
5 connectionCatalogDisplayUrl,
6 pullRequestRoutingConnectionKey,
7 pullRequestRoutingPermissionFor,
8 type PullRequestRoutingPermission,
9} from "@t3tools/client-runtime/connection";
10import { useState } from "react";
11import { Pressable, View } from "react-native";
12​
13import { AppText as Text } from "../../components/ui/AppText";
14import { SymbolView } from "../../components/ui/AppSymbol";
15import { environmentCatalog } from "../../connection/catalog";
16import { useAtomCommand } from "../../state/use-atom-command";
17import { SettingsSection } from "../settings/components/SettingsSection";
18​
19const options: ReadonlyArray<{
20 value: PullRequestRoutingPermission;
21 label: string;
22 description: string;
23}> = [
24 { value: "off", label: "Off", description: "Keep source control requests on this environment." },
25 {
26 value: "read",
27 label: "Read PRs",
28 description: "Share PR data with other enabled environments.",
29 },
30 {
31 value: "read-write",
32 label: "Read and act",
33 description:
34 "Actions may use broader source control permissions than the original environment.",
35 },
36];
37​
38export function PullRequestRoutingSettings() {
39 const catalog = useAtomValue(environmentCatalog.catalogValueAtom);
40 const permissions = useAtomValue(environmentCatalog.pullRequestRoutingPermissionsValueAtom);
41 const update = useAtomCommand(environmentCatalog.setPullRequestRoutingPermission);
42 const [expanded, setExpanded] = useState<string | null>(null);
43 const [saving, setSaving] = useState(false);
44 if (catalog.entries.size === 0) return null;
45​
46 return (
47 <View className="mt-5 gap-3">
48 <SettingsSection title="Pull request routing">
49 {[...catalog.entries.values()].map((entry) => {
50 const environmentId = entry.target.environmentId;
51 const selected = pullRequestRoutingPermissionFor(entry, permissions);
52 const disabled =
53 !catalog.isReady || saving || pullRequestRoutingConnectionKey(entry) === null;
54 return (
55 <View key={environmentId}>
56 <Pressable
57 accessibilityRole="button"
58 accessibilityLabel={`${entry.target.label} pull request routing`}
59 accessibilityState={{ expanded: expanded === environmentId }}
60 className="flex-row items-center gap-3 p-4"
61 onPress={() => setExpanded(expanded === environmentId ? null : environmentId)}
62 >
63 <View className="min-w-0 flex-1 gap-0.5">
64 <Text className="text-base font-t3-bold text-foreground">
65 {entry.target.label}
66 </Text>
67 <Text className="text-xs text-foreground-muted" numberOfLines={1}>
68 {connectionCatalogDisplayUrl(entry) ?? "T3 Connect"}
69 </Text>
70 </View>
71 <Text className="text-sm text-foreground-muted">
72 {options.find((option) => option.value === selected)?.label}
73 </Text>
74 <SymbolView
75 name={expanded === environmentId ? "chevron.up" : "chevron.down"}
76 size={12}
77 tintColorClassName="accent-icon-muted"
78 />
79 </Pressable>
80 {expanded === environmentId
81 ? options.map((option) => (
82 <ListChoiceRow
83 key={option.value}
84 label={option.label}
85 description={option.description}
86 selected={selected === option.value}
87 disabled={disabled}
88 onPress={() => {
89 setSaving(true);
90 void update({ environmentId, permission: option.value }).then((result) => {
91 setSaving(false);
92 if (result._tag === "Failure")
93 Dialog.alert(
94 "Could not save pull request routing permission",
95 "Try again before leaving this screen.",
96 );
97 });
98 }}
99 />
100 ))
101 : null}
102 </View>
103 );
104 })}
105 </SettingsSection>
106 <Text className="px-2 text-sm text-foreground-muted">
107 Choose environments you trust to share PR data and use each other's source control access.
108 Enable both environments. This applies only to this client.
109 </Text>
110 </View>
111 );