diff --git a/app/src/components/files/FileActions.jsx b/app/src/components/files/FileActions.tsx similarity index 82% rename from app/src/components/files/FileActions.jsx rename to app/src/components/files/FileActions.tsx index d8b4f18..b846c9d 100644 --- a/app/src/components/files/FileActions.jsx +++ b/app/src/components/files/FileActions.tsx @@ -9,7 +9,15 @@ import { import { useModalContext } from '../../contexts/ModalContext'; import { useWorkspace } from '../../contexts/WorkspaceContext'; -const FileActions = ({ handlePullChanges, selectedFile }) => { +interface FileActionsProps { + handlePullChanges: () => Promise; + selectedFile: string | null; +} + +const FileActions: React.FC = ({ + handlePullChanges, + selectedFile, +}) => { const { settings } = useWorkspace(); const { setNewFileModalVisible, @@ -17,9 +25,9 @@ const FileActions = ({ handlePullChanges, selectedFile }) => { setCommitMessageModalVisible, } = useModalContext(); - const handleCreateFile = () => setNewFileModalVisible(true); - const handleDeleteFile = () => setDeleteFileModalVisible(true); - const handleCommitAndPush = () => setCommitMessageModalVisible(true); + const handleCreateFile = (): void => setNewFileModalVisible(true); + const handleDeleteFile = (): void => setDeleteFileModalVisible(true); + const handleCommitAndPush = (): void => setCommitMessageModalVisible(true); return ( diff --git a/app/src/components/files/FileTree.jsx b/app/src/components/files/FileTree.tsx similarity index 53% rename from app/src/components/files/FileTree.jsx rename to app/src/components/files/FileTree.tsx index 280ce31..ec5c4fe 100644 --- a/app/src/components/files/FileTree.jsx +++ b/app/src/components/files/FileTree.tsx @@ -1,21 +1,35 @@ import React, { useRef, useState, useLayoutEffect } from 'react'; -import { Tree } from 'react-arborist'; +import { Tree, NodeApi } from 'react-arborist'; import { IconFile, IconFolder, IconFolderOpen } from '@tabler/icons-react'; import { Tooltip } from '@mantine/core'; import useResizeObserver from '@react-hook/resize-observer'; +import { FileNode } from '../../types/fileApi'; -const useSize = (target) => { - const [size, setSize] = useState(); +interface Size { + width: number; + height: number; +} + +interface FileTreeProps { + files: FileNode[]; + handleFileSelect: (filePath: string | null) => Promise; + showHiddenFiles: boolean; +} + +const useSize = (target: React.RefObject): Size | undefined => { + const [size, setSize] = useState(); useLayoutEffect(() => { - setSize(target.current.getBoundingClientRect()); + if (target.current) { + setSize(target.current.getBoundingClientRect()); + } }, [target]); useResizeObserver(target, (entry) => setSize(entry.contentRect)); return size; }; -const FileIcon = ({ node }) => { +const FileIcon = ({ node }: { node: NodeApi }) => { if (node.isLeaf) { return ; } @@ -26,7 +40,21 @@ const FileIcon = ({ node }) => { ); }; -const Node = ({ node, style, dragHandle }) => { +// Define a Node component that matches what React-Arborist expects +function Node(props: any) { + const { node, style, dragHandle } = props; + + const handleClick = () => { + if (node.isInternal) { + node.toggle(); + } else { + const treeProps = node.tree.props as any; + if (typeof treeProps.onNodeClick === 'function') { + treeProps.onNodeClick(node); + } + } + }; + return (
{ whiteSpace: 'nowrap', overflow: 'hidden', }} - onClick={() => { - if (node.isInternal) { - node.toggle(); - } else { - node.tree.props.onNodeClick(node); - } - }} + onClick={handleClick} > {
); -}; +} -const FileTree = ({ files, handleFileSelect, showHiddenFiles }) => { - const target = useRef(null); +const FileTree: React.FC = ({ + files, + handleFileSelect, + showHiddenFiles, +}) => { + const target = useRef(null); const size = useSize(target); - files = files.filter((file) => { + const filteredFiles = files.filter((file) => { if (file.name.startsWith('.') && !showHiddenFiles) { return false; } @@ -83,22 +109,27 @@ const FileTree = ({ files, handleFileSelect, showHiddenFiles }) => { > {size && ( { + const fileNode = node.data as FileNode; if (!node.isInternal) { - handleFileSelect(node.data.path); - } - }} - onNodeClick={(node) => { - if (!node.isInternal) { - handleFileSelect(node.data.path); + handleFileSelect(fileNode.path); } }} + {...({ + // Use a spread with type assertion to add onNodeClick + onNodeClick: (node: NodeApi) => { + const fileNode = node.data as FileNode; + if (!node.isInternal) { + handleFileSelect(fileNode.path); + } + }, + } as any)} > {Node}