feat: request for tree
This commit is contained in:
@@ -1,117 +1,81 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { FiEdit3, FiPlay } from "react-icons/fi";
|
||||
import { FaSpinner } from "react-icons/fa";
|
||||
import { FilePicker, useFilePickerStore } from "../modules/ide";
|
||||
import type { FileNode } from "../modules/ide";
|
||||
import { scriptsApi } from "../modules/ide/api/scripts.api";
|
||||
|
||||
const mockFiles: FileNode = {
|
||||
name: "templates",
|
||||
type: "folder",
|
||||
children: [
|
||||
{
|
||||
name: "python-basic",
|
||||
type: "folder",
|
||||
children: [
|
||||
{
|
||||
name: "src",
|
||||
type: "folder",
|
||||
children: [
|
||||
{
|
||||
name: "main.py",
|
||||
type: "file",
|
||||
content:
|
||||
'print("Hello, World!")\n\ndef main():\n print("Welcome!")\n\nif __name__ == "__main__":\n main()',
|
||||
},
|
||||
{
|
||||
name: "utils.py",
|
||||
type: "file",
|
||||
content: "def helper():\n return 42",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "README.md",
|
||||
type: "file",
|
||||
content: "# Python Project\n\nA basic Python project.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "react-starter",
|
||||
type: "folder",
|
||||
children: [
|
||||
{
|
||||
name: "src",
|
||||
type: "folder",
|
||||
children: [
|
||||
{
|
||||
name: "App.tsx",
|
||||
type: "file",
|
||||
content:
|
||||
'import React from "react";\n\nexport const App: React.FC = () => {\n return <div>Hello React!</div>;\n};',
|
||||
},
|
||||
{
|
||||
name: "index.tsx",
|
||||
type: "file",
|
||||
content:
|
||||
'import React from "react";\nimport { createRoot } from "react-dom/client";\nimport { App } from "./App";\n\ncreateRoot(document.getElementById("root")!).render(<App />);',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "package.json",
|
||||
type: "file",
|
||||
content: '{\n "name": "react-project",\n "version": "1.0.0"\n}',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "node-api",
|
||||
type: "folder",
|
||||
children: [
|
||||
{
|
||||
name: "src",
|
||||
type: "folder",
|
||||
children: [
|
||||
{
|
||||
name: "index.js",
|
||||
type: "file",
|
||||
content:
|
||||
'const express = require("express");\nconst app = express();\nconst PORT = 3000;\n\napp.get("/", (req, res) => {\n res.json({ message: "Hello!" });\n});\n\napp.listen(PORT, () => {\n console.log(`Server running on port ${PORT}`);\n});',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "package.json",
|
||||
type: "file",
|
||||
content:
|
||||
'{\n "name": "api-project",\n "dependencies": {\n "express": "^4.18.0"\n }\n}',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "html-css",
|
||||
type: "folder",
|
||||
children: [
|
||||
{
|
||||
name: "index.html",
|
||||
type: "file",
|
||||
content:
|
||||
'<!DOCTYPE html>\n<html>\n<head>\n <title>My Landing</title>\n <link rel="stylesheet" href="styles.css">\n</head>\n<body>\n <h1>Welcome!</h1>\n</body>\n</html>',
|
||||
},
|
||||
{
|
||||
name: "styles.css",
|
||||
type: "file",
|
||||
content:
|
||||
"body {\n font-family: sans-serif;\n margin: 0;\n padding: 2rem;\n background: #f5f5f5;\n}\n\nh1 {\n color: #333;\n}",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
const convertTreeToFileNode = (data: any[]): FileNode => {
|
||||
const nodeMap = new Map<string, FileNode>();
|
||||
const childrenMap = new Map<string, string[]>();
|
||||
|
||||
// Создаём все узлы
|
||||
data.forEach((item) => {
|
||||
nodeMap.set(item.name, {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
type: item.type === "folder" ? "folder" : "file",
|
||||
content: item.content || "",
|
||||
path: item.name,
|
||||
interpreter_id: item.interpreter_id,
|
||||
children: item.type === "folder" ? [] : undefined,
|
||||
});
|
||||
|
||||
if (item.children && item.children.length > 0) {
|
||||
childrenMap.set(item.name, item.children);
|
||||
}
|
||||
});
|
||||
|
||||
// Строим дерево
|
||||
const roots: FileNode[] = [];
|
||||
const hasParent = new Set<string>();
|
||||
|
||||
childrenMap.forEach((children, parentName) => {
|
||||
const parentNode = nodeMap.get(parentName);
|
||||
if (!parentNode) return;
|
||||
|
||||
children.forEach((childName: string) => {
|
||||
hasParent.add(childName);
|
||||
const childNode = nodeMap.get(childName);
|
||||
if (childNode && parentNode.children) {
|
||||
parentNode.children.push(childNode);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Корневые элементы — те у кого нет родителя
|
||||
nodeMap.forEach((node, name) => {
|
||||
if (!hasParent.has(name)) {
|
||||
roots.push(node);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
name: "templates",
|
||||
type: "folder",
|
||||
children: roots,
|
||||
};
|
||||
};
|
||||
|
||||
export const TemplatesPage = () => {
|
||||
const navigate = useNavigate();
|
||||
const selectedPaths = useFilePickerStore((s) => s.selectedPaths);
|
||||
const [files, setFiles] = useState<FileNode | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
scriptsApi
|
||||
.getTree()
|
||||
.then((data) => {
|
||||
setFiles(convertTreeToFileNode(data));
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error("Failed to load tree:", e);
|
||||
setFiles({ name: "templates", type: "folder", children: [] });
|
||||
})
|
||||
.finally(() => setLoading(false));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -183,7 +147,26 @@ export const TemplatesPage = () => {
|
||||
|
||||
{/* File Picker */}
|
||||
<div style={{ height: "100%", overflow: "hidden" }}>
|
||||
<FilePicker files={mockFiles} />
|
||||
{loading ? (
|
||||
<div
|
||||
style={{
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<FaSpinner
|
||||
size={24}
|
||||
style={{
|
||||
color: "var(--accent)",
|
||||
animation: "spin 1s linear infinite",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : files ? (
|
||||
<FilePicker files={files} />
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user