@@ -2,7 +2,10 @@ 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 { FilePicker } from "../modules/ide";
|
||||
import { RunScriptModal } from "../modules/ide/components/RunScriptModal";
|
||||
import { TerminalOutput } from "../modules/terminal";
|
||||
import { useTerminalStore } from "../modules/terminal/store/useTerminalStore";
|
||||
import type { FileNode } from "../modules/ide";
|
||||
import { scriptsApi } from "../modules/ide/api/scripts.api";
|
||||
|
||||
@@ -40,11 +43,15 @@ const convertTreeToFileNode = (data: any[]): FileNode => {
|
||||
|
||||
export const TemplatesPage = () => {
|
||||
const navigate = useNavigate();
|
||||
const selectedPaths = useFilePickerStore((s) => s.selectedPaths);
|
||||
const runningScripts = useFilePickerStore((s) => s.runningScripts);
|
||||
const runScript = useFilePickerStore((s) => s.runScript);
|
||||
const [files, setFiles] = useState<FileNode | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [runModal, setRunModal] = useState<{
|
||||
scriptPath: string;
|
||||
scriptId: number;
|
||||
} | null>(null);
|
||||
|
||||
const terminalOpen = useTerminalStore((s) => s.isOpen);
|
||||
const [terminalHeight] = useState(300);
|
||||
|
||||
useEffect(() => {
|
||||
scriptsApi
|
||||
@@ -59,18 +66,22 @@ export const TemplatesPage = () => {
|
||||
.finally(() => setLoading(false));
|
||||
}, []);
|
||||
|
||||
const handleRun = async (path: string) => {
|
||||
await runScript(path);
|
||||
const handleRun = (path: string, id?: number) => {
|
||||
if (!id) {
|
||||
console.warn("Script ID not found for:", path);
|
||||
return;
|
||||
}
|
||||
setRunModal({ scriptPath: path, scriptId: id });
|
||||
};
|
||||
|
||||
const runningCount = runningScripts.size;
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
height: "100vh",
|
||||
position: "relative",
|
||||
backgroundColor: "var(--bg-primary)",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
{/* Floating header */}
|
||||
@@ -85,24 +96,6 @@ export const TemplatesPage = () => {
|
||||
gap: "16px",
|
||||
}}
|
||||
>
|
||||
{/* Running scripts counter */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "8px",
|
||||
padding: "6px 12px",
|
||||
backgroundColor: "var(--card-bg)",
|
||||
borderRadius: "4px",
|
||||
border: "1px solid var(--border)",
|
||||
}}
|
||||
>
|
||||
<FiPlay size={13} color="#61c454" />
|
||||
<span style={{ fontSize: "12px", color: "var(--text-secondary)" }}>
|
||||
{runningCount} script{runningCount !== 1 ? "s" : ""} running
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Open in Editor button */}
|
||||
<button
|
||||
onClick={() => navigate("/ide")}
|
||||
@@ -132,29 +125,78 @@ export const TemplatesPage = () => {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* File Picker */}
|
||||
<div style={{ height: "100%", overflow: "hidden" }}>
|
||||
{loading ? (
|
||||
<div
|
||||
style={{
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<FaSpinner
|
||||
size={24}
|
||||
{/* File Picker + Terminal */}
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
<div style={{ flex: 1, overflow: "hidden" }}>
|
||||
{loading ? (
|
||||
<div
|
||||
style={{
|
||||
color: "var(--accent)",
|
||||
animation: "spin 1s linear infinite",
|
||||
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}
|
||||
onRun={(path) => {
|
||||
// Находим ID скрипта по пути
|
||||
const findNodeById = (
|
||||
node: FileNode,
|
||||
p: string,
|
||||
): FileNode | null => {
|
||||
if (node.path === p) return node;
|
||||
if (node.children) {
|
||||
for (const child of node.children) {
|
||||
const found = findNodeById(child, p);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
const node = findNodeById(files, path);
|
||||
if (node?.id) {
|
||||
handleRun(path, node.id);
|
||||
} else {
|
||||
console.warn("Script ID not found for path:", path);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
{/* Terminal */}
|
||||
{terminalOpen && (
|
||||
<div style={{ height: `${terminalHeight}px`, flexShrink: 0 }}>
|
||||
<TerminalOutput />
|
||||
</div>
|
||||
) : files ? (
|
||||
<FilePicker files={files} onRun={handleRun} />
|
||||
) : null}
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Run Script Modal */}
|
||||
{runModal && (
|
||||
<RunScriptModal
|
||||
scriptPath={runModal.scriptPath}
|
||||
scriptId={runModal.scriptId}
|
||||
onClose={() => setRunModal(null)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user