import { useCallback, useRef, useState } from "react"; import type { Changes } from "@ace/channel/protocol"; import type { Listing } from "@ace/host/protocol"; import { SessionDetailsView, Sidebar, useLayoutRight } from "@ace/ui"; import { Conversation } from "./conversation"; import { host } from "./host"; import { CHAT, Layout } from "./layout/layout"; import { Diff } from "./panels/diff"; import { Terminal } from "./panels/terminal"; // Channels have one chat today; its tabs follow the chat the Chat tab shows. const chat = 1; export type ChannelDraft = { channel: string; text: string }; type Props = { channel: Listing; user: string; remote: boolean; draft?: ChannelDraft; onDraftLoaded: () => void; onSettings?: () => void; }; export function ChannelDetails({ channel }: { channel: Listing }) { const right = useLayoutRight(); return ( right.setOpen(false)} /> ); } /** A channel's tabs: its chat, plus Diff and Terminal views of that chat's lane. */ export function Channel({ channel, user, remote, draft, onDraftLoaded, onSettings }: Props) { const [changed, setChanged] = useState(); const check = useRef({ busy: false, again: false }); // One check at a time; work that lands during a check asks for one more after it. const inspect = useCallback(() => { const run = check.current; if (run.busy) { run.again = true; return; } run.busy = true; host.channel(channel.id, { op: "changes", chat }).then( (value) => setChanged(value.files.length > 0), () => {}, ).finally(() => { run.busy = false; if (!run.again) return; run.again = false; inspect(); }); }, [channel.id]); return ( { if (uid === CHAT) { return ( ); } if (data.type === "diff") { return ; } if (data.type !== "terminal") return null; return ( update({ terminal })} /> ); }} onTabClose={(_, data) => { if (data.type !== "terminal" || !data.terminal) return; host.request({ op: "terminal-close", terminal: data.terminal }).catch(() => {}); }} /> ); }