import type { EditorId, EnvironmentId, PreviewAnnotationPayload, ProjectId, ResolvedKeybindingsConfig, ScopedThreadRef, ThreadLinkedPullRequest, ThreadPullRequestLink, } from "@t3tools/contracts"; import { scopedThreadKey } from "@t3tools/client-runtime/environment"; import { lazy, Suspense } from "react"; import type { ComposerImageAttachment, DraftId } from "../../composerDraftStore"; import type { ShortcutMatchContext } from "../../keybindings"; import { type RightPanelSurface, useRightPanelStore } from "../../rightPanelStore"; import { PersistentThreadTerminalPanel, type PersistentThreadTerminalPanelProps, } from "../PersistentThreadTerminals"; import { pullRequestPanelContext } from "../pullRequest/pullRequestDetail.logic"; import { PullRequestDetailPanel } from "../pullRequest/PullRequestDetailPanel"; import { PullRequestDetailGhost } from "../pullRequest/PullRequestGhosts"; import { PullRequestsUnavailableState } from "../pullRequest/PullRequestsUnavailableState"; import { ThreadPullRequestsPanel } from "../pullRequest/ThreadPullRequestsPanel"; const PreviewPanel = lazy(() => import("../preview/PreviewPanel").then((module) => ({ default: module.PreviewPanel })), ); const DiffPanel = lazy(() => import("../DiffPanel")); const DevicePanel = lazy(() => import("../device/DevicePanel").then((module) => ({ default: module.DevicePanel })), ); const FilePreviewPanel = lazy(() => import("../files/FilePreviewPanel")); export type RightPanelTerminalProps = Omit< PersistentThreadTerminalPanelProps, "visible" | "threadRef" | "surface" >; export interface RightPanelPullRequestProps { readonly capabilityKnown: boolean; readonly supported: boolean; readonly projectId: ProjectId | null; readonly pullRequests: ReadonlyArray; readonly linkedPullRequest: ThreadLinkedPullRequest | null; readonly branchPullRequest: ThreadLinkedPullRequest | null | undefined; readonly onBack: (() => void) | undefined; } export interface RightPanelFileProps { readonly projectName: string | null; readonly workspaceRoot: string | undefined; readonly availableEditors: ReadonlyArray; readonly pendingSurfaceIds: ReadonlySet; readonly onOpenFile: (relativePath: string) => void; readonly onPendingChange: (relativePath: string, pending: boolean) => void; } export function RightPanelSurfaceContent(props: { readonly surface: RightPanelSurface | null; readonly activeSurfaceId: string | null; readonly threadRef: ScopedThreadRef; readonly environmentId: EnvironmentId; readonly visible: boolean; readonly composerDraftTarget: ScopedThreadRef | DraftId; readonly keybindings: ResolvedKeybindingsConfig; readonly configuredPreviewUrls: ReadonlyArray; readonly workspaceMutationId: string | null; readonly getShortcutContext: () => ShortcutMatchContext; readonly onSendAnnotation: ( annotation: PreviewAnnotationPayload, image: ComposerImageAttachment | null, ) => void; readonly onCloseSurface: (surface: RightPanelSurface) => void; readonly terminal: RightPanelTerminalProps; readonly pullRequest: RightPanelPullRequestProps; readonly files: RightPanelFileProps; }) { const { surface, threadRef, visible } = props; if (surface === null) return null; switch (surface.kind) { case "preview": return ( ); case "terminal": return ( ); case "diff": return ( ); case "pull-request": { const pullRequest = props.pullRequest; if (!pullRequest.capabilityKnown) return ; if (!pullRequest.supported) { return ( ); } return ( { useRightPanelStore.getState().openPullRequest(threadRef, { projectId: reference.projectId, repository: reference.repository, number: reference.number, ...(reference.host ? { host: reference.host } : {}), }); }} threadRef={threadRef} reference={{ projectId: surface.projectId as ProjectId, ...(surface.host ? { host: surface.host } : {}), repository: surface.repository, number: surface.number, }} initialTab={surface.detailTab ?? "summary"} onTabChange={(tab) => { useRightPanelStore.getState().setPullRequestDetailTab(threadRef, surface.id, tab); }} context={pullRequestPanelContext( { projectId: pullRequest.projectId, pullRequests: pullRequest.pullRequests, linkedPullRequest: pullRequest.linkedPullRequest, branchPullRequest: pullRequest.branchPullRequest, }, surface, )} composerDraftTarget={props.composerDraftTarget} onBack={pullRequest.onBack} /> ); } case "pull-requests": return ; case "device": return ( { props.onCloseSurface(surface); useRightPanelStore.getState().show(threadRef); }} /> ); case "files": case "file": { const files = props.files; const attachment = surface.kind === "file" ? surface.attachment : undefined; if (!attachment && (files.projectName === null || !files.workspaceRoot)) return null; return ( useRightPanelStore .getState() .navigateFolder(threadRef, surface.id, relativePath, folderTrail, keepSource) } folderTrail={surface.folderTrail} onPendingChange={files.onPendingChange} selectedFilePending={surface.kind === "file" && files.pendingSurfaceIds.has(surface.id)} workspaceMutationId={props.workspaceMutationId} /> ); } } }