import React, { useState } from 'react' import { Menu, MenuItem, Typography } from '@mui/material' import ExpandMoreIcon from '@mui/icons-material/ExpandMore' import ChevronRightIcon from '@mui/icons-material/ChevronRight' import MuiTreeView from '@mui/lab/TreeView' import MuiTreeItem from '@mui/lab/TreeItem' import DeleteConfirmationModal from './deleteConfirmationModal' import NameInputModal from './nameInputModal' import { TreeNode } from '../utils/types' interface Props { node: TreeNode handleSelect: (filePath: string) => void deleteNode: (path: string, isFolder: boolean) => void addFile: (path: string) => void addFolder: (path: string) => void rename: (oldPath: string, newPath: string) => void } interface TreeViewProps extends Props { defaultExpanded?: string[] } const TreeView = ({ node, handleSelect, deleteNode, addFile, addFolder, rename, defaultExpanded }: TreeViewProps) => { const renderTree = (nodes: TreeNode) => ( } > {Array.isArray(nodes.children) ? nodes.children.map((node) => renderTree(node)) : null} ) return ( } defaultExpandIcon={} defaultExpanded={defaultExpanded} sx={{ flexGrow: 1, maxWidth: 400, overflowY: 'auto' }} > {renderTree(node)} ) } export default TreeView const TreeItemWithContextMenu = ({ node, handleSelect, deleteNode, addFile, addFolder, rename }: Props) => { const [deleteConfirmationModalOpen, setDeleteConfirmationModalOpen] = useState(false) const [deleteConfirmationModalMessage, setDeleteConfirmationModalMessage] = useState('') const [defaultInputModalName, setDefaultInputModalName] = useState('') const [nameInputModalOpen, setNameInputModalOpen] = useState(false) const [nameInputModalTitle, setNameInputModalTitle] = useState('') const [nameInputModalActionLabel, setNameInputModalActionLabel] = useState('') const [nameInputModalForFolder, setNameInputModalForFolder] = useState(false) const [contextMenu, setContextMenu] = useState<{ mouseX: number mouseY: number } | null>(null) const launchProgram = (event: React.MouseEvent) => { event.stopPropagation() const baseUrl = window.location.origin window.open(`${baseUrl}/SASjsApi/stp/execute?_program=${node.relativePath}`) } const launchProgramWithDebug = (event: React.MouseEvent) => { event.stopPropagation() const baseUrl = window.location.origin window.open( `${baseUrl}/SASjsApi/stp/execute?_program=${node.relativePath}&_debug=131` ) } const handleContextMenu = (event: React.MouseEvent) => { event.preventDefault() event.stopPropagation() setContextMenu( contextMenu === null ? { mouseX: event.clientX + 2, mouseY: event.clientY - 6 } : null ) } const handleClose = (event: any) => { event.stopPropagation() setContextMenu(null) } const handleItemClick = (event: React.MouseEvent) => { if (node.children.length) return handleSelect(node.relativePath) } const handleDeleteItemClick = (event: React.MouseEvent) => { event.stopPropagation() setContextMenu(null) setDeleteConfirmationModalOpen(true) setDeleteConfirmationModalMessage( `Are you sure you want to delete ${node.isFolder ? 'folder' : 'file'} "${ node.relativePath }"?` ) } const deleteConfirm = () => { setDeleteConfirmationModalOpen(false) deleteNode(node.relativePath, node.isFolder) } const handleNewFolderItemClick = (event: React.MouseEvent) => { event.stopPropagation() setContextMenu(null) setNameInputModalOpen(true) setNameInputModalTitle('Add Folder') setNameInputModalActionLabel('Add') setNameInputModalForFolder(true) setDefaultInputModalName('') } const handleNewFileItemClick = (event: React.MouseEvent) => { event.stopPropagation() setContextMenu(null) setNameInputModalOpen(true) setNameInputModalTitle('Add File') setNameInputModalActionLabel('Add') setNameInputModalForFolder(false) setDefaultInputModalName('') } const addFileFolder = (name: string) => { setNameInputModalOpen(false) const path = node.relativePath + '/' + name if (nameInputModalForFolder) addFolder(path) else addFile(path) } const handleRenameItemClick = (event: React.MouseEvent) => { event.stopPropagation() setContextMenu(null) setNameInputModalOpen(true) setNameInputModalTitle('Rename') setNameInputModalActionLabel('Rename') setNameInputModalForFolder(node.isFolder) setDefaultInputModalName(node.relativePath.split('/').pop() ?? '') } const renameFileFolder = (name: string) => { setNameInputModalOpen(false) const oldPath = node.relativePath const splittedPath = node.relativePath.split('/') splittedPath.splice(-1, 1, name) const newPath = splittedPath.join('/') rename(oldPath, newPath) } return (
{node.name} {node.isFolder ? ( <> Add Folder Add File ) : ( <> Launch Launch and Debug )} {!!node.relativePath && ( <> Rename Delete )}
) }