1import { uuidv4 } from "../../lib/uuid";
2import * as Dialog from "../../components/ui/Dialog";
3import { useNavigation } from "@react-navigation/native";
4import { AsyncResult } from "effect/reactivity";
5import * as Cause from "effect/Cause";
6import { AuthFilesystemReadScope, AuthSourceControlWriteScope } from "@t3tools/contracts";
7import type {
8 EnvironmentProject,
9 EnvironmentThreadShell,
10} from "@t3tools/client-runtime/state/shell";
11import { useEnvironmentQuery } from "../../state/query";
12import { useEnvironmentScope } from "../../state/session";
13import { useAtomCommand } from "../../state/use-atom-command";
14import { vcsActionManager, vcsEnvironment } from "../../state/vcs";
15import { useVcsActionState } from "../../state/use-vcs-action-state";
16import { ThreadHeader } from "./ThreadHeader";
17
18export function DraftThreadHeader(props: {
19 readonly thread: EnvironmentThreadShell;
20 readonly project: EnvironmentProject;
21 readonly cwd: string | null;
22}) {
23 const navigation = useNavigation();
24 const environmentId = props.thread.environmentId;
25 const canReadFiles = useEnvironmentScope(environmentId, AuthFilesystemReadScope);
26 const canWriteGit = useEnvironmentScope(environmentId, AuthSourceControlWriteScope);
27 const status = useEnvironmentQuery(
28 props.cwd ? vcsEnvironment.status({ environmentId, input: { cwd: props.cwd } }) : null,
29 );
30 const target = { environmentId, cwd: props.cwd };
31 const progress = useVcsActionState(target);
32 const runAction = useAtomCommand(vcsActionManager.runStackedAction(target), {
33 reportFailure: false,
34 });
35 const pull = useAtomCommand(vcsEnvironment.pull, { reportFailure: false });
36 const openFiles = () => {
37 if (!props.cwd || !canReadFiles) return;
38 navigation.navigate("NewTaskFiles", {
39 environmentId,
40 cwd: props.cwd,
41 projectName: props.project.title,
42 });
43 };
44 const requiresThread = () =>
45 Dialog.alert("Available after the first message", "This action needs a saved thread.");
46 return (
47 <ThreadHeader
48 draft
49 title="New thread"
50 subtitle=""
51 hasThreadCwd={props.cwd !== null}
52 inspectorMode={null}
53 onOpenFilesInspector={openFiles}
54 gitControls={{
55 environmentId,
56 threadId: props.thread.id,
57 hasThread: false,
58 currentBranch: props.thread.branch,
59 gitStatus: status.data,
60 gitOperationLabel: progress.currentLabel,
61 canOpenTerminal: false,
62 canOperateTerminal: false,
63 canOpenFiles: canReadFiles && props.cwd !== null,
64 projectScripts: [],
65 terminalSessions: [],
66 onOpenFilesInspector: openFiles,
67 onOpenGitInspector: requiresThread,
68 onOpenTerminal: requiresThread,
69 onOpenNewTerminal: requiresThread,
70 onRunProjectScript: async () => {
71 requiresThread();
72 },
73 onPull: async () => {
74 if (!canWriteGit || !props.cwd) return;
75 const result = await pull({ environmentId, input: { cwd: props.cwd } });
76 if (AsyncResult.isFailure(result))
77 Dialog.alert("Could not pull", String(Cause.squash(result.cause)));
78 },
79 onRunAction: async (input) => {
80 if (!canWriteGit || !props.cwd) return null;
81 const result = await runAction({
82 ...input,
83 projectId: props.project.id,
84 actionId: uuidv4(),
85 });
86 if (AsyncResult.isFailure(result)) {
87 Dialog.alert("Git action failed", String(Cause.squash(result.cause)));
88 return null;
89 }
90 return result.value;
91 },
92 }}
93 />
94 );
95}