mirror of
https://github.com/binaricat/Netcatty.git
synced 2026-10-09 15:58:34 +00:00
00784a6b0e
Drops support for the built-in image viewer, including related UI, state, and file association logic. Simplifies file opener options and context menus to support only text editing and external system applications. Streamlines codebase by eliminating redundant image preview code and reduces maintenance overhead for this feature.
185 lines
5.4 KiB
TypeScript
185 lines
5.4 KiB
TypeScript
/**
|
|
* useSftpFileOperations - Shared file operations for SFTP components
|
|
*
|
|
* This hook provides common file operations like open, edit, preview
|
|
* that can be shared between SFTPModal and SftpView components.
|
|
*/
|
|
|
|
import { useCallback, useState } from "react";
|
|
import { getFileExtension, isTextFile, FileOpenerType } from "../../lib/sftpFileUtils";
|
|
import { toast } from "../../components/ui/toast";
|
|
import { useI18n } from "../i18n/I18nProvider";
|
|
import { useSftpFileAssociations } from "./useSftpFileAssociations";
|
|
|
|
export interface FileOperationsState {
|
|
// Text editor state
|
|
showTextEditor: boolean;
|
|
textEditorTarget: { name: string; fullPath: string } | null;
|
|
textEditorContent: string;
|
|
loadingTextContent: boolean;
|
|
|
|
// File opener dialog state
|
|
showFileOpenerDialog: boolean;
|
|
fileOpenerTarget: { name: string; fullPath: string } | null;
|
|
}
|
|
|
|
export interface FileOperationsActions {
|
|
// Open file based on type/association
|
|
openFile: (fileName: string, fullPath: string) => void;
|
|
|
|
// Edit text file
|
|
editFile: (
|
|
fileName: string,
|
|
fullPath: string,
|
|
readContent: () => Promise<string>
|
|
) => Promise<void>;
|
|
|
|
// Save text file
|
|
saveTextFile: (
|
|
content: string,
|
|
writeContent: (path: string, content: string) => Promise<void>
|
|
) => Promise<void>;
|
|
|
|
// Handle file opener selection
|
|
handleFileOpenerSelect: (
|
|
openerType: FileOpenerType,
|
|
setAsDefault: boolean,
|
|
readTextContent: () => Promise<string>,
|
|
readImageData: () => Promise<ArrayBuffer>
|
|
) => Promise<void>;
|
|
|
|
// Close modals
|
|
closeTextEditor: () => void;
|
|
closeFileOpenerDialog: () => void;
|
|
|
|
// Check if file can be edited
|
|
canEditFile: (fileName: string) => boolean;
|
|
}
|
|
|
|
export interface UseSftpFileOperationsResult {
|
|
state: FileOperationsState;
|
|
actions: FileOperationsActions;
|
|
}
|
|
|
|
export function useSftpFileOperations(): UseSftpFileOperationsResult {
|
|
const { t } = useI18n();
|
|
const { getOpenerForFile, setOpenerForExtension } = useSftpFileAssociations();
|
|
|
|
// Text editor state
|
|
const [showTextEditor, setShowTextEditor] = useState(false);
|
|
const [textEditorTarget, setTextEditorTarget] = useState<{ name: string; fullPath: string } | null>(null);
|
|
const [textEditorContent, setTextEditorContent] = useState("");
|
|
const [loadingTextContent, setLoadingTextContent] = useState(false);
|
|
|
|
// File opener dialog state
|
|
const [showFileOpenerDialog, setShowFileOpenerDialog] = useState(false);
|
|
const [fileOpenerTarget, setFileOpenerTarget] = useState<{ name: string; fullPath: string } | null>(null);
|
|
|
|
const canEditFile = useCallback((fileName: string) => {
|
|
return isTextFile(fileName);
|
|
}, []);
|
|
|
|
const closeTextEditor = useCallback(() => {
|
|
setShowTextEditor(false);
|
|
setTextEditorTarget(null);
|
|
setTextEditorContent("");
|
|
}, []);
|
|
|
|
const closeFileOpenerDialog = useCallback(() => {
|
|
setShowFileOpenerDialog(false);
|
|
setFileOpenerTarget(null);
|
|
}, []);
|
|
|
|
const editFile = useCallback(async (
|
|
fileName: string,
|
|
fullPath: string,
|
|
readContent: () => Promise<string>
|
|
) => {
|
|
try {
|
|
setLoadingTextContent(true);
|
|
setTextEditorTarget({ name: fileName, fullPath });
|
|
const content = await readContent();
|
|
setTextEditorContent(content);
|
|
setShowTextEditor(true);
|
|
} catch (e) {
|
|
toast.error(
|
|
e instanceof Error ? e.message : t("sftp.error.loadFailed"),
|
|
"SFTP",
|
|
);
|
|
} finally {
|
|
setLoadingTextContent(false);
|
|
}
|
|
}, [t]);
|
|
|
|
const saveTextFile = useCallback(async (
|
|
content: string,
|
|
writeContent: (path: string, content: string) => Promise<void>
|
|
) => {
|
|
if (!textEditorTarget) return;
|
|
await writeContent(textEditorTarget.fullPath, content);
|
|
}, [textEditorTarget]);
|
|
|
|
const openFile = useCallback((fileName: string, fullPath: string) => {
|
|
const savedOpener = getOpenerForFile(fileName);
|
|
|
|
if (savedOpener) {
|
|
// User has saved an opener for this file type
|
|
// We'll just set the target and let the caller handle it
|
|
setFileOpenerTarget({ name: fileName, fullPath });
|
|
|
|
// Return the opener type so caller knows which operation to perform
|
|
if (savedOpener === 'builtin-editor' && canEditFile(fileName)) {
|
|
// Don't show dialog, caller should call editFile
|
|
return 'edit' as const;
|
|
}
|
|
}
|
|
|
|
// No saved opener, show the dialog
|
|
setFileOpenerTarget({ name: fileName, fullPath });
|
|
setShowFileOpenerDialog(true);
|
|
return 'dialog' as const;
|
|
}, [getOpenerForFile, canEditFile]);
|
|
|
|
const handleFileOpenerSelect = useCallback(async (
|
|
openerType: FileOpenerType,
|
|
setAsDefault: boolean,
|
|
readTextContent: () => Promise<string>,
|
|
_readImageData: () => Promise<ArrayBuffer>
|
|
) => {
|
|
if (!fileOpenerTarget) return;
|
|
|
|
if (setAsDefault) {
|
|
const ext = getFileExtension(fileOpenerTarget.name);
|
|
if (ext !== 'file') {
|
|
setOpenerForExtension(ext, openerType);
|
|
}
|
|
}
|
|
|
|
setShowFileOpenerDialog(false);
|
|
|
|
if (openerType === 'builtin-editor') {
|
|
await editFile(fileOpenerTarget.name, fileOpenerTarget.fullPath, readTextContent);
|
|
}
|
|
}, [fileOpenerTarget, setOpenerForExtension, editFile]);
|
|
|
|
return {
|
|
state: {
|
|
showTextEditor,
|
|
textEditorTarget,
|
|
textEditorContent,
|
|
loadingTextContent,
|
|
showFileOpenerDialog,
|
|
fileOpenerTarget,
|
|
},
|
|
actions: {
|
|
openFile,
|
|
editFile,
|
|
saveTextFile,
|
|
handleFileOpenerSelect,
|
|
closeTextEditor,
|
|
closeFileOpenerDialog,
|
|
canEditFile,
|
|
},
|
|
};
|
|
}
|