Dominic Elm commited on
Commit
fb2d957
·
unverified ·
1 Parent(s): d5a29c2

fix(FileTree): correctly sort file tree (#36)

Browse files
packages/bolt/app/components/workbench/FileTree.tsx CHANGED
@@ -1,7 +1,9 @@
1
  import { memo, useEffect, useMemo, useState, type ReactNode } from 'react';
2
  import type { FileMap } from '~/lib/stores/files';
3
  import { classNames } from '~/utils/classNames';
4
- import { renderLogger } from '~/utils/logger';
 
 
5
 
6
  const NODE_PADDING_LEFT = 8;
7
  const DEFAULT_HIDDEN_FILES = [/\/node_modules\//, /\/\.next/, /\/\.astro/];
@@ -279,7 +281,7 @@ function buildFileList(files: FileMap, rootFolder = '/', hiddenFiles: Array<stri
279
  }
280
  }
281
 
282
- return fileList;
283
  }
284
 
285
  function isHiddenFile(filePath: string, fileName: string, hiddenFiles: Array<string | RegExp>) {
@@ -291,3 +293,77 @@ function isHiddenFile(filePath: string, fileName: string, hiddenFiles: Array<str
291
  return pathOrRegex.test(filePath);
292
  });
293
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import { memo, useEffect, useMemo, useState, type ReactNode } from 'react';
2
  import type { FileMap } from '~/lib/stores/files';
3
  import { classNames } from '~/utils/classNames';
4
+ import { createScopedLogger, renderLogger } from '~/utils/logger';
5
+
6
+ const logger = createScopedLogger('FileTree');
7
 
8
  const NODE_PADDING_LEFT = 8;
9
  const DEFAULT_HIDDEN_FILES = [/\/node_modules\//, /\/\.next/, /\/\.astro/];
 
281
  }
282
  }
283
 
284
+ return sortFileList(rootFolder, fileList);
285
  }
286
 
287
  function isHiddenFile(filePath: string, fileName: string, hiddenFiles: Array<string | RegExp>) {
 
293
  return pathOrRegex.test(filePath);
294
  });
295
  }
296
+
297
+ /**
298
+ * Sorts the given list of nodes into a tree structure (still a flat list).
299
+ *
300
+ * This function organizes the nodes into a hierarchical structure based on their paths,
301
+ * with folders appearing before files and all items sorted alphabetically within their level.
302
+ *
303
+ * @note This function mutates the given `nodeList` array for performance reasons.
304
+ *
305
+ * @param rootFolder - The path of the root folder to start the sorting from.
306
+ * @param nodeList - The list of nodes to be sorted.
307
+ *
308
+ * @returns A new array of nodes sorted in depth-first order.
309
+ */
310
+ function sortFileList(rootFolder: string, nodeList: Node[]): Node[] {
311
+ logger.trace('sortFileList');
312
+
313
+ const nodeMap = new Map<string, Node>();
314
+ const childrenMap = new Map<string, Node[]>();
315
+
316
+ // pre-sort nodes by name and type
317
+ nodeList.sort((a, b) => compareNodes(a, b));
318
+
319
+ for (const node of nodeList) {
320
+ nodeMap.set(node.fullPath, node);
321
+
322
+ const parentPath = node.fullPath.slice(0, node.fullPath.lastIndexOf('/'));
323
+
324
+ if (parentPath !== rootFolder.slice(0, rootFolder.lastIndexOf('/'))) {
325
+ if (!childrenMap.has(parentPath)) {
326
+ childrenMap.set(parentPath, []);
327
+ }
328
+
329
+ childrenMap.get(parentPath)?.push(node);
330
+ }
331
+ }
332
+
333
+ const sortedList: Node[] = [];
334
+
335
+ const depthFirstTraversal = (path: string): void => {
336
+ const node = nodeMap.get(path);
337
+
338
+ if (!node) {
339
+ logger.warn(`Node not found for path: ${path}`);
340
+ return;
341
+ }
342
+
343
+ sortedList.push(node);
344
+
345
+ const children = childrenMap.get(path);
346
+
347
+ if (children) {
348
+ for (const child of children) {
349
+ if (child.kind === 'folder') {
350
+ depthFirstTraversal(child.fullPath);
351
+ } else {
352
+ sortedList.push(child);
353
+ }
354
+ }
355
+ }
356
+ };
357
+
358
+ depthFirstTraversal(rootFolder);
359
+
360
+ return sortedList;
361
+ }
362
+
363
+ function compareNodes(a: Node, b: Node): number {
364
+ if (a.kind !== b.kind) {
365
+ return a.kind === 'folder' ? -1 : 1;
366
+ }
367
+
368
+ return a.name.localeCompare(b.name, undefined, { numeric: true, sensitivity: 'base' });
369
+ }
packages/bolt/app/lib/runtime/action-runner.ts CHANGED
@@ -91,7 +91,7 @@ export class ActionRunner {
91
  return this.#executeAction(actionId);
92
  })
93
  .catch((error) => {
94
- console.error('Action execution failed:', error);
95
  });
96
  }
97
 
 
91
  return this.#executeAction(actionId);
92
  })
93
  .catch((error) => {
94
+ console.error('Action failed:', error);
95
  });
96
  }
97