반응형
참고
- 파일 브라우저 만들기 (React File Browser with chonky)
- glob으로 파일, 폴더 목록 찾기
- Mui Tree View로 파일, 폴더 뷰 만들기
- Mui Tree View로 파일, 폴더 뷰 만들기 (with Node JS)
- Mui로 파일 브라우저 만들기
- 파일 브라우저 만들기 (with Node JS)
- 파일 브라우저에서 파일 다운로드하기
파일 브라우저를 로컬에서 만들었으니, Node JS 서버와 파일 브라우저를 연동해보자.
위의 폴더/파일이 React Mui로 File Browser가 나오도록 구현하였다.
Node JS 연동
먼저 FileBrowser에 localData를 지우고, 다시 Node JS와 연동한다.
import React, { useEffect, useState } from "react";
import TreeView from "@mui/lab/TreeView";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
import TreeItem from "@mui/lab/TreeItem";
import FileUI from "./FileUI";
const FileBrowser = () => {
const [treeInfo, setTreeInfo] = useState({});
let tmpTreeInfo = {};
let nodeId = 0;
const appendChild = (arr, info) => {
if (arr.child === undefined) arr.child = [];
if (arr.child.findIndex((item) => item.label === info) === -1) {
arr.child.push({ label: info, nodeId });
nodeId++;
}
};
const makeDirectories = (directories) => {
tmpTreeInfo = {};
for (let d of directories) {
let split = d.split("/");
let len = split.length;
let current = tmpTreeInfo;
for (let i = 0; i < len; i++) {
appendChild(current, split[i]);
current = current.child.find((item) => item.label === split[i]);
}
}
console.log(tmpTreeInfo);
setTreeInfo(tmpTreeInfo);
};
const getFiles = () => {
// setTreeInfo(localData);
// return;
let server = `http://192.168.55.120:3002`;
let path = `D:\\github\\globfiles\\**`;
fetch(`${server}/useGlob?path=${path}`)
.then((res) => res.json())
.then((data) => makeDirectories(data.findPath));
};
const makeTreeItem = (info, parent) => {
if (info.child === undefined) return;
return info.child.map((item, idx) => (
<TreeItem
key={idx}
nodeId={item.nodeId.toString()}
label={item.label}
onClick={() => console.log(`${parent}/${item.label}`)}
>
{makeTreeItem(item, `${parent}/${item.label}`)}
</TreeItem>
));
};
useEffect(() => {
getFiles();
}, []);
return (
<div
style={{
display: "grid",
gridTemplateColumns: "20% 1% auto",
gridGap: "25px",
width: "100%",
}}
>
{/* <button onClick={getFiles}>test</button> */}
<div>
<TreeView
aria-label="file system navigator"
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
sx={{ height: 500, overflowX: "hidden" }}
//sx={{ height: 240, flexGrow: 1, maxWidth: 400, overflowY: "auto" }}
>
{makeTreeItem(treeInfo, "")}
</TreeView>
</div>
<div style={{ borderRight: "2px solid black" }} />
<div>
<FileUI pathInfo={"test/folder/temp"}/>
<FileUI pathInfo={"test/folder/abcdef.json"}/>
<FileUI pathInfo={"test/folder/abc12341234.txt"}/>
<FileUI pathInfo={"test/folder/abc12341234.txt"}/>
<FileUI pathInfo={"test/folder/abc1234123412341234.txt"}/>
<FileUI pathInfo={"test/folder/abc123412341234123412341234.json"}/>
<FileUI pathInfo={"test/folder/text.csv"}/>
<FileUI pathInfo={"test/folder/text.txt"}/>
<FileUI pathInfo={"test/folder/text.txt"}/>
<FileUI pathInfo={"test/folder/text.txt"}/>
</div>
</div>
);
};
export default FileBrowser;
현재 구현된 내용으로 TreeItem에는 onClick에서 해당 경로를 출력하도록 구현하였다.
const makeTreeItem = (info, parent) => {
if (info.child === undefined) return;
return info.child.map((item, idx) => (
<TreeItem
key={idx}
nodeId={item.nodeId.toString()}
label={item.label}
onClick={() => console.log(`${parent}/${item.label}`)}
>
{makeTreeItem(item, `${parent}/${item.label}`)}
</TreeItem>
));
};
실제로 폴더 뷰를 클릭하면 경로가 출력된다.
선택한 폴더 정보 가져오기
getFiles를 참고하여 아래의 함수를 만든다.
const [fileUi, setFileUI] = useState([]);
...
const getFilesForFileBrowser = (path) => {
let server = `http://192.168.55.120:3002`;
/* /D:/... 앞의 / 삭제 */
path = path.substring(1, path.length);
fetch(`${server}/useGlob?path=${path}/*`)
.then((res) => res.json())
.then((data) => setFileUI(data.findPath));
}
makeTreeItem의 onClick을 위의 메서드로 수정한다.
그러면 fileUi에 useState로 현재 선택된 폴더에 대한 정보를 가져올 수 있다.
const makeTreeItem = (info, parent) => {
if (info.child === undefined) return;
return info.child.map((item, idx) => (
<TreeItem
key={idx}
nodeId={item.nodeId.toString()}
label={item.label}
onClick={() => getFilesForFileBrowser(`${parent}/${item.label}`)}
>
{makeTreeItem(item, `${parent}/${item.label}`)}
</TreeItem>
));
};
TreeView에 있던 FileUI는 모두 삭제하고 fileUi를 map을 이용해 표현한다.
<div>
<TreeView
aria-label="file system navigator"
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
sx={{ height: 500, overflowX: "hidden" }}
//sx={{ height: 240, flexGrow: 1, maxWidth: 400, overflowY: "auto" }}
>
{makeTreeItem(treeInfo, "")}
</TreeView>
</div>
<div style={{ borderRight: "2px solid black" }} />
<div>
{fileUi.map((f) => <FileUI pathInfo={f}/>)}
</div>
다음과 같은 에러가 난다면 key를 추가하면 된다.
{fileUi.map((f, idx) => <FileUI key={idx} pathInfo={f}/>)}
이제 React를 실행하면 선택한 폴더에 있는 폴더와 파일이 보이게 된다.
전체 코드는 다음과 같다.
import React, { useEffect, useState } from "react";
import TreeView from "@mui/lab/TreeView";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
import TreeItem from "@mui/lab/TreeItem";
import FileUI from "./FileUI";
const FileBrowser = () => {
const [treeInfo, setTreeInfo] = useState({});
const [fileUi, setFileUI] = useState([]);
let tmpTreeInfo = {};
let nodeId = 0;
const appendChild = (arr, info) => {
if (arr.child === undefined) arr.child = [];
if (arr.child.findIndex((item) => item.label === info) === -1) {
arr.child.push({ label: info, nodeId });
nodeId++;
}
};
const makeDirectories = (directories) => {
tmpTreeInfo = {};
for (let d of directories) {
let split = d.split("/");
let len = split.length;
let current = tmpTreeInfo;
for (let i = 0; i < len; i++) {
appendChild(current, split[i]);
current = current.child.find((item) => item.label === split[i]);
}
}
console.log(tmpTreeInfo);
setTreeInfo(tmpTreeInfo);
};
const getFiles = () => {
// setTreeInfo(localData);
// return;
let server = `http://192.168.55.120:3002`;
let path = `D:\\github\\globfiles\\**`;
fetch(`${server}/useGlob?path=${path}`)
.then((res) => res.json())
.then((data) => makeDirectories(data.findPath));
};
const getFilesForFileBrowser = (path) => {
let server = `http://192.168.55.120:3002`;
/* /D:/... 앞의 / 삭제 */
path = path.substring(1, path.length);
fetch(`${server}/useGlob?path=${path}/*`)
.then((res) => res.json())
.then((data) => setFileUI(data.findPath));
}
const makeTreeItem = (info, parent) => {
if (info.child === undefined) return;
return info.child.map((item, idx) => (
<TreeItem
key={idx}
nodeId={item.nodeId.toString()}
label={item.label}
onClick={() => getFilesForFileBrowser(`${parent}/${item.label}`)}
>
{makeTreeItem(item, `${parent}/${item.label}`)}
</TreeItem>
));
};
useEffect(() => {
getFiles();
}, []);
return (
<div
style={{
display: "grid",
gridTemplateColumns: "20% 1% auto",
gridGap: "25px",
width: "100%",
}}
>
{/* <button onClick={getFiles}>test</button> */}
<div>
<TreeView
aria-label="file system navigator"
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
sx={{ height: 500, overflowX: "hidden" }}
//sx={{ height: 240, flexGrow: 1, maxWidth: 400, overflowY: "auto" }}
>
{makeTreeItem(treeInfo, "")}
</TreeView>
</div>
<div style={{ borderRight: "2px solid black" }} />
<div>
{fileUi.map((f, idx) => <FileUI key={idx} pathInfo={f}/>)}
</div>
</div>
);
};
export default FileBrowser;
반응형
댓글