From fb2d9573511b78af1c689a030702e552807b127f Mon Sep 17 00:00:00 2001 From: Dominic Elm Date: Wed, 14 Aug 2024 14:27:41 +0200 Subject: [PATCH] fix(FileTree): correctly sort file tree (#36) --- .../app/components/workbench/FileTree.tsx | 80 ++++++++++++++++++- .../bolt/app/lib/runtime/action-runner.ts | 2 +- 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/packages/bolt/app/components/workbench/FileTree.tsx b/packages/bolt/app/components/workbench/FileTree.tsx index 456f1cc..ec5ca8d 100644 --- a/packages/bolt/app/components/workbench/FileTree.tsx +++ b/packages/bolt/app/components/workbench/FileTree.tsx @@ -1,7 +1,9 @@ import { memo, useEffect, useMemo, useState, type ReactNode } from 'react'; import type { FileMap } from '~/lib/stores/files'; import { classNames } from '~/utils/classNames'; -import { renderLogger } from '~/utils/logger'; +import { createScopedLogger, renderLogger } from '~/utils/logger'; + +const logger = createScopedLogger('FileTree'); const NODE_PADDING_LEFT = 8; const DEFAULT_HIDDEN_FILES = [/\/node_modules\//, /\/\.next/, /\/\.astro/]; @@ -279,7 +281,7 @@ function buildFileList(files: FileMap, rootFolder = '/', hiddenFiles: Array) { @@ -291,3 +293,77 @@ function isHiddenFile(filePath: string, fileName: string, hiddenFiles: Array(); + const childrenMap = new Map(); + + // pre-sort nodes by name and type + nodeList.sort((a, b) => compareNodes(a, b)); + + for (const node of nodeList) { + nodeMap.set(node.fullPath, node); + + const parentPath = node.fullPath.slice(0, node.fullPath.lastIndexOf('/')); + + if (parentPath !== rootFolder.slice(0, rootFolder.lastIndexOf('/'))) { + if (!childrenMap.has(parentPath)) { + childrenMap.set(parentPath, []); + } + + childrenMap.get(parentPath)?.push(node); + } + } + + const sortedList: Node[] = []; + + const depthFirstTraversal = (path: string): void => { + const node = nodeMap.get(path); + + if (!node) { + logger.warn(`Node not found for path: ${path}`); + return; + } + + sortedList.push(node); + + const children = childrenMap.get(path); + + if (children) { + for (const child of children) { + if (child.kind === 'folder') { + depthFirstTraversal(child.fullPath); + } else { + sortedList.push(child); + } + } + } + }; + + depthFirstTraversal(rootFolder); + + return sortedList; +} + +function compareNodes(a: Node, b: Node): number { + if (a.kind !== b.kind) { + return a.kind === 'folder' ? -1 : 1; + } + + return a.name.localeCompare(b.name, undefined, { numeric: true, sensitivity: 'base' }); +} diff --git a/packages/bolt/app/lib/runtime/action-runner.ts b/packages/bolt/app/lib/runtime/action-runner.ts index 9833942..cb65f87 100644 --- a/packages/bolt/app/lib/runtime/action-runner.ts +++ b/packages/bolt/app/lib/runtime/action-runner.ts @@ -91,7 +91,7 @@ export class ActionRunner { return this.#executeAction(actionId); }) .catch((error) => { - console.error('Action execution failed:', error); + console.error('Action failed:', error); }); }