feat: remove folders & create folder

This commit is contained in:
nikita
2026-04-05 03:28:31 +03:00
parent 5073cfd357
commit 178c3b53f7
6 changed files with 206 additions and 38 deletions
+101 -32
View File
@@ -1,5 +1,5 @@
import { create } from "zustand";
import type { FileNode } from "../types";
import type { FileNode, Interpreter, DialogState } from "../types";
import {
addPaths,
getAllFolderPaths,
@@ -52,13 +52,11 @@ interface IDEState {
searchQuery: string;
showSearch: boolean;
isInitialized: boolean;
interpreters: Interpreter[];
// Диалоги и контекстные меню
contextMenu: { x: number; y: number; node: FileNode | null } | null;
dialog: {
type: "newFile" | "newFolder" | "rename";
node: FileNode | null;
} | null;
dialog: DialogState | null;
tabContextMenu: { x: number; y: number; file: FileNode } | null;
// Действия с файлами
@@ -78,6 +76,9 @@ interface IDEState {
deleteRoot: () => void;
createNewProject: () => void;
// Интерпретаторы
fetchInterpreters: () => Promise<void>;
// API методы
fetchTree: () => Promise<void>;
createScript: (payload: {
@@ -85,11 +86,13 @@ interface IDEState {
interpreter_id: number;
path: string;
}) => Promise<void>;
createFolder: (path: string) => Promise<void>;
updateScript: (
id: number,
payload: { content: string; interpreter_id: number; path: string },
) => Promise<void>;
deleteScript: (id: number) => Promise<void>;
deleteFolder: (payload: { path: string }) => Promise<void>;
saveActiveFile: () => Promise<void>;
// Поиск
@@ -114,7 +117,7 @@ interface IDEState {
initialize: (initialFiles: FileNode) => void;
// Диалог подтверждения
handleDialogConfirm: (value: string) => Promise<void>;
handleDialogConfirm: (value: string, interpreterId?: number) => Promise<void>;
handleDeleteNode: (node: FileNode) => Promise<void>;
}
@@ -131,6 +134,7 @@ export const useIDEStore = create<IDEState>((set, get) => ({
contextMenu: null,
dialog: null,
tabContextMenu: null,
interpreters: [],
// Инициализация
initialize: (initialFiles: FileNode) => {
@@ -295,10 +299,21 @@ export const useIDEStore = create<IDEState>((set, get) => ({
});
},
// Интерпретаторы
fetchInterpreters: async () => {
try {
const interpreters = await scriptsApi.getInterpreters();
set({ interpreters });
} catch (e) {
console.error("Failed to fetch interpreters:", e);
}
},
// API: загрузка дерева с сервера
fetchTree: async () => {
try {
const data = await scriptsApi.getTree();
const { expandedFolders } = get();
const convertItem = (item: any): FileNode => {
const node: FileNode = {
@@ -332,7 +347,7 @@ export const useIDEStore = create<IDEState>((set, get) => ({
type: "folder",
children: roots,
},
expandedFolders: new Set(),
expandedFolders,
isInitialized: true,
});
} catch (e) {
@@ -352,6 +367,37 @@ export const useIDEStore = create<IDEState>((set, get) => ({
}
},
// API: создание папки
createFolder: async (path: string) => {
try {
await scriptsApi.createFolder(path);
await get().fetchTree();
} catch (e) {
console.error("Failed to create folder:", e);
throw e;
}
},
// API: удаление папки
deleteFolder: async ({ path }: { path: string }) => {
try {
const { openFiles } = get();
// Закрываем все файлы, которые находятся в удаляемой папке
const folderPathPrefix = path.endsWith("/") ? path : `${path}/`;
const filesToClose = openFiles.filter(
(f) => f.path === path || f.path?.startsWith(folderPathPrefix),
);
filesToClose.forEach((f) => get().closeFile(f));
await scriptsApi.deleteFolder(path);
await get().fetchTree();
} catch (e) {
console.error("Failed to delete folder:", e);
throw e;
}
},
// API: обновление скрипта
updateScript: async (id, payload) => {
try {
@@ -412,7 +458,7 @@ export const useIDEStore = create<IDEState>((set, get) => ({
setTabContextMenu: (menu) => set({ tabContextMenu: menu }),
// Подтверждение диалога
handleDialogConfirm: async (value: string) => {
handleDialogConfirm: async (value: string, interpreterId?: number) => {
const { dialog, files, toggleFolder, autoExpandPaths } = get();
if (!dialog) return;
@@ -480,31 +526,52 @@ export const useIDEStore = create<IDEState>((set, get) => ({
const savedExpandedFolders = new Set(get().expandedFolders);
try {
const result = await scriptsApi.createScript({
content: "",
interpreter_id: 1,
path: fullPath,
});
// Создание папки
if (dialog.type === "newFolder" && !isFile) {
await scriptsApi.createFolder(fullPath);
await get().fetchTree();
await get().fetchTree();
// Восстанавливаем раскрытые папки
set({ expandedFolders: savedExpandedFolders });
// Восстанавливаем раскрытые папки
set({ expandedFolders: savedExpandedFolders });
// Собираем все пути от корня до родительской папки
const allParentPaths: string[] = [];
let current = parentPath;
while (current) {
allParentPaths.push(current);
const parts = current.split("/");
parts.pop();
current = parts.join("/");
}
// Собираем все пути от корня до родительской папки
const allParentPaths: string[] = [];
let current = parentPath;
while (current) {
allParentPaths.push(current);
const parts = current.split("/");
parts.pop();
current = parts.join("/");
}
// Раскрываем родительскую цепочку
autoExpandPaths(new Set(allParentPaths));
} else {
// Создание файла
const result = await scriptsApi.createScript({
content: "",
interpreter_id: interpreterId || 0,
path: fullPath,
});
// Раскрываем родительскую цепочку
autoExpandPaths(new Set(allParentPaths));
await get().fetchTree();
// Восстанавливаем раскрытые папки
set({ expandedFolders: savedExpandedFolders });
// Собираем все пути от корня до родительской папки
const allParentPaths: string[] = [];
let current = parentPath;
while (current) {
allParentPaths.push(current);
const parts = current.split("/");
parts.pop();
current = parts.join("/");
}
// Раскрываем родительскую цепочку
autoExpandPaths(new Set(allParentPaths));
if (isFile) {
const createdNode: FileNode = {
id: result.id,
name: finalName,
@@ -529,12 +596,14 @@ export const useIDEStore = create<IDEState>((set, get) => ({
if (isRootNode) {
get().deleteRoot();
} else if (window.confirm(`Delete "${node.name}"?`)) {
if (node.id) {
try {
try {
if (node.type === "folder") {
await get().deleteFolder({ path: node.path || node.name });
} else if (node.id) {
await get().deleteScript(node.id);
} catch (e) {
console.error("Failed to delete:", e);
}
} catch (e) {
console.error("Failed to delete:", e);
}
}
},