214 lines
7.6 KiB
TypeScript
214 lines
7.6 KiB
TypeScript
import React from "react";
|
|
import type { Host, SftpFileEntry } from "../../types";
|
|
import type { FileOpenerType, SystemAppInfo } from "../../lib/sftpFileUtils";
|
|
import type { useSftpState } from "../../application/state/useSftpState";
|
|
import type { HotkeyScheme, KeyBinding } from "../../domain/models";
|
|
import type { TransferTask } from "../../types";
|
|
import FileOpenerDialog from "../FileOpenerDialog";
|
|
import TextEditorModal from "../TextEditorModal";
|
|
import type { TextEditorModalSnapshot } from "../TextEditorModal";
|
|
import { TerminalHostKeyVerification } from "../terminal/TerminalHostKeyVerification";
|
|
import { Dialog, DialogContent, DialogTitle } from "../ui/dialog";
|
|
import { SftpConflictDialog } from "./SftpConflictDialog";
|
|
import { SftpHostPicker } from "./SftpHostPicker";
|
|
import { SftpPermissionsDialog } from "./SftpPermissionsDialog";
|
|
import { SftpTransferQueue } from "./SftpTransferQueue";
|
|
|
|
type SftpState = ReturnType<typeof useSftpState>;
|
|
|
|
interface SftpOverlaysProps {
|
|
hosts: Host[];
|
|
sftp: SftpState;
|
|
visibleTransfers: SftpState["transfers"];
|
|
showTransferQueue?: boolean;
|
|
canRevealTransferTarget?: (task: TransferTask) => boolean;
|
|
onRevealTransferTarget?: (task: TransferTask) => void | Promise<void>;
|
|
canCopyTransferTargetPath?: (task: TransferTask) => boolean;
|
|
onCopyTransferTargetPath?: (task: TransferTask) => void | Promise<void>;
|
|
showHostPickerLeft: boolean;
|
|
showHostPickerRight: boolean;
|
|
hostSearchLeft: string;
|
|
hostSearchRight: string;
|
|
setShowHostPickerLeft: (open: boolean) => void;
|
|
setShowHostPickerRight: (open: boolean) => void;
|
|
setHostSearchLeft: (value: string) => void;
|
|
setHostSearchRight: (value: string) => void;
|
|
handleHostSelectLeft: (host: Host | "local") => void;
|
|
handleHostSelectRight: (host: Host | "local") => void;
|
|
permissionsState: { file: SftpFileEntry; side: "left" | "right"; fullPath: string } | null;
|
|
setPermissionsState: (state: { file: SftpFileEntry; side: "left" | "right"; fullPath: string } | null) => void;
|
|
showTextEditor: boolean;
|
|
setShowTextEditor: (open: boolean) => void;
|
|
textEditorTarget: { file: SftpFileEntry; side: "left" | "right"; fullPath: string } | null;
|
|
setTextEditorTarget: (target: { file: SftpFileEntry; side: "left" | "right"; fullPath: string } | null) => void;
|
|
textEditorContent: string;
|
|
setTextEditorContent: (content: string) => void;
|
|
handleSaveTextFile: (content: string) => Promise<void>;
|
|
editorWordWrap: boolean;
|
|
setEditorWordWrap: (enabled: boolean) => void;
|
|
hotkeyScheme: HotkeyScheme;
|
|
keyBindings: KeyBinding[];
|
|
showFileOpenerDialog: boolean;
|
|
setShowFileOpenerDialog: (open: boolean) => void;
|
|
fileOpenerTarget: { file: SftpFileEntry; side: "left" | "right"; fullPath: string } | null;
|
|
setFileOpenerTarget: (target: { file: SftpFileEntry; side: "left" | "right"; fullPath: string } | null) => void;
|
|
handleFileOpenerSelect: (openerType: FileOpenerType, setAsDefault: boolean, systemApp?: SystemAppInfo) => void;
|
|
handleSelectSystemApp: (systemApp: { path: string; name: string }) => void;
|
|
onPromoteToTab?: (snapshot: TextEditorModalSnapshot) => void;
|
|
onRequestTerminalFocus?: () => void;
|
|
}
|
|
|
|
export const SftpOverlays: React.FC<SftpOverlaysProps> = React.memo(({
|
|
hosts,
|
|
sftp,
|
|
visibleTransfers,
|
|
showTransferQueue = true,
|
|
canRevealTransferTarget,
|
|
onRevealTransferTarget,
|
|
canCopyTransferTargetPath,
|
|
onCopyTransferTargetPath,
|
|
showHostPickerLeft,
|
|
showHostPickerRight,
|
|
hostSearchLeft,
|
|
hostSearchRight,
|
|
setShowHostPickerLeft,
|
|
setShowHostPickerRight,
|
|
setHostSearchLeft,
|
|
setHostSearchRight,
|
|
handleHostSelectLeft,
|
|
handleHostSelectRight,
|
|
permissionsState,
|
|
setPermissionsState,
|
|
showTextEditor,
|
|
setShowTextEditor,
|
|
textEditorTarget,
|
|
setTextEditorTarget,
|
|
textEditorContent,
|
|
setTextEditorContent,
|
|
handleSaveTextFile,
|
|
editorWordWrap,
|
|
setEditorWordWrap,
|
|
hotkeyScheme,
|
|
keyBindings,
|
|
showFileOpenerDialog,
|
|
setShowFileOpenerDialog,
|
|
fileOpenerTarget,
|
|
setFileOpenerTarget,
|
|
handleFileOpenerSelect,
|
|
handleSelectSystemApp,
|
|
onPromoteToTab,
|
|
onRequestTerminalFocus,
|
|
}) => {
|
|
return (
|
|
<>
|
|
{/* Host pickers for adding new tabs */}
|
|
<SftpHostPicker
|
|
open={showHostPickerLeft}
|
|
onOpenChange={setShowHostPickerLeft}
|
|
hosts={hosts}
|
|
side="left"
|
|
hostSearch={hostSearchLeft}
|
|
onHostSearchChange={setHostSearchLeft}
|
|
onSelectLocal={() => handleHostSelectLeft("local")}
|
|
onSelectHost={handleHostSelectLeft}
|
|
/>
|
|
<SftpHostPicker
|
|
open={showHostPickerRight}
|
|
onOpenChange={setShowHostPickerRight}
|
|
hosts={hosts}
|
|
side="right"
|
|
hostSearch={hostSearchRight}
|
|
onHostSearchChange={setHostSearchRight}
|
|
onSelectLocal={() => handleHostSelectRight("local")}
|
|
onSelectHost={handleHostSelectRight}
|
|
/>
|
|
|
|
{showTransferQueue && (
|
|
<SftpTransferQueue
|
|
sftp={sftp}
|
|
visibleTransfers={visibleTransfers}
|
|
allTransfers={sftp.transfers}
|
|
canRevealTransferTarget={canRevealTransferTarget}
|
|
onRevealTransferTarget={onRevealTransferTarget}
|
|
canCopyTransferTargetPath={canCopyTransferTargetPath}
|
|
onCopyTransferTargetPath={onCopyTransferTargetPath}
|
|
/>
|
|
)}
|
|
|
|
<SftpConflictDialog
|
|
conflicts={sftp.conflicts}
|
|
onResolve={sftp.resolveConflict}
|
|
formatFileSize={sftp.formatFileSize}
|
|
/>
|
|
|
|
<Dialog
|
|
open={!!sftp.hostKeyVerification}
|
|
onOpenChange={(open) => {
|
|
if (!open) sftp.rejectHostKeyVerification();
|
|
}}
|
|
>
|
|
<DialogContent className="max-w-lg" hideCloseButton>
|
|
<DialogTitle className="sr-only">Confirm host key</DialogTitle>
|
|
{sftp.hostKeyVerification && (
|
|
<TerminalHostKeyVerification
|
|
hostKeyInfo={sftp.hostKeyVerification.hostKeyInfo}
|
|
showLogs={sftp.hostKeyVerification.progressLogs.length > 0}
|
|
progressLogs={sftp.hostKeyVerification.progressLogs}
|
|
onClose={sftp.rejectHostKeyVerification}
|
|
onContinue={sftp.acceptHostKeyVerification}
|
|
onAddAndContinue={sftp.acceptAndSaveHostKeyVerification}
|
|
/>
|
|
)}
|
|
</DialogContent>
|
|
</Dialog>
|
|
|
|
<SftpPermissionsDialog
|
|
open={!!permissionsState}
|
|
onOpenChange={(open) => !open && setPermissionsState(null)}
|
|
file={permissionsState?.file ?? null}
|
|
onSave={(_file, permissions) => {
|
|
if (permissionsState) {
|
|
sftp.changePermissions(
|
|
permissionsState.side,
|
|
permissionsState.fullPath,
|
|
permissions,
|
|
);
|
|
}
|
|
setPermissionsState(null);
|
|
}}
|
|
/>
|
|
|
|
{/* Text Editor Modal */}
|
|
<TextEditorModal
|
|
open={showTextEditor}
|
|
onClose={() => {
|
|
setShowTextEditor(false);
|
|
setTextEditorTarget(null);
|
|
setTextEditorContent("");
|
|
onRequestTerminalFocus?.();
|
|
}}
|
|
fileName={textEditorTarget?.file.name || ""}
|
|
initialContent={textEditorContent}
|
|
onSave={handleSaveTextFile}
|
|
editorWordWrap={editorWordWrap}
|
|
onToggleWordWrap={() => setEditorWordWrap(!editorWordWrap)}
|
|
hotkeyScheme={hotkeyScheme}
|
|
keyBindings={keyBindings}
|
|
onPromoteToTab={onPromoteToTab}
|
|
/>
|
|
|
|
{/* File Opener Dialog */}
|
|
<FileOpenerDialog
|
|
open={showFileOpenerDialog}
|
|
onClose={() => {
|
|
setShowFileOpenerDialog(false);
|
|
setFileOpenerTarget(null);
|
|
}}
|
|
fileName={fileOpenerTarget?.file.name || ""}
|
|
onSelect={handleFileOpenerSelect}
|
|
onSelectSystemApp={handleSelectSystemApp}
|
|
/>
|
|
</>
|
|
);
|
|
});
|