feat: request for tree

This commit is contained in:
nikita
2026-04-05 00:56:48 +03:00
parent 6b82c99d50
commit 07066ec8c0
5 changed files with 359 additions and 162 deletions
+88 -105
View File
@@ -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>
);