feat: update tamplates
ci-front / build (push) Successful in 2m18s

This commit is contained in:
nikita
2026-04-05 07:07:14 +03:00
parent 2bc3da21fd
commit 337e5891f3
3 changed files with 64 additions and 81 deletions
@@ -2,6 +2,8 @@ import React from "react";
import type { FileNode } from "../types"; import type { FileNode } from "../types";
import { FilePickerItem } from "./FilePickerItem"; import { FilePickerItem } from "./FilePickerItem";
import { useFilePickerStore } from "../store/useFilePickerStore"; import { useFilePickerStore } from "../store/useFilePickerStore";
import { TerminalOutput } from "@/modules/terminal";
import { useTerminalStore } from "@/modules/terminal/store/useTerminalStore";
interface FilePickerProps { interface FilePickerProps {
files: FileNode; files: FileNode;
@@ -55,6 +57,9 @@ const FilePickerTree: React.FC<{
}; };
export const FilePicker: React.FC<FilePickerProps> = ({ files, onRun }) => { export const FilePicker: React.FC<FilePickerProps> = ({ files, onRun }) => {
const terminalOpen = useTerminalStore((s) => s.isOpen);
const jobs = useTerminalStore((s) => s.jobs);
return ( return (
<div <div
style={{ style={{
@@ -63,6 +68,13 @@ export const FilePicker: React.FC<FilePickerProps> = ({ files, onRun }) => {
backgroundColor: "var(--bg-primary)", backgroundColor: "var(--bg-primary)",
}} }}
> >
{/* Terminal — сверху, над списком файлов */}
{terminalOpen && jobs.length > 0 && (
<div style={{ height: 250 }}>
<TerminalOutput />
</div>
)}
{(files.children || []).map((child, idx) => ( {(files.children || []).map((child, idx) => (
<FilePickerTree key={idx} node={child} level={0} onRun={onRun} /> <FilePickerTree key={idx} node={child} level={0} onRun={onRun} />
))} ))}
@@ -60,21 +60,14 @@ export const RunScriptModal: React.FC<RunScriptModalProps> = ({
// 4. Ждём завершения по id // 4. Ждём завершения по id
const jobResult = await scriptsApi.waitJob(runResult.id); const jobResult = await scriptsApi.waitJob(runResult.id);
// 5. Обновляем джоб // 5. Обновляем существующий джоб (не создаём новый!)
addJob({ const terminalStore = useTerminalStore.getState();
id: jobResult.id, terminalStore.updateJob(runResult.id, {
scriptPath,
command: jobResult.command, command: jobResult.command,
stdin: jobResult.stdin, stdin: jobResult.stdin,
});
// Обновляем с финальным статусом
const terminalStore = useTerminalStore.getState();
terminalStore.updateJob(jobResult.id, {
status: jobResult.status, status: jobResult.status,
stdout: jobResult.stdout, stdout: jobResult.stdout,
stderr: jobResult.stderr, stderr: jobResult.stderr,
stdin: jobResult.stdin,
isRunning: false, isRunning: false,
}); });
+49 -71
View File
@@ -1,11 +1,9 @@
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { FiEdit3, FiPlay } from "react-icons/fi"; import { FiEdit3 } from "react-icons/fi";
import { FaSpinner } from "react-icons/fa"; import { FaSpinner } from "react-icons/fa";
import { FilePicker } from "../modules/ide"; import { FilePicker } from "../modules/ide";
import { RunScriptModal } from "../modules/ide/components/RunScriptModal"; 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 type { FileNode } from "../modules/ide";
import { scriptsApi } from "../modules/ide/api/scripts.api"; import { scriptsApi } from "../modules/ide/api/scripts.api";
@@ -50,9 +48,6 @@ export const TemplatesPage = () => {
scriptId: number; scriptId: number;
} | null>(null); } | null>(null);
const terminalOpen = useTerminalStore((s) => s.isOpen);
const [terminalHeight] = useState(300);
useEffect(() => { useEffect(() => {
scriptsApi scriptsApi
.getTree() .getTree()
@@ -78,22 +73,21 @@ export const TemplatesPage = () => {
<div <div
style={{ style={{
height: "100vh", height: "100vh",
position: "relative",
backgroundColor: "var(--bg-primary)", backgroundColor: "var(--bg-primary)",
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
}} }}
> >
{/* Floating header */} {/* Header bar */}
<div <div
style={{ style={{
position: "absolute",
top: "16px",
right: "16px",
zIndex: 10,
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
gap: "16px", justifyContent: "flex-end",
padding: "12px 16px",
borderBottom: "1px solid var(--border)",
backgroundColor: "var(--card-bg)",
flexShrink: 0,
}} }}
> >
{/* Open in Editor button */} {/* Open in Editor button */}
@@ -125,68 +119,52 @@ export const TemplatesPage = () => {
</button> </button>
</div> </div>
{/* File Picker + Terminal */} {/* File Picker (terminal встроен внутрь) */}
<div <div style={{ flex: 1, overflow: "hidden" }}>
style={{ {loading ? (
flex: 1, <div
display: "flex", style={{
flexDirection: "column", height: "100%",
overflow: "hidden", display: "flex",
}} alignItems: "center",
> justifyContent: "center",
<div style={{ flex: 1, overflow: "hidden" }}> }}
{loading ? ( >
<div <FaSpinner
size={24}
style={{ style={{
height: "100%", color: "var(--accent)",
display: "flex", animation: "spin 1s linear infinite",
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> </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> </div>
{/* Run Script Modal */} {/* Run Script Modal */}